display.c revision 5f95f4f77efc46ff53593d750491c8f60698c983
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% DDDD IIIII SSSSS PPPP L AAA Y Y % 7% D D I SS P P L A A Y Y % 8% D D I SSS PPPP L AAAAA Y % 9% D D I SS P L A A Y % 10% DDDD IIIII SSSSS P LLLLL A A Y % 11% % 12% % 13% MagickCore Methods to Interactively Display and Edit an Image % 14% % 15% Software Design % 16% John Cristy % 17% July 1992 % 18% % 19% % 20% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization % 21% dedicated to making software imaging solutions freely available. % 22% % 23% You may not use this file except in compliance with the License. You may % 24% obtain a copy of the License at % 25% % 26% http://www.imagemagick.org/script/license.php % 27% % 28% Unless required by applicable law or agreed to in writing, software % 29% distributed under the License is distributed on an "AS IS" BASIS, % 30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31% See the License for the specific language governing permissions and % 32% limitations under the License. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 36% 37*/ 38 39/* 40 Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/artifact.h" 44#include "MagickCore/blob.h" 45#include "MagickCore/cache.h" 46#include "MagickCore/cache-private.h" 47#include "MagickCore/client.h" 48#include "MagickCore/color.h" 49#include "MagickCore/colorspace.h" 50#include "MagickCore/composite.h" 51#include "MagickCore/constitute.h" 52#include "MagickCore/decorate.h" 53#include "MagickCore/delegate.h" 54#include "MagickCore/display.h" 55#include "MagickCore/display-private.h" 56#include "MagickCore/draw.h" 57#include "MagickCore/effect.h" 58#include "MagickCore/enhance.h" 59#include "MagickCore/exception.h" 60#include "MagickCore/exception-private.h" 61#include "MagickCore/fx.h" 62#include "MagickCore/geometry.h" 63#include "MagickCore/image.h" 64#include "MagickCore/image-private.h" 65#include "MagickCore/list.h" 66#include "MagickCore/log.h" 67#include "MagickCore/magick.h" 68#include "MagickCore/memory_.h" 69#include "MagickCore/monitor.h" 70#include "MagickCore/monitor-private.h" 71#include "MagickCore/montage.h" 72#include "MagickCore/option.h" 73#include "MagickCore/paint.h" 74#include "MagickCore/pixel.h" 75#include "MagickCore/pixel-accessor.h" 76#include "MagickCore/PreRvIcccm.h" 77#include "MagickCore/property.h" 78#include "MagickCore/quantum.h" 79#include "MagickCore/quantum-private.h" 80#include "MagickCore/resize.h" 81#include "MagickCore/resource_.h" 82#include "MagickCore/shear.h" 83#include "MagickCore/segment.h" 84#include "MagickCore/string_.h" 85#include "MagickCore/string-private.h" 86#include "MagickCore/transform.h" 87#include "MagickCore/threshold.h" 88#include "MagickCore/utility.h" 89#include "MagickCore/utility-private.h" 90#include "MagickCore/version.h" 91#include "MagickCore/widget.h" 92#include "MagickCore/widget-private.h" 93#include "MagickCore/xwindow.h" 94#include "MagickCore/xwindow-private.h" 95 96#if defined(MAGICKCORE_X11_DELEGATE) 97/* 98 Define declarations. 99*/ 100#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L) 101 102/* 103 Constant declarations. 104*/ 105static const unsigned char 106 HighlightBitmap[8] = 107 { 108 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 109 }, 110 OpaqueBitmap[8] = 111 { 112 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 113 }, 114 ShadowBitmap[8] = 115 { 116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 117 }; 118 119static const char 120 *PageSizes[] = 121 { 122 "Letter", 123 "Tabloid", 124 "Ledger", 125 "Legal", 126 "Statement", 127 "Executive", 128 "A3", 129 "A4", 130 "A5", 131 "B4", 132 "B5", 133 "Folio", 134 "Quarto", 135 "10x14", 136 (char *) NULL 137 }; 138 139/* 140 Help widget declarations. 141*/ 142static const char 143 *ImageAnnotateHelp[] = 144 { 145 "In annotate mode, the Command widget has these options:", 146 "", 147 " Font Name", 148 " fixed", 149 " variable", 150 " 5x8", 151 " 6x10", 152 " 7x13bold", 153 " 8x13bold", 154 " 9x15bold", 155 " 10x20", 156 " 12x24", 157 " Browser...", 158 " Font Color", 159 " black", 160 " blue", 161 " cyan", 162 " green", 163 " gray", 164 " red", 165 " magenta", 166 " yellow", 167 " white", 168 " transparent", 169 " Browser...", 170 " Font Color", 171 " black", 172 " blue", 173 " cyan", 174 " green", 175 " gray", 176 " red", 177 " magenta", 178 " yellow", 179 " white", 180 " transparent", 181 " Browser...", 182 " Rotate Text", 183 " -90", 184 " -45", 185 " -30", 186 " 0", 187 " 30", 188 " 45", 189 " 90", 190 " 180", 191 " Dialog...", 192 " Help", 193 " Dismiss", 194 "", 195 "Choose a font name from the Font Name sub-menu. Additional", 196 "font names can be specified with the font browser. You can", 197 "change the menu names by setting the X resources font1", 198 "through font9.", 199 "", 200 "Choose a font color from the Font Color sub-menu.", 201 "Additional font colors can be specified with the color", 202 "browser. You can change the menu colors by setting the X", 203 "resources pen1 through pen9.", 204 "", 205 "If you select the color browser and press Grab, you can", 206 "choose the font color by moving the pointer to the desired", 207 "color on the screen and press any button.", 208 "", 209 "If you choose to rotate the text, choose Rotate Text from the", 210 "menu and select an angle. Typically you will only want to", 211 "rotate one line of text at a time. Depending on the angle you", 212 "choose, subsequent lines may end up overwriting each other.", 213 "", 214 "Choosing a font and its color is optional. The default font", 215 "is fixed and the default color is black. However, you must", 216 "choose a location to begin entering text and press button 1.", 217 "An underscore character will appear at the location of the", 218 "pointer. The cursor changes to a pencil to indicate you are", 219 "in text mode. To exit immediately, press Dismiss.", 220 "", 221 "In text mode, any key presses will display the character at", 222 "the location of the underscore and advance the underscore", 223 "cursor. Enter your text and once completed press Apply to", 224 "finish your image annotation. To correct errors press BACK", 225 "SPACE. To delete an entire line of text, press DELETE. Any", 226 "text that exceeds the boundaries of the image window is", 227 "automagically continued onto the next line.", 228 "", 229 "The actual color you request for the font is saved in the", 230 "image. However, the color that appears in your image window", 231 "may be different. For example, on a monochrome screen the", 232 "text will appear black or white even if you choose the color", 233 "red as the font color. However, the image saved to a file", 234 "with -write is written with red lettering. To assure the", 235 "correct color text in the final image, any PseudoClass image", 236 "is promoted to DirectClass (see miff(5)). To force a", 237 "PseudoClass image to remain PseudoClass, use -colors.", 238 (char *) NULL, 239 }, 240 *ImageChopHelp[] = 241 { 242 "In chop mode, the Command widget has these options:", 243 "", 244 " Direction", 245 " horizontal", 246 " vertical", 247 " Help", 248 " Dismiss", 249 "", 250 "If the you choose the horizontal direction (this the", 251 "default), the area of the image between the two horizontal", 252 "endpoints of the chop line is removed. Otherwise, the area", 253 "of the image between the two vertical endpoints of the chop", 254 "line is removed.", 255 "", 256 "Select a location within the image window to begin your chop,", 257 "press and hold any button. Next, move the pointer to", 258 "another location in the image. As you move a line will", 259 "connect the initial location and the pointer. When you", 260 "release the button, the area within the image to chop is", 261 "determined by which direction you choose from the Command", 262 "widget.", 263 "", 264 "To cancel the image chopping, move the pointer back to the", 265 "starting point of the line and release the button.", 266 (char *) NULL, 267 }, 268 *ImageColorEditHelp[] = 269 { 270 "In color edit mode, the Command widget has these options:", 271 "", 272 " Method", 273 " point", 274 " replace", 275 " floodfill", 276 " filltoborder", 277 " reset", 278 " Pixel Color", 279 " black", 280 " blue", 281 " cyan", 282 " green", 283 " gray", 284 " red", 285 " magenta", 286 " yellow", 287 " white", 288 " Browser...", 289 " Border Color", 290 " black", 291 " blue", 292 " cyan", 293 " green", 294 " gray", 295 " red", 296 " magenta", 297 " yellow", 298 " white", 299 " Browser...", 300 " Fuzz", 301 " 0%", 302 " 2%", 303 " 5%", 304 " 10%", 305 " 15%", 306 " Dialog...", 307 " Undo", 308 " Help", 309 " Dismiss", 310 "", 311 "Choose a color editing method from the Method sub-menu", 312 "of the Command widget. The point method recolors any pixel", 313 "selected with the pointer until the button is released. The", 314 "replace method recolors any pixel that matches the color of", 315 "the pixel you select with a button press. Floodfill recolors", 316 "any pixel that matches the color of the pixel you select with", 317 "a button press and is a neighbor. Whereas filltoborder recolors", 318 "any neighbor pixel that is not the border color. Finally reset", 319 "changes the entire image to the designated color.", 320 "", 321 "Next, choose a pixel color from the Pixel Color sub-menu.", 322 "Additional pixel colors can be specified with the color", 323 "browser. You can change the menu colors by setting the X", 324 "resources pen1 through pen9.", 325 "", 326 "Now press button 1 to select a pixel within the image window", 327 "to change its color. Additional pixels may be recolored as", 328 "prescribed by the method you choose.", 329 "", 330 "If the Magnify widget is mapped, it can be helpful in positioning", 331 "your pointer within the image (refer to button 2).", 332 "", 333 "The actual color you request for the pixels is saved in the", 334 "image. However, the color that appears in your image window", 335 "may be different. For example, on a monochrome screen the", 336 "pixel will appear black or white even if you choose the", 337 "color red as the pixel color. However, the image saved to a", 338 "file with -write is written with red pixels. To assure the", 339 "correct color text in the final image, any PseudoClass image", 340 "is promoted to DirectClass (see miff(5)). To force a", 341 "PseudoClass image to remain PseudoClass, use -colors.", 342 (char *) NULL, 343 }, 344 *ImageCompositeHelp[] = 345 { 346 "First a widget window is displayed requesting you to enter an", 347 "image name. Press Composite, Grab or type a file name.", 348 "Press Cancel if you choose not to create a composite image.", 349 "When you choose Grab, move the pointer to the desired window", 350 "and press any button.", 351 "", 352 "If the Composite image does not have any matte information,", 353 "you are informed and the file browser is displayed again.", 354 "Enter the name of a mask image. The image is typically", 355 "grayscale and the same size as the composite image. If the", 356 "image is not grayscale, it is converted to grayscale and the", 357 "resulting intensities are used as matte information.", 358 "", 359 "A small window appears showing the location of the cursor in", 360 "the image window. You are now in composite mode. To exit", 361 "immediately, press Dismiss. In composite mode, the Command", 362 "widget has these options:", 363 "", 364 " Operators", 365 " Over", 366 " In", 367 " Out", 368 " Atop", 369 " Xor", 370 " Plus", 371 " Minus", 372 " Add", 373 " Subtract", 374 " Difference", 375 " Multiply", 376 " Bumpmap", 377 " Copy", 378 " CopyRed", 379 " CopyGreen", 380 " CopyBlue", 381 " CopyOpacity", 382 " Clear", 383 " Dissolve", 384 " Displace", 385 " Help", 386 " Dismiss", 387 "", 388 "Choose a composite operation from the Operators sub-menu of", 389 "the Command widget. How each operator behaves is described", 390 "below. Image window is the image currently displayed on", 391 "your X server and image is the image obtained with the File", 392 "Browser widget.", 393 "", 394 "Over The result is the union of the two image shapes,", 395 " with image obscuring image window in the region of", 396 " overlap.", 397 "", 398 "In The result is simply image cut by the shape of", 399 " image window. None of the image data of image", 400 " window is in the result.", 401 "", 402 "Out The resulting image is image with the shape of", 403 " image window cut out.", 404 "", 405 "Atop The result is the same shape as image image window,", 406 " with image obscuring image window where the image", 407 " shapes overlap. Note this differs from over", 408 " because the portion of image outside image window's", 409 " shape does not appear in the result.", 410 "", 411 "Xor The result is the image data from both image and", 412 " image window that is outside the overlap region.", 413 " The overlap region is blank.", 414 "", 415 "Plus The result is just the sum of the image data.", 416 " Output values are cropped to QuantumRange (no overflow).", 417 "", 418 "Minus The result of image - image window, with underflow", 419 " cropped to zero.", 420 "", 421 "Add The result of image + image window, with overflow", 422 " wrapping around (mod 256).", 423 "", 424 "Subtract The result of image - image window, with underflow", 425 " wrapping around (mod 256). The add and subtract", 426 " operators can be used to perform reversible", 427 " transformations.", 428 "", 429 "Difference", 430 " The result of abs(image - image window). This", 431 " useful for comparing two very similar images.", 432 "", 433 "Multiply", 434 " The result of image * image window. This", 435 " useful for the creation of drop-shadows.", 436 "", 437 "Bumpmap The result of surface normals from image * image", 438 " window.", 439 "", 440 "Copy The resulting image is image window replaced with", 441 " image. Here the matte information is ignored.", 442 "", 443 "CopyRed The red layer of the image window is replace with", 444 " the red layer of the image. The other layers are", 445 " untouched.", 446 "", 447 "CopyGreen", 448 " The green layer of the image window is replace with", 449 " the green layer of the image. The other layers are", 450 " untouched.", 451 "", 452 "CopyBlue The blue layer of the image window is replace with", 453 " the blue layer of the image. The other layers are", 454 " untouched.", 455 "", 456 "CopyOpacity", 457 " The matte layer of the image window is replace with", 458 " the matte layer of the image. The other layers are", 459 " untouched.", 460 "", 461 "The image compositor requires a matte, or alpha channel in", 462 "the image for some operations. This extra channel usually", 463 "defines a mask which represents a sort of a cookie-cutter", 464 "for the image. This the case when matte is opaque (full", 465 "coverage) for pixels inside the shape, zero outside, and", 466 "between 0 and QuantumRange on the boundary. If image does not", 467 "have a matte channel, it is initialized with 0 for any pixel", 468 "matching in color to pixel location (0,0), otherwise QuantumRange.", 469 "", 470 "If you choose Dissolve, the composite operator becomes Over. The", 471 "image matte channel percent transparency is initialized to factor.", 472 "The image window is initialized to (100-factor). Where factor is the", 473 "value you specify in the Dialog widget.", 474 "", 475 "Displace shifts the image pixels as defined by a displacement", 476 "map. With this option, image is used as a displacement map.", 477 "Black, within the displacement map, is a maximum positive", 478 "displacement. White is a maximum negative displacement and", 479 "middle gray is neutral. The displacement is scaled to determine", 480 "the pixel shift. By default, the displacement applies in both the", 481 "horizontal and vertical directions. However, if you specify a mask,", 482 "image is the horizontal X displacement and mask the vertical Y", 483 "displacement.", 484 "", 485 "Note that matte information for image window is not retained", 486 "for colormapped X server visuals (e.g. StaticColor,", 487 "StaticColor, GrayScale, PseudoColor). Correct compositing", 488 "behavior may require a TrueColor or DirectColor visual or a", 489 "Standard Colormap.", 490 "", 491 "Choosing a composite operator is optional. The default", 492 "operator is replace. However, you must choose a location to", 493 "composite your image and press button 1. Press and hold the", 494 "button before releasing and an outline of the image will", 495 "appear to help you identify your location.", 496 "", 497 "The actual colors of the composite image is saved. However,", 498 "the color that appears in image window may be different.", 499 "For example, on a monochrome screen image window will appear", 500 "black or white even though your composited image may have", 501 "many colors. If the image is saved to a file it is written", 502 "with the correct colors. To assure the correct colors are", 503 "saved in the final image, any PseudoClass image is promoted", 504 "to DirectClass (see miff(5)). To force a PseudoClass image", 505 "to remain PseudoClass, use -colors.", 506 (char *) NULL, 507 }, 508 *ImageCutHelp[] = 509 { 510 "In cut mode, the Command widget has these options:", 511 "", 512 " Help", 513 " Dismiss", 514 "", 515 "To define a cut region, press button 1 and drag. The", 516 "cut region is defined by a highlighted rectangle that", 517 "expands or contracts as it follows the pointer. Once you", 518 "are satisfied with the cut region, release the button.", 519 "You are now in rectify mode. In rectify mode, the Command", 520 "widget has these options:", 521 "", 522 " Cut", 523 " Help", 524 " Dismiss", 525 "", 526 "You can make adjustments by moving the pointer to one of the", 527 "cut rectangle corners, pressing a button, and dragging.", 528 "Finally, press Cut to commit your copy region. To", 529 "exit without cutting the image, press Dismiss.", 530 (char *) NULL, 531 }, 532 *ImageCopyHelp[] = 533 { 534 "In copy mode, the Command widget has these options:", 535 "", 536 " Help", 537 " Dismiss", 538 "", 539 "To define a copy region, press button 1 and drag. The", 540 "copy region is defined by a highlighted rectangle that", 541 "expands or contracts as it follows the pointer. Once you", 542 "are satisfied with the copy region, release the button.", 543 "You are now in rectify mode. In rectify mode, the Command", 544 "widget has these options:", 545 "", 546 " Copy", 547 " Help", 548 " Dismiss", 549 "", 550 "You can make adjustments by moving the pointer to one of the", 551 "copy rectangle corners, pressing a button, and dragging.", 552 "Finally, press Copy to commit your copy region. To", 553 "exit without copying the image, press Dismiss.", 554 (char *) NULL, 555 }, 556 *ImageCropHelp[] = 557 { 558 "In crop mode, the Command widget has these options:", 559 "", 560 " Help", 561 " Dismiss", 562 "", 563 "To define a cropping region, press button 1 and drag. The", 564 "cropping region is defined by a highlighted rectangle that", 565 "expands or contracts as it follows the pointer. Once you", 566 "are satisfied with the cropping region, release the button.", 567 "You are now in rectify mode. In rectify mode, the Command", 568 "widget has these options:", 569 "", 570 " Crop", 571 " Help", 572 " Dismiss", 573 "", 574 "You can make adjustments by moving the pointer to one of the", 575 "cropping rectangle corners, pressing a button, and dragging.", 576 "Finally, press Crop to commit your cropping region. To", 577 "exit without cropping the image, press Dismiss.", 578 (char *) NULL, 579 }, 580 *ImageDrawHelp[] = 581 { 582 "The cursor changes to a crosshair to indicate you are in", 583 "draw mode. To exit immediately, press Dismiss. In draw mode,", 584 "the Command widget has these options:", 585 "", 586 " Element", 587 " point", 588 " line", 589 " rectangle", 590 " fill rectangle", 591 " circle", 592 " fill circle", 593 " ellipse", 594 " fill ellipse", 595 " polygon", 596 " fill polygon", 597 " Color", 598 " black", 599 " blue", 600 " cyan", 601 " green", 602 " gray", 603 " red", 604 " magenta", 605 " yellow", 606 " white", 607 " transparent", 608 " Browser...", 609 " Stipple", 610 " Brick", 611 " Diagonal", 612 " Scales", 613 " Vertical", 614 " Wavy", 615 " Translucent", 616 " Opaque", 617 " Open...", 618 " Width", 619 " 1", 620 " 2", 621 " 4", 622 " 8", 623 " 16", 624 " Dialog...", 625 " Undo", 626 " Help", 627 " Dismiss", 628 "", 629 "Choose a drawing primitive from the Element sub-menu.", 630 "", 631 "Choose a color from the Color sub-menu. Additional", 632 "colors can be specified with the color browser.", 633 "", 634 "If you choose the color browser and press Grab, you can", 635 "select the color by moving the pointer to the desired", 636 "color on the screen and press any button. The transparent", 637 "color updates the image matte channel and is useful for", 638 "image compositing.", 639 "", 640 "Choose a stipple, if appropriate, from the Stipple sub-menu.", 641 "Additional stipples can be specified with the file browser.", 642 "Stipples obtained from the file browser must be on disk in the", 643 "X11 bitmap format.", 644 "", 645 "Choose a width, if appropriate, from the Width sub-menu. To", 646 "choose a specific width select the Dialog widget.", 647 "", 648 "Choose a point in the Image window and press button 1 and", 649 "hold. Next, move the pointer to another location in the", 650 "image. As you move, a line connects the initial location and", 651 "the pointer. When you release the button, the image is", 652 "updated with the primitive you just drew. For polygons, the", 653 "image is updated when you press and release the button without", 654 "moving the pointer.", 655 "", 656 "To cancel image drawing, move the pointer back to the", 657 "starting point of the line and release the button.", 658 (char *) NULL, 659 }, 660 *DisplayHelp[] = 661 { 662 "BUTTONS", 663 " The effects of each button press is described below. Three", 664 " buttons are required. If you have a two button mouse,", 665 " button 1 and 3 are returned. Press ALT and button 3 to", 666 " simulate button 2.", 667 "", 668 " 1 Press this button to map or unmap the Command widget.", 669 "", 670 " 2 Press and drag to define a region of the image to", 671 " magnify.", 672 "", 673 " 3 Press and drag to choose from a select set of commands.", 674 " This button behaves differently if the image being", 675 " displayed is a visual image directory. Here, choose a", 676 " particular tile of the directory and press this button and", 677 " drag to select a command from a pop-up menu. Choose from", 678 " these menu items:", 679 "", 680 " Open", 681 " Next", 682 " Former", 683 " Delete", 684 " Update", 685 "", 686 " If you choose Open, the image represented by the tile is", 687 " displayed. To return to the visual image directory, choose", 688 " Next from the Command widget. Next and Former moves to the", 689 " next or former image respectively. Choose Delete to delete", 690 " a particular image tile. Finally, choose Update to", 691 " synchronize all the image tiles with their respective", 692 " images.", 693 "", 694 "COMMAND WIDGET", 695 " The Command widget lists a number of sub-menus and commands.", 696 " They are", 697 "", 698 " File", 699 " Open...", 700 " Next", 701 " Former", 702 " Select...", 703 " Save...", 704 " Print...", 705 " Delete...", 706 " New...", 707 " Visual Directory...", 708 " Quit", 709 " Edit", 710 " Undo", 711 " Redo", 712 " Cut", 713 " Copy", 714 " Paste", 715 " View", 716 " Half Size", 717 " Original Size", 718 " Double Size", 719 " Resize...", 720 " Apply", 721 " Refresh", 722 " Restore", 723 " Transform", 724 " Crop", 725 " Chop", 726 " Flop", 727 " Flip", 728 " Rotate Right", 729 " Rotate Left", 730 " Rotate...", 731 " Shear...", 732 " Roll...", 733 " Trim Edges", 734 " Enhance", 735 " Brightness...", 736 " Saturation...", 737 " Hue...", 738 " Gamma...", 739 " Sharpen...", 740 " Dull", 741 " Contrast Stretch...", 742 " Sigmoidal Contrast...", 743 " Normalize", 744 " Equalize", 745 " Negate", 746 " Grayscale", 747 " Map...", 748 " Quantize...", 749 " Effects", 750 " Despeckle", 751 " Emboss", 752 " Reduce Noise", 753 " Add Noise", 754 " Sharpen...", 755 " Blur...", 756 " Threshold...", 757 " Edge Detect...", 758 " Spread...", 759 " Shade...", 760 " Painting...", 761 " Segment...", 762 " F/X", 763 " Solarize...", 764 " Sepia Tone...", 765 " Swirl...", 766 " Implode...", 767 " Vignette...", 768 " Wave...", 769 " Oil Painting...", 770 " Charcoal Drawing...", 771 " Image Edit", 772 " Annotate...", 773 " Draw...", 774 " Color...", 775 " Matte...", 776 " Composite...", 777 " Add Border...", 778 " Add Frame...", 779 " Comment...", 780 " Launch...", 781 " Region of Interest...", 782 " Miscellany", 783 " Image Info", 784 " Zoom Image", 785 " Show Preview...", 786 " Show Histogram", 787 " Show Matte", 788 " Background...", 789 " Slide Show", 790 " Preferences...", 791 " Help", 792 " Overview", 793 " Browse Documentation", 794 " About Display", 795 "", 796 " Menu items with a indented triangle have a sub-menu. They", 797 " are represented above as the indented items. To access a", 798 " sub-menu item, move the pointer to the appropriate menu and", 799 " press a button and drag. When you find the desired sub-menu", 800 " item, release the button and the command is executed. Move", 801 " the pointer away from the sub-menu if you decide not to", 802 " execute a particular command.", 803 "", 804 "KEYBOARD ACCELERATORS", 805 " Accelerators are one or two key presses that effect a", 806 " particular command. The keyboard accelerators that", 807 " display(1) understands is:", 808 "", 809 " Ctl+O Press to open an image from a file.", 810 "", 811 " space Press to display the next image.", 812 "", 813 " If the image is a multi-paged document such as a Postscript", 814 " document, you can skip ahead several pages by preceding", 815 " this command with a number. For example to display the", 816 " third page beyond the current page, press 3<space>.", 817 "", 818 " backspace Press to display the former image.", 819 "", 820 " If the image is a multi-paged document such as a Postscript", 821 " document, you can skip behind several pages by preceding", 822 " this command with a number. For example to display the", 823 " third page preceding the current page, press 3<backspace>.", 824 "", 825 " Ctl+S Press to write the image to a file.", 826 "", 827 " Ctl+P Press to print the image to a Postscript printer.", 828 "", 829 " Ctl+D Press to delete an image file.", 830 "", 831 " Ctl+N Press to create a blank canvas.", 832 "", 833 " Ctl+Q Press to discard all images and exit program.", 834 "", 835 " Ctl+Z Press to undo last image transformation.", 836 "", 837 " Ctl+R Press to redo last image transformation.", 838 "", 839 " Ctl+X Press to cut a region of the image.", 840 "", 841 " Ctl+C Press to copy a region of the image.", 842 "", 843 " Ctl+V Press to paste a region to the image.", 844 "", 845 " < Press to half the image size.", 846 "", 847 " - Press to return to the original image size.", 848 "", 849 " > Press to double the image size.", 850 "", 851 " % Press to resize the image to a width and height you", 852 " specify.", 853 "", 854 "Cmd-A Press to make any image transformations permanent." 855 "", 856 " By default, any image size transformations are applied", 857 " to the original image to create the image displayed on", 858 " the X server. However, the transformations are not", 859 " permanent (i.e. the original image does not change", 860 " size only the X image does). For example, if you", 861 " press > the X image will appear to double in size,", 862 " but the original image will in fact remain the same size.", 863 " To force the original image to double in size, press >", 864 " followed by Cmd-A.", 865 "", 866 " @ Press to refresh the image window.", 867 "", 868 " C Press to cut out a rectangular region of the image.", 869 "", 870 " [ Press to chop the image.", 871 "", 872 " H Press to flop image in the horizontal direction.", 873 "", 874 " V Press to flip image in the vertical direction.", 875 "", 876 " / Press to rotate the image 90 degrees clockwise.", 877 "", 878 " \\ Press to rotate the image 90 degrees counter-clockwise.", 879 "", 880 " * Press to rotate the image the number of degrees you", 881 " specify.", 882 "", 883 " S Press to shear the image the number of degrees you", 884 " specify.", 885 "", 886 " R Press to roll the image.", 887 "", 888 " T Press to trim the image edges.", 889 "", 890 " Shft-H Press to vary the image hue.", 891 "", 892 " Shft-S Press to vary the color saturation.", 893 "", 894 " Shft-L Press to vary the color brightness.", 895 "", 896 " Shft-G Press to gamma correct the image.", 897 "", 898 " Shft-C Press to sharpen the image contrast.", 899 "", 900 " Shft-Z Press to dull the image contrast.", 901 "", 902 " = Press to perform histogram equalization on the image.", 903 "", 904 " Shft-N Press to perform histogram normalization on the image.", 905 "", 906 " Shft-~ Press to negate the colors of the image.", 907 "", 908 " . Press to convert the image colors to gray.", 909 "", 910 " Shft-# Press to set the maximum number of unique colors in the", 911 " image.", 912 "", 913 " F2 Press to reduce the speckles in an image.", 914 "", 915 " F3 Press to eliminate peak noise from an image.", 916 "", 917 " F4 Press to add noise to an image.", 918 "", 919 " F5 Press to sharpen an image.", 920 "", 921 " F6 Press to delete an image file.", 922 "", 923 " F7 Press to threshold the image.", 924 "", 925 " F8 Press to detect edges within an image.", 926 "", 927 " F9 Press to emboss an image.", 928 "", 929 " F10 Press to displace pixels by a random amount.", 930 "", 931 " F11 Press to negate all pixels above the threshold level.", 932 "", 933 " F12 Press to shade the image using a distant light source.", 934 "", 935 " F13 Press to lighten or darken image edges to create a 3-D effect.", 936 "", 937 " F14 Press to segment the image by color.", 938 "", 939 " Meta-S Press to swirl image pixels about the center.", 940 "", 941 " Meta-I Press to implode image pixels about the center.", 942 "", 943 " Meta-W Press to alter an image along a sine wave.", 944 "", 945 " Meta-P Press to simulate an oil painting.", 946 "", 947 " Meta-C Press to simulate a charcoal drawing.", 948 "", 949 " Alt-A Press to annotate the image with text.", 950 "", 951 " Alt-D Press to draw on an image.", 952 "", 953 " Alt-P Press to edit an image pixel color.", 954 "", 955 " Alt-M Press to edit the image matte information.", 956 "", 957 " Alt-V Press to composite the image with another.", 958 "", 959 " Alt-B Press to add a border to the image.", 960 "", 961 " Alt-F Press to add an ornamental border to the image.", 962 "", 963 " Alt-Shft-!", 964 " Press to add an image comment.", 965 "", 966 " Ctl-A Press to apply image processing techniques to a region", 967 " of interest.", 968 "", 969 " Shft-? Press to display information about the image.", 970 "", 971 " Shft-+ Press to map the zoom image window.", 972 "", 973 " Shft-P Press to preview an image enhancement, effect, or f/x.", 974 "", 975 " F1 Press to display helpful information about display(1).", 976 "", 977 " Find Press to browse documentation about ImageMagick.", 978 "", 979 " 1-9 Press to change the level of magnification.", 980 "", 981 " Use the arrow keys to move the image one pixel up, down,", 982 " left, or right within the magnify window. Be sure to first", 983 " map the magnify window by pressing button 2.", 984 "", 985 " Press ALT and one of the arrow keys to trim off one pixel", 986 " from any side of the image.", 987 (char *) NULL, 988 }, 989 *ImageMatteEditHelp[] = 990 { 991 "Matte information within an image is useful for some", 992 "operations such as image compositing (See IMAGE", 993 "COMPOSITING). This extra channel usually defines a mask", 994 "which represents a sort of a cookie-cutter for the image.", 995 "This the case when matte is opaque (full coverage) for", 996 "pixels inside the shape, zero outside, and between 0 and", 997 "QuantumRange on the boundary.", 998 "", 999 "A small window appears showing the location of the cursor in", 1000 "the image window. You are now in matte edit mode. To exit", 1001 "immediately, press Dismiss. In matte edit mode, the Command", 1002 "widget has these options:", 1003 "", 1004 " Method", 1005 " point", 1006 " replace", 1007 " floodfill", 1008 " filltoborder", 1009 " reset", 1010 " Border Color", 1011 " black", 1012 " blue", 1013 " cyan", 1014 " green", 1015 " gray", 1016 " red", 1017 " magenta", 1018 " yellow", 1019 " white", 1020 " Browser...", 1021 " Fuzz", 1022 " 0%", 1023 " 2%", 1024 " 5%", 1025 " 10%", 1026 " 15%", 1027 " Dialog...", 1028 " Matte", 1029 " Opaque", 1030 " Transparent", 1031 " Dialog...", 1032 " Undo", 1033 " Help", 1034 " Dismiss", 1035 "", 1036 "Choose a matte editing method from the Method sub-menu of", 1037 "the Command widget. The point method changes the matte value", 1038 "of any pixel selected with the pointer until the button is", 1039 "is released. The replace method changes the matte value of", 1040 "any pixel that matches the color of the pixel you select with", 1041 "a button press. Floodfill changes the matte value of any pixel", 1042 "that matches the color of the pixel you select with a button", 1043 "press and is a neighbor. Whereas filltoborder changes the matte", 1044 "value any neighbor pixel that is not the border color. Finally", 1045 "reset changes the entire image to the designated matte value.", 1046 "", 1047 "Choose Matte Value and pick Opaque or Transarent. For other values", 1048 "select the Dialog entry. Here a dialog appears requesting a matte", 1049 "value. The value you select is assigned as the opacity value of the", 1050 "selected pixel or pixels.", 1051 "", 1052 "Now, press any button to select a pixel within the image", 1053 "window to change its matte value.", 1054 "", 1055 "If the Magnify widget is mapped, it can be helpful in positioning", 1056 "your pointer within the image (refer to button 2).", 1057 "", 1058 "Matte information is only valid in a DirectClass image.", 1059 "Therefore, any PseudoClass image is promoted to DirectClass", 1060 "(see miff(5)). Note that matte information for PseudoClass", 1061 "is not retained for colormapped X server visuals (e.g.", 1062 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you", 1063 "immediately save your image to a file (refer to Write).", 1064 "Correct matte editing behavior may require a TrueColor or", 1065 "DirectColor visual or a Standard Colormap.", 1066 (char *) NULL, 1067 }, 1068 *ImagePanHelp[] = 1069 { 1070 "When an image exceeds the width or height of the X server", 1071 "screen, display maps a small panning icon. The rectangle", 1072 "within the panning icon shows the area that is currently", 1073 "displayed in the image window. To pan about the image,", 1074 "press any button and drag the pointer within the panning", 1075 "icon. The pan rectangle moves with the pointer and the", 1076 "image window is updated to reflect the location of the", 1077 "rectangle within the panning icon. When you have selected", 1078 "the area of the image you wish to view, release the button.", 1079 "", 1080 "Use the arrow keys to pan the image one pixel up, down,", 1081 "left, or right within the image window.", 1082 "", 1083 "The panning icon is withdrawn if the image becomes smaller", 1084 "than the dimensions of the X server screen.", 1085 (char *) NULL, 1086 }, 1087 *ImagePasteHelp[] = 1088 { 1089 "A small window appears showing the location of the cursor in", 1090 "the image window. You are now in paste mode. To exit", 1091 "immediately, press Dismiss. In paste mode, the Command", 1092 "widget has these options:", 1093 "", 1094 " Operators", 1095 " over", 1096 " in", 1097 " out", 1098 " atop", 1099 " xor", 1100 " plus", 1101 " minus", 1102 " add", 1103 " subtract", 1104 " difference", 1105 " replace", 1106 " Help", 1107 " Dismiss", 1108 "", 1109 "Choose a composite operation from the Operators sub-menu of", 1110 "the Command widget. How each operator behaves is described", 1111 "below. Image window is the image currently displayed on", 1112 "your X server and image is the image obtained with the File", 1113 "Browser widget.", 1114 "", 1115 "Over The result is the union of the two image shapes,", 1116 " with image obscuring image window in the region of", 1117 " overlap.", 1118 "", 1119 "In The result is simply image cut by the shape of", 1120 " image window. None of the image data of image", 1121 " window is in the result.", 1122 "", 1123 "Out The resulting image is image with the shape of", 1124 " image window cut out.", 1125 "", 1126 "Atop The result is the same shape as image image window,", 1127 " with image obscuring image window where the image", 1128 " shapes overlap. Note this differs from over", 1129 " because the portion of image outside image window's", 1130 " shape does not appear in the result.", 1131 "", 1132 "Xor The result is the image data from both image and", 1133 " image window that is outside the overlap region.", 1134 " The overlap region is blank.", 1135 "", 1136 "Plus The result is just the sum of the image data.", 1137 " Output values are cropped to QuantumRange (no overflow).", 1138 " This operation is independent of the matte", 1139 " channels.", 1140 "", 1141 "Minus The result of image - image window, with underflow", 1142 " cropped to zero.", 1143 "", 1144 "Add The result of image + image window, with overflow", 1145 " wrapping around (mod 256).", 1146 "", 1147 "Subtract The result of image - image window, with underflow", 1148 " wrapping around (mod 256). The add and subtract", 1149 " operators can be used to perform reversible", 1150 " transformations.", 1151 "", 1152 "Difference", 1153 " The result of abs(image - image window). This", 1154 " useful for comparing two very similar images.", 1155 "", 1156 "Copy The resulting image is image window replaced with", 1157 " image. Here the matte information is ignored.", 1158 "", 1159 "CopyRed The red layer of the image window is replace with", 1160 " the red layer of the image. The other layers are", 1161 " untouched.", 1162 "", 1163 "CopyGreen", 1164 " The green layer of the image window is replace with", 1165 " the green layer of the image. The other layers are", 1166 " untouched.", 1167 "", 1168 "CopyBlue The blue layer of the image window is replace with", 1169 " the blue layer of the image. The other layers are", 1170 " untouched.", 1171 "", 1172 "CopyOpacity", 1173 " The matte layer of the image window is replace with", 1174 " the matte layer of the image. The other layers are", 1175 " untouched.", 1176 "", 1177 "The image compositor requires a matte, or alpha channel in", 1178 "the image for some operations. This extra channel usually", 1179 "defines a mask which represents a sort of a cookie-cutter", 1180 "for the image. This the case when matte is opaque (full", 1181 "coverage) for pixels inside the shape, zero outside, and", 1182 "between 0 and QuantumRange on the boundary. If image does not", 1183 "have a matte channel, it is initialized with 0 for any pixel", 1184 "matching in color to pixel location (0,0), otherwise QuantumRange.", 1185 "", 1186 "Note that matte information for image window is not retained", 1187 "for colormapped X server visuals (e.g. StaticColor,", 1188 "StaticColor, GrayScale, PseudoColor). Correct compositing", 1189 "behavior may require a TrueColor or DirectColor visual or a", 1190 "Standard Colormap.", 1191 "", 1192 "Choosing a composite operator is optional. The default", 1193 "operator is replace. However, you must choose a location to", 1194 "paste your image and press button 1. Press and hold the", 1195 "button before releasing and an outline of the image will", 1196 "appear to help you identify your location.", 1197 "", 1198 "The actual colors of the pasted image is saved. However,", 1199 "the color that appears in image window may be different.", 1200 "For example, on a monochrome screen image window will appear", 1201 "black or white even though your pasted image may have", 1202 "many colors. If the image is saved to a file it is written", 1203 "with the correct colors. To assure the correct colors are", 1204 "saved in the final image, any PseudoClass image is promoted", 1205 "to DirectClass (see miff(5)). To force a PseudoClass image", 1206 "to remain PseudoClass, use -colors.", 1207 (char *) NULL, 1208 }, 1209 *ImageROIHelp[] = 1210 { 1211 "In region of interest mode, the Command widget has these", 1212 "options:", 1213 "", 1214 " Help", 1215 " Dismiss", 1216 "", 1217 "To define a region of interest, press button 1 and drag.", 1218 "The region of interest is defined by a highlighted rectangle", 1219 "that expands or contracts as it follows the pointer. Once", 1220 "you are satisfied with the region of interest, release the", 1221 "button. You are now in apply mode. In apply mode the", 1222 "Command widget has these options:", 1223 "", 1224 " File", 1225 " Save...", 1226 " Print...", 1227 " Edit", 1228 " Undo", 1229 " Redo", 1230 " Transform", 1231 " Flop", 1232 " Flip", 1233 " Rotate Right", 1234 " Rotate Left", 1235 " Enhance", 1236 " Hue...", 1237 " Saturation...", 1238 " Brightness...", 1239 " Gamma...", 1240 " Spiff", 1241 " Dull", 1242 " Contrast Stretch", 1243 " Sigmoidal Contrast...", 1244 " Normalize", 1245 " Equalize", 1246 " Negate", 1247 " Grayscale", 1248 " Map...", 1249 " Quantize...", 1250 " Effects", 1251 " Despeckle", 1252 " Emboss", 1253 " Reduce Noise", 1254 " Sharpen...", 1255 " Blur...", 1256 " Threshold...", 1257 " Edge Detect...", 1258 " Spread...", 1259 " Shade...", 1260 " Raise...", 1261 " Segment...", 1262 " F/X", 1263 " Solarize...", 1264 " Sepia Tone...", 1265 " Swirl...", 1266 " Implode...", 1267 " Vignette...", 1268 " Wave...", 1269 " Oil Painting...", 1270 " Charcoal Drawing...", 1271 " Miscellany", 1272 " Image Info", 1273 " Zoom Image", 1274 " Show Preview...", 1275 " Show Histogram", 1276 " Show Matte", 1277 " Help", 1278 " Dismiss", 1279 "", 1280 "You can make adjustments to the region of interest by moving", 1281 "the pointer to one of the rectangle corners, pressing a", 1282 "button, and dragging. Finally, choose an image processing", 1283 "technique from the Command widget. You can choose more than", 1284 "one image processing technique to apply to an area.", 1285 "Alternatively, you can move the region of interest before", 1286 "applying another image processing technique. To exit, press", 1287 "Dismiss.", 1288 (char *) NULL, 1289 }, 1290 *ImageRotateHelp[] = 1291 { 1292 "In rotate mode, the Command widget has these options:", 1293 "", 1294 " Pixel Color", 1295 " black", 1296 " blue", 1297 " cyan", 1298 " green", 1299 " gray", 1300 " red", 1301 " magenta", 1302 " yellow", 1303 " white", 1304 " Browser...", 1305 " Direction", 1306 " horizontal", 1307 " vertical", 1308 " Help", 1309 " Dismiss", 1310 "", 1311 "Choose a background color from the Pixel Color sub-menu.", 1312 "Additional background colors can be specified with the color", 1313 "browser. You can change the menu colors by setting the X", 1314 "resources pen1 through pen9.", 1315 "", 1316 "If you choose the color browser and press Grab, you can", 1317 "select the background color by moving the pointer to the", 1318 "desired color on the screen and press any button.", 1319 "", 1320 "Choose a point in the image window and press this button and", 1321 "hold. Next, move the pointer to another location in the", 1322 "image. As you move a line connects the initial location and", 1323 "the pointer. When you release the button, the degree of", 1324 "image rotation is determined by the slope of the line you", 1325 "just drew. The slope is relative to the direction you", 1326 "choose from the Direction sub-menu of the Command widget.", 1327 "", 1328 "To cancel the image rotation, move the pointer back to the", 1329 "starting point of the line and release the button.", 1330 (char *) NULL, 1331 }; 1332 1333/* 1334 Enumeration declarations. 1335*/ 1336typedef enum 1337{ 1338 CopyMode, 1339 CropMode, 1340 CutMode 1341} ClipboardMode; 1342 1343typedef enum 1344{ 1345 OpenCommand, 1346 NextCommand, 1347 FormerCommand, 1348 SelectCommand, 1349 SaveCommand, 1350 PrintCommand, 1351 DeleteCommand, 1352 NewCommand, 1353 VisualDirectoryCommand, 1354 QuitCommand, 1355 UndoCommand, 1356 RedoCommand, 1357 CutCommand, 1358 CopyCommand, 1359 PasteCommand, 1360 HalfSizeCommand, 1361 OriginalSizeCommand, 1362 DoubleSizeCommand, 1363 ResizeCommand, 1364 ApplyCommand, 1365 RefreshCommand, 1366 RestoreCommand, 1367 CropCommand, 1368 ChopCommand, 1369 FlopCommand, 1370 FlipCommand, 1371 RotateRightCommand, 1372 RotateLeftCommand, 1373 RotateCommand, 1374 ShearCommand, 1375 RollCommand, 1376 TrimCommand, 1377 HueCommand, 1378 SaturationCommand, 1379 BrightnessCommand, 1380 GammaCommand, 1381 SpiffCommand, 1382 DullCommand, 1383 ContrastStretchCommand, 1384 SigmoidalContrastCommand, 1385 NormalizeCommand, 1386 EqualizeCommand, 1387 NegateCommand, 1388 GrayscaleCommand, 1389 MapCommand, 1390 QuantizeCommand, 1391 DespeckleCommand, 1392 EmbossCommand, 1393 ReduceNoiseCommand, 1394 AddNoiseCommand, 1395 SharpenCommand, 1396 BlurCommand, 1397 ThresholdCommand, 1398 EdgeDetectCommand, 1399 SpreadCommand, 1400 ShadeCommand, 1401 RaiseCommand, 1402 SegmentCommand, 1403 SolarizeCommand, 1404 SepiaToneCommand, 1405 SwirlCommand, 1406 ImplodeCommand, 1407 VignetteCommand, 1408 WaveCommand, 1409 OilPaintCommand, 1410 CharcoalDrawCommand, 1411 AnnotateCommand, 1412 DrawCommand, 1413 ColorCommand, 1414 MatteCommand, 1415 CompositeCommand, 1416 AddBorderCommand, 1417 AddFrameCommand, 1418 CommentCommand, 1419 LaunchCommand, 1420 RegionofInterestCommand, 1421 ROIHelpCommand, 1422 ROIDismissCommand, 1423 InfoCommand, 1424 ZoomCommand, 1425 ShowPreviewCommand, 1426 ShowHistogramCommand, 1427 ShowMatteCommand, 1428 BackgroundCommand, 1429 SlideShowCommand, 1430 PreferencesCommand, 1431 HelpCommand, 1432 BrowseDocumentationCommand, 1433 VersionCommand, 1434 SaveToUndoBufferCommand, 1435 FreeBuffersCommand, 1436 NullCommand 1437} CommandType; 1438 1439typedef enum 1440{ 1441 AnnotateNameCommand, 1442 AnnotateFontColorCommand, 1443 AnnotateBackgroundColorCommand, 1444 AnnotateRotateCommand, 1445 AnnotateHelpCommand, 1446 AnnotateDismissCommand, 1447 TextHelpCommand, 1448 TextApplyCommand, 1449 ChopDirectionCommand, 1450 ChopHelpCommand, 1451 ChopDismissCommand, 1452 HorizontalChopCommand, 1453 VerticalChopCommand, 1454 ColorEditMethodCommand, 1455 ColorEditColorCommand, 1456 ColorEditBorderCommand, 1457 ColorEditFuzzCommand, 1458 ColorEditUndoCommand, 1459 ColorEditHelpCommand, 1460 ColorEditDismissCommand, 1461 CompositeOperatorsCommand, 1462 CompositeDissolveCommand, 1463 CompositeDisplaceCommand, 1464 CompositeHelpCommand, 1465 CompositeDismissCommand, 1466 CropHelpCommand, 1467 CropDismissCommand, 1468 RectifyCopyCommand, 1469 RectifyHelpCommand, 1470 RectifyDismissCommand, 1471 DrawElementCommand, 1472 DrawColorCommand, 1473 DrawStippleCommand, 1474 DrawWidthCommand, 1475 DrawUndoCommand, 1476 DrawHelpCommand, 1477 DrawDismissCommand, 1478 MatteEditMethod, 1479 MatteEditBorderCommand, 1480 MatteEditFuzzCommand, 1481 MatteEditValueCommand, 1482 MatteEditUndoCommand, 1483 MatteEditHelpCommand, 1484 MatteEditDismissCommand, 1485 PasteOperatorsCommand, 1486 PasteHelpCommand, 1487 PasteDismissCommand, 1488 RotateColorCommand, 1489 RotateDirectionCommand, 1490 RotateCropCommand, 1491 RotateSharpenCommand, 1492 RotateHelpCommand, 1493 RotateDismissCommand, 1494 HorizontalRotateCommand, 1495 VerticalRotateCommand, 1496 TileLoadCommand, 1497 TileNextCommand, 1498 TileFormerCommand, 1499 TileDeleteCommand, 1500 TileUpdateCommand 1501} ModeType; 1502 1503/* 1504 Stipples. 1505*/ 1506#define BricksWidth 20 1507#define BricksHeight 20 1508#define DiagonalWidth 16 1509#define DiagonalHeight 16 1510#define HighlightWidth 8 1511#define HighlightHeight 8 1512#define OpaqueWidth 8 1513#define OpaqueHeight 8 1514#define ScalesWidth 16 1515#define ScalesHeight 16 1516#define ShadowWidth 8 1517#define ShadowHeight 8 1518#define VerticalWidth 16 1519#define VerticalHeight 16 1520#define WavyWidth 16 1521#define WavyHeight 16 1522 1523/* 1524 Constant declaration. 1525*/ 1526static const int 1527 RoiDelta = 8; 1528 1529static const unsigned char 1530 BricksBitmap[] = 1531 { 1532 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 1533 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 1534 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 1535 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 1536 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01 1537 }, 1538 DiagonalBitmap[] = 1539 { 1540 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 1541 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 1542 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22 1543 }, 1544 ScalesBitmap[] = 1545 { 1546 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80, 1547 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 1548 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e 1549 }, 1550 VerticalBitmap[] = 1551 { 1552 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1553 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1554 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 1555 }, 1556 WavyBitmap[] = 1557 { 1558 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff, 1559 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf, 1560 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f 1561 }; 1562 1563/* 1564 Function prototypes. 1565*/ 1566static CommandType 1567 XImageWindowCommand(Display *,XResourceInfo *,XWindows *, 1568 const MagickStatusType,KeySym,Image **,ExceptionInfo *); 1569 1570static Image 1571 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType, 1572 Image **,ExceptionInfo *), 1573 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType), 1574 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *, 1575 ExceptionInfo *), 1576 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *, 1577 ExceptionInfo *); 1578 1579static MagickBooleanType 1580 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *, 1581 ExceptionInfo *), 1582 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **, 1583 ExceptionInfo *), 1584 XChopImage(Display *,XResourceInfo *,XWindows *,Image **, 1585 ExceptionInfo *), 1586 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode, 1587 ExceptionInfo *), 1588 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1589 ExceptionInfo *), 1590 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *, 1591 ExceptionInfo *), 1592 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1593 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1594 ExceptionInfo *), 1595 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1596 ExceptionInfo *), 1597 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1598 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1599 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **, 1600 ExceptionInfo *), 1601 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *), 1602 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1603 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *); 1604 1605static void 1606 XDrawPanRectangle(Display *,XWindows *), 1607 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **, 1608 ExceptionInfo *), 1609 XMagnifyImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1610 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1611 XPanImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1612 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType, 1613 const KeySym,ExceptionInfo *), 1614 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *), 1615 XScreenEvent(Display *,XWindows *,XEvent *,ExceptionInfo *), 1616 XTranslateImage(Display *,XWindows *,Image *,const KeySym); 1617 1618/* 1619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1620% % 1621% % 1622% % 1623% D i s p l a y I m a g e s % 1624% % 1625% % 1626% % 1627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1628% 1629% DisplayImages() displays an image sequence to any X window screen. It 1630% returns a value other than 0 if successful. Check the exception member 1631% of image to determine the reason for any failure. 1632% 1633% The format of the DisplayImages method is: 1634% 1635% MagickBooleanType DisplayImages(const ImageInfo *image_info, 1636% Image *images,ExceptionInfo *exception) 1637% 1638% A description of each parameter follows: 1639% 1640% o image_info: the image info. 1641% 1642% o image: the image. 1643% 1644% o exception: return any errors or warnings in this structure. 1645% 1646*/ 1647MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 1648 Image *images,ExceptionInfo *exception) 1649{ 1650 char 1651 *argv[1]; 1652 1653 Display 1654 *display; 1655 1656 Image 1657 *image; 1658 1659 register ssize_t 1660 i; 1661 1662 size_t 1663 state; 1664 1665 XrmDatabase 1666 resource_database; 1667 1668 XResourceInfo 1669 resource_info; 1670 1671 assert(image_info != (const ImageInfo *) NULL); 1672 assert(image_info->signature == MagickSignature); 1673 assert(images != (Image *) NULL); 1674 assert(images->signature == MagickSignature); 1675 if (images->debug != MagickFalse) 1676 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 1677 display=XOpenDisplay(image_info->server_name); 1678 if (display == (Display *) NULL) 1679 { 1680 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1681 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1682 return(MagickFalse); 1683 } 1684 if (exception->severity != UndefinedException) 1685 CatchException(exception); 1686 (void) XSetErrorHandler(XError); 1687 resource_database=XGetResourceDatabase(display,GetClientName()); 1688 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info)); 1689 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info); 1690 if (image_info->page != (char *) NULL) 1691 resource_info.image_geometry=AcquireString(image_info->page); 1692 resource_info.immutable=MagickTrue; 1693 argv[0]=AcquireString(GetClientName()); 1694 state=DefaultState; 1695 for (i=0; (state & ExitState) == 0; i++) 1696 { 1697 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations)) 1698 break; 1699 image=GetImageFromList(images,i % GetImageListLength(images)); 1700 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception); 1701 } 1702 SetErrorHandler((ErrorHandler) NULL); 1703 SetWarningHandler((WarningHandler) NULL); 1704 argv[0]=DestroyString(argv[0]); 1705 (void) XCloseDisplay(display); 1706 XDestroyResourceInfo(&resource_info); 1707 if (exception->severity != UndefinedException) 1708 return(MagickFalse); 1709 return(MagickTrue); 1710} 1711 1712/* 1713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1714% % 1715% % 1716% % 1717% R e m o t e D i s p l a y C o m m a n d % 1718% % 1719% % 1720% % 1721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1722% 1723% RemoteDisplayCommand() encourages a remote display program to display the 1724% specified image filename. 1725% 1726% The format of the RemoteDisplayCommand method is: 1727% 1728% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1729% const char *window,const char *filename,ExceptionInfo *exception) 1730% 1731% A description of each parameter follows: 1732% 1733% o image_info: the image info. 1734% 1735% o window: Specifies the name or id of an X window. 1736% 1737% o filename: the name of the image filename to display. 1738% 1739% o exception: return any errors or warnings in this structure. 1740% 1741*/ 1742MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1743 const char *window,const char *filename,ExceptionInfo *exception) 1744{ 1745 Display 1746 *display; 1747 1748 MagickStatusType 1749 status; 1750 1751 assert(image_info != (const ImageInfo *) NULL); 1752 assert(image_info->signature == MagickSignature); 1753 assert(filename != (char *) NULL); 1754 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 1755 display=XOpenDisplay(image_info->server_name); 1756 if (display == (Display *) NULL) 1757 { 1758 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1759 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1760 return(MagickFalse); 1761 } 1762 (void) XSetErrorHandler(XError); 1763 status=XRemoteCommand(display,window,filename); 1764 (void) XCloseDisplay(display); 1765 return(status != 0 ? MagickTrue : MagickFalse); 1766} 1767 1768/* 1769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1770% % 1771% % 1772% % 1773+ X A n n o t a t e E d i t I m a g e % 1774% % 1775% % 1776% % 1777%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1778% 1779% XAnnotateEditImage() annotates the image with text. 1780% 1781% The format of the XAnnotateEditImage method is: 1782% 1783% MagickBooleanType XAnnotateEditImage(Display *display, 1784% XResourceInfo *resource_info,XWindows *windows,Image *image, 1785% ExceptionInfo *exception) 1786% 1787% A description of each parameter follows: 1788% 1789% o display: Specifies a connection to an X server; returned from 1790% XOpenDisplay. 1791% 1792% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 1793% 1794% o windows: Specifies a pointer to a XWindows structure. 1795% 1796% o image: the image; returned from ReadImage. 1797% 1798*/ 1799 1800static inline ssize_t MagickMax(const ssize_t x,const ssize_t y) 1801{ 1802 if (x > y) 1803 return(x); 1804 return(y); 1805} 1806 1807static inline ssize_t MagickMin(const ssize_t x,const ssize_t y) 1808{ 1809 if (x < y) 1810 return(x); 1811 return(y); 1812} 1813 1814static MagickBooleanType XAnnotateEditImage(Display *display, 1815 XResourceInfo *resource_info,XWindows *windows,Image *image, 1816 ExceptionInfo *exception) 1817{ 1818 static const char 1819 *AnnotateMenu[] = 1820 { 1821 "Font Name", 1822 "Font Color", 1823 "Box Color", 1824 "Rotate Text", 1825 "Help", 1826 "Dismiss", 1827 (char *) NULL 1828 }, 1829 *TextMenu[] = 1830 { 1831 "Help", 1832 "Apply", 1833 (char *) NULL 1834 }; 1835 1836 static const ModeType 1837 AnnotateCommands[] = 1838 { 1839 AnnotateNameCommand, 1840 AnnotateFontColorCommand, 1841 AnnotateBackgroundColorCommand, 1842 AnnotateRotateCommand, 1843 AnnotateHelpCommand, 1844 AnnotateDismissCommand 1845 }, 1846 TextCommands[] = 1847 { 1848 TextHelpCommand, 1849 TextApplyCommand 1850 }; 1851 1852 static MagickBooleanType 1853 transparent_box = MagickTrue, 1854 transparent_pen = MagickFalse; 1855 1856 static MagickRealType 1857 degrees = 0.0; 1858 1859 static unsigned int 1860 box_id = MaxNumberPens-2, 1861 font_id = 0, 1862 pen_id = 0; 1863 1864 char 1865 command[MaxTextExtent], 1866 text[MaxTextExtent]; 1867 1868 const char 1869 *ColorMenu[MaxNumberPens+1]; 1870 1871 Cursor 1872 cursor; 1873 1874 GC 1875 annotate_context; 1876 1877 int 1878 id, 1879 pen_number, 1880 status, 1881 x, 1882 y; 1883 1884 KeySym 1885 key_symbol; 1886 1887 register char 1888 *p; 1889 1890 register ssize_t 1891 i; 1892 1893 unsigned int 1894 height, 1895 width; 1896 1897 size_t 1898 state; 1899 1900 XAnnotateInfo 1901 *annotate_info, 1902 *previous_info; 1903 1904 XColor 1905 color; 1906 1907 XFontStruct 1908 *font_info; 1909 1910 XEvent 1911 event, 1912 text_event; 1913 1914 /* 1915 Map Command widget. 1916 */ 1917 (void) CloneString(&windows->command.name,"Annotate"); 1918 windows->command.data=4; 1919 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL); 1920 (void) XMapRaised(display,windows->command.id); 1921 XClientMessage(display,windows->image.id,windows->im_protocols, 1922 windows->im_update_widget,CurrentTime); 1923 /* 1924 Track pointer until button 1 is pressed. 1925 */ 1926 XQueryPosition(display,windows->image.id,&x,&y); 1927 (void) XSelectInput(display,windows->image.id, 1928 windows->image.attributes.event_mask | PointerMotionMask); 1929 cursor=XCreateFontCursor(display,XC_left_side); 1930 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1931 state=DefaultState; 1932 do 1933 { 1934 if (windows->info.mapped != MagickFalse) 1935 { 1936 /* 1937 Display pointer position. 1938 */ 1939 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 1940 x+windows->image.x,y+windows->image.y); 1941 XInfoWidget(display,windows,text); 1942 } 1943 /* 1944 Wait for next event. 1945 */ 1946 XScreenEvent(display,windows,&event,exception); 1947 if (event.xany.window == windows->command.id) 1948 { 1949 /* 1950 Select a command from the Command widget. 1951 */ 1952 id=XCommandWidget(display,windows,AnnotateMenu,&event); 1953 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1954 if (id < 0) 1955 continue; 1956 switch (AnnotateCommands[id]) 1957 { 1958 case AnnotateNameCommand: 1959 { 1960 const char 1961 *FontMenu[MaxNumberFonts]; 1962 1963 int 1964 font_number; 1965 1966 /* 1967 Initialize menu selections. 1968 */ 1969 for (i=0; i < MaxNumberFonts; i++) 1970 FontMenu[i]=resource_info->font_name[i]; 1971 FontMenu[MaxNumberFonts-2]="Browser..."; 1972 FontMenu[MaxNumberFonts-1]=(const char *) NULL; 1973 /* 1974 Select a font name from the pop-up menu. 1975 */ 1976 font_number=XMenuWidget(display,windows,AnnotateMenu[id], 1977 (const char **) FontMenu,command); 1978 if (font_number < 0) 1979 break; 1980 if (font_number == (MaxNumberFonts-2)) 1981 { 1982 static char 1983 font_name[MaxTextExtent] = "fixed"; 1984 1985 /* 1986 Select a font name from a browser. 1987 */ 1988 resource_info->font_name[font_number]=font_name; 1989 XFontBrowserWidget(display,windows,"Select",font_name); 1990 if (*font_name == '\0') 1991 break; 1992 } 1993 /* 1994 Initialize font info. 1995 */ 1996 font_info=XLoadQueryFont(display,resource_info->font_name[ 1997 font_number]); 1998 if (font_info == (XFontStruct *) NULL) 1999 { 2000 XNoticeWidget(display,windows,"Unable to load font:", 2001 resource_info->font_name[font_number]); 2002 break; 2003 } 2004 font_id=(unsigned int) font_number; 2005 (void) XFreeFont(display,font_info); 2006 break; 2007 } 2008 case AnnotateFontColorCommand: 2009 { 2010 /* 2011 Initialize menu selections. 2012 */ 2013 for (i=0; i < (int) (MaxNumberPens-2); i++) 2014 ColorMenu[i]=resource_info->pen_colors[i]; 2015 ColorMenu[MaxNumberPens-2]="transparent"; 2016 ColorMenu[MaxNumberPens-1]="Browser..."; 2017 ColorMenu[MaxNumberPens]=(const char *) NULL; 2018 /* 2019 Select a pen color from the pop-up menu. 2020 */ 2021 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2022 (const char **) ColorMenu,command); 2023 if (pen_number < 0) 2024 break; 2025 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue : 2026 MagickFalse; 2027 if (transparent_pen != MagickFalse) 2028 break; 2029 if (pen_number == (MaxNumberPens-1)) 2030 { 2031 static char 2032 color_name[MaxTextExtent] = "gray"; 2033 2034 /* 2035 Select a pen color from a dialog. 2036 */ 2037 resource_info->pen_colors[pen_number]=color_name; 2038 XColorBrowserWidget(display,windows,"Select",color_name); 2039 if (*color_name == '\0') 2040 break; 2041 } 2042 /* 2043 Set pen color. 2044 */ 2045 (void) XParseColor(display,windows->map_info->colormap, 2046 resource_info->pen_colors[pen_number],&color); 2047 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2048 (unsigned int) MaxColors,&color); 2049 windows->pixel_info->pen_colors[pen_number]=color; 2050 pen_id=(unsigned int) pen_number; 2051 break; 2052 } 2053 case AnnotateBackgroundColorCommand: 2054 { 2055 /* 2056 Initialize menu selections. 2057 */ 2058 for (i=0; i < (int) (MaxNumberPens-2); i++) 2059 ColorMenu[i]=resource_info->pen_colors[i]; 2060 ColorMenu[MaxNumberPens-2]="transparent"; 2061 ColorMenu[MaxNumberPens-1]="Browser..."; 2062 ColorMenu[MaxNumberPens]=(const char *) NULL; 2063 /* 2064 Select a pen color from the pop-up menu. 2065 */ 2066 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2067 (const char **) ColorMenu,command); 2068 if (pen_number < 0) 2069 break; 2070 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue : 2071 MagickFalse; 2072 if (transparent_box != MagickFalse) 2073 break; 2074 if (pen_number == (MaxNumberPens-1)) 2075 { 2076 static char 2077 color_name[MaxTextExtent] = "gray"; 2078 2079 /* 2080 Select a pen color from a dialog. 2081 */ 2082 resource_info->pen_colors[pen_number]=color_name; 2083 XColorBrowserWidget(display,windows,"Select",color_name); 2084 if (*color_name == '\0') 2085 break; 2086 } 2087 /* 2088 Set pen color. 2089 */ 2090 (void) XParseColor(display,windows->map_info->colormap, 2091 resource_info->pen_colors[pen_number],&color); 2092 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2093 (unsigned int) MaxColors,&color); 2094 windows->pixel_info->pen_colors[pen_number]=color; 2095 box_id=(unsigned int) pen_number; 2096 break; 2097 } 2098 case AnnotateRotateCommand: 2099 { 2100 int 2101 entry; 2102 2103 static char 2104 angle[MaxTextExtent] = "30.0"; 2105 2106 static const char 2107 *RotateMenu[] = 2108 { 2109 "-90", 2110 "-45", 2111 "-30", 2112 "0", 2113 "30", 2114 "45", 2115 "90", 2116 "180", 2117 "Dialog...", 2118 (char *) NULL, 2119 }; 2120 2121 /* 2122 Select a command from the pop-up menu. 2123 */ 2124 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu, 2125 command); 2126 if (entry < 0) 2127 break; 2128 if (entry != 8) 2129 { 2130 degrees=InterpretLocaleValue(RotateMenu[entry],(char **) NULL); 2131 break; 2132 } 2133 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:", 2134 angle); 2135 if (*angle == '\0') 2136 break; 2137 degrees=InterpretLocaleValue(angle,(char **) NULL); 2138 break; 2139 } 2140 case AnnotateHelpCommand: 2141 { 2142 XTextViewWidget(display,resource_info,windows,MagickFalse, 2143 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2144 break; 2145 } 2146 case AnnotateDismissCommand: 2147 { 2148 /* 2149 Prematurely exit. 2150 */ 2151 state|=EscapeState; 2152 state|=ExitState; 2153 break; 2154 } 2155 default: 2156 break; 2157 } 2158 continue; 2159 } 2160 switch (event.type) 2161 { 2162 case ButtonPress: 2163 { 2164 if (event.xbutton.button != Button1) 2165 break; 2166 if (event.xbutton.window != windows->image.id) 2167 break; 2168 /* 2169 Change to text entering mode. 2170 */ 2171 x=event.xbutton.x; 2172 y=event.xbutton.y; 2173 state|=ExitState; 2174 break; 2175 } 2176 case ButtonRelease: 2177 break; 2178 case Expose: 2179 break; 2180 case KeyPress: 2181 { 2182 if (event.xkey.window != windows->image.id) 2183 break; 2184 /* 2185 Respond to a user key press. 2186 */ 2187 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2188 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2189 switch ((int) key_symbol) 2190 { 2191 case XK_Escape: 2192 case XK_F20: 2193 { 2194 /* 2195 Prematurely exit. 2196 */ 2197 state|=EscapeState; 2198 state|=ExitState; 2199 break; 2200 } 2201 case XK_F1: 2202 case XK_Help: 2203 { 2204 XTextViewWidget(display,resource_info,windows,MagickFalse, 2205 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2206 break; 2207 } 2208 default: 2209 { 2210 (void) XBell(display,0); 2211 break; 2212 } 2213 } 2214 break; 2215 } 2216 case MotionNotify: 2217 { 2218 /* 2219 Map and unmap Info widget as cursor crosses its boundaries. 2220 */ 2221 x=event.xmotion.x; 2222 y=event.xmotion.y; 2223 if (windows->info.mapped != MagickFalse) 2224 { 2225 if ((x < (int) (windows->info.x+windows->info.width)) && 2226 (y < (int) (windows->info.y+windows->info.height))) 2227 (void) XWithdrawWindow(display,windows->info.id, 2228 windows->info.screen); 2229 } 2230 else 2231 if ((x > (int) (windows->info.x+windows->info.width)) || 2232 (y > (int) (windows->info.y+windows->info.height))) 2233 (void) XMapWindow(display,windows->info.id); 2234 break; 2235 } 2236 default: 2237 break; 2238 } 2239 } while ((state & ExitState) == 0); 2240 (void) XSelectInput(display,windows->image.id, 2241 windows->image.attributes.event_mask); 2242 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 2243 if ((state & EscapeState) != 0) 2244 return(MagickTrue); 2245 /* 2246 Set font info and check boundary conditions. 2247 */ 2248 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]); 2249 if (font_info == (XFontStruct *) NULL) 2250 { 2251 XNoticeWidget(display,windows,"Unable to load font:", 2252 resource_info->font_name[font_id]); 2253 font_info=windows->font_info; 2254 } 2255 if ((x+font_info->max_bounds.width) >= (int) windows->image.width) 2256 x=(int) windows->image.width-font_info->max_bounds.width; 2257 if (y < (int) (font_info->ascent+font_info->descent)) 2258 y=(int) font_info->ascent+font_info->descent; 2259 if (((int) font_info->max_bounds.width > (int) windows->image.width) || 2260 ((font_info->ascent+font_info->descent) >= (int) windows->image.height)) 2261 return(MagickFalse); 2262 /* 2263 Initialize annotate structure. 2264 */ 2265 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info)); 2266 if (annotate_info == (XAnnotateInfo *) NULL) 2267 return(MagickFalse); 2268 XGetAnnotateInfo(annotate_info); 2269 annotate_info->x=x; 2270 annotate_info->y=y; 2271 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse)) 2272 annotate_info->stencil=OpaqueStencil; 2273 else 2274 if (transparent_box == MagickFalse) 2275 annotate_info->stencil=BackgroundStencil; 2276 else 2277 annotate_info->stencil=ForegroundStencil; 2278 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent; 2279 annotate_info->degrees=degrees; 2280 annotate_info->font_info=font_info; 2281 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2282 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL, 2283 sizeof(*annotate_info->text)); 2284 if (annotate_info->text == (char *) NULL) 2285 return(MagickFalse); 2286 /* 2287 Create cursor and set graphic context. 2288 */ 2289 cursor=XCreateFontCursor(display,XC_pencil); 2290 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2291 annotate_context=windows->image.annotate_context; 2292 (void) XSetFont(display,annotate_context,font_info->fid); 2293 (void) XSetBackground(display,annotate_context, 2294 windows->pixel_info->pen_colors[box_id].pixel); 2295 (void) XSetForeground(display,annotate_context, 2296 windows->pixel_info->pen_colors[pen_id].pixel); 2297 /* 2298 Begin annotating the image with text. 2299 */ 2300 (void) CloneString(&windows->command.name,"Text"); 2301 windows->command.data=0; 2302 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL); 2303 state=DefaultState; 2304 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2305 text_event.xexpose.width=(int) font_info->max_bounds.width; 2306 text_event.xexpose.height=font_info->max_bounds.ascent+ 2307 font_info->max_bounds.descent; 2308 p=annotate_info->text; 2309 do 2310 { 2311 /* 2312 Display text cursor. 2313 */ 2314 *p='\0'; 2315 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2316 /* 2317 Wait for next event. 2318 */ 2319 XScreenEvent(display,windows,&event,exception); 2320 if (event.xany.window == windows->command.id) 2321 { 2322 /* 2323 Select a command from the Command widget. 2324 */ 2325 (void) XSetBackground(display,annotate_context, 2326 windows->pixel_info->background_color.pixel); 2327 (void) XSetForeground(display,annotate_context, 2328 windows->pixel_info->foreground_color.pixel); 2329 id=XCommandWidget(display,windows,AnnotateMenu,&event); 2330 (void) XSetBackground(display,annotate_context, 2331 windows->pixel_info->pen_colors[box_id].pixel); 2332 (void) XSetForeground(display,annotate_context, 2333 windows->pixel_info->pen_colors[pen_id].pixel); 2334 if (id < 0) 2335 continue; 2336 switch (TextCommands[id]) 2337 { 2338 case TextHelpCommand: 2339 { 2340 XTextViewWidget(display,resource_info,windows,MagickFalse, 2341 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2342 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2343 break; 2344 } 2345 case TextApplyCommand: 2346 { 2347 /* 2348 Finished annotating. 2349 */ 2350 annotate_info->width=(unsigned int) XTextWidth(font_info, 2351 annotate_info->text,(int) strlen(annotate_info->text)); 2352 XRefreshWindow(display,&windows->image,&text_event); 2353 state|=ExitState; 2354 break; 2355 } 2356 default: 2357 break; 2358 } 2359 continue; 2360 } 2361 /* 2362 Erase text cursor. 2363 */ 2364 text_event.xexpose.x=x; 2365 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2366 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y, 2367 (unsigned int) text_event.xexpose.width,(unsigned int) 2368 text_event.xexpose.height,MagickFalse); 2369 XRefreshWindow(display,&windows->image,&text_event); 2370 switch (event.type) 2371 { 2372 case ButtonPress: 2373 { 2374 if (event.xbutton.window != windows->image.id) 2375 break; 2376 if (event.xbutton.button == Button2) 2377 { 2378 /* 2379 Request primary selection. 2380 */ 2381 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, 2382 windows->image.id,CurrentTime); 2383 break; 2384 } 2385 break; 2386 } 2387 case Expose: 2388 { 2389 if (event.xexpose.count == 0) 2390 { 2391 XAnnotateInfo 2392 *text_info; 2393 2394 /* 2395 Refresh Image window. 2396 */ 2397 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 2398 text_info=annotate_info; 2399 while (text_info != (XAnnotateInfo *) NULL) 2400 { 2401 if (annotate_info->stencil == ForegroundStencil) 2402 (void) XDrawString(display,windows->image.id,annotate_context, 2403 text_info->x,text_info->y,text_info->text, 2404 (int) strlen(text_info->text)); 2405 else 2406 (void) XDrawImageString(display,windows->image.id, 2407 annotate_context,text_info->x,text_info->y,text_info->text, 2408 (int) strlen(text_info->text)); 2409 text_info=text_info->previous; 2410 } 2411 (void) XDrawString(display,windows->image.id,annotate_context, 2412 x,y,"_",1); 2413 } 2414 break; 2415 } 2416 case KeyPress: 2417 { 2418 int 2419 length; 2420 2421 if (event.xkey.window != windows->image.id) 2422 break; 2423 /* 2424 Respond to a user key press. 2425 */ 2426 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 2427 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2428 *(command+length)='\0'; 2429 if (((event.xkey.state & ControlMask) != 0) || 2430 ((event.xkey.state & Mod1Mask) != 0)) 2431 state|=ModifierState; 2432 if ((state & ModifierState) != 0) 2433 switch ((int) key_symbol) 2434 { 2435 case XK_u: 2436 case XK_U: 2437 { 2438 key_symbol=DeleteCommand; 2439 break; 2440 } 2441 default: 2442 break; 2443 } 2444 switch ((int) key_symbol) 2445 { 2446 case XK_BackSpace: 2447 { 2448 /* 2449 Erase one character. 2450 */ 2451 if (p == annotate_info->text) 2452 { 2453 if (annotate_info->previous == (XAnnotateInfo *) NULL) 2454 break; 2455 else 2456 { 2457 /* 2458 Go to end of the previous line of text. 2459 */ 2460 annotate_info=annotate_info->previous; 2461 p=annotate_info->text; 2462 x=annotate_info->x+annotate_info->width; 2463 y=annotate_info->y; 2464 if (annotate_info->width != 0) 2465 p+=strlen(annotate_info->text); 2466 break; 2467 } 2468 } 2469 p--; 2470 x-=XTextWidth(font_info,p,1); 2471 text_event.xexpose.x=x; 2472 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2473 XRefreshWindow(display,&windows->image,&text_event); 2474 break; 2475 } 2476 case XK_bracketleft: 2477 { 2478 key_symbol=XK_Escape; 2479 break; 2480 } 2481 case DeleteCommand: 2482 { 2483 /* 2484 Erase the entire line of text. 2485 */ 2486 while (p != annotate_info->text) 2487 { 2488 p--; 2489 x-=XTextWidth(font_info,p,1); 2490 text_event.xexpose.x=x; 2491 XRefreshWindow(display,&windows->image,&text_event); 2492 } 2493 break; 2494 } 2495 case XK_Escape: 2496 case XK_F20: 2497 { 2498 /* 2499 Finished annotating. 2500 */ 2501 annotate_info->width=(unsigned int) XTextWidth(font_info, 2502 annotate_info->text,(int) strlen(annotate_info->text)); 2503 XRefreshWindow(display,&windows->image,&text_event); 2504 state|=ExitState; 2505 break; 2506 } 2507 default: 2508 { 2509 /* 2510 Draw a single character on the Image window. 2511 */ 2512 if ((state & ModifierState) != 0) 2513 break; 2514 if (*command == '\0') 2515 break; 2516 *p=(*command); 2517 if (annotate_info->stencil == ForegroundStencil) 2518 (void) XDrawString(display,windows->image.id,annotate_context, 2519 x,y,p,1); 2520 else 2521 (void) XDrawImageString(display,windows->image.id, 2522 annotate_context,x,y,p,1); 2523 x+=XTextWidth(font_info,p,1); 2524 p++; 2525 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2526 break; 2527 } 2528 case XK_Return: 2529 case XK_KP_Enter: 2530 { 2531 /* 2532 Advance to the next line of text. 2533 */ 2534 *p='\0'; 2535 annotate_info->width=(unsigned int) XTextWidth(font_info, 2536 annotate_info->text,(int) strlen(annotate_info->text)); 2537 if (annotate_info->next != (XAnnotateInfo *) NULL) 2538 { 2539 /* 2540 Line of text already exists. 2541 */ 2542 annotate_info=annotate_info->next; 2543 x=annotate_info->x; 2544 y=annotate_info->y; 2545 p=annotate_info->text; 2546 break; 2547 } 2548 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2549 sizeof(*annotate_info->next)); 2550 if (annotate_info->next == (XAnnotateInfo *) NULL) 2551 return(MagickFalse); 2552 *annotate_info->next=(*annotate_info); 2553 annotate_info->next->previous=annotate_info; 2554 annotate_info=annotate_info->next; 2555 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2556 windows->image.width/MagickMax((ssize_t) 2557 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2558 if (annotate_info->text == (char *) NULL) 2559 return(MagickFalse); 2560 annotate_info->y+=annotate_info->height; 2561 if (annotate_info->y > (int) windows->image.height) 2562 annotate_info->y=(int) annotate_info->height; 2563 annotate_info->next=(XAnnotateInfo *) NULL; 2564 x=annotate_info->x; 2565 y=annotate_info->y; 2566 p=annotate_info->text; 2567 break; 2568 } 2569 } 2570 break; 2571 } 2572 case KeyRelease: 2573 { 2574 /* 2575 Respond to a user key release. 2576 */ 2577 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2578 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2579 state&=(~ModifierState); 2580 break; 2581 } 2582 case SelectionNotify: 2583 { 2584 Atom 2585 type; 2586 2587 int 2588 format; 2589 2590 unsigned char 2591 *data; 2592 2593 unsigned long 2594 after, 2595 length; 2596 2597 /* 2598 Obtain response from primary selection. 2599 */ 2600 if (event.xselection.property == (Atom) None) 2601 break; 2602 status=XGetWindowProperty(display,event.xselection.requestor, 2603 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING, 2604 &type,&format,&length,&after,&data); 2605 if ((status != Success) || (type != XA_STRING) || (format == 32) || 2606 (length == 0)) 2607 break; 2608 /* 2609 Annotate Image window with primary selection. 2610 */ 2611 for (i=0; i < (ssize_t) length; i++) 2612 { 2613 if ((char) data[i] != '\n') 2614 { 2615 /* 2616 Draw a single character on the Image window. 2617 */ 2618 *p=(char) data[i]; 2619 (void) XDrawString(display,windows->image.id,annotate_context, 2620 x,y,p,1); 2621 x+=XTextWidth(font_info,p,1); 2622 p++; 2623 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2624 continue; 2625 } 2626 /* 2627 Advance to the next line of text. 2628 */ 2629 *p='\0'; 2630 annotate_info->width=(unsigned int) XTextWidth(font_info, 2631 annotate_info->text,(int) strlen(annotate_info->text)); 2632 if (annotate_info->next != (XAnnotateInfo *) NULL) 2633 { 2634 /* 2635 Line of text already exists. 2636 */ 2637 annotate_info=annotate_info->next; 2638 x=annotate_info->x; 2639 y=annotate_info->y; 2640 p=annotate_info->text; 2641 continue; 2642 } 2643 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2644 sizeof(*annotate_info->next)); 2645 if (annotate_info->next == (XAnnotateInfo *) NULL) 2646 return(MagickFalse); 2647 *annotate_info->next=(*annotate_info); 2648 annotate_info->next->previous=annotate_info; 2649 annotate_info=annotate_info->next; 2650 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2651 windows->image.width/MagickMax((ssize_t) 2652 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2653 if (annotate_info->text == (char *) NULL) 2654 return(MagickFalse); 2655 annotate_info->y+=annotate_info->height; 2656 if (annotate_info->y > (int) windows->image.height) 2657 annotate_info->y=(int) annotate_info->height; 2658 annotate_info->next=(XAnnotateInfo *) NULL; 2659 x=annotate_info->x; 2660 y=annotate_info->y; 2661 p=annotate_info->text; 2662 } 2663 (void) XFree((void *) data); 2664 break; 2665 } 2666 default: 2667 break; 2668 } 2669 } while ((state & ExitState) == 0); 2670 (void) XFreeCursor(display,cursor); 2671 /* 2672 Annotation is relative to image configuration. 2673 */ 2674 width=(unsigned int) image->columns; 2675 height=(unsigned int) image->rows; 2676 x=0; 2677 y=0; 2678 if (windows->image.crop_geometry != (char *) NULL) 2679 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 2680 /* 2681 Initialize annotated image. 2682 */ 2683 XSetCursorState(display,windows,MagickTrue); 2684 XCheckRefreshWindows(display,windows); 2685 while (annotate_info != (XAnnotateInfo *) NULL) 2686 { 2687 if (annotate_info->width == 0) 2688 { 2689 /* 2690 No text on this line-- go to the next line of text. 2691 */ 2692 previous_info=annotate_info->previous; 2693 annotate_info->text=(char *) 2694 RelinquishMagickMemory(annotate_info->text); 2695 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2696 annotate_info=previous_info; 2697 continue; 2698 } 2699 /* 2700 Determine pixel index for box and pen color. 2701 */ 2702 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id]; 2703 if (windows->pixel_info->colors != 0) 2704 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2705 if (windows->pixel_info->pixels[i] == 2706 windows->pixel_info->pen_colors[box_id].pixel) 2707 { 2708 windows->pixel_info->box_index=(unsigned short) i; 2709 break; 2710 } 2711 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 2712 if (windows->pixel_info->colors != 0) 2713 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2714 if (windows->pixel_info->pixels[i] == 2715 windows->pixel_info->pen_colors[pen_id].pixel) 2716 { 2717 windows->pixel_info->pen_index=(unsigned short) i; 2718 break; 2719 } 2720 /* 2721 Define the annotate geometry string. 2722 */ 2723 annotate_info->x=(int) 2724 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width; 2725 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+ 2726 windows->image.y)/windows->image.ximage->height; 2727 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent, 2728 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width, 2729 height*annotate_info->height/windows->image.ximage->height, 2730 annotate_info->x+x,annotate_info->y+y); 2731 /* 2732 Annotate image with text. 2733 */ 2734 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image, 2735 exception); 2736 if (status == 0) 2737 return(MagickFalse); 2738 /* 2739 Free up memory. 2740 */ 2741 previous_info=annotate_info->previous; 2742 annotate_info->text=DestroyString(annotate_info->text); 2743 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2744 annotate_info=previous_info; 2745 } 2746 (void) XSetForeground(display,annotate_context, 2747 windows->pixel_info->foreground_color.pixel); 2748 (void) XSetBackground(display,annotate_context, 2749 windows->pixel_info->background_color.pixel); 2750 (void) XSetFont(display,annotate_context,windows->font_info->fid); 2751 XSetCursorState(display,windows,MagickFalse); 2752 (void) XFreeFont(display,font_info); 2753 /* 2754 Update image configuration. 2755 */ 2756 XConfigureImageColormap(display,resource_info,windows,image,exception); 2757 (void) XConfigureImage(display,resource_info,windows,image,exception); 2758 return(MagickTrue); 2759} 2760 2761/* 2762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2763% % 2764% % 2765% % 2766+ X B a c k g r o u n d I m a g e % 2767% % 2768% % 2769% % 2770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2771% 2772% XBackgroundImage() displays the image in the background of a window. 2773% 2774% The format of the XBackgroundImage method is: 2775% 2776% MagickBooleanType XBackgroundImage(Display *display, 2777% XResourceInfo *resource_info,XWindows *windows,Image **image, 2778% ExceptionInfo *exception) 2779% 2780% A description of each parameter follows: 2781% 2782% o display: Specifies a connection to an X server; returned from 2783% XOpenDisplay. 2784% 2785% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2786% 2787% o windows: Specifies a pointer to a XWindows structure. 2788% 2789% o image: the image. 2790% 2791% o exception: return any errors or warnings in this structure. 2792% 2793*/ 2794static MagickBooleanType XBackgroundImage(Display *display, 2795 XResourceInfo *resource_info,XWindows *windows,Image **image, 2796 ExceptionInfo *exception) 2797{ 2798#define BackgroundImageTag "Background/Image" 2799 2800 int 2801 status; 2802 2803 static char 2804 window_id[MaxTextExtent] = "root"; 2805 2806 XResourceInfo 2807 background_resources; 2808 2809 /* 2810 Put image in background. 2811 */ 2812 status=XDialogWidget(display,windows,"Background", 2813 "Enter window id (id 0x00 selects window with pointer):",window_id); 2814 if (*window_id == '\0') 2815 return(MagickFalse); 2816 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 2817 exception); 2818 XInfoWidget(display,windows,BackgroundImageTag); 2819 XSetCursorState(display,windows,MagickTrue); 2820 XCheckRefreshWindows(display,windows); 2821 background_resources=(*resource_info); 2822 background_resources.window_id=window_id; 2823 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse; 2824 status=XDisplayBackgroundImage(display,&background_resources,*image, 2825 exception); 2826 if (status != MagickFalse) 2827 XClientMessage(display,windows->image.id,windows->im_protocols, 2828 windows->im_retain_colors,CurrentTime); 2829 XSetCursorState(display,windows,MagickFalse); 2830 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image, 2831 exception); 2832 return(MagickTrue); 2833} 2834 2835/* 2836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2837% % 2838% % 2839% % 2840+ X C h o p I m a g e % 2841% % 2842% % 2843% % 2844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2845% 2846% XChopImage() chops the X image. 2847% 2848% The format of the XChopImage method is: 2849% 2850% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info, 2851% XWindows *windows,Image **image,ExceptionInfo *exception) 2852% 2853% A description of each parameter follows: 2854% 2855% o display: Specifies a connection to an X server; returned from 2856% XOpenDisplay. 2857% 2858% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2859% 2860% o windows: Specifies a pointer to a XWindows structure. 2861% 2862% o image: the image. 2863% 2864% o exception: return any errors or warnings in this structure. 2865% 2866*/ 2867static MagickBooleanType XChopImage(Display *display, 2868 XResourceInfo *resource_info,XWindows *windows,Image **image, 2869 ExceptionInfo *exception) 2870{ 2871 static const char 2872 *ChopMenu[] = 2873 { 2874 "Direction", 2875 "Help", 2876 "Dismiss", 2877 (char *) NULL 2878 }; 2879 2880 static ModeType 2881 direction = HorizontalChopCommand; 2882 2883 static const ModeType 2884 ChopCommands[] = 2885 { 2886 ChopDirectionCommand, 2887 ChopHelpCommand, 2888 ChopDismissCommand 2889 }, 2890 DirectionCommands[] = 2891 { 2892 HorizontalChopCommand, 2893 VerticalChopCommand 2894 }; 2895 2896 char 2897 text[MaxTextExtent]; 2898 2899 Image 2900 *chop_image; 2901 2902 int 2903 id, 2904 x, 2905 y; 2906 2907 MagickRealType 2908 scale_factor; 2909 2910 RectangleInfo 2911 chop_info; 2912 2913 unsigned int 2914 distance, 2915 height, 2916 width; 2917 2918 size_t 2919 state; 2920 2921 XEvent 2922 event; 2923 2924 XSegment 2925 segment_info; 2926 2927 /* 2928 Map Command widget. 2929 */ 2930 (void) CloneString(&windows->command.name,"Chop"); 2931 windows->command.data=1; 2932 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL); 2933 (void) XMapRaised(display,windows->command.id); 2934 XClientMessage(display,windows->image.id,windows->im_protocols, 2935 windows->im_update_widget,CurrentTime); 2936 /* 2937 Track pointer until button 1 is pressed. 2938 */ 2939 XQueryPosition(display,windows->image.id,&x,&y); 2940 (void) XSelectInput(display,windows->image.id, 2941 windows->image.attributes.event_mask | PointerMotionMask); 2942 state=DefaultState; 2943 do 2944 { 2945 if (windows->info.mapped != MagickFalse) 2946 { 2947 /* 2948 Display pointer position. 2949 */ 2950 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 2951 x+windows->image.x,y+windows->image.y); 2952 XInfoWidget(display,windows,text); 2953 } 2954 /* 2955 Wait for next event. 2956 */ 2957 XScreenEvent(display,windows,&event,exception); 2958 if (event.xany.window == windows->command.id) 2959 { 2960 /* 2961 Select a command from the Command widget. 2962 */ 2963 id=XCommandWidget(display,windows,ChopMenu,&event); 2964 if (id < 0) 2965 continue; 2966 switch (ChopCommands[id]) 2967 { 2968 case ChopDirectionCommand: 2969 { 2970 char 2971 command[MaxTextExtent]; 2972 2973 static const char 2974 *Directions[] = 2975 { 2976 "horizontal", 2977 "vertical", 2978 (char *) NULL, 2979 }; 2980 2981 /* 2982 Select a command from the pop-up menu. 2983 */ 2984 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 2985 if (id >= 0) 2986 direction=DirectionCommands[id]; 2987 break; 2988 } 2989 case ChopHelpCommand: 2990 { 2991 XTextViewWidget(display,resource_info,windows,MagickFalse, 2992 "Help Viewer - Image Chop",ImageChopHelp); 2993 break; 2994 } 2995 case ChopDismissCommand: 2996 { 2997 /* 2998 Prematurely exit. 2999 */ 3000 state|=EscapeState; 3001 state|=ExitState; 3002 break; 3003 } 3004 default: 3005 break; 3006 } 3007 continue; 3008 } 3009 switch (event.type) 3010 { 3011 case ButtonPress: 3012 { 3013 if (event.xbutton.button != Button1) 3014 break; 3015 if (event.xbutton.window != windows->image.id) 3016 break; 3017 /* 3018 User has committed to start point of chopping line. 3019 */ 3020 segment_info.x1=(short int) event.xbutton.x; 3021 segment_info.x2=(short int) event.xbutton.x; 3022 segment_info.y1=(short int) event.xbutton.y; 3023 segment_info.y2=(short int) event.xbutton.y; 3024 state|=ExitState; 3025 break; 3026 } 3027 case ButtonRelease: 3028 break; 3029 case Expose: 3030 break; 3031 case KeyPress: 3032 { 3033 char 3034 command[MaxTextExtent]; 3035 3036 KeySym 3037 key_symbol; 3038 3039 if (event.xkey.window != windows->image.id) 3040 break; 3041 /* 3042 Respond to a user key press. 3043 */ 3044 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3045 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3046 switch ((int) key_symbol) 3047 { 3048 case XK_Escape: 3049 case XK_F20: 3050 { 3051 /* 3052 Prematurely exit. 3053 */ 3054 state|=EscapeState; 3055 state|=ExitState; 3056 break; 3057 } 3058 case XK_F1: 3059 case XK_Help: 3060 { 3061 (void) XSetFunction(display,windows->image.highlight_context, 3062 GXcopy); 3063 XTextViewWidget(display,resource_info,windows,MagickFalse, 3064 "Help Viewer - Image Chop",ImageChopHelp); 3065 (void) XSetFunction(display,windows->image.highlight_context, 3066 GXinvert); 3067 break; 3068 } 3069 default: 3070 { 3071 (void) XBell(display,0); 3072 break; 3073 } 3074 } 3075 break; 3076 } 3077 case MotionNotify: 3078 { 3079 /* 3080 Map and unmap Info widget as text cursor crosses its boundaries. 3081 */ 3082 x=event.xmotion.x; 3083 y=event.xmotion.y; 3084 if (windows->info.mapped != MagickFalse) 3085 { 3086 if ((x < (int) (windows->info.x+windows->info.width)) && 3087 (y < (int) (windows->info.y+windows->info.height))) 3088 (void) XWithdrawWindow(display,windows->info.id, 3089 windows->info.screen); 3090 } 3091 else 3092 if ((x > (int) (windows->info.x+windows->info.width)) || 3093 (y > (int) (windows->info.y+windows->info.height))) 3094 (void) XMapWindow(display,windows->info.id); 3095 } 3096 } 3097 } while ((state & ExitState) == 0); 3098 (void) XSelectInput(display,windows->image.id, 3099 windows->image.attributes.event_mask); 3100 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3101 if ((state & EscapeState) != 0) 3102 return(MagickTrue); 3103 /* 3104 Draw line as pointer moves until the mouse button is released. 3105 */ 3106 chop_info.width=0; 3107 chop_info.height=0; 3108 chop_info.x=0; 3109 chop_info.y=0; 3110 distance=0; 3111 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3112 state=DefaultState; 3113 do 3114 { 3115 if (distance > 9) 3116 { 3117 /* 3118 Display info and draw chopping line. 3119 */ 3120 if (windows->info.mapped == MagickFalse) 3121 (void) XMapWindow(display,windows->info.id); 3122 (void) FormatLocaleString(text,MaxTextExtent, 3123 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 3124 chop_info.height,(double) chop_info.x,(double) chop_info.y); 3125 XInfoWidget(display,windows,text); 3126 XHighlightLine(display,windows->image.id, 3127 windows->image.highlight_context,&segment_info); 3128 } 3129 else 3130 if (windows->info.mapped != MagickFalse) 3131 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3132 /* 3133 Wait for next event. 3134 */ 3135 XScreenEvent(display,windows,&event,exception); 3136 if (distance > 9) 3137 XHighlightLine(display,windows->image.id, 3138 windows->image.highlight_context,&segment_info); 3139 switch (event.type) 3140 { 3141 case ButtonPress: 3142 { 3143 segment_info.x2=(short int) event.xmotion.x; 3144 segment_info.y2=(short int) event.xmotion.y; 3145 break; 3146 } 3147 case ButtonRelease: 3148 { 3149 /* 3150 User has committed to chopping line. 3151 */ 3152 segment_info.x2=(short int) event.xbutton.x; 3153 segment_info.y2=(short int) event.xbutton.y; 3154 state|=ExitState; 3155 break; 3156 } 3157 case Expose: 3158 break; 3159 case MotionNotify: 3160 { 3161 segment_info.x2=(short int) event.xmotion.x; 3162 segment_info.y2=(short int) event.xmotion.y; 3163 } 3164 default: 3165 break; 3166 } 3167 /* 3168 Check boundary conditions. 3169 */ 3170 if (segment_info.x2 < 0) 3171 segment_info.x2=0; 3172 else 3173 if (segment_info.x2 > windows->image.ximage->width) 3174 segment_info.x2=windows->image.ximage->width; 3175 if (segment_info.y2 < 0) 3176 segment_info.y2=0; 3177 else 3178 if (segment_info.y2 > windows->image.ximage->height) 3179 segment_info.y2=windows->image.ximage->height; 3180 distance=(unsigned int) 3181 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 3182 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 3183 /* 3184 Compute chopping geometry. 3185 */ 3186 if (direction == HorizontalChopCommand) 3187 { 3188 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 3189 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 3190 chop_info.height=0; 3191 chop_info.y=0; 3192 if (segment_info.x1 > (int) segment_info.x2) 3193 { 3194 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 3195 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 3196 } 3197 } 3198 else 3199 { 3200 chop_info.width=0; 3201 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 3202 chop_info.x=0; 3203 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 3204 if (segment_info.y1 > segment_info.y2) 3205 { 3206 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 3207 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 3208 } 3209 } 3210 } while ((state & ExitState) == 0); 3211 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 3212 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3213 if (distance <= 9) 3214 return(MagickTrue); 3215 /* 3216 Image chopping is relative to image configuration. 3217 */ 3218 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 3219 exception); 3220 XSetCursorState(display,windows,MagickTrue); 3221 XCheckRefreshWindows(display,windows); 3222 windows->image.window_changes.width=windows->image.ximage->width- 3223 (unsigned int) chop_info.width; 3224 windows->image.window_changes.height=windows->image.ximage->height- 3225 (unsigned int) chop_info.height; 3226 width=(unsigned int) (*image)->columns; 3227 height=(unsigned int) (*image)->rows; 3228 x=0; 3229 y=0; 3230 if (windows->image.crop_geometry != (char *) NULL) 3231 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 3232 scale_factor=(MagickRealType) width/windows->image.ximage->width; 3233 chop_info.x+=x; 3234 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 3235 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 3236 scale_factor=(MagickRealType) height/windows->image.ximage->height; 3237 chop_info.y+=y; 3238 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 3239 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 3240 /* 3241 Chop image. 3242 */ 3243 chop_image=ChopImage(*image,&chop_info,exception); 3244 XSetCursorState(display,windows,MagickFalse); 3245 if (chop_image == (Image *) NULL) 3246 return(MagickFalse); 3247 *image=DestroyImage(*image); 3248 *image=chop_image; 3249 /* 3250 Update image configuration. 3251 */ 3252 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3253 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3254 return(MagickTrue); 3255} 3256 3257/* 3258%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3259% % 3260% % 3261% % 3262+ X C o l o r E d i t I m a g e % 3263% % 3264% % 3265% % 3266%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3267% 3268% XColorEditImage() allows the user to interactively change the color of one 3269% pixel for a DirectColor image or one colormap entry for a PseudoClass image. 3270% 3271% The format of the XColorEditImage method is: 3272% 3273% MagickBooleanType XColorEditImage(Display *display, 3274% XResourceInfo *resource_info,XWindows *windows,Image **image, 3275% ExceptionInfo *exception) 3276% 3277% A description of each parameter follows: 3278% 3279% o display: Specifies a connection to an X server; returned from 3280% XOpenDisplay. 3281% 3282% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3283% 3284% o windows: Specifies a pointer to a XWindows structure. 3285% 3286% o image: the image; returned from ReadImage. 3287% 3288% o exception: return any errors or warnings in this structure. 3289% 3290*/ 3291static MagickBooleanType XColorEditImage(Display *display, 3292 XResourceInfo *resource_info,XWindows *windows,Image **image, 3293 ExceptionInfo *exception) 3294{ 3295 static const char 3296 *ColorEditMenu[] = 3297 { 3298 "Method", 3299 "Pixel Color", 3300 "Border Color", 3301 "Fuzz", 3302 "Undo", 3303 "Help", 3304 "Dismiss", 3305 (char *) NULL 3306 }; 3307 3308 static const ModeType 3309 ColorEditCommands[] = 3310 { 3311 ColorEditMethodCommand, 3312 ColorEditColorCommand, 3313 ColorEditBorderCommand, 3314 ColorEditFuzzCommand, 3315 ColorEditUndoCommand, 3316 ColorEditHelpCommand, 3317 ColorEditDismissCommand 3318 }; 3319 3320 static PaintMethod 3321 method = PointMethod; 3322 3323 static unsigned int 3324 pen_id = 0; 3325 3326 static XColor 3327 border_color = { 0, 0, 0, 0, 0, 0 }; 3328 3329 char 3330 command[MaxTextExtent], 3331 text[MaxTextExtent]; 3332 3333 Cursor 3334 cursor; 3335 3336 int 3337 entry, 3338 id, 3339 x, 3340 x_offset, 3341 y, 3342 y_offset; 3343 3344 register Quantum 3345 *q; 3346 3347 register ssize_t 3348 i; 3349 3350 unsigned int 3351 height, 3352 width; 3353 3354 size_t 3355 state; 3356 3357 XColor 3358 color; 3359 3360 XEvent 3361 event; 3362 3363 /* 3364 Map Command widget. 3365 */ 3366 (void) CloneString(&windows->command.name,"Color Edit"); 3367 windows->command.data=4; 3368 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 3369 (void) XMapRaised(display,windows->command.id); 3370 XClientMessage(display,windows->image.id,windows->im_protocols, 3371 windows->im_update_widget,CurrentTime); 3372 /* 3373 Make cursor. 3374 */ 3375 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 3376 resource_info->background_color,resource_info->foreground_color); 3377 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3378 /* 3379 Track pointer until button 1 is pressed. 3380 */ 3381 XQueryPosition(display,windows->image.id,&x,&y); 3382 (void) XSelectInput(display,windows->image.id, 3383 windows->image.attributes.event_mask | PointerMotionMask); 3384 state=DefaultState; 3385 do 3386 { 3387 if (windows->info.mapped != MagickFalse) 3388 { 3389 /* 3390 Display pointer position. 3391 */ 3392 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 3393 x+windows->image.x,y+windows->image.y); 3394 XInfoWidget(display,windows,text); 3395 } 3396 /* 3397 Wait for next event. 3398 */ 3399 XScreenEvent(display,windows,&event,exception); 3400 if (event.xany.window == windows->command.id) 3401 { 3402 /* 3403 Select a command from the Command widget. 3404 */ 3405 id=XCommandWidget(display,windows,ColorEditMenu,&event); 3406 if (id < 0) 3407 { 3408 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3409 continue; 3410 } 3411 switch (ColorEditCommands[id]) 3412 { 3413 case ColorEditMethodCommand: 3414 { 3415 char 3416 **methods; 3417 3418 /* 3419 Select a method from the pop-up menu. 3420 */ 3421 methods=(char **) GetCommandOptions(MagickMethodOptions); 3422 if (methods == (char **) NULL) 3423 break; 3424 entry=XMenuWidget(display,windows,ColorEditMenu[id], 3425 (const char **) methods,command); 3426 if (entry >= 0) 3427 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 3428 MagickFalse,methods[entry]); 3429 methods=DestroyStringList(methods); 3430 break; 3431 } 3432 case ColorEditColorCommand: 3433 { 3434 const char 3435 *ColorMenu[MaxNumberPens]; 3436 3437 int 3438 pen_number; 3439 3440 /* 3441 Initialize menu selections. 3442 */ 3443 for (i=0; i < (int) (MaxNumberPens-2); i++) 3444 ColorMenu[i]=resource_info->pen_colors[i]; 3445 ColorMenu[MaxNumberPens-2]="Browser..."; 3446 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3447 /* 3448 Select a pen color from the pop-up menu. 3449 */ 3450 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3451 (const char **) ColorMenu,command); 3452 if (pen_number < 0) 3453 break; 3454 if (pen_number == (MaxNumberPens-2)) 3455 { 3456 static char 3457 color_name[MaxTextExtent] = "gray"; 3458 3459 /* 3460 Select a pen color from a dialog. 3461 */ 3462 resource_info->pen_colors[pen_number]=color_name; 3463 XColorBrowserWidget(display,windows,"Select",color_name); 3464 if (*color_name == '\0') 3465 break; 3466 } 3467 /* 3468 Set pen color. 3469 */ 3470 (void) XParseColor(display,windows->map_info->colormap, 3471 resource_info->pen_colors[pen_number],&color); 3472 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 3473 (unsigned int) MaxColors,&color); 3474 windows->pixel_info->pen_colors[pen_number]=color; 3475 pen_id=(unsigned int) pen_number; 3476 break; 3477 } 3478 case ColorEditBorderCommand: 3479 { 3480 const char 3481 *ColorMenu[MaxNumberPens]; 3482 3483 int 3484 pen_number; 3485 3486 /* 3487 Initialize menu selections. 3488 */ 3489 for (i=0; i < (int) (MaxNumberPens-2); i++) 3490 ColorMenu[i]=resource_info->pen_colors[i]; 3491 ColorMenu[MaxNumberPens-2]="Browser..."; 3492 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3493 /* 3494 Select a pen color from the pop-up menu. 3495 */ 3496 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3497 (const char **) ColorMenu,command); 3498 if (pen_number < 0) 3499 break; 3500 if (pen_number == (MaxNumberPens-2)) 3501 { 3502 static char 3503 color_name[MaxTextExtent] = "gray"; 3504 3505 /* 3506 Select a pen color from a dialog. 3507 */ 3508 resource_info->pen_colors[pen_number]=color_name; 3509 XColorBrowserWidget(display,windows,"Select",color_name); 3510 if (*color_name == '\0') 3511 break; 3512 } 3513 /* 3514 Set border color. 3515 */ 3516 (void) XParseColor(display,windows->map_info->colormap, 3517 resource_info->pen_colors[pen_number],&border_color); 3518 break; 3519 } 3520 case ColorEditFuzzCommand: 3521 { 3522 static char 3523 fuzz[MaxTextExtent]; 3524 3525 static const char 3526 *FuzzMenu[] = 3527 { 3528 "0%", 3529 "2%", 3530 "5%", 3531 "10%", 3532 "15%", 3533 "Dialog...", 3534 (char *) NULL, 3535 }; 3536 3537 /* 3538 Select a command from the pop-up menu. 3539 */ 3540 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 3541 command); 3542 if (entry < 0) 3543 break; 3544 if (entry != 5) 3545 { 3546 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],(double) 3547 QuantumRange+1.0); 3548 break; 3549 } 3550 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 3551 (void) XDialogWidget(display,windows,"Ok", 3552 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 3553 if (*fuzz == '\0') 3554 break; 3555 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 3556 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0); 3557 break; 3558 } 3559 case ColorEditUndoCommand: 3560 { 3561 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 3562 image,exception); 3563 break; 3564 } 3565 case ColorEditHelpCommand: 3566 default: 3567 { 3568 XTextViewWidget(display,resource_info,windows,MagickFalse, 3569 "Help Viewer - Image Annotation",ImageColorEditHelp); 3570 break; 3571 } 3572 case ColorEditDismissCommand: 3573 { 3574 /* 3575 Prematurely exit. 3576 */ 3577 state|=EscapeState; 3578 state|=ExitState; 3579 break; 3580 } 3581 } 3582 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3583 continue; 3584 } 3585 switch (event.type) 3586 { 3587 case ButtonPress: 3588 { 3589 if (event.xbutton.button != Button1) 3590 break; 3591 if ((event.xbutton.window != windows->image.id) && 3592 (event.xbutton.window != windows->magnify.id)) 3593 break; 3594 /* 3595 exit loop. 3596 */ 3597 x=event.xbutton.x; 3598 y=event.xbutton.y; 3599 (void) XMagickCommand(display,resource_info,windows, 3600 SaveToUndoBufferCommand,image,exception); 3601 state|=UpdateConfigurationState; 3602 break; 3603 } 3604 case ButtonRelease: 3605 { 3606 if (event.xbutton.button != Button1) 3607 break; 3608 if ((event.xbutton.window != windows->image.id) && 3609 (event.xbutton.window != windows->magnify.id)) 3610 break; 3611 /* 3612 Update colormap information. 3613 */ 3614 x=event.xbutton.x; 3615 y=event.xbutton.y; 3616 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3617 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3618 XInfoWidget(display,windows,text); 3619 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3620 state&=(~UpdateConfigurationState); 3621 break; 3622 } 3623 case Expose: 3624 break; 3625 case KeyPress: 3626 { 3627 KeySym 3628 key_symbol; 3629 3630 if (event.xkey.window == windows->magnify.id) 3631 { 3632 Window 3633 window; 3634 3635 window=windows->magnify.id; 3636 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 3637 } 3638 if (event.xkey.window != windows->image.id) 3639 break; 3640 /* 3641 Respond to a user key press. 3642 */ 3643 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3644 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3645 switch ((int) key_symbol) 3646 { 3647 case XK_Escape: 3648 case XK_F20: 3649 { 3650 /* 3651 Prematurely exit. 3652 */ 3653 state|=ExitState; 3654 break; 3655 } 3656 case XK_F1: 3657 case XK_Help: 3658 { 3659 XTextViewWidget(display,resource_info,windows,MagickFalse, 3660 "Help Viewer - Image Annotation",ImageColorEditHelp); 3661 break; 3662 } 3663 default: 3664 { 3665 (void) XBell(display,0); 3666 break; 3667 } 3668 } 3669 break; 3670 } 3671 case MotionNotify: 3672 { 3673 /* 3674 Map and unmap Info widget as cursor crosses its boundaries. 3675 */ 3676 x=event.xmotion.x; 3677 y=event.xmotion.y; 3678 if (windows->info.mapped != MagickFalse) 3679 { 3680 if ((x < (int) (windows->info.x+windows->info.width)) && 3681 (y < (int) (windows->info.y+windows->info.height))) 3682 (void) XWithdrawWindow(display,windows->info.id, 3683 windows->info.screen); 3684 } 3685 else 3686 if ((x > (int) (windows->info.x+windows->info.width)) || 3687 (y > (int) (windows->info.y+windows->info.height))) 3688 (void) XMapWindow(display,windows->info.id); 3689 break; 3690 } 3691 default: 3692 break; 3693 } 3694 if (event.xany.window == windows->magnify.id) 3695 { 3696 x=windows->magnify.x-windows->image.x; 3697 y=windows->magnify.y-windows->image.y; 3698 } 3699 x_offset=x; 3700 y_offset=y; 3701 if ((state & UpdateConfigurationState) != 0) 3702 { 3703 CacheView 3704 *image_view; 3705 3706 int 3707 x, 3708 y; 3709 3710 /* 3711 Pixel edit is relative to image configuration. 3712 */ 3713 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 3714 MagickTrue); 3715 color=windows->pixel_info->pen_colors[pen_id]; 3716 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 3717 width=(unsigned int) (*image)->columns; 3718 height=(unsigned int) (*image)->rows; 3719 x=0; 3720 y=0; 3721 if (windows->image.crop_geometry != (char *) NULL) 3722 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 3723 &width,&height); 3724 x_offset=(int) 3725 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 3726 y_offset=(int) 3727 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 3728 if ((x_offset < 0) || (y_offset < 0)) 3729 continue; 3730 if ((x_offset >= (int) (*image)->columns) || 3731 (y_offset >= (int) (*image)->rows)) 3732 continue; 3733 image_view=AcquireCacheView(*image); 3734 switch (method) 3735 { 3736 case PointMethod: 3737 default: 3738 { 3739 /* 3740 Update color information using point algorithm. 3741 */ 3742 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3743 return(MagickFalse); 3744 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 3745 (ssize_t) y_offset,1,1,exception); 3746 if (q == (Quantum *) NULL) 3747 break; 3748 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3749 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3750 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3751 (void) SyncCacheViewAuthenticPixels(image_view,exception); 3752 break; 3753 } 3754 case ReplaceMethod: 3755 { 3756 PixelInfo 3757 pixel, 3758 target; 3759 3760 Quantum 3761 virtual_pixel[CompositePixelChannel]; 3762 3763 /* 3764 Update color information using replace algorithm. 3765 */ 3766 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 3767 (ssize_t) y_offset,virtual_pixel,exception); 3768 target.red=virtual_pixel[RedPixelChannel]; 3769 target.green=virtual_pixel[GreenPixelChannel]; 3770 target.blue=virtual_pixel[BluePixelChannel]; 3771 target.alpha=virtual_pixel[AlphaPixelChannel]; 3772 if ((*image)->storage_class == DirectClass) 3773 { 3774 for (y=0; y < (int) (*image)->rows; y++) 3775 { 3776 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3777 (*image)->columns,1,exception); 3778 if (q == (Quantum *) NULL) 3779 break; 3780 for (x=0; x < (int) (*image)->columns; x++) 3781 { 3782 GetPixelInfoPixel(*image,q,&pixel); 3783 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 3784 { 3785 SetPixelRed(*image,ScaleShortToQuantum( 3786 color.red),q); 3787 SetPixelGreen(*image,ScaleShortToQuantum( 3788 color.green),q); 3789 SetPixelBlue(*image,ScaleShortToQuantum( 3790 color.blue),q); 3791 } 3792 q+=GetPixelChannels(*image); 3793 } 3794 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3795 break; 3796 } 3797 } 3798 else 3799 { 3800 for (i=0; i < (ssize_t) (*image)->colors; i++) 3801 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target)) 3802 { 3803 (*image)->colormap[i].red=ScaleShortToQuantum( 3804 color.red); 3805 (*image)->colormap[i].green=ScaleShortToQuantum( 3806 color.green); 3807 (*image)->colormap[i].blue=ScaleShortToQuantum( 3808 color.blue); 3809 } 3810 (void) SyncImage(*image,exception); 3811 } 3812 break; 3813 } 3814 case FloodfillMethod: 3815 case FillToBorderMethod: 3816 { 3817 DrawInfo 3818 *draw_info; 3819 3820 PixelInfo 3821 target; 3822 3823 /* 3824 Update color information using floodfill algorithm. 3825 */ 3826 (void) GetOneVirtualMagickPixel(*image, 3827 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 3828 y_offset,&target,exception); 3829 if (method == FillToBorderMethod) 3830 { 3831 target.red=(MagickRealType) 3832 ScaleShortToQuantum(border_color.red); 3833 target.green=(MagickRealType) 3834 ScaleShortToQuantum(border_color.green); 3835 target.blue=(MagickRealType) 3836 ScaleShortToQuantum(border_color.blue); 3837 } 3838 draw_info=CloneDrawInfo(resource_info->image_info, 3839 (DrawInfo *) NULL); 3840 (void) QueryColorCompliance(resource_info->pen_colors[pen_id], 3841 AllCompliance,&draw_info->fill,exception); 3842 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 3843 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 3844 MagickFalse : MagickTrue,exception); 3845 draw_info=DestroyDrawInfo(draw_info); 3846 break; 3847 } 3848 case ResetMethod: 3849 { 3850 /* 3851 Update color information using reset algorithm. 3852 */ 3853 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3854 return(MagickFalse); 3855 for (y=0; y < (int) (*image)->rows; y++) 3856 { 3857 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3858 (*image)->columns,1,exception); 3859 if (q == (Quantum *) NULL) 3860 break; 3861 for (x=0; x < (int) (*image)->columns; x++) 3862 { 3863 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3864 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3865 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3866 q+=GetPixelChannels(*image); 3867 } 3868 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3869 break; 3870 } 3871 break; 3872 } 3873 } 3874 image_view=DestroyCacheView(image_view); 3875 state&=(~UpdateConfigurationState); 3876 } 3877 } while ((state & ExitState) == 0); 3878 (void) XSelectInput(display,windows->image.id, 3879 windows->image.attributes.event_mask); 3880 XSetCursorState(display,windows,MagickFalse); 3881 (void) XFreeCursor(display,cursor); 3882 return(MagickTrue); 3883} 3884 3885/* 3886%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3887% % 3888% % 3889% % 3890+ X C o m p o s i t e I m a g e % 3891% % 3892% % 3893% % 3894%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3895% 3896% XCompositeImage() requests an image name from the user, reads the image and 3897% composites it with the X window image at a location the user chooses with 3898% the pointer. 3899% 3900% The format of the XCompositeImage method is: 3901% 3902% MagickBooleanType XCompositeImage(Display *display, 3903% XResourceInfo *resource_info,XWindows *windows,Image *image, 3904% ExceptionInfo *exception) 3905% 3906% A description of each parameter follows: 3907% 3908% o display: Specifies a connection to an X server; returned from 3909% XOpenDisplay. 3910% 3911% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3912% 3913% o windows: Specifies a pointer to a XWindows structure. 3914% 3915% o image: the image; returned from ReadImage. 3916% 3917% o exception: return any errors or warnings in this structure. 3918% 3919*/ 3920static MagickBooleanType XCompositeImage(Display *display, 3921 XResourceInfo *resource_info,XWindows *windows,Image *image, 3922 ExceptionInfo *exception) 3923{ 3924 static char 3925 displacement_geometry[MaxTextExtent] = "30x30", 3926 filename[MaxTextExtent] = "\0"; 3927 3928 static const char 3929 *CompositeMenu[] = 3930 { 3931 "Operators", 3932 "Dissolve", 3933 "Displace", 3934 "Help", 3935 "Dismiss", 3936 (char *) NULL 3937 }; 3938 3939 static CompositeOperator 3940 compose = CopyCompositeOp; 3941 3942 static const ModeType 3943 CompositeCommands[] = 3944 { 3945 CompositeOperatorsCommand, 3946 CompositeDissolveCommand, 3947 CompositeDisplaceCommand, 3948 CompositeHelpCommand, 3949 CompositeDismissCommand 3950 }; 3951 3952 char 3953 text[MaxTextExtent]; 3954 3955 Cursor 3956 cursor; 3957 3958 Image 3959 *composite_image; 3960 3961 int 3962 entry, 3963 id, 3964 x, 3965 y; 3966 3967 MagickRealType 3968 blend, 3969 scale_factor; 3970 3971 RectangleInfo 3972 highlight_info, 3973 composite_info; 3974 3975 unsigned int 3976 height, 3977 width; 3978 3979 size_t 3980 state; 3981 3982 XEvent 3983 event; 3984 3985 /* 3986 Request image file name from user. 3987 */ 3988 XFileBrowserWidget(display,windows,"Composite",filename); 3989 if (*filename == '\0') 3990 return(MagickTrue); 3991 /* 3992 Read image. 3993 */ 3994 XSetCursorState(display,windows,MagickTrue); 3995 XCheckRefreshWindows(display,windows); 3996 (void) CopyMagickString(resource_info->image_info->filename,filename, 3997 MaxTextExtent); 3998 composite_image=ReadImage(resource_info->image_info,exception); 3999 CatchException(exception); 4000 XSetCursorState(display,windows,MagickFalse); 4001 if (composite_image == (Image *) NULL) 4002 return(MagickFalse); 4003 /* 4004 Map Command widget. 4005 */ 4006 (void) CloneString(&windows->command.name,"Composite"); 4007 windows->command.data=1; 4008 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 4009 (void) XMapRaised(display,windows->command.id); 4010 XClientMessage(display,windows->image.id,windows->im_protocols, 4011 windows->im_update_widget,CurrentTime); 4012 /* 4013 Track pointer until button 1 is pressed. 4014 */ 4015 XQueryPosition(display,windows->image.id,&x,&y); 4016 (void) XSelectInput(display,windows->image.id, 4017 windows->image.attributes.event_mask | PointerMotionMask); 4018 composite_info.x=(ssize_t) windows->image.x+x; 4019 composite_info.y=(ssize_t) windows->image.y+y; 4020 composite_info.width=0; 4021 composite_info.height=0; 4022 cursor=XCreateFontCursor(display,XC_ul_angle); 4023 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4024 blend=0.0; 4025 state=DefaultState; 4026 do 4027 { 4028 if (windows->info.mapped != MagickFalse) 4029 { 4030 /* 4031 Display pointer position. 4032 */ 4033 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4034 (long) composite_info.x,(long) composite_info.y); 4035 XInfoWidget(display,windows,text); 4036 } 4037 highlight_info=composite_info; 4038 highlight_info.x=composite_info.x-windows->image.x; 4039 highlight_info.y=composite_info.y-windows->image.y; 4040 XHighlightRectangle(display,windows->image.id, 4041 windows->image.highlight_context,&highlight_info); 4042 /* 4043 Wait for next event. 4044 */ 4045 XScreenEvent(display,windows,&event,exception); 4046 XHighlightRectangle(display,windows->image.id, 4047 windows->image.highlight_context,&highlight_info); 4048 if (event.xany.window == windows->command.id) 4049 { 4050 /* 4051 Select a command from the Command widget. 4052 */ 4053 id=XCommandWidget(display,windows,CompositeMenu,&event); 4054 if (id < 0) 4055 continue; 4056 switch (CompositeCommands[id]) 4057 { 4058 case CompositeOperatorsCommand: 4059 { 4060 char 4061 command[MaxTextExtent], 4062 **operators; 4063 4064 /* 4065 Select a command from the pop-up menu. 4066 */ 4067 operators=GetCommandOptions(MagickComposeOptions); 4068 if (operators == (char **) NULL) 4069 break; 4070 entry=XMenuWidget(display,windows,CompositeMenu[id], 4071 (const char **) operators,command); 4072 if (entry >= 0) 4073 compose=(CompositeOperator) ParseCommandOption( 4074 MagickComposeOptions,MagickFalse,operators[entry]); 4075 operators=DestroyStringList(operators); 4076 break; 4077 } 4078 case CompositeDissolveCommand: 4079 { 4080 static char 4081 factor[MaxTextExtent] = "20.0"; 4082 4083 /* 4084 Dissolve the two images a given percent. 4085 */ 4086 (void) XSetFunction(display,windows->image.highlight_context, 4087 GXcopy); 4088 (void) XDialogWidget(display,windows,"Dissolve", 4089 "Enter the blend factor (0.0 - 99.9%):",factor); 4090 (void) XSetFunction(display,windows->image.highlight_context, 4091 GXinvert); 4092 if (*factor == '\0') 4093 break; 4094 blend=InterpretLocaleValue(factor,(char **) NULL); 4095 compose=DissolveCompositeOp; 4096 break; 4097 } 4098 case CompositeDisplaceCommand: 4099 { 4100 /* 4101 Get horizontal and vertical scale displacement geometry. 4102 */ 4103 (void) XSetFunction(display,windows->image.highlight_context, 4104 GXcopy); 4105 (void) XDialogWidget(display,windows,"Displace", 4106 "Enter the horizontal and vertical scale:",displacement_geometry); 4107 (void) XSetFunction(display,windows->image.highlight_context, 4108 GXinvert); 4109 if (*displacement_geometry == '\0') 4110 break; 4111 compose=DisplaceCompositeOp; 4112 break; 4113 } 4114 case CompositeHelpCommand: 4115 { 4116 (void) XSetFunction(display,windows->image.highlight_context, 4117 GXcopy); 4118 XTextViewWidget(display,resource_info,windows,MagickFalse, 4119 "Help Viewer - Image Composite",ImageCompositeHelp); 4120 (void) XSetFunction(display,windows->image.highlight_context, 4121 GXinvert); 4122 break; 4123 } 4124 case CompositeDismissCommand: 4125 { 4126 /* 4127 Prematurely exit. 4128 */ 4129 state|=EscapeState; 4130 state|=ExitState; 4131 break; 4132 } 4133 default: 4134 break; 4135 } 4136 continue; 4137 } 4138 switch (event.type) 4139 { 4140 case ButtonPress: 4141 { 4142 if (image->debug != MagickFalse) 4143 (void) LogMagickEvent(X11Event,GetMagickModule(), 4144 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 4145 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4146 if (event.xbutton.button != Button1) 4147 break; 4148 if (event.xbutton.window != windows->image.id) 4149 break; 4150 /* 4151 Change cursor. 4152 */ 4153 composite_info.width=composite_image->columns; 4154 composite_info.height=composite_image->rows; 4155 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4156 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4157 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4158 break; 4159 } 4160 case ButtonRelease: 4161 { 4162 if (image->debug != MagickFalse) 4163 (void) LogMagickEvent(X11Event,GetMagickModule(), 4164 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 4165 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4166 if (event.xbutton.button != Button1) 4167 break; 4168 if (event.xbutton.window != windows->image.id) 4169 break; 4170 if ((composite_info.width != 0) && (composite_info.height != 0)) 4171 { 4172 /* 4173 User has selected the location of the composite image. 4174 */ 4175 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4176 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4177 state|=ExitState; 4178 } 4179 break; 4180 } 4181 case Expose: 4182 break; 4183 case KeyPress: 4184 { 4185 char 4186 command[MaxTextExtent]; 4187 4188 KeySym 4189 key_symbol; 4190 4191 int 4192 length; 4193 4194 if (event.xkey.window != windows->image.id) 4195 break; 4196 /* 4197 Respond to a user key press. 4198 */ 4199 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 4200 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4201 *(command+length)='\0'; 4202 if (image->debug != MagickFalse) 4203 (void) LogMagickEvent(X11Event,GetMagickModule(), 4204 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 4205 switch ((int) key_symbol) 4206 { 4207 case XK_Escape: 4208 case XK_F20: 4209 { 4210 /* 4211 Prematurely exit. 4212 */ 4213 composite_image=DestroyImage(composite_image); 4214 state|=EscapeState; 4215 state|=ExitState; 4216 break; 4217 } 4218 case XK_F1: 4219 case XK_Help: 4220 { 4221 (void) XSetFunction(display,windows->image.highlight_context, 4222 GXcopy); 4223 XTextViewWidget(display,resource_info,windows,MagickFalse, 4224 "Help Viewer - Image Composite",ImageCompositeHelp); 4225 (void) XSetFunction(display,windows->image.highlight_context, 4226 GXinvert); 4227 break; 4228 } 4229 default: 4230 { 4231 (void) XBell(display,0); 4232 break; 4233 } 4234 } 4235 break; 4236 } 4237 case MotionNotify: 4238 { 4239 /* 4240 Map and unmap Info widget as text cursor crosses its boundaries. 4241 */ 4242 x=event.xmotion.x; 4243 y=event.xmotion.y; 4244 if (windows->info.mapped != MagickFalse) 4245 { 4246 if ((x < (int) (windows->info.x+windows->info.width)) && 4247 (y < (int) (windows->info.y+windows->info.height))) 4248 (void) XWithdrawWindow(display,windows->info.id, 4249 windows->info.screen); 4250 } 4251 else 4252 if ((x > (int) (windows->info.x+windows->info.width)) || 4253 (y > (int) (windows->info.y+windows->info.height))) 4254 (void) XMapWindow(display,windows->info.id); 4255 composite_info.x=(ssize_t) windows->image.x+x; 4256 composite_info.y=(ssize_t) windows->image.y+y; 4257 break; 4258 } 4259 default: 4260 { 4261 if (image->debug != MagickFalse) 4262 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 4263 event.type); 4264 break; 4265 } 4266 } 4267 } while ((state & ExitState) == 0); 4268 (void) XSelectInput(display,windows->image.id, 4269 windows->image.attributes.event_mask); 4270 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4271 XSetCursorState(display,windows,MagickFalse); 4272 (void) XFreeCursor(display,cursor); 4273 if ((state & EscapeState) != 0) 4274 return(MagickTrue); 4275 /* 4276 Image compositing is relative to image configuration. 4277 */ 4278 XSetCursorState(display,windows,MagickTrue); 4279 XCheckRefreshWindows(display,windows); 4280 width=(unsigned int) image->columns; 4281 height=(unsigned int) image->rows; 4282 x=0; 4283 y=0; 4284 if (windows->image.crop_geometry != (char *) NULL) 4285 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 4286 scale_factor=(MagickRealType) width/windows->image.ximage->width; 4287 composite_info.x+=x; 4288 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 4289 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 4290 scale_factor=(MagickRealType) height/windows->image.ximage->height; 4291 composite_info.y+=y; 4292 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 4293 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 4294 if ((composite_info.width != composite_image->columns) || 4295 (composite_info.height != composite_image->rows)) 4296 { 4297 Image 4298 *resize_image; 4299 4300 /* 4301 Scale composite image. 4302 */ 4303 resize_image=ResizeImage(composite_image,composite_info.width, 4304 composite_info.height,composite_image->filter,composite_image->blur, 4305 exception); 4306 composite_image=DestroyImage(composite_image); 4307 if (resize_image == (Image *) NULL) 4308 { 4309 XSetCursorState(display,windows,MagickFalse); 4310 return(MagickFalse); 4311 } 4312 composite_image=resize_image; 4313 } 4314 if (compose == DisplaceCompositeOp) 4315 (void) SetImageArtifact(composite_image,"compose:args", 4316 displacement_geometry); 4317 if (blend != 0.0) 4318 { 4319 CacheView 4320 *image_view; 4321 4322 int 4323 y; 4324 4325 Quantum 4326 opacity; 4327 4328 register int 4329 x; 4330 4331 register Quantum 4332 *q; 4333 4334 /* 4335 Create mattes for blending. 4336 */ 4337 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception); 4338 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)- 4339 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100); 4340 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 4341 return(MagickFalse); 4342 image->matte=MagickTrue; 4343 image_view=AcquireCacheView(image); 4344 for (y=0; y < (int) image->rows; y++) 4345 { 4346 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 4347 exception); 4348 if (q == (Quantum *) NULL) 4349 break; 4350 for (x=0; x < (int) image->columns; x++) 4351 { 4352 SetPixelAlpha(image,opacity,q); 4353 q+=GetPixelChannels(image); 4354 } 4355 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 4356 break; 4357 } 4358 image_view=DestroyCacheView(image_view); 4359 } 4360 /* 4361 Composite image with X Image window. 4362 */ 4363 (void) CompositeImage(image,compose,composite_image,composite_info.x, 4364 composite_info.y,exception); 4365 composite_image=DestroyImage(composite_image); 4366 XSetCursorState(display,windows,MagickFalse); 4367 /* 4368 Update image configuration. 4369 */ 4370 XConfigureImageColormap(display,resource_info,windows,image,exception); 4371 (void) XConfigureImage(display,resource_info,windows,image,exception); 4372 return(MagickTrue); 4373} 4374 4375/* 4376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4377% % 4378% % 4379% % 4380+ X C o n f i g u r e I m a g e % 4381% % 4382% % 4383% % 4384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4385% 4386% XConfigureImage() creates a new X image. It also notifies the window 4387% manager of the new image size and configures the transient widows. 4388% 4389% The format of the XConfigureImage method is: 4390% 4391% MagickBooleanType XConfigureImage(Display *display, 4392% XResourceInfo *resource_info,XWindows *windows,Image *image, 4393% ExceptionInfo *exception) 4394% 4395% A description of each parameter follows: 4396% 4397% o display: Specifies a connection to an X server; returned from 4398% XOpenDisplay. 4399% 4400% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4401% 4402% o windows: Specifies a pointer to a XWindows structure. 4403% 4404% o image: the image. 4405% 4406% o exception: return any errors or warnings in this structure. 4407% 4408% o exception: return any errors or warnings in this structure. 4409% 4410*/ 4411static MagickBooleanType XConfigureImage(Display *display, 4412 XResourceInfo *resource_info,XWindows *windows,Image *image, 4413 ExceptionInfo *exception) 4414{ 4415 char 4416 geometry[MaxTextExtent]; 4417 4418 MagickStatusType 4419 status; 4420 4421 size_t 4422 mask, 4423 height, 4424 width; 4425 4426 ssize_t 4427 x, 4428 y; 4429 4430 XSizeHints 4431 *size_hints; 4432 4433 XWindowChanges 4434 window_changes; 4435 4436 /* 4437 Dismiss if window dimensions are zero. 4438 */ 4439 width=(unsigned int) windows->image.window_changes.width; 4440 height=(unsigned int) windows->image.window_changes.height; 4441 if (image->debug != MagickFalse) 4442 (void) LogMagickEvent(X11Event,GetMagickModule(), 4443 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 4444 windows->image.ximage->height,(double) width,(double) height); 4445 if ((width*height) == 0) 4446 return(MagickTrue); 4447 x=0; 4448 y=0; 4449 /* 4450 Resize image to fit Image window dimensions. 4451 */ 4452 XSetCursorState(display,windows,MagickTrue); 4453 (void) XFlush(display); 4454 if (((int) width != windows->image.ximage->width) || 4455 ((int) height != windows->image.ximage->height)) 4456 image->taint=MagickTrue; 4457 windows->magnify.x=(int) 4458 width*windows->magnify.x/windows->image.ximage->width; 4459 windows->magnify.y=(int) 4460 height*windows->magnify.y/windows->image.ximage->height; 4461 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 4462 windows->image.y=(int) 4463 (height*windows->image.y/windows->image.ximage->height); 4464 status=XMakeImage(display,resource_info,&windows->image,image, 4465 (unsigned int) width,(unsigned int) height,exception); 4466 if (status == MagickFalse) 4467 XNoticeWidget(display,windows,"Unable to configure X image:", 4468 windows->image.name); 4469 /* 4470 Notify window manager of the new configuration. 4471 */ 4472 if (resource_info->image_geometry != (char *) NULL) 4473 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!", 4474 resource_info->image_geometry); 4475 else 4476 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 4477 XDisplayWidth(display,windows->image.screen), 4478 XDisplayHeight(display,windows->image.screen)); 4479 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 4480 window_changes.width=(int) width; 4481 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 4482 window_changes.width=XDisplayWidth(display,windows->image.screen); 4483 window_changes.height=(int) height; 4484 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 4485 window_changes.height=XDisplayHeight(display,windows->image.screen); 4486 mask=(size_t) (CWWidth | CWHeight); 4487 if (resource_info->backdrop) 4488 { 4489 mask|=CWX | CWY; 4490 window_changes.x=(int) 4491 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 4492 window_changes.y=(int) 4493 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 4494 } 4495 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 4496 (unsigned int) mask,&window_changes); 4497 (void) XClearWindow(display,windows->image.id); 4498 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 4499 /* 4500 Update Magnify window configuration. 4501 */ 4502 if (windows->magnify.mapped != MagickFalse) 4503 XMakeMagnifyImage(display,windows,exception); 4504 windows->pan.crop_geometry=windows->image.crop_geometry; 4505 XBestIconSize(display,&windows->pan,image); 4506 while (((windows->pan.width << 1) < MaxIconSize) && 4507 ((windows->pan.height << 1) < MaxIconSize)) 4508 { 4509 windows->pan.width<<=1; 4510 windows->pan.height<<=1; 4511 } 4512 if (windows->pan.geometry != (char *) NULL) 4513 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 4514 &windows->pan.width,&windows->pan.height); 4515 window_changes.width=(int) windows->pan.width; 4516 window_changes.height=(int) windows->pan.height; 4517 size_hints=XAllocSizeHints(); 4518 if (size_hints != (XSizeHints *) NULL) 4519 { 4520 /* 4521 Set new size hints. 4522 */ 4523 size_hints->flags=PSize | PMinSize | PMaxSize; 4524 size_hints->width=window_changes.width; 4525 size_hints->height=window_changes.height; 4526 size_hints->min_width=size_hints->width; 4527 size_hints->min_height=size_hints->height; 4528 size_hints->max_width=size_hints->width; 4529 size_hints->max_height=size_hints->height; 4530 (void) XSetNormalHints(display,windows->pan.id,size_hints); 4531 (void) XFree((void *) size_hints); 4532 } 4533 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 4534 (unsigned int) (CWWidth | CWHeight),&window_changes); 4535 /* 4536 Update icon window configuration. 4537 */ 4538 windows->icon.crop_geometry=windows->image.crop_geometry; 4539 XBestIconSize(display,&windows->icon,image); 4540 window_changes.width=(int) windows->icon.width; 4541 window_changes.height=(int) windows->icon.height; 4542 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 4543 (unsigned int) (CWWidth | CWHeight),&window_changes); 4544 XSetCursorState(display,windows,MagickFalse); 4545 return(status != 0 ? MagickTrue : MagickFalse); 4546} 4547 4548/* 4549%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4550% % 4551% % 4552% % 4553+ X C r o p I m a g e % 4554% % 4555% % 4556% % 4557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4558% 4559% XCropImage() allows the user to select a region of the image and crop, copy, 4560% or cut it. For copy or cut, the image can subsequently be composited onto 4561% the image with XPasteImage. 4562% 4563% The format of the XCropImage method is: 4564% 4565% MagickBooleanType XCropImage(Display *display, 4566% XResourceInfo *resource_info,XWindows *windows,Image *image, 4567% const ClipboardMode mode,ExceptionInfo *exception) 4568% 4569% A description of each parameter follows: 4570% 4571% o display: Specifies a connection to an X server; returned from 4572% XOpenDisplay. 4573% 4574% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4575% 4576% o windows: Specifies a pointer to a XWindows structure. 4577% 4578% o image: the image; returned from ReadImage. 4579% 4580% o mode: This unsigned value specified whether the image should be 4581% cropped, copied, or cut. 4582% 4583% o exception: return any errors or warnings in this structure. 4584% 4585*/ 4586static MagickBooleanType XCropImage(Display *display, 4587 XResourceInfo *resource_info,XWindows *windows,Image *image, 4588 const ClipboardMode mode,ExceptionInfo *exception) 4589{ 4590 static const char 4591 *CropModeMenu[] = 4592 { 4593 "Help", 4594 "Dismiss", 4595 (char *) NULL 4596 }, 4597 *RectifyModeMenu[] = 4598 { 4599 "Crop", 4600 "Help", 4601 "Dismiss", 4602 (char *) NULL 4603 }; 4604 4605 static const ModeType 4606 CropCommands[] = 4607 { 4608 CropHelpCommand, 4609 CropDismissCommand 4610 }, 4611 RectifyCommands[] = 4612 { 4613 RectifyCopyCommand, 4614 RectifyHelpCommand, 4615 RectifyDismissCommand 4616 }; 4617 4618 CacheView 4619 *image_view; 4620 4621 char 4622 command[MaxTextExtent], 4623 text[MaxTextExtent]; 4624 4625 Cursor 4626 cursor; 4627 4628 int 4629 id, 4630 x, 4631 y; 4632 4633 KeySym 4634 key_symbol; 4635 4636 Image 4637 *crop_image; 4638 4639 MagickRealType 4640 scale_factor; 4641 4642 RectangleInfo 4643 crop_info, 4644 highlight_info; 4645 4646 register Quantum 4647 *q; 4648 4649 unsigned int 4650 height, 4651 width; 4652 4653 size_t 4654 state; 4655 4656 XEvent 4657 event; 4658 4659 /* 4660 Map Command widget. 4661 */ 4662 switch (mode) 4663 { 4664 case CopyMode: 4665 { 4666 (void) CloneString(&windows->command.name,"Copy"); 4667 break; 4668 } 4669 case CropMode: 4670 { 4671 (void) CloneString(&windows->command.name,"Crop"); 4672 break; 4673 } 4674 case CutMode: 4675 { 4676 (void) CloneString(&windows->command.name,"Cut"); 4677 break; 4678 } 4679 } 4680 RectifyModeMenu[0]=windows->command.name; 4681 windows->command.data=0; 4682 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 4683 (void) XMapRaised(display,windows->command.id); 4684 XClientMessage(display,windows->image.id,windows->im_protocols, 4685 windows->im_update_widget,CurrentTime); 4686 /* 4687 Track pointer until button 1 is pressed. 4688 */ 4689 XQueryPosition(display,windows->image.id,&x,&y); 4690 (void) XSelectInput(display,windows->image.id, 4691 windows->image.attributes.event_mask | PointerMotionMask); 4692 crop_info.x=(ssize_t) windows->image.x+x; 4693 crop_info.y=(ssize_t) windows->image.y+y; 4694 crop_info.width=0; 4695 crop_info.height=0; 4696 cursor=XCreateFontCursor(display,XC_fleur); 4697 state=DefaultState; 4698 do 4699 { 4700 if (windows->info.mapped != MagickFalse) 4701 { 4702 /* 4703 Display pointer position. 4704 */ 4705 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4706 (long) crop_info.x,(long) crop_info.y); 4707 XInfoWidget(display,windows,text); 4708 } 4709 /* 4710 Wait for next event. 4711 */ 4712 XScreenEvent(display,windows,&event,exception); 4713 if (event.xany.window == windows->command.id) 4714 { 4715 /* 4716 Select a command from the Command widget. 4717 */ 4718 id=XCommandWidget(display,windows,CropModeMenu,&event); 4719 if (id < 0) 4720 continue; 4721 switch (CropCommands[id]) 4722 { 4723 case CropHelpCommand: 4724 { 4725 switch (mode) 4726 { 4727 case CopyMode: 4728 { 4729 XTextViewWidget(display,resource_info,windows,MagickFalse, 4730 "Help Viewer - Image Copy",ImageCopyHelp); 4731 break; 4732 } 4733 case CropMode: 4734 { 4735 XTextViewWidget(display,resource_info,windows,MagickFalse, 4736 "Help Viewer - Image Crop",ImageCropHelp); 4737 break; 4738 } 4739 case CutMode: 4740 { 4741 XTextViewWidget(display,resource_info,windows,MagickFalse, 4742 "Help Viewer - Image Cut",ImageCutHelp); 4743 break; 4744 } 4745 } 4746 break; 4747 } 4748 case CropDismissCommand: 4749 { 4750 /* 4751 Prematurely exit. 4752 */ 4753 state|=EscapeState; 4754 state|=ExitState; 4755 break; 4756 } 4757 default: 4758 break; 4759 } 4760 continue; 4761 } 4762 switch (event.type) 4763 { 4764 case ButtonPress: 4765 { 4766 if (event.xbutton.button != Button1) 4767 break; 4768 if (event.xbutton.window != windows->image.id) 4769 break; 4770 /* 4771 Note first corner of cropping rectangle-- exit loop. 4772 */ 4773 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4774 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4775 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4776 state|=ExitState; 4777 break; 4778 } 4779 case ButtonRelease: 4780 break; 4781 case Expose: 4782 break; 4783 case KeyPress: 4784 { 4785 if (event.xkey.window != windows->image.id) 4786 break; 4787 /* 4788 Respond to a user key press. 4789 */ 4790 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 4791 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4792 switch ((int) key_symbol) 4793 { 4794 case XK_Escape: 4795 case XK_F20: 4796 { 4797 /* 4798 Prematurely exit. 4799 */ 4800 state|=EscapeState; 4801 state|=ExitState; 4802 break; 4803 } 4804 case XK_F1: 4805 case XK_Help: 4806 { 4807 switch (mode) 4808 { 4809 case CopyMode: 4810 { 4811 XTextViewWidget(display,resource_info,windows,MagickFalse, 4812 "Help Viewer - Image Copy",ImageCopyHelp); 4813 break; 4814 } 4815 case CropMode: 4816 { 4817 XTextViewWidget(display,resource_info,windows,MagickFalse, 4818 "Help Viewer - Image Crop",ImageCropHelp); 4819 break; 4820 } 4821 case CutMode: 4822 { 4823 XTextViewWidget(display,resource_info,windows,MagickFalse, 4824 "Help Viewer - Image Cut",ImageCutHelp); 4825 break; 4826 } 4827 } 4828 break; 4829 } 4830 default: 4831 { 4832 (void) XBell(display,0); 4833 break; 4834 } 4835 } 4836 break; 4837 } 4838 case MotionNotify: 4839 { 4840 if (event.xmotion.window != windows->image.id) 4841 break; 4842 /* 4843 Map and unmap Info widget as text cursor crosses its boundaries. 4844 */ 4845 x=event.xmotion.x; 4846 y=event.xmotion.y; 4847 if (windows->info.mapped != MagickFalse) 4848 { 4849 if ((x < (int) (windows->info.x+windows->info.width)) && 4850 (y < (int) (windows->info.y+windows->info.height))) 4851 (void) XWithdrawWindow(display,windows->info.id, 4852 windows->info.screen); 4853 } 4854 else 4855 if ((x > (int) (windows->info.x+windows->info.width)) || 4856 (y > (int) (windows->info.y+windows->info.height))) 4857 (void) XMapWindow(display,windows->info.id); 4858 crop_info.x=(ssize_t) windows->image.x+x; 4859 crop_info.y=(ssize_t) windows->image.y+y; 4860 break; 4861 } 4862 default: 4863 break; 4864 } 4865 } while ((state & ExitState) == 0); 4866 (void) XSelectInput(display,windows->image.id, 4867 windows->image.attributes.event_mask); 4868 if ((state & EscapeState) != 0) 4869 { 4870 /* 4871 User want to exit without cropping. 4872 */ 4873 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4874 (void) XFreeCursor(display,cursor); 4875 return(MagickTrue); 4876 } 4877 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4878 do 4879 { 4880 /* 4881 Size rectangle as pointer moves until the mouse button is released. 4882 */ 4883 x=(int) crop_info.x; 4884 y=(int) crop_info.y; 4885 crop_info.width=0; 4886 crop_info.height=0; 4887 state=DefaultState; 4888 do 4889 { 4890 highlight_info=crop_info; 4891 highlight_info.x=crop_info.x-windows->image.x; 4892 highlight_info.y=crop_info.y-windows->image.y; 4893 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4894 { 4895 /* 4896 Display info and draw cropping rectangle. 4897 */ 4898 if (windows->info.mapped == MagickFalse) 4899 (void) XMapWindow(display,windows->info.id); 4900 (void) FormatLocaleString(text,MaxTextExtent, 4901 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4902 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4903 XInfoWidget(display,windows,text); 4904 XHighlightRectangle(display,windows->image.id, 4905 windows->image.highlight_context,&highlight_info); 4906 } 4907 else 4908 if (windows->info.mapped != MagickFalse) 4909 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4910 /* 4911 Wait for next event. 4912 */ 4913 XScreenEvent(display,windows,&event,exception); 4914 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4915 XHighlightRectangle(display,windows->image.id, 4916 windows->image.highlight_context,&highlight_info); 4917 switch (event.type) 4918 { 4919 case ButtonPress: 4920 { 4921 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4922 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4923 break; 4924 } 4925 case ButtonRelease: 4926 { 4927 /* 4928 User has committed to cropping rectangle. 4929 */ 4930 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4931 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4932 XSetCursorState(display,windows,MagickFalse); 4933 state|=ExitState; 4934 windows->command.data=0; 4935 (void) XCommandWidget(display,windows,RectifyModeMenu, 4936 (XEvent *) NULL); 4937 break; 4938 } 4939 case Expose: 4940 break; 4941 case MotionNotify: 4942 { 4943 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 4944 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 4945 } 4946 default: 4947 break; 4948 } 4949 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 4950 ((state & ExitState) != 0)) 4951 { 4952 /* 4953 Check boundary conditions. 4954 */ 4955 if (crop_info.x < 0) 4956 crop_info.x=0; 4957 else 4958 if (crop_info.x > (ssize_t) windows->image.ximage->width) 4959 crop_info.x=(ssize_t) windows->image.ximage->width; 4960 if ((int) crop_info.x < x) 4961 crop_info.width=(unsigned int) (x-crop_info.x); 4962 else 4963 { 4964 crop_info.width=(unsigned int) (crop_info.x-x); 4965 crop_info.x=(ssize_t) x; 4966 } 4967 if (crop_info.y < 0) 4968 crop_info.y=0; 4969 else 4970 if (crop_info.y > (ssize_t) windows->image.ximage->height) 4971 crop_info.y=(ssize_t) windows->image.ximage->height; 4972 if ((int) crop_info.y < y) 4973 crop_info.height=(unsigned int) (y-crop_info.y); 4974 else 4975 { 4976 crop_info.height=(unsigned int) (crop_info.y-y); 4977 crop_info.y=(ssize_t) y; 4978 } 4979 } 4980 } while ((state & ExitState) == 0); 4981 /* 4982 Wait for user to grab a corner of the rectangle or press return. 4983 */ 4984 state=DefaultState; 4985 (void) XMapWindow(display,windows->info.id); 4986 do 4987 { 4988 if (windows->info.mapped != MagickFalse) 4989 { 4990 /* 4991 Display pointer position. 4992 */ 4993 (void) FormatLocaleString(text,MaxTextExtent, 4994 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4995 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4996 XInfoWidget(display,windows,text); 4997 } 4998 highlight_info=crop_info; 4999 highlight_info.x=crop_info.x-windows->image.x; 5000 highlight_info.y=crop_info.y-windows->image.y; 5001 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 5002 { 5003 state|=EscapeState; 5004 state|=ExitState; 5005 break; 5006 } 5007 XHighlightRectangle(display,windows->image.id, 5008 windows->image.highlight_context,&highlight_info); 5009 XScreenEvent(display,windows,&event,exception); 5010 if (event.xany.window == windows->command.id) 5011 { 5012 /* 5013 Select a command from the Command widget. 5014 */ 5015 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5016 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 5017 (void) XSetFunction(display,windows->image.highlight_context, 5018 GXinvert); 5019 XHighlightRectangle(display,windows->image.id, 5020 windows->image.highlight_context,&highlight_info); 5021 if (id >= 0) 5022 switch (RectifyCommands[id]) 5023 { 5024 case RectifyCopyCommand: 5025 { 5026 state|=ExitState; 5027 break; 5028 } 5029 case RectifyHelpCommand: 5030 { 5031 (void) XSetFunction(display,windows->image.highlight_context, 5032 GXcopy); 5033 switch (mode) 5034 { 5035 case CopyMode: 5036 { 5037 XTextViewWidget(display,resource_info,windows,MagickFalse, 5038 "Help Viewer - Image Copy",ImageCopyHelp); 5039 break; 5040 } 5041 case CropMode: 5042 { 5043 XTextViewWidget(display,resource_info,windows,MagickFalse, 5044 "Help Viewer - Image Crop",ImageCropHelp); 5045 break; 5046 } 5047 case CutMode: 5048 { 5049 XTextViewWidget(display,resource_info,windows,MagickFalse, 5050 "Help Viewer - Image Cut",ImageCutHelp); 5051 break; 5052 } 5053 } 5054 (void) XSetFunction(display,windows->image.highlight_context, 5055 GXinvert); 5056 break; 5057 } 5058 case RectifyDismissCommand: 5059 { 5060 /* 5061 Prematurely exit. 5062 */ 5063 state|=EscapeState; 5064 state|=ExitState; 5065 break; 5066 } 5067 default: 5068 break; 5069 } 5070 continue; 5071 } 5072 XHighlightRectangle(display,windows->image.id, 5073 windows->image.highlight_context,&highlight_info); 5074 switch (event.type) 5075 { 5076 case ButtonPress: 5077 { 5078 if (event.xbutton.button != Button1) 5079 break; 5080 if (event.xbutton.window != windows->image.id) 5081 break; 5082 x=windows->image.x+event.xbutton.x; 5083 y=windows->image.y+event.xbutton.y; 5084 if ((x < (int) (crop_info.x+RoiDelta)) && 5085 (x > (int) (crop_info.x-RoiDelta)) && 5086 (y < (int) (crop_info.y+RoiDelta)) && 5087 (y > (int) (crop_info.y-RoiDelta))) 5088 { 5089 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5090 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5091 state|=UpdateConfigurationState; 5092 break; 5093 } 5094 if ((x < (int) (crop_info.x+RoiDelta)) && 5095 (x > (int) (crop_info.x-RoiDelta)) && 5096 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5097 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5098 { 5099 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5100 state|=UpdateConfigurationState; 5101 break; 5102 } 5103 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5104 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5105 (y < (int) (crop_info.y+RoiDelta)) && 5106 (y > (int) (crop_info.y-RoiDelta))) 5107 { 5108 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5109 state|=UpdateConfigurationState; 5110 break; 5111 } 5112 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5113 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5114 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5115 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5116 { 5117 state|=UpdateConfigurationState; 5118 break; 5119 } 5120 } 5121 case ButtonRelease: 5122 { 5123 if (event.xbutton.window == windows->pan.id) 5124 if ((highlight_info.x != crop_info.x-windows->image.x) || 5125 (highlight_info.y != crop_info.y-windows->image.y)) 5126 XHighlightRectangle(display,windows->image.id, 5127 windows->image.highlight_context,&highlight_info); 5128 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5129 event.xbutton.time); 5130 break; 5131 } 5132 case Expose: 5133 { 5134 if (event.xexpose.window == windows->image.id) 5135 if (event.xexpose.count == 0) 5136 { 5137 event.xexpose.x=(int) highlight_info.x; 5138 event.xexpose.y=(int) highlight_info.y; 5139 event.xexpose.width=(int) highlight_info.width; 5140 event.xexpose.height=(int) highlight_info.height; 5141 XRefreshWindow(display,&windows->image,&event); 5142 } 5143 if (event.xexpose.window == windows->info.id) 5144 if (event.xexpose.count == 0) 5145 XInfoWidget(display,windows,text); 5146 break; 5147 } 5148 case KeyPress: 5149 { 5150 if (event.xkey.window != windows->image.id) 5151 break; 5152 /* 5153 Respond to a user key press. 5154 */ 5155 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5156 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5157 switch ((int) key_symbol) 5158 { 5159 case XK_Escape: 5160 case XK_F20: 5161 state|=EscapeState; 5162 case XK_Return: 5163 { 5164 state|=ExitState; 5165 break; 5166 } 5167 case XK_Home: 5168 case XK_KP_Home: 5169 { 5170 crop_info.x=(ssize_t) (windows->image.width/2L- 5171 crop_info.width/2L); 5172 crop_info.y=(ssize_t) (windows->image.height/2L- 5173 crop_info.height/2L); 5174 break; 5175 } 5176 case XK_Left: 5177 case XK_KP_Left: 5178 { 5179 crop_info.x--; 5180 break; 5181 } 5182 case XK_Up: 5183 case XK_KP_Up: 5184 case XK_Next: 5185 { 5186 crop_info.y--; 5187 break; 5188 } 5189 case XK_Right: 5190 case XK_KP_Right: 5191 { 5192 crop_info.x++; 5193 break; 5194 } 5195 case XK_Prior: 5196 case XK_Down: 5197 case XK_KP_Down: 5198 { 5199 crop_info.y++; 5200 break; 5201 } 5202 case XK_F1: 5203 case XK_Help: 5204 { 5205 (void) XSetFunction(display,windows->image.highlight_context, 5206 GXcopy); 5207 switch (mode) 5208 { 5209 case CopyMode: 5210 { 5211 XTextViewWidget(display,resource_info,windows,MagickFalse, 5212 "Help Viewer - Image Copy",ImageCopyHelp); 5213 break; 5214 } 5215 case CropMode: 5216 { 5217 XTextViewWidget(display,resource_info,windows,MagickFalse, 5218 "Help Viewer - Image Cropg",ImageCropHelp); 5219 break; 5220 } 5221 case CutMode: 5222 { 5223 XTextViewWidget(display,resource_info,windows,MagickFalse, 5224 "Help Viewer - Image Cutg",ImageCutHelp); 5225 break; 5226 } 5227 } 5228 (void) XSetFunction(display,windows->image.highlight_context, 5229 GXinvert); 5230 break; 5231 } 5232 default: 5233 { 5234 (void) XBell(display,0); 5235 break; 5236 } 5237 } 5238 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5239 event.xkey.time); 5240 break; 5241 } 5242 case KeyRelease: 5243 break; 5244 case MotionNotify: 5245 { 5246 if (event.xmotion.window != windows->image.id) 5247 break; 5248 /* 5249 Map and unmap Info widget as text cursor crosses its boundaries. 5250 */ 5251 x=event.xmotion.x; 5252 y=event.xmotion.y; 5253 if (windows->info.mapped != MagickFalse) 5254 { 5255 if ((x < (int) (windows->info.x+windows->info.width)) && 5256 (y < (int) (windows->info.y+windows->info.height))) 5257 (void) XWithdrawWindow(display,windows->info.id, 5258 windows->info.screen); 5259 } 5260 else 5261 if ((x > (int) (windows->info.x+windows->info.width)) || 5262 (y > (int) (windows->info.y+windows->info.height))) 5263 (void) XMapWindow(display,windows->info.id); 5264 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 5265 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 5266 break; 5267 } 5268 case SelectionRequest: 5269 { 5270 XSelectionEvent 5271 notify; 5272 5273 XSelectionRequestEvent 5274 *request; 5275 5276 /* 5277 Set primary selection. 5278 */ 5279 (void) FormatLocaleString(text,MaxTextExtent, 5280 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 5281 crop_info.height,(double) crop_info.x,(double) crop_info.y); 5282 request=(&(event.xselectionrequest)); 5283 (void) XChangeProperty(request->display,request->requestor, 5284 request->property,request->target,8,PropModeReplace, 5285 (unsigned char *) text,(int) strlen(text)); 5286 notify.type=SelectionNotify; 5287 notify.display=request->display; 5288 notify.requestor=request->requestor; 5289 notify.selection=request->selection; 5290 notify.target=request->target; 5291 notify.time=request->time; 5292 if (request->property == None) 5293 notify.property=request->target; 5294 else 5295 notify.property=request->property; 5296 (void) XSendEvent(request->display,request->requestor,False,0, 5297 (XEvent *) ¬ify); 5298 } 5299 default: 5300 break; 5301 } 5302 if ((state & UpdateConfigurationState) != 0) 5303 { 5304 (void) XPutBackEvent(display,&event); 5305 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5306 break; 5307 } 5308 } while ((state & ExitState) == 0); 5309 } while ((state & ExitState) == 0); 5310 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5311 XSetCursorState(display,windows,MagickFalse); 5312 if ((state & EscapeState) != 0) 5313 return(MagickTrue); 5314 if (mode == CropMode) 5315 if (((int) crop_info.width != windows->image.ximage->width) || 5316 ((int) crop_info.height != windows->image.ximage->height)) 5317 { 5318 /* 5319 Reconfigure Image window as defined by cropping rectangle. 5320 */ 5321 XSetCropGeometry(display,windows,&crop_info,image); 5322 windows->image.window_changes.width=(int) crop_info.width; 5323 windows->image.window_changes.height=(int) crop_info.height; 5324 (void) XConfigureImage(display,resource_info,windows,image,exception); 5325 return(MagickTrue); 5326 } 5327 /* 5328 Copy image before applying image transforms. 5329 */ 5330 XSetCursorState(display,windows,MagickTrue); 5331 XCheckRefreshWindows(display,windows); 5332 width=(unsigned int) image->columns; 5333 height=(unsigned int) image->rows; 5334 x=0; 5335 y=0; 5336 if (windows->image.crop_geometry != (char *) NULL) 5337 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 5338 scale_factor=(MagickRealType) width/windows->image.ximage->width; 5339 crop_info.x+=x; 5340 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 5341 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 5342 scale_factor=(MagickRealType) height/windows->image.ximage->height; 5343 crop_info.y+=y; 5344 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 5345 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5); 5346 crop_image=CropImage(image,&crop_info,exception); 5347 XSetCursorState(display,windows,MagickFalse); 5348 if (crop_image == (Image *) NULL) 5349 return(MagickFalse); 5350 if (resource_info->copy_image != (Image *) NULL) 5351 resource_info->copy_image=DestroyImage(resource_info->copy_image); 5352 resource_info->copy_image=crop_image; 5353 if (mode == CopyMode) 5354 { 5355 (void) XConfigureImage(display,resource_info,windows,image,exception); 5356 return(MagickTrue); 5357 } 5358 /* 5359 Cut image. 5360 */ 5361 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 5362 return(MagickFalse); 5363 image->matte=MagickTrue; 5364 image_view=AcquireCacheView(image); 5365 for (y=0; y < (int) crop_info.height; y++) 5366 { 5367 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y, 5368 crop_info.width,1,exception); 5369 if (q == (Quantum *) NULL) 5370 break; 5371 for (x=0; x < (int) crop_info.width; x++) 5372 { 5373 SetPixelAlpha(image,TransparentAlpha,q); 5374 q+=GetPixelChannels(image); 5375 } 5376 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 5377 break; 5378 } 5379 image_view=DestroyCacheView(image_view); 5380 /* 5381 Update image configuration. 5382 */ 5383 XConfigureImageColormap(display,resource_info,windows,image,exception); 5384 (void) XConfigureImage(display,resource_info,windows,image,exception); 5385 return(MagickTrue); 5386} 5387 5388/* 5389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5390% % 5391% % 5392% % 5393+ X D r a w I m a g e % 5394% % 5395% % 5396% % 5397%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5398% 5399% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on 5400% the image. 5401% 5402% The format of the XDrawEditImage method is: 5403% 5404% MagickBooleanType XDrawEditImage(Display *display, 5405% XResourceInfo *resource_info,XWindows *windows,Image **image, 5406% ExceptionInfo *exception) 5407% 5408% A description of each parameter follows: 5409% 5410% o display: Specifies a connection to an X server; returned from 5411% XOpenDisplay. 5412% 5413% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 5414% 5415% o windows: Specifies a pointer to a XWindows structure. 5416% 5417% o image: the image. 5418% 5419% o exception: return any errors or warnings in this structure. 5420% 5421*/ 5422static MagickBooleanType XDrawEditImage(Display *display, 5423 XResourceInfo *resource_info,XWindows *windows,Image **image, 5424 ExceptionInfo *exception) 5425{ 5426 static const char 5427 *DrawMenu[] = 5428 { 5429 "Element", 5430 "Color", 5431 "Stipple", 5432 "Width", 5433 "Undo", 5434 "Help", 5435 "Dismiss", 5436 (char *) NULL 5437 }; 5438 5439 static ElementType 5440 element = PointElement; 5441 5442 static const ModeType 5443 DrawCommands[] = 5444 { 5445 DrawElementCommand, 5446 DrawColorCommand, 5447 DrawStippleCommand, 5448 DrawWidthCommand, 5449 DrawUndoCommand, 5450 DrawHelpCommand, 5451 DrawDismissCommand 5452 }; 5453 5454 static Pixmap 5455 stipple = (Pixmap) NULL; 5456 5457 static unsigned int 5458 pen_id = 0, 5459 line_width = 1; 5460 5461 char 5462 command[MaxTextExtent], 5463 text[MaxTextExtent]; 5464 5465 Cursor 5466 cursor; 5467 5468 int 5469 entry, 5470 id, 5471 number_coordinates, 5472 x, 5473 y; 5474 5475 MagickRealType 5476 degrees; 5477 5478 MagickStatusType 5479 status; 5480 5481 RectangleInfo 5482 rectangle_info; 5483 5484 register int 5485 i; 5486 5487 unsigned int 5488 distance, 5489 height, 5490 max_coordinates, 5491 width; 5492 5493 size_t 5494 state; 5495 5496 Window 5497 root_window; 5498 5499 XDrawInfo 5500 draw_info; 5501 5502 XEvent 5503 event; 5504 5505 XPoint 5506 *coordinate_info; 5507 5508 XSegment 5509 line_info; 5510 5511 /* 5512 Allocate polygon info. 5513 */ 5514 max_coordinates=2048; 5515 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates, 5516 sizeof(*coordinate_info)); 5517 if (coordinate_info == (XPoint *) NULL) 5518 { 5519 (void) ThrowMagickException(exception,GetMagickModule(), 5520 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 5521 return(MagickFalse); 5522 } 5523 /* 5524 Map Command widget. 5525 */ 5526 (void) CloneString(&windows->command.name,"Draw"); 5527 windows->command.data=4; 5528 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL); 5529 (void) XMapRaised(display,windows->command.id); 5530 XClientMessage(display,windows->image.id,windows->im_protocols, 5531 windows->im_update_widget,CurrentTime); 5532 /* 5533 Wait for first button press. 5534 */ 5535 root_window=XRootWindow(display,XDefaultScreen(display)); 5536 draw_info.stencil=OpaqueStencil; 5537 status=MagickTrue; 5538 cursor=XCreateFontCursor(display,XC_tcross); 5539 for ( ; ; ) 5540 { 5541 XQueryPosition(display,windows->image.id,&x,&y); 5542 (void) XSelectInput(display,windows->image.id, 5543 windows->image.attributes.event_mask | PointerMotionMask); 5544 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5545 state=DefaultState; 5546 do 5547 { 5548 if (windows->info.mapped != MagickFalse) 5549 { 5550 /* 5551 Display pointer position. 5552 */ 5553 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 5554 x+windows->image.x,y+windows->image.y); 5555 XInfoWidget(display,windows,text); 5556 } 5557 /* 5558 Wait for next event. 5559 */ 5560 XScreenEvent(display,windows,&event,exception); 5561 if (event.xany.window == windows->command.id) 5562 { 5563 /* 5564 Select a command from the Command widget. 5565 */ 5566 id=XCommandWidget(display,windows,DrawMenu,&event); 5567 if (id < 0) 5568 continue; 5569 switch (DrawCommands[id]) 5570 { 5571 case DrawElementCommand: 5572 { 5573 static const char 5574 *Elements[] = 5575 { 5576 "point", 5577 "line", 5578 "rectangle", 5579 "fill rectangle", 5580 "circle", 5581 "fill circle", 5582 "ellipse", 5583 "fill ellipse", 5584 "polygon", 5585 "fill polygon", 5586 (char *) NULL, 5587 }; 5588 5589 /* 5590 Select a command from the pop-up menu. 5591 */ 5592 element=(ElementType) (XMenuWidget(display,windows, 5593 DrawMenu[id],Elements,command)+1); 5594 break; 5595 } 5596 case DrawColorCommand: 5597 { 5598 const char 5599 *ColorMenu[MaxNumberPens+1]; 5600 5601 int 5602 pen_number; 5603 5604 MagickBooleanType 5605 transparent; 5606 5607 XColor 5608 color; 5609 5610 /* 5611 Initialize menu selections. 5612 */ 5613 for (i=0; i < (int) (MaxNumberPens-2); i++) 5614 ColorMenu[i]=resource_info->pen_colors[i]; 5615 ColorMenu[MaxNumberPens-2]="transparent"; 5616 ColorMenu[MaxNumberPens-1]="Browser..."; 5617 ColorMenu[MaxNumberPens]=(char *) NULL; 5618 /* 5619 Select a pen color from the pop-up menu. 5620 */ 5621 pen_number=XMenuWidget(display,windows,DrawMenu[id], 5622 (const char **) ColorMenu,command); 5623 if (pen_number < 0) 5624 break; 5625 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue : 5626 MagickFalse; 5627 if (transparent != MagickFalse) 5628 { 5629 draw_info.stencil=TransparentStencil; 5630 break; 5631 } 5632 if (pen_number == (MaxNumberPens-1)) 5633 { 5634 static char 5635 color_name[MaxTextExtent] = "gray"; 5636 5637 /* 5638 Select a pen color from a dialog. 5639 */ 5640 resource_info->pen_colors[pen_number]=color_name; 5641 XColorBrowserWidget(display,windows,"Select",color_name); 5642 if (*color_name == '\0') 5643 break; 5644 } 5645 /* 5646 Set pen color. 5647 */ 5648 (void) XParseColor(display,windows->map_info->colormap, 5649 resource_info->pen_colors[pen_number],&color); 5650 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 5651 (unsigned int) MaxColors,&color); 5652 windows->pixel_info->pen_colors[pen_number]=color; 5653 pen_id=(unsigned int) pen_number; 5654 draw_info.stencil=OpaqueStencil; 5655 break; 5656 } 5657 case DrawStippleCommand: 5658 { 5659 Image 5660 *stipple_image; 5661 5662 ImageInfo 5663 *image_info; 5664 5665 int 5666 status; 5667 5668 static char 5669 filename[MaxTextExtent] = "\0"; 5670 5671 static const char 5672 *StipplesMenu[] = 5673 { 5674 "Brick", 5675 "Diagonal", 5676 "Scales", 5677 "Vertical", 5678 "Wavy", 5679 "Translucent", 5680 "Opaque", 5681 (char *) NULL, 5682 (char *) NULL, 5683 }; 5684 5685 /* 5686 Select a command from the pop-up menu. 5687 */ 5688 StipplesMenu[7]="Open..."; 5689 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu, 5690 command); 5691 if (entry < 0) 5692 break; 5693 if (stipple != (Pixmap) NULL) 5694 (void) XFreePixmap(display,stipple); 5695 stipple=(Pixmap) NULL; 5696 if (entry != 7) 5697 { 5698 switch (entry) 5699 { 5700 case 0: 5701 { 5702 stipple=XCreateBitmapFromData(display,root_window, 5703 (char *) BricksBitmap,BricksWidth,BricksHeight); 5704 break; 5705 } 5706 case 1: 5707 { 5708 stipple=XCreateBitmapFromData(display,root_window, 5709 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight); 5710 break; 5711 } 5712 case 2: 5713 { 5714 stipple=XCreateBitmapFromData(display,root_window, 5715 (char *) ScalesBitmap,ScalesWidth,ScalesHeight); 5716 break; 5717 } 5718 case 3: 5719 { 5720 stipple=XCreateBitmapFromData(display,root_window, 5721 (char *) VerticalBitmap,VerticalWidth,VerticalHeight); 5722 break; 5723 } 5724 case 4: 5725 { 5726 stipple=XCreateBitmapFromData(display,root_window, 5727 (char *) WavyBitmap,WavyWidth,WavyHeight); 5728 break; 5729 } 5730 case 5: 5731 { 5732 stipple=XCreateBitmapFromData(display,root_window, 5733 (char *) HighlightBitmap,HighlightWidth, 5734 HighlightHeight); 5735 break; 5736 } 5737 case 6: 5738 default: 5739 { 5740 stipple=XCreateBitmapFromData(display,root_window, 5741 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight); 5742 break; 5743 } 5744 } 5745 break; 5746 } 5747 XFileBrowserWidget(display,windows,"Stipple",filename); 5748 if (*filename == '\0') 5749 break; 5750 /* 5751 Read image. 5752 */ 5753 XSetCursorState(display,windows,MagickTrue); 5754 XCheckRefreshWindows(display,windows); 5755 image_info=AcquireImageInfo(); 5756 (void) CopyMagickString(image_info->filename,filename, 5757 MaxTextExtent); 5758 stipple_image=ReadImage(image_info,exception); 5759 CatchException(exception); 5760 XSetCursorState(display,windows,MagickFalse); 5761 if (stipple_image == (Image *) NULL) 5762 break; 5763 (void) AcquireUniqueFileResource(filename); 5764 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent, 5765 "xbm:%s",filename); 5766 (void) WriteImage(image_info,stipple_image,exception); 5767 stipple_image=DestroyImage(stipple_image); 5768 image_info=DestroyImageInfo(image_info); 5769 status=XReadBitmapFile(display,root_window,filename,&width, 5770 &height,&stipple,&x,&y); 5771 (void) RelinquishUniqueFileResource(filename); 5772 if ((status != BitmapSuccess) != 0) 5773 XNoticeWidget(display,windows,"Unable to read X bitmap image:", 5774 filename); 5775 break; 5776 } 5777 case DrawWidthCommand: 5778 { 5779 static char 5780 width[MaxTextExtent] = "0"; 5781 5782 static const char 5783 *WidthsMenu[] = 5784 { 5785 "1", 5786 "2", 5787 "4", 5788 "8", 5789 "16", 5790 "Dialog...", 5791 (char *) NULL, 5792 }; 5793 5794 /* 5795 Select a command from the pop-up menu. 5796 */ 5797 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu, 5798 command); 5799 if (entry < 0) 5800 break; 5801 if (entry != 5) 5802 { 5803 line_width=(unsigned int) StringToUnsignedLong( 5804 WidthsMenu[entry]); 5805 break; 5806 } 5807 (void) XDialogWidget(display,windows,"Ok","Enter line width:", 5808 width); 5809 if (*width == '\0') 5810 break; 5811 line_width=(unsigned int) StringToUnsignedLong(width); 5812 break; 5813 } 5814 case DrawUndoCommand: 5815 { 5816 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 5817 image,exception); 5818 break; 5819 } 5820 case DrawHelpCommand: 5821 { 5822 XTextViewWidget(display,resource_info,windows,MagickFalse, 5823 "Help Viewer - Image Rotation",ImageDrawHelp); 5824 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5825 break; 5826 } 5827 case DrawDismissCommand: 5828 { 5829 /* 5830 Prematurely exit. 5831 */ 5832 state|=EscapeState; 5833 state|=ExitState; 5834 break; 5835 } 5836 default: 5837 break; 5838 } 5839 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5840 continue; 5841 } 5842 switch (event.type) 5843 { 5844 case ButtonPress: 5845 { 5846 if (event.xbutton.button != Button1) 5847 break; 5848 if (event.xbutton.window != windows->image.id) 5849 break; 5850 /* 5851 exit loop. 5852 */ 5853 x=event.xbutton.x; 5854 y=event.xbutton.y; 5855 state|=ExitState; 5856 break; 5857 } 5858 case ButtonRelease: 5859 break; 5860 case Expose: 5861 break; 5862 case KeyPress: 5863 { 5864 KeySym 5865 key_symbol; 5866 5867 if (event.xkey.window != windows->image.id) 5868 break; 5869 /* 5870 Respond to a user key press. 5871 */ 5872 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5873 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5874 switch ((int) key_symbol) 5875 { 5876 case XK_Escape: 5877 case XK_F20: 5878 { 5879 /* 5880 Prematurely exit. 5881 */ 5882 state|=EscapeState; 5883 state|=ExitState; 5884 break; 5885 } 5886 case XK_F1: 5887 case XK_Help: 5888 { 5889 XTextViewWidget(display,resource_info,windows,MagickFalse, 5890 "Help Viewer - Image Rotation",ImageDrawHelp); 5891 break; 5892 } 5893 default: 5894 { 5895 (void) XBell(display,0); 5896 break; 5897 } 5898 } 5899 break; 5900 } 5901 case MotionNotify: 5902 { 5903 /* 5904 Map and unmap Info widget as text cursor crosses its boundaries. 5905 */ 5906 x=event.xmotion.x; 5907 y=event.xmotion.y; 5908 if (windows->info.mapped != MagickFalse) 5909 { 5910 if ((x < (int) (windows->info.x+windows->info.width)) && 5911 (y < (int) (windows->info.y+windows->info.height))) 5912 (void) XWithdrawWindow(display,windows->info.id, 5913 windows->info.screen); 5914 } 5915 else 5916 if ((x > (int) (windows->info.x+windows->info.width)) || 5917 (y > (int) (windows->info.y+windows->info.height))) 5918 (void) XMapWindow(display,windows->info.id); 5919 break; 5920 } 5921 } 5922 } while ((state & ExitState) == 0); 5923 (void) XSelectInput(display,windows->image.id, 5924 windows->image.attributes.event_mask); 5925 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 5926 if ((state & EscapeState) != 0) 5927 break; 5928 /* 5929 Draw element as pointer moves until the button is released. 5930 */ 5931 distance=0; 5932 degrees=0.0; 5933 line_info.x1=x; 5934 line_info.y1=y; 5935 line_info.x2=x; 5936 line_info.y2=y; 5937 rectangle_info.x=(ssize_t) x; 5938 rectangle_info.y=(ssize_t) y; 5939 rectangle_info.width=0; 5940 rectangle_info.height=0; 5941 number_coordinates=1; 5942 coordinate_info->x=x; 5943 coordinate_info->y=y; 5944 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 5945 state=DefaultState; 5946 do 5947 { 5948 switch (element) 5949 { 5950 case PointElement: 5951 default: 5952 { 5953 if (number_coordinates > 1) 5954 { 5955 (void) XDrawLines(display,windows->image.id, 5956 windows->image.highlight_context,coordinate_info, 5957 number_coordinates,CoordModeOrigin); 5958 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d", 5959 coordinate_info[number_coordinates-1].x, 5960 coordinate_info[number_coordinates-1].y); 5961 XInfoWidget(display,windows,text); 5962 } 5963 break; 5964 } 5965 case LineElement: 5966 { 5967 if (distance > 9) 5968 { 5969 /* 5970 Display angle of the line. 5971 */ 5972 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 5973 line_info.y1),(double) (line_info.x2-line_info.x1))); 5974 (void) FormatLocaleString(text,MaxTextExtent," %g", 5975 (double) degrees); 5976 XInfoWidget(display,windows,text); 5977 XHighlightLine(display,windows->image.id, 5978 windows->image.highlight_context,&line_info); 5979 } 5980 else 5981 if (windows->info.mapped != MagickFalse) 5982 (void) XWithdrawWindow(display,windows->info.id, 5983 windows->info.screen); 5984 break; 5985 } 5986 case RectangleElement: 5987 case FillRectangleElement: 5988 { 5989 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5990 { 5991 /* 5992 Display info and draw drawing rectangle. 5993 */ 5994 (void) FormatLocaleString(text,MaxTextExtent, 5995 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5996 (double) rectangle_info.height,(double) rectangle_info.x, 5997 (double) rectangle_info.y); 5998 XInfoWidget(display,windows,text); 5999 XHighlightRectangle(display,windows->image.id, 6000 windows->image.highlight_context,&rectangle_info); 6001 } 6002 else 6003 if (windows->info.mapped != MagickFalse) 6004 (void) XWithdrawWindow(display,windows->info.id, 6005 windows->info.screen); 6006 break; 6007 } 6008 case CircleElement: 6009 case FillCircleElement: 6010 case EllipseElement: 6011 case FillEllipseElement: 6012 { 6013 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6014 { 6015 /* 6016 Display info and draw drawing rectangle. 6017 */ 6018 (void) FormatLocaleString(text,MaxTextExtent, 6019 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 6020 (double) rectangle_info.height,(double) rectangle_info.x, 6021 (double) rectangle_info.y); 6022 XInfoWidget(display,windows,text); 6023 XHighlightEllipse(display,windows->image.id, 6024 windows->image.highlight_context,&rectangle_info); 6025 } 6026 else 6027 if (windows->info.mapped != MagickFalse) 6028 (void) XWithdrawWindow(display,windows->info.id, 6029 windows->info.screen); 6030 break; 6031 } 6032 case PolygonElement: 6033 case FillPolygonElement: 6034 { 6035 if (number_coordinates > 1) 6036 (void) XDrawLines(display,windows->image.id, 6037 windows->image.highlight_context,coordinate_info, 6038 number_coordinates,CoordModeOrigin); 6039 if (distance > 9) 6040 { 6041 /* 6042 Display angle of the line. 6043 */ 6044 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 6045 line_info.y1),(double) (line_info.x2-line_info.x1))); 6046 (void) FormatLocaleString(text,MaxTextExtent," %g", 6047 (double) degrees); 6048 XInfoWidget(display,windows,text); 6049 XHighlightLine(display,windows->image.id, 6050 windows->image.highlight_context,&line_info); 6051 } 6052 else 6053 if (windows->info.mapped != MagickFalse) 6054 (void) XWithdrawWindow(display,windows->info.id, 6055 windows->info.screen); 6056 break; 6057 } 6058 } 6059 /* 6060 Wait for next event. 6061 */ 6062 XScreenEvent(display,windows,&event,exception); 6063 switch (element) 6064 { 6065 case PointElement: 6066 default: 6067 { 6068 if (number_coordinates > 1) 6069 (void) XDrawLines(display,windows->image.id, 6070 windows->image.highlight_context,coordinate_info, 6071 number_coordinates,CoordModeOrigin); 6072 break; 6073 } 6074 case LineElement: 6075 { 6076 if (distance > 9) 6077 XHighlightLine(display,windows->image.id, 6078 windows->image.highlight_context,&line_info); 6079 break; 6080 } 6081 case RectangleElement: 6082 case FillRectangleElement: 6083 { 6084 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6085 XHighlightRectangle(display,windows->image.id, 6086 windows->image.highlight_context,&rectangle_info); 6087 break; 6088 } 6089 case CircleElement: 6090 case FillCircleElement: 6091 case EllipseElement: 6092 case FillEllipseElement: 6093 { 6094 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6095 XHighlightEllipse(display,windows->image.id, 6096 windows->image.highlight_context,&rectangle_info); 6097 break; 6098 } 6099 case PolygonElement: 6100 case FillPolygonElement: 6101 { 6102 if (number_coordinates > 1) 6103 (void) XDrawLines(display,windows->image.id, 6104 windows->image.highlight_context,coordinate_info, 6105 number_coordinates,CoordModeOrigin); 6106 if (distance > 9) 6107 XHighlightLine(display,windows->image.id, 6108 windows->image.highlight_context,&line_info); 6109 break; 6110 } 6111 } 6112 switch (event.type) 6113 { 6114 case ButtonPress: 6115 break; 6116 case ButtonRelease: 6117 { 6118 /* 6119 User has committed to element. 6120 */ 6121 line_info.x2=event.xbutton.x; 6122 line_info.y2=event.xbutton.y; 6123 rectangle_info.x=(ssize_t) event.xbutton.x; 6124 rectangle_info.y=(ssize_t) event.xbutton.y; 6125 coordinate_info[number_coordinates].x=event.xbutton.x; 6126 coordinate_info[number_coordinates].y=event.xbutton.y; 6127 if (((element != PolygonElement) && 6128 (element != FillPolygonElement)) || (distance <= 9)) 6129 { 6130 state|=ExitState; 6131 break; 6132 } 6133 number_coordinates++; 6134 if (number_coordinates < (int) max_coordinates) 6135 { 6136 line_info.x1=event.xbutton.x; 6137 line_info.y1=event.xbutton.y; 6138 break; 6139 } 6140 max_coordinates<<=1; 6141 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6142 max_coordinates,sizeof(*coordinate_info)); 6143 if (coordinate_info == (XPoint *) NULL) 6144 (void) ThrowMagickException(exception,GetMagickModule(), 6145 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6146 break; 6147 } 6148 case Expose: 6149 break; 6150 case MotionNotify: 6151 { 6152 if (event.xmotion.window != windows->image.id) 6153 break; 6154 if (element != PointElement) 6155 { 6156 line_info.x2=event.xmotion.x; 6157 line_info.y2=event.xmotion.y; 6158 rectangle_info.x=(ssize_t) event.xmotion.x; 6159 rectangle_info.y=(ssize_t) event.xmotion.y; 6160 break; 6161 } 6162 coordinate_info[number_coordinates].x=event.xbutton.x; 6163 coordinate_info[number_coordinates].y=event.xbutton.y; 6164 number_coordinates++; 6165 if (number_coordinates < (int) max_coordinates) 6166 break; 6167 max_coordinates<<=1; 6168 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6169 max_coordinates,sizeof(*coordinate_info)); 6170 if (coordinate_info == (XPoint *) NULL) 6171 (void) ThrowMagickException(exception,GetMagickModule(), 6172 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6173 break; 6174 } 6175 default: 6176 break; 6177 } 6178 /* 6179 Check boundary conditions. 6180 */ 6181 if (line_info.x2 < 0) 6182 line_info.x2=0; 6183 else 6184 if (line_info.x2 > (int) windows->image.width) 6185 line_info.x2=(short) windows->image.width; 6186 if (line_info.y2 < 0) 6187 line_info.y2=0; 6188 else 6189 if (line_info.y2 > (int) windows->image.height) 6190 line_info.y2=(short) windows->image.height; 6191 distance=(unsigned int) 6192 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+ 6193 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1))); 6194 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) || 6195 ((state & ExitState) != 0)) 6196 { 6197 if (rectangle_info.x < 0) 6198 rectangle_info.x=0; 6199 else 6200 if (rectangle_info.x > (ssize_t) windows->image.width) 6201 rectangle_info.x=(ssize_t) windows->image.width; 6202 if ((int) rectangle_info.x < x) 6203 rectangle_info.width=(unsigned int) (x-rectangle_info.x); 6204 else 6205 { 6206 rectangle_info.width=(unsigned int) (rectangle_info.x-x); 6207 rectangle_info.x=(ssize_t) x; 6208 } 6209 if (rectangle_info.y < 0) 6210 rectangle_info.y=0; 6211 else 6212 if (rectangle_info.y > (ssize_t) windows->image.height) 6213 rectangle_info.y=(ssize_t) windows->image.height; 6214 if ((int) rectangle_info.y < y) 6215 rectangle_info.height=(unsigned int) (y-rectangle_info.y); 6216 else 6217 { 6218 rectangle_info.height=(unsigned int) (rectangle_info.y-y); 6219 rectangle_info.y=(ssize_t) y; 6220 } 6221 } 6222 } while ((state & ExitState) == 0); 6223 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 6224 if ((element == PointElement) || (element == PolygonElement) || 6225 (element == FillPolygonElement)) 6226 { 6227 /* 6228 Determine polygon bounding box. 6229 */ 6230 rectangle_info.x=(ssize_t) coordinate_info->x; 6231 rectangle_info.y=(ssize_t) coordinate_info->y; 6232 x=coordinate_info->x; 6233 y=coordinate_info->y; 6234 for (i=1; i < number_coordinates; i++) 6235 { 6236 if (coordinate_info[i].x > x) 6237 x=coordinate_info[i].x; 6238 if (coordinate_info[i].y > y) 6239 y=coordinate_info[i].y; 6240 if ((ssize_t) coordinate_info[i].x < rectangle_info.x) 6241 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0); 6242 if ((ssize_t) coordinate_info[i].y < rectangle_info.y) 6243 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0); 6244 } 6245 rectangle_info.width=(size_t) (x-rectangle_info.x); 6246 rectangle_info.height=(size_t) (y-rectangle_info.y); 6247 for (i=0; i < number_coordinates; i++) 6248 { 6249 coordinate_info[i].x-=rectangle_info.x; 6250 coordinate_info[i].y-=rectangle_info.y; 6251 } 6252 } 6253 else 6254 if (distance <= 9) 6255 continue; 6256 else 6257 if ((element == RectangleElement) || 6258 (element == CircleElement) || (element == EllipseElement)) 6259 { 6260 rectangle_info.width--; 6261 rectangle_info.height--; 6262 } 6263 /* 6264 Drawing is relative to image configuration. 6265 */ 6266 draw_info.x=(int) rectangle_info.x; 6267 draw_info.y=(int) rectangle_info.y; 6268 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand, 6269 image,exception); 6270 width=(unsigned int) (*image)->columns; 6271 height=(unsigned int) (*image)->rows; 6272 x=0; 6273 y=0; 6274 if (windows->image.crop_geometry != (char *) NULL) 6275 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 6276 draw_info.x+=windows->image.x-(line_width/2); 6277 if (draw_info.x < 0) 6278 draw_info.x=0; 6279 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width); 6280 draw_info.y+=windows->image.y-(line_width/2); 6281 if (draw_info.y < 0) 6282 draw_info.y=0; 6283 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height; 6284 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1); 6285 if (draw_info.width > (unsigned int) (*image)->columns) 6286 draw_info.width=(unsigned int) (*image)->columns; 6287 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1); 6288 if (draw_info.height > (unsigned int) (*image)->rows) 6289 draw_info.height=(unsigned int) (*image)->rows; 6290 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d", 6291 width*draw_info.width/windows->image.ximage->width, 6292 height*draw_info.height/windows->image.ximage->height, 6293 draw_info.x+x,draw_info.y+y); 6294 /* 6295 Initialize drawing attributes. 6296 */ 6297 draw_info.degrees=0.0; 6298 draw_info.element=element; 6299 draw_info.stipple=stipple; 6300 draw_info.line_width=line_width; 6301 draw_info.line_info=line_info; 6302 if (line_info.x1 > (int) (line_width/2)) 6303 draw_info.line_info.x1=(short) line_width/2; 6304 if (line_info.y1 > (int) (line_width/2)) 6305 draw_info.line_info.y1=(short) line_width/2; 6306 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2)); 6307 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2)); 6308 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0)) 6309 { 6310 draw_info.line_info.x2=(-draw_info.line_info.x2); 6311 draw_info.line_info.y2=(-draw_info.line_info.y2); 6312 } 6313 if (draw_info.line_info.x2 < 0) 6314 { 6315 draw_info.line_info.x2=(-draw_info.line_info.x2); 6316 Swap(draw_info.line_info.x1,draw_info.line_info.x2); 6317 } 6318 if (draw_info.line_info.y2 < 0) 6319 { 6320 draw_info.line_info.y2=(-draw_info.line_info.y2); 6321 Swap(draw_info.line_info.y1,draw_info.line_info.y2); 6322 } 6323 draw_info.rectangle_info=rectangle_info; 6324 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2)) 6325 draw_info.rectangle_info.x=(ssize_t) line_width/2; 6326 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2)) 6327 draw_info.rectangle_info.y=(ssize_t) line_width/2; 6328 draw_info.number_coordinates=(unsigned int) number_coordinates; 6329 draw_info.coordinate_info=coordinate_info; 6330 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 6331 /* 6332 Draw element on image. 6333 */ 6334 XSetCursorState(display,windows,MagickTrue); 6335 XCheckRefreshWindows(display,windows); 6336 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception); 6337 XSetCursorState(display,windows,MagickFalse); 6338 /* 6339 Update image colormap and return to image drawing. 6340 */ 6341 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6342 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6343 } 6344 XSetCursorState(display,windows,MagickFalse); 6345 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info); 6346 return(status != 0 ? MagickTrue : MagickFalse); 6347} 6348 6349/* 6350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6351% % 6352% % 6353% % 6354+ X D r a w P a n R e c t a n g l e % 6355% % 6356% % 6357% % 6358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6359% 6360% XDrawPanRectangle() draws a rectangle in the pan window. The pan window 6361% displays a zoom image and the rectangle shows which portion of the image is 6362% displayed in the Image window. 6363% 6364% The format of the XDrawPanRectangle method is: 6365% 6366% XDrawPanRectangle(Display *display,XWindows *windows) 6367% 6368% A description of each parameter follows: 6369% 6370% o display: Specifies a connection to an X server; returned from 6371% XOpenDisplay. 6372% 6373% o windows: Specifies a pointer to a XWindows structure. 6374% 6375*/ 6376static void XDrawPanRectangle(Display *display,XWindows *windows) 6377{ 6378 MagickRealType 6379 scale_factor; 6380 6381 RectangleInfo 6382 highlight_info; 6383 6384 /* 6385 Determine dimensions of the panning rectangle. 6386 */ 6387 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width; 6388 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5); 6389 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5); 6390 scale_factor=(MagickRealType) 6391 windows->pan.height/windows->image.ximage->height; 6392 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5); 6393 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5); 6394 /* 6395 Display the panning rectangle. 6396 */ 6397 (void) XClearWindow(display,windows->pan.id); 6398 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context, 6399 &highlight_info); 6400} 6401 6402/* 6403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6404% % 6405% % 6406% % 6407+ X I m a g e C a c h e % 6408% % 6409% % 6410% % 6411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6412% 6413% XImageCache() handles the creation, manipulation, and destruction of the 6414% image cache (undo and redo buffers). 6415% 6416% The format of the XImageCache method is: 6417% 6418% void XImageCache(Display *display,XResourceInfo *resource_info, 6419% XWindows *windows,const CommandType command,Image **image, 6420% ExceptionInfo *exception) 6421% 6422% A description of each parameter follows: 6423% 6424% o display: Specifies a connection to an X server; returned from 6425% XOpenDisplay. 6426% 6427% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6428% 6429% o windows: Specifies a pointer to a XWindows structure. 6430% 6431% o command: Specifies a command to perform. 6432% 6433% o image: the image; XImageCache may transform the image and return a new 6434% image pointer. 6435% 6436% o exception: return any errors or warnings in this structure. 6437% 6438*/ 6439static void XImageCache(Display *display,XResourceInfo *resource_info, 6440 XWindows *windows,const CommandType command,Image **image, 6441 ExceptionInfo *exception) 6442{ 6443 Image 6444 *cache_image; 6445 6446 static Image 6447 *redo_image = (Image *) NULL, 6448 *undo_image = (Image *) NULL; 6449 6450 switch (command) 6451 { 6452 case FreeBuffersCommand: 6453 { 6454 /* 6455 Free memory from the undo and redo cache. 6456 */ 6457 while (undo_image != (Image *) NULL) 6458 { 6459 cache_image=undo_image; 6460 undo_image=GetPreviousImageInList(undo_image); 6461 cache_image->list=DestroyImage(cache_image->list); 6462 cache_image=DestroyImage(cache_image); 6463 } 6464 undo_image=NewImageList(); 6465 if (redo_image != (Image *) NULL) 6466 redo_image=DestroyImage(redo_image); 6467 redo_image=NewImageList(); 6468 return; 6469 } 6470 case UndoCommand: 6471 { 6472 char 6473 image_geometry[MaxTextExtent]; 6474 6475 /* 6476 Undo the last image transformation. 6477 */ 6478 if (undo_image == (Image *) NULL) 6479 { 6480 (void) XBell(display,0); 6481 return; 6482 } 6483 cache_image=undo_image; 6484 undo_image=GetPreviousImageInList(undo_image); 6485 windows->image.window_changes.width=(int) cache_image->columns; 6486 windows->image.window_changes.height=(int) cache_image->rows; 6487 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 6488 windows->image.ximage->width,windows->image.ximage->height); 6489 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 6490 exception); 6491 if (windows->image.crop_geometry != (char *) NULL) 6492 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 6493 windows->image.crop_geometry); 6494 windows->image.crop_geometry=cache_image->geometry; 6495 if (redo_image != (Image *) NULL) 6496 redo_image=DestroyImage(redo_image); 6497 redo_image=(*image); 6498 *image=cache_image->list; 6499 cache_image=DestroyImage(cache_image); 6500 if (windows->image.orphan != MagickFalse) 6501 return; 6502 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6503 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6504 return; 6505 } 6506 case CutCommand: 6507 case PasteCommand: 6508 case ApplyCommand: 6509 case HalfSizeCommand: 6510 case OriginalSizeCommand: 6511 case DoubleSizeCommand: 6512 case ResizeCommand: 6513 case TrimCommand: 6514 case CropCommand: 6515 case ChopCommand: 6516 case FlipCommand: 6517 case FlopCommand: 6518 case RotateRightCommand: 6519 case RotateLeftCommand: 6520 case RotateCommand: 6521 case ShearCommand: 6522 case RollCommand: 6523 case NegateCommand: 6524 case ContrastStretchCommand: 6525 case SigmoidalContrastCommand: 6526 case NormalizeCommand: 6527 case EqualizeCommand: 6528 case HueCommand: 6529 case SaturationCommand: 6530 case BrightnessCommand: 6531 case GammaCommand: 6532 case SpiffCommand: 6533 case DullCommand: 6534 case GrayscaleCommand: 6535 case MapCommand: 6536 case QuantizeCommand: 6537 case DespeckleCommand: 6538 case EmbossCommand: 6539 case ReduceNoiseCommand: 6540 case AddNoiseCommand: 6541 case SharpenCommand: 6542 case BlurCommand: 6543 case ThresholdCommand: 6544 case EdgeDetectCommand: 6545 case SpreadCommand: 6546 case ShadeCommand: 6547 case RaiseCommand: 6548 case SegmentCommand: 6549 case SolarizeCommand: 6550 case SepiaToneCommand: 6551 case SwirlCommand: 6552 case ImplodeCommand: 6553 case VignetteCommand: 6554 case WaveCommand: 6555 case OilPaintCommand: 6556 case CharcoalDrawCommand: 6557 case AnnotateCommand: 6558 case AddBorderCommand: 6559 case AddFrameCommand: 6560 case CompositeCommand: 6561 case CommentCommand: 6562 case LaunchCommand: 6563 case RegionofInterestCommand: 6564 case SaveToUndoBufferCommand: 6565 case RedoCommand: 6566 { 6567 Image 6568 *previous_image; 6569 6570 ssize_t 6571 bytes; 6572 6573 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo)); 6574 if (undo_image != (Image *) NULL) 6575 { 6576 /* 6577 Ensure the undo cache has enough memory available. 6578 */ 6579 previous_image=undo_image; 6580 while (previous_image != (Image *) NULL) 6581 { 6582 bytes+=previous_image->list->columns*previous_image->list->rows* 6583 sizeof(PixelInfo); 6584 if (bytes <= (ssize_t) (resource_info->undo_cache << 20)) 6585 { 6586 previous_image=GetPreviousImageInList(previous_image); 6587 continue; 6588 } 6589 bytes-=previous_image->list->columns*previous_image->list->rows* 6590 sizeof(PixelInfo); 6591 if (previous_image == undo_image) 6592 undo_image=NewImageList(); 6593 else 6594 previous_image->next->previous=NewImageList(); 6595 break; 6596 } 6597 while (previous_image != (Image *) NULL) 6598 { 6599 /* 6600 Delete any excess memory from undo cache. 6601 */ 6602 cache_image=previous_image; 6603 previous_image=GetPreviousImageInList(previous_image); 6604 cache_image->list=DestroyImage(cache_image->list); 6605 cache_image=DestroyImage(cache_image); 6606 } 6607 } 6608 if (bytes > (ssize_t) (resource_info->undo_cache << 20)) 6609 break; 6610 /* 6611 Save image before transformations are applied. 6612 */ 6613 cache_image=AcquireImage((ImageInfo *) NULL,exception); 6614 if (cache_image == (Image *) NULL) 6615 break; 6616 XSetCursorState(display,windows,MagickTrue); 6617 XCheckRefreshWindows(display,windows); 6618 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception); 6619 XSetCursorState(display,windows,MagickFalse); 6620 if (cache_image->list == (Image *) NULL) 6621 { 6622 cache_image=DestroyImage(cache_image); 6623 break; 6624 } 6625 cache_image->columns=(size_t) windows->image.ximage->width; 6626 cache_image->rows=(size_t) windows->image.ximage->height; 6627 cache_image->geometry=windows->image.crop_geometry; 6628 if (windows->image.crop_geometry != (char *) NULL) 6629 { 6630 cache_image->geometry=AcquireString((char *) NULL); 6631 (void) CopyMagickString(cache_image->geometry, 6632 windows->image.crop_geometry,MaxTextExtent); 6633 } 6634 if (undo_image == (Image *) NULL) 6635 { 6636 undo_image=cache_image; 6637 break; 6638 } 6639 undo_image->next=cache_image; 6640 undo_image->next->previous=undo_image; 6641 undo_image=undo_image->next; 6642 break; 6643 } 6644 default: 6645 break; 6646 } 6647 if (command == RedoCommand) 6648 { 6649 /* 6650 Redo the last image transformation. 6651 */ 6652 if (redo_image == (Image *) NULL) 6653 { 6654 (void) XBell(display,0); 6655 return; 6656 } 6657 windows->image.window_changes.width=(int) redo_image->columns; 6658 windows->image.window_changes.height=(int) redo_image->rows; 6659 if (windows->image.crop_geometry != (char *) NULL) 6660 windows->image.crop_geometry=(char *) 6661 RelinquishMagickMemory(windows->image.crop_geometry); 6662 windows->image.crop_geometry=redo_image->geometry; 6663 *image=DestroyImage(*image); 6664 *image=redo_image; 6665 redo_image=NewImageList(); 6666 if (windows->image.orphan != MagickFalse) 6667 return; 6668 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6669 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6670 return; 6671 } 6672 if (command != InfoCommand) 6673 return; 6674 /* 6675 Display image info. 6676 */ 6677 XSetCursorState(display,windows,MagickTrue); 6678 XCheckRefreshWindows(display,windows); 6679 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception); 6680 XSetCursorState(display,windows,MagickFalse); 6681} 6682 6683/* 6684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6685% % 6686% % 6687% % 6688+ X I m a g e W i n d o w C o m m a n d % 6689% % 6690% % 6691% % 6692%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6693% 6694% XImageWindowCommand() makes a transform to the image or Image window as 6695% specified by a user menu button or keyboard command. 6696% 6697% The format of the XImageWindowCommand method is: 6698% 6699% CommandType XImageWindowCommand(Display *display, 6700% XResourceInfo *resource_info,XWindows *windows, 6701% const MagickStatusType state,KeySym key_symbol,Image **image, 6702% ExceptionInfo *exception) 6703% 6704% A description of each parameter follows: 6705% 6706% o nexus: Method XImageWindowCommand returns an image when the 6707% user chooses 'Open Image' from the command menu. Otherwise a null 6708% image is returned. 6709% 6710% o display: Specifies a connection to an X server; returned from 6711% XOpenDisplay. 6712% 6713% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6714% 6715% o windows: Specifies a pointer to a XWindows structure. 6716% 6717% o state: key mask. 6718% 6719% o key_symbol: Specifies a command to perform. 6720% 6721% o image: the image; XImageWIndowCommand may transform the image and 6722% return a new image pointer. 6723% 6724% o exception: return any errors or warnings in this structure. 6725% 6726*/ 6727static CommandType XImageWindowCommand(Display *display, 6728 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state, 6729 KeySym key_symbol,Image **image,ExceptionInfo *exception) 6730{ 6731 static char 6732 delta[MaxTextExtent] = ""; 6733 6734 static const char 6735 Digits[] = "01234567890"; 6736 6737 static KeySym 6738 last_symbol = XK_0; 6739 6740 if ((key_symbol >= XK_0) && (key_symbol <= XK_9)) 6741 { 6742 if (((last_symbol < XK_0) || (last_symbol > XK_9))) 6743 { 6744 *delta='\0'; 6745 resource_info->quantum=1; 6746 } 6747 last_symbol=key_symbol; 6748 delta[strlen(delta)+1]='\0'; 6749 delta[strlen(delta)]=Digits[key_symbol-XK_0]; 6750 resource_info->quantum=StringToLong(delta); 6751 return(NullCommand); 6752 } 6753 last_symbol=key_symbol; 6754 if (resource_info->immutable) 6755 { 6756 /* 6757 Virtual image window has a restricted command set. 6758 */ 6759 switch (key_symbol) 6760 { 6761 case XK_question: 6762 return(InfoCommand); 6763 case XK_p: 6764 case XK_Print: 6765 return(PrintCommand); 6766 case XK_space: 6767 return(NextCommand); 6768 case XK_q: 6769 case XK_Escape: 6770 return(QuitCommand); 6771 default: 6772 break; 6773 } 6774 return(NullCommand); 6775 } 6776 switch ((int) key_symbol) 6777 { 6778 case XK_o: 6779 { 6780 if ((state & ControlMask) == 0) 6781 break; 6782 return(OpenCommand); 6783 } 6784 case XK_space: 6785 return(NextCommand); 6786 case XK_BackSpace: 6787 return(FormerCommand); 6788 case XK_s: 6789 { 6790 if ((state & Mod1Mask) != 0) 6791 return(SwirlCommand); 6792 if ((state & ControlMask) == 0) 6793 return(ShearCommand); 6794 return(SaveCommand); 6795 } 6796 case XK_p: 6797 case XK_Print: 6798 { 6799 if ((state & Mod1Mask) != 0) 6800 return(OilPaintCommand); 6801 if ((state & Mod4Mask) != 0) 6802 return(ColorCommand); 6803 if ((state & ControlMask) == 0) 6804 return(NullCommand); 6805 return(PrintCommand); 6806 } 6807 case XK_d: 6808 { 6809 if ((state & Mod4Mask) != 0) 6810 return(DrawCommand); 6811 if ((state & ControlMask) == 0) 6812 return(NullCommand); 6813 return(DeleteCommand); 6814 } 6815 case XK_Select: 6816 { 6817 if ((state & ControlMask) == 0) 6818 return(NullCommand); 6819 return(SelectCommand); 6820 } 6821 case XK_n: 6822 { 6823 if ((state & ControlMask) == 0) 6824 return(NullCommand); 6825 return(NewCommand); 6826 } 6827 case XK_q: 6828 case XK_Escape: 6829 return(QuitCommand); 6830 case XK_z: 6831 case XK_Undo: 6832 { 6833 if ((state & ControlMask) == 0) 6834 return(NullCommand); 6835 return(UndoCommand); 6836 } 6837 case XK_r: 6838 case XK_Redo: 6839 { 6840 if ((state & ControlMask) == 0) 6841 return(RollCommand); 6842 return(RedoCommand); 6843 } 6844 case XK_x: 6845 { 6846 if ((state & ControlMask) == 0) 6847 return(NullCommand); 6848 return(CutCommand); 6849 } 6850 case XK_c: 6851 { 6852 if ((state & Mod1Mask) != 0) 6853 return(CharcoalDrawCommand); 6854 if ((state & ControlMask) == 0) 6855 return(CropCommand); 6856 return(CopyCommand); 6857 } 6858 case XK_v: 6859 case XK_Insert: 6860 { 6861 if ((state & Mod4Mask) != 0) 6862 return(CompositeCommand); 6863 if ((state & ControlMask) == 0) 6864 return(FlipCommand); 6865 return(PasteCommand); 6866 } 6867 case XK_less: 6868 return(HalfSizeCommand); 6869 case XK_minus: 6870 return(OriginalSizeCommand); 6871 case XK_greater: 6872 return(DoubleSizeCommand); 6873 case XK_percent: 6874 return(ResizeCommand); 6875 case XK_at: 6876 return(RefreshCommand); 6877 case XK_bracketleft: 6878 return(ChopCommand); 6879 case XK_h: 6880 return(FlopCommand); 6881 case XK_slash: 6882 return(RotateRightCommand); 6883 case XK_backslash: 6884 return(RotateLeftCommand); 6885 case XK_asterisk: 6886 return(RotateCommand); 6887 case XK_t: 6888 return(TrimCommand); 6889 case XK_H: 6890 return(HueCommand); 6891 case XK_S: 6892 return(SaturationCommand); 6893 case XK_L: 6894 return(BrightnessCommand); 6895 case XK_G: 6896 return(GammaCommand); 6897 case XK_C: 6898 return(SpiffCommand); 6899 case XK_Z: 6900 return(DullCommand); 6901 case XK_N: 6902 return(NormalizeCommand); 6903 case XK_equal: 6904 return(EqualizeCommand); 6905 case XK_asciitilde: 6906 return(NegateCommand); 6907 case XK_period: 6908 return(GrayscaleCommand); 6909 case XK_numbersign: 6910 return(QuantizeCommand); 6911 case XK_F2: 6912 return(DespeckleCommand); 6913 case XK_F3: 6914 return(EmbossCommand); 6915 case XK_F4: 6916 return(ReduceNoiseCommand); 6917 case XK_F5: 6918 return(AddNoiseCommand); 6919 case XK_F6: 6920 return(SharpenCommand); 6921 case XK_F7: 6922 return(BlurCommand); 6923 case XK_F8: 6924 return(ThresholdCommand); 6925 case XK_F9: 6926 return(EdgeDetectCommand); 6927 case XK_F10: 6928 return(SpreadCommand); 6929 case XK_F11: 6930 return(ShadeCommand); 6931 case XK_F12: 6932 return(RaiseCommand); 6933 case XK_F13: 6934 return(SegmentCommand); 6935 case XK_i: 6936 { 6937 if ((state & Mod1Mask) == 0) 6938 return(NullCommand); 6939 return(ImplodeCommand); 6940 } 6941 case XK_w: 6942 { 6943 if ((state & Mod1Mask) == 0) 6944 return(NullCommand); 6945 return(WaveCommand); 6946 } 6947 case XK_m: 6948 { 6949 if ((state & Mod4Mask) == 0) 6950 return(NullCommand); 6951 return(MatteCommand); 6952 } 6953 case XK_b: 6954 { 6955 if ((state & Mod4Mask) == 0) 6956 return(NullCommand); 6957 return(AddBorderCommand); 6958 } 6959 case XK_f: 6960 { 6961 if ((state & Mod4Mask) == 0) 6962 return(NullCommand); 6963 return(AddFrameCommand); 6964 } 6965 case XK_exclam: 6966 { 6967 if ((state & Mod4Mask) == 0) 6968 return(NullCommand); 6969 return(CommentCommand); 6970 } 6971 case XK_a: 6972 { 6973 if ((state & Mod1Mask) != 0) 6974 return(ApplyCommand); 6975 if ((state & Mod4Mask) != 0) 6976 return(AnnotateCommand); 6977 if ((state & ControlMask) == 0) 6978 return(NullCommand); 6979 return(RegionofInterestCommand); 6980 } 6981 case XK_question: 6982 return(InfoCommand); 6983 case XK_plus: 6984 return(ZoomCommand); 6985 case XK_P: 6986 { 6987 if ((state & ShiftMask) == 0) 6988 return(NullCommand); 6989 return(ShowPreviewCommand); 6990 } 6991 case XK_Execute: 6992 return(LaunchCommand); 6993 case XK_F1: 6994 return(HelpCommand); 6995 case XK_Find: 6996 return(BrowseDocumentationCommand); 6997 case XK_Menu: 6998 { 6999 (void) XMapRaised(display,windows->command.id); 7000 return(NullCommand); 7001 } 7002 case XK_Next: 7003 case XK_Prior: 7004 case XK_Home: 7005 case XK_KP_Home: 7006 { 7007 XTranslateImage(display,windows,*image,key_symbol); 7008 return(NullCommand); 7009 } 7010 case XK_Up: 7011 case XK_KP_Up: 7012 case XK_Down: 7013 case XK_KP_Down: 7014 case XK_Left: 7015 case XK_KP_Left: 7016 case XK_Right: 7017 case XK_KP_Right: 7018 { 7019 if ((state & Mod1Mask) != 0) 7020 { 7021 RectangleInfo 7022 crop_info; 7023 7024 /* 7025 Trim one pixel from edge of image. 7026 */ 7027 crop_info.x=0; 7028 crop_info.y=0; 7029 crop_info.width=(size_t) windows->image.ximage->width; 7030 crop_info.height=(size_t) windows->image.ximage->height; 7031 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up)) 7032 { 7033 if (resource_info->quantum >= (int) crop_info.height) 7034 resource_info->quantum=(int) crop_info.height-1; 7035 crop_info.height-=resource_info->quantum; 7036 } 7037 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down)) 7038 { 7039 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y)) 7040 resource_info->quantum=(int) (crop_info.height-crop_info.y-1); 7041 crop_info.y+=resource_info->quantum; 7042 crop_info.height-=resource_info->quantum; 7043 } 7044 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left)) 7045 { 7046 if (resource_info->quantum >= (int) crop_info.width) 7047 resource_info->quantum=(int) crop_info.width-1; 7048 crop_info.width-=resource_info->quantum; 7049 } 7050 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right)) 7051 { 7052 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x)) 7053 resource_info->quantum=(int) (crop_info.width-crop_info.x-1); 7054 crop_info.x+=resource_info->quantum; 7055 crop_info.width-=resource_info->quantum; 7056 } 7057 if ((int) (windows->image.x+windows->image.width) > 7058 (int) crop_info.width) 7059 windows->image.x=(int) (crop_info.width-windows->image.width); 7060 if ((int) (windows->image.y+windows->image.height) > 7061 (int) crop_info.height) 7062 windows->image.y=(int) (crop_info.height-windows->image.height); 7063 XSetCropGeometry(display,windows,&crop_info,*image); 7064 windows->image.window_changes.width=(int) crop_info.width; 7065 windows->image.window_changes.height=(int) crop_info.height; 7066 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None); 7067 (void) XConfigureImage(display,resource_info,windows,*image, 7068 exception); 7069 return(NullCommand); 7070 } 7071 XTranslateImage(display,windows,*image,key_symbol); 7072 return(NullCommand); 7073 } 7074 default: 7075 return(NullCommand); 7076 } 7077 return(NullCommand); 7078} 7079 7080/* 7081%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7082% % 7083% % 7084% % 7085+ X M a g i c k C o m m a n d % 7086% % 7087% % 7088% % 7089%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7090% 7091% XMagickCommand() makes a transform to the image or Image window as 7092% specified by a user menu button or keyboard command. 7093% 7094% The format of the XMagickCommand method is: 7095% 7096% Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7097% XWindows *windows,const CommandType command,Image **image, 7098% ExceptionInfo *exception) 7099% 7100% A description of each parameter follows: 7101% 7102% o display: Specifies a connection to an X server; returned from 7103% XOpenDisplay. 7104% 7105% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 7106% 7107% o windows: Specifies a pointer to a XWindows structure. 7108% 7109% o command: Specifies a command to perform. 7110% 7111% o image: the image; XMagickCommand may transform the image and return a 7112% new image pointer. 7113% 7114% o exception: return any errors or warnings in this structure. 7115% 7116*/ 7117static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7118 XWindows *windows,const CommandType command,Image **image, 7119 ExceptionInfo *exception) 7120{ 7121 char 7122 filename[MaxTextExtent], 7123 geometry[MaxTextExtent], 7124 modulate_factors[MaxTextExtent]; 7125 7126 GeometryInfo 7127 geometry_info; 7128 7129 Image 7130 *nexus; 7131 7132 ImageInfo 7133 *image_info; 7134 7135 int 7136 x, 7137 y; 7138 7139 MagickStatusType 7140 flags, 7141 status; 7142 7143 QuantizeInfo 7144 quantize_info; 7145 7146 RectangleInfo 7147 page_geometry; 7148 7149 register int 7150 i; 7151 7152 static char 7153 color[MaxTextExtent] = "gray"; 7154 7155 unsigned int 7156 height, 7157 width; 7158 7159 /* 7160 Process user command. 7161 */ 7162 XCheckRefreshWindows(display,windows); 7163 XImageCache(display,resource_info,windows,command,image,exception); 7164 nexus=NewImageList(); 7165 windows->image.window_changes.width=windows->image.ximage->width; 7166 windows->image.window_changes.height=windows->image.ximage->height; 7167 image_info=CloneImageInfo(resource_info->image_info); 7168 SetGeometryInfo(&geometry_info); 7169 GetQuantizeInfo(&quantize_info); 7170 switch (command) 7171 { 7172 case OpenCommand: 7173 { 7174 /* 7175 Load image. 7176 */ 7177 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 7178 break; 7179 } 7180 case NextCommand: 7181 { 7182 /* 7183 Display next image. 7184 */ 7185 for (i=0; i < resource_info->quantum; i++) 7186 XClientMessage(display,windows->image.id,windows->im_protocols, 7187 windows->im_next_image,CurrentTime); 7188 break; 7189 } 7190 case FormerCommand: 7191 { 7192 /* 7193 Display former image. 7194 */ 7195 for (i=0; i < resource_info->quantum; i++) 7196 XClientMessage(display,windows->image.id,windows->im_protocols, 7197 windows->im_former_image,CurrentTime); 7198 break; 7199 } 7200 case SelectCommand: 7201 { 7202 int 7203 status; 7204 7205 /* 7206 Select image. 7207 */ 7208 status=chdir(resource_info->home_directory); 7209 if (status == -1) 7210 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 7211 "UnableToOpenFile","%s",resource_info->home_directory); 7212 nexus=XOpenImage(display,resource_info,windows,MagickTrue); 7213 break; 7214 } 7215 case SaveCommand: 7216 { 7217 /* 7218 Save image. 7219 */ 7220 status=XSaveImage(display,resource_info,windows,*image,exception); 7221 if (status == MagickFalse) 7222 { 7223 char 7224 message[MaxTextExtent]; 7225 7226 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7227 exception->reason != (char *) NULL ? exception->reason : "", 7228 exception->description != (char *) NULL ? exception->description : 7229 ""); 7230 XNoticeWidget(display,windows,"Unable to save file:",message); 7231 break; 7232 } 7233 break; 7234 } 7235 case PrintCommand: 7236 { 7237 /* 7238 Print image. 7239 */ 7240 status=XPrintImage(display,resource_info,windows,*image,exception); 7241 if (status == MagickFalse) 7242 { 7243 char 7244 message[MaxTextExtent]; 7245 7246 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7247 exception->reason != (char *) NULL ? exception->reason : "", 7248 exception->description != (char *) NULL ? exception->description : 7249 ""); 7250 XNoticeWidget(display,windows,"Unable to print file:",message); 7251 break; 7252 } 7253 break; 7254 } 7255 case DeleteCommand: 7256 { 7257 static char 7258 filename[MaxTextExtent] = "\0"; 7259 7260 /* 7261 Delete image file. 7262 */ 7263 XFileBrowserWidget(display,windows,"Delete",filename); 7264 if (*filename == '\0') 7265 break; 7266 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse; 7267 if (status != MagickFalse) 7268 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7269 break; 7270 } 7271 case NewCommand: 7272 { 7273 int 7274 status; 7275 7276 static char 7277 color[MaxTextExtent] = "gray", 7278 geometry[MaxTextExtent] = "640x480"; 7279 7280 static const char 7281 *format = "gradient"; 7282 7283 /* 7284 Query user for canvas geometry. 7285 */ 7286 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7287 geometry); 7288 if (*geometry == '\0') 7289 break; 7290 if (status == 0) 7291 format="xc"; 7292 XColorBrowserWidget(display,windows,"Select",color); 7293 if (*color == '\0') 7294 break; 7295 /* 7296 Create canvas. 7297 */ 7298 (void) FormatLocaleString(image_info->filename,MaxTextExtent, 7299 "%s:%s",format,color); 7300 (void) CloneString(&image_info->size,geometry); 7301 nexus=ReadImage(image_info,exception); 7302 CatchException(exception); 7303 XClientMessage(display,windows->image.id,windows->im_protocols, 7304 windows->im_next_image,CurrentTime); 7305 break; 7306 } 7307 case VisualDirectoryCommand: 7308 { 7309 /* 7310 Visual Image directory. 7311 */ 7312 nexus=XVisualDirectoryImage(display,resource_info,windows,exception); 7313 break; 7314 } 7315 case QuitCommand: 7316 { 7317 /* 7318 exit program. 7319 */ 7320 if (resource_info->confirm_exit == MagickFalse) 7321 XClientMessage(display,windows->image.id,windows->im_protocols, 7322 windows->im_exit,CurrentTime); 7323 else 7324 { 7325 int 7326 status; 7327 7328 /* 7329 Confirm program exit. 7330 */ 7331 status=XConfirmWidget(display,windows,"Do you really want to exit", 7332 resource_info->client_name); 7333 if (status > 0) 7334 XClientMessage(display,windows->image.id,windows->im_protocols, 7335 windows->im_exit,CurrentTime); 7336 } 7337 break; 7338 } 7339 case CutCommand: 7340 { 7341 /* 7342 Cut image. 7343 */ 7344 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception); 7345 break; 7346 } 7347 case CopyCommand: 7348 { 7349 /* 7350 Copy image. 7351 */ 7352 (void) XCropImage(display,resource_info,windows,*image,CopyMode, 7353 exception); 7354 break; 7355 } 7356 case PasteCommand: 7357 { 7358 /* 7359 Paste image. 7360 */ 7361 status=XPasteImage(display,resource_info,windows,*image,exception); 7362 if (status == MagickFalse) 7363 { 7364 XNoticeWidget(display,windows,"Unable to paste X image", 7365 (*image)->filename); 7366 break; 7367 } 7368 break; 7369 } 7370 case HalfSizeCommand: 7371 { 7372 /* 7373 Half image size. 7374 */ 7375 windows->image.window_changes.width=windows->image.ximage->width/2; 7376 windows->image.window_changes.height=windows->image.ximage->height/2; 7377 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7378 break; 7379 } 7380 case OriginalSizeCommand: 7381 { 7382 /* 7383 Original image size. 7384 */ 7385 windows->image.window_changes.width=(int) (*image)->columns; 7386 windows->image.window_changes.height=(int) (*image)->rows; 7387 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7388 break; 7389 } 7390 case DoubleSizeCommand: 7391 { 7392 /* 7393 Double the image size. 7394 */ 7395 windows->image.window_changes.width=windows->image.ximage->width << 1; 7396 windows->image.window_changes.height=windows->image.ximage->height << 1; 7397 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7398 break; 7399 } 7400 case ResizeCommand: 7401 { 7402 int 7403 status; 7404 7405 size_t 7406 height, 7407 width; 7408 7409 ssize_t 7410 x, 7411 y; 7412 7413 /* 7414 Resize image. 7415 */ 7416 width=(size_t) windows->image.ximage->width; 7417 height=(size_t) windows->image.ximage->height; 7418 x=0; 7419 y=0; 7420 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0", 7421 (double) width,(double) height); 7422 status=XDialogWidget(display,windows,"Resize", 7423 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7424 if (*geometry == '\0') 7425 break; 7426 if (status == 0) 7427 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent); 7428 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7429 windows->image.window_changes.width=(int) width; 7430 windows->image.window_changes.height=(int) height; 7431 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7432 break; 7433 } 7434 case ApplyCommand: 7435 { 7436 char 7437 image_geometry[MaxTextExtent]; 7438 7439 if ((windows->image.crop_geometry == (char *) NULL) && 7440 ((int) (*image)->columns == windows->image.ximage->width) && 7441 ((int) (*image)->rows == windows->image.ximage->height)) 7442 break; 7443 /* 7444 Apply size transforms to image. 7445 */ 7446 XSetCursorState(display,windows,MagickTrue); 7447 XCheckRefreshWindows(display,windows); 7448 /* 7449 Crop and/or scale displayed image. 7450 */ 7451 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 7452 windows->image.ximage->width,windows->image.ximage->height); 7453 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 7454 exception); 7455 if (windows->image.crop_geometry != (char *) NULL) 7456 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 7457 windows->image.crop_geometry); 7458 windows->image.x=0; 7459 windows->image.y=0; 7460 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7461 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7462 break; 7463 } 7464 case RefreshCommand: 7465 { 7466 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7467 break; 7468 } 7469 case RestoreCommand: 7470 { 7471 /* 7472 Restore Image window to its original size. 7473 */ 7474 if ((windows->image.width == (unsigned int) (*image)->columns) && 7475 (windows->image.height == (unsigned int) (*image)->rows) && 7476 (windows->image.crop_geometry == (char *) NULL)) 7477 { 7478 (void) XBell(display,0); 7479 break; 7480 } 7481 windows->image.window_changes.width=(int) (*image)->columns; 7482 windows->image.window_changes.height=(int) (*image)->rows; 7483 if (windows->image.crop_geometry != (char *) NULL) 7484 { 7485 windows->image.crop_geometry=(char *) 7486 RelinquishMagickMemory(windows->image.crop_geometry); 7487 windows->image.crop_geometry=(char *) NULL; 7488 windows->image.x=0; 7489 windows->image.y=0; 7490 } 7491 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7492 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7493 break; 7494 } 7495 case CropCommand: 7496 { 7497 /* 7498 Crop image. 7499 */ 7500 (void) XCropImage(display,resource_info,windows,*image,CropMode, 7501 exception); 7502 break; 7503 } 7504 case ChopCommand: 7505 { 7506 /* 7507 Chop image. 7508 */ 7509 status=XChopImage(display,resource_info,windows,image,exception); 7510 if (status == MagickFalse) 7511 { 7512 XNoticeWidget(display,windows,"Unable to cut X image", 7513 (*image)->filename); 7514 break; 7515 } 7516 break; 7517 } 7518 case FlopCommand: 7519 { 7520 Image 7521 *flop_image; 7522 7523 /* 7524 Flop image scanlines. 7525 */ 7526 XSetCursorState(display,windows,MagickTrue); 7527 XCheckRefreshWindows(display,windows); 7528 flop_image=FlopImage(*image,exception); 7529 if (flop_image != (Image *) NULL) 7530 { 7531 *image=DestroyImage(*image); 7532 *image=flop_image; 7533 } 7534 CatchException(exception); 7535 XSetCursorState(display,windows,MagickFalse); 7536 if (windows->image.crop_geometry != (char *) NULL) 7537 { 7538 /* 7539 Flop crop geometry. 7540 */ 7541 width=(unsigned int) (*image)->columns; 7542 height=(unsigned int) (*image)->rows; 7543 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7544 &width,&height); 7545 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7546 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7547 } 7548 if (windows->image.orphan != MagickFalse) 7549 break; 7550 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7551 break; 7552 } 7553 case FlipCommand: 7554 { 7555 Image 7556 *flip_image; 7557 7558 /* 7559 Flip image scanlines. 7560 */ 7561 XSetCursorState(display,windows,MagickTrue); 7562 XCheckRefreshWindows(display,windows); 7563 flip_image=FlipImage(*image,exception); 7564 if (flip_image != (Image *) NULL) 7565 { 7566 *image=DestroyImage(*image); 7567 *image=flip_image; 7568 } 7569 CatchException(exception); 7570 XSetCursorState(display,windows,MagickFalse); 7571 if (windows->image.crop_geometry != (char *) NULL) 7572 { 7573 /* 7574 Flip crop geometry. 7575 */ 7576 width=(unsigned int) (*image)->columns; 7577 height=(unsigned int) (*image)->rows; 7578 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7579 &width,&height); 7580 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7581 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7582 } 7583 if (windows->image.orphan != MagickFalse) 7584 break; 7585 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7586 break; 7587 } 7588 case RotateRightCommand: 7589 { 7590 /* 7591 Rotate image 90 degrees clockwise. 7592 */ 7593 status=XRotateImage(display,resource_info,windows,90.0,image,exception); 7594 if (status == MagickFalse) 7595 { 7596 XNoticeWidget(display,windows,"Unable to rotate X image", 7597 (*image)->filename); 7598 break; 7599 } 7600 break; 7601 } 7602 case RotateLeftCommand: 7603 { 7604 /* 7605 Rotate image 90 degrees counter-clockwise. 7606 */ 7607 status=XRotateImage(display,resource_info,windows,-90.0,image,exception); 7608 if (status == MagickFalse) 7609 { 7610 XNoticeWidget(display,windows,"Unable to rotate X image", 7611 (*image)->filename); 7612 break; 7613 } 7614 break; 7615 } 7616 case RotateCommand: 7617 { 7618 /* 7619 Rotate image. 7620 */ 7621 status=XRotateImage(display,resource_info,windows,0.0,image,exception); 7622 if (status == MagickFalse) 7623 { 7624 XNoticeWidget(display,windows,"Unable to rotate X image", 7625 (*image)->filename); 7626 break; 7627 } 7628 break; 7629 } 7630 case ShearCommand: 7631 { 7632 Image 7633 *shear_image; 7634 7635 static char 7636 geometry[MaxTextExtent] = "45.0x45.0"; 7637 7638 /* 7639 Query user for shear color and geometry. 7640 */ 7641 XColorBrowserWidget(display,windows,"Select",color); 7642 if (*color == '\0') 7643 break; 7644 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7645 geometry); 7646 if (*geometry == '\0') 7647 break; 7648 /* 7649 Shear image. 7650 */ 7651 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7652 exception); 7653 XSetCursorState(display,windows,MagickTrue); 7654 XCheckRefreshWindows(display,windows); 7655 (void) QueryColorCompliance(color,AllCompliance, 7656 &(*image)->background_color,exception); 7657 flags=ParseGeometry(geometry,&geometry_info); 7658 if ((flags & SigmaValue) == 0) 7659 geometry_info.sigma=geometry_info.rho; 7660 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7661 exception); 7662 if (shear_image != (Image *) NULL) 7663 { 7664 *image=DestroyImage(*image); 7665 *image=shear_image; 7666 } 7667 CatchException(exception); 7668 XSetCursorState(display,windows,MagickFalse); 7669 if (windows->image.orphan != MagickFalse) 7670 break; 7671 windows->image.window_changes.width=(int) (*image)->columns; 7672 windows->image.window_changes.height=(int) (*image)->rows; 7673 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7674 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7675 break; 7676 } 7677 case RollCommand: 7678 { 7679 Image 7680 *roll_image; 7681 7682 static char 7683 geometry[MaxTextExtent] = "+2+2"; 7684 7685 /* 7686 Query user for the roll geometry. 7687 */ 7688 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7689 geometry); 7690 if (*geometry == '\0') 7691 break; 7692 /* 7693 Roll image. 7694 */ 7695 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7696 exception); 7697 XSetCursorState(display,windows,MagickTrue); 7698 XCheckRefreshWindows(display,windows); 7699 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7700 exception); 7701 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7702 exception); 7703 if (roll_image != (Image *) NULL) 7704 { 7705 *image=DestroyImage(*image); 7706 *image=roll_image; 7707 } 7708 CatchException(exception); 7709 XSetCursorState(display,windows,MagickFalse); 7710 if (windows->image.orphan != MagickFalse) 7711 break; 7712 windows->image.window_changes.width=(int) (*image)->columns; 7713 windows->image.window_changes.height=(int) (*image)->rows; 7714 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7715 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7716 break; 7717 } 7718 case TrimCommand: 7719 { 7720 static char 7721 fuzz[MaxTextExtent]; 7722 7723 /* 7724 Query user for the fuzz factor. 7725 */ 7726 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0* 7727 (*image)->fuzz/(QuantumRange+1.0)); 7728 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7729 if (*fuzz == '\0') 7730 break; 7731 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0); 7732 /* 7733 Trim image. 7734 */ 7735 status=XTrimImage(display,resource_info,windows,*image,exception); 7736 if (status == MagickFalse) 7737 { 7738 XNoticeWidget(display,windows,"Unable to trim X image", 7739 (*image)->filename); 7740 break; 7741 } 7742 break; 7743 } 7744 case HueCommand: 7745 { 7746 static char 7747 hue_percent[MaxTextExtent] = "110"; 7748 7749 /* 7750 Query user for percent hue change. 7751 */ 7752 (void) XDialogWidget(display,windows,"Apply", 7753 "Enter percent change in image hue (0-200):",hue_percent); 7754 if (*hue_percent == '\0') 7755 break; 7756 /* 7757 Vary the image hue. 7758 */ 7759 XSetCursorState(display,windows,MagickTrue); 7760 XCheckRefreshWindows(display,windows); 7761 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent); 7762 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7763 MaxTextExtent); 7764 (void) ModulateImage(*image,modulate_factors,exception); 7765 XSetCursorState(display,windows,MagickFalse); 7766 if (windows->image.orphan != MagickFalse) 7767 break; 7768 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7769 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7770 break; 7771 } 7772 case SaturationCommand: 7773 { 7774 static char 7775 saturation_percent[MaxTextExtent] = "110"; 7776 7777 /* 7778 Query user for percent saturation change. 7779 */ 7780 (void) XDialogWidget(display,windows,"Apply", 7781 "Enter percent change in color saturation (0-200):",saturation_percent); 7782 if (*saturation_percent == '\0') 7783 break; 7784 /* 7785 Vary color saturation. 7786 */ 7787 XSetCursorState(display,windows,MagickTrue); 7788 XCheckRefreshWindows(display,windows); 7789 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent); 7790 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7791 MaxTextExtent); 7792 (void) ModulateImage(*image,modulate_factors,exception); 7793 XSetCursorState(display,windows,MagickFalse); 7794 if (windows->image.orphan != MagickFalse) 7795 break; 7796 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7797 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7798 break; 7799 } 7800 case BrightnessCommand: 7801 { 7802 static char 7803 brightness_percent[MaxTextExtent] = "110"; 7804 7805 /* 7806 Query user for percent brightness change. 7807 */ 7808 (void) XDialogWidget(display,windows,"Apply", 7809 "Enter percent change in color brightness (0-200):",brightness_percent); 7810 if (*brightness_percent == '\0') 7811 break; 7812 /* 7813 Vary the color brightness. 7814 */ 7815 XSetCursorState(display,windows,MagickTrue); 7816 XCheckRefreshWindows(display,windows); 7817 (void) CopyMagickString(modulate_factors,brightness_percent, 7818 MaxTextExtent); 7819 (void) ModulateImage(*image,modulate_factors,exception); 7820 XSetCursorState(display,windows,MagickFalse); 7821 if (windows->image.orphan != MagickFalse) 7822 break; 7823 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7824 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7825 break; 7826 } 7827 case GammaCommand: 7828 { 7829 static char 7830 factor[MaxTextExtent] = "1.6"; 7831 7832 /* 7833 Query user for gamma value. 7834 */ 7835 (void) XDialogWidget(display,windows,"Gamma", 7836 "Enter gamma value (e.g. 1.2):",factor); 7837 if (*factor == '\0') 7838 break; 7839 /* 7840 Gamma correct image. 7841 */ 7842 XSetCursorState(display,windows,MagickTrue); 7843 XCheckRefreshWindows(display,windows); 7844 (void) GammaImage(*image,atof(factor),exception); 7845 XSetCursorState(display,windows,MagickFalse); 7846 if (windows->image.orphan != MagickFalse) 7847 break; 7848 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7849 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7850 break; 7851 } 7852 case SpiffCommand: 7853 { 7854 /* 7855 Sharpen the image contrast. 7856 */ 7857 XSetCursorState(display,windows,MagickTrue); 7858 XCheckRefreshWindows(display,windows); 7859 (void) ContrastImage(*image,MagickTrue,exception); 7860 XSetCursorState(display,windows,MagickFalse); 7861 if (windows->image.orphan != MagickFalse) 7862 break; 7863 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7864 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7865 break; 7866 } 7867 case DullCommand: 7868 { 7869 /* 7870 Dull the image contrast. 7871 */ 7872 XSetCursorState(display,windows,MagickTrue); 7873 XCheckRefreshWindows(display,windows); 7874 (void) ContrastImage(*image,MagickFalse,exception); 7875 XSetCursorState(display,windows,MagickFalse); 7876 if (windows->image.orphan != MagickFalse) 7877 break; 7878 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7879 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7880 break; 7881 } 7882 case ContrastStretchCommand: 7883 { 7884 double 7885 black_point, 7886 white_point; 7887 7888 static char 7889 levels[MaxTextExtent] = "1%"; 7890 7891 /* 7892 Query user for gamma value. 7893 */ 7894 (void) XDialogWidget(display,windows,"Contrast Stretch", 7895 "Enter black and white points:",levels); 7896 if (*levels == '\0') 7897 break; 7898 /* 7899 Contrast stretch image. 7900 */ 7901 XSetCursorState(display,windows,MagickTrue); 7902 XCheckRefreshWindows(display,windows); 7903 flags=ParseGeometry(levels,&geometry_info); 7904 black_point=geometry_info.rho; 7905 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7906 if ((flags & PercentValue) != 0) 7907 { 7908 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7909 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7910 } 7911 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point; 7912 (void) ContrastStretchImage(*image,black_point,white_point, 7913 exception); 7914 XSetCursorState(display,windows,MagickFalse); 7915 if (windows->image.orphan != MagickFalse) 7916 break; 7917 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7918 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7919 break; 7920 } 7921 case SigmoidalContrastCommand: 7922 { 7923 GeometryInfo 7924 geometry_info; 7925 7926 MagickStatusType 7927 flags; 7928 7929 static char 7930 levels[MaxTextExtent] = "3x50%"; 7931 7932 /* 7933 Query user for gamma value. 7934 */ 7935 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7936 "Enter contrast and midpoint:",levels); 7937 if (*levels == '\0') 7938 break; 7939 /* 7940 Contrast stretch image. 7941 */ 7942 XSetCursorState(display,windows,MagickTrue); 7943 XCheckRefreshWindows(display,windows); 7944 flags=ParseGeometry(levels,&geometry_info); 7945 if ((flags & SigmaValue) == 0) 7946 geometry_info.sigma=1.0*QuantumRange/2.0; 7947 if ((flags & PercentValue) != 0) 7948 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0; 7949 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho, 7950 geometry_info.sigma,exception); 7951 XSetCursorState(display,windows,MagickFalse); 7952 if (windows->image.orphan != MagickFalse) 7953 break; 7954 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7955 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7956 break; 7957 } 7958 case NormalizeCommand: 7959 { 7960 /* 7961 Perform histogram normalization on the image. 7962 */ 7963 XSetCursorState(display,windows,MagickTrue); 7964 XCheckRefreshWindows(display,windows); 7965 (void) NormalizeImage(*image,exception); 7966 XSetCursorState(display,windows,MagickFalse); 7967 if (windows->image.orphan != MagickFalse) 7968 break; 7969 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7970 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7971 break; 7972 } 7973 case EqualizeCommand: 7974 { 7975 /* 7976 Perform histogram equalization on the image. 7977 */ 7978 XSetCursorState(display,windows,MagickTrue); 7979 XCheckRefreshWindows(display,windows); 7980 (void) EqualizeImage(*image,exception); 7981 XSetCursorState(display,windows,MagickFalse); 7982 if (windows->image.orphan != MagickFalse) 7983 break; 7984 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7985 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7986 break; 7987 } 7988 case NegateCommand: 7989 { 7990 /* 7991 Negate colors in image. 7992 */ 7993 XSetCursorState(display,windows,MagickTrue); 7994 XCheckRefreshWindows(display,windows); 7995 (void) NegateImage(*image,MagickFalse,exception); 7996 XSetCursorState(display,windows,MagickFalse); 7997 if (windows->image.orphan != MagickFalse) 7998 break; 7999 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8000 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8001 break; 8002 } 8003 case GrayscaleCommand: 8004 { 8005 /* 8006 Convert image to grayscale. 8007 */ 8008 XSetCursorState(display,windows,MagickTrue); 8009 XCheckRefreshWindows(display,windows); 8010 (void) SetImageType(*image,(*image)->matte == MagickFalse ? 8011 GrayscaleType : GrayscaleMatteType,exception); 8012 XSetCursorState(display,windows,MagickFalse); 8013 if (windows->image.orphan != MagickFalse) 8014 break; 8015 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8016 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8017 break; 8018 } 8019 case MapCommand: 8020 { 8021 Image 8022 *affinity_image; 8023 8024 static char 8025 filename[MaxTextExtent] = "\0"; 8026 8027 /* 8028 Request image file name from user. 8029 */ 8030 XFileBrowserWidget(display,windows,"Map",filename); 8031 if (*filename == '\0') 8032 break; 8033 /* 8034 Map image. 8035 */ 8036 XSetCursorState(display,windows,MagickTrue); 8037 XCheckRefreshWindows(display,windows); 8038 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 8039 affinity_image=ReadImage(image_info,exception); 8040 if (affinity_image != (Image *) NULL) 8041 { 8042 (void) RemapImage(&quantize_info,*image,affinity_image,exception); 8043 affinity_image=DestroyImage(affinity_image); 8044 } 8045 CatchException(exception); 8046 XSetCursorState(display,windows,MagickFalse); 8047 if (windows->image.orphan != MagickFalse) 8048 break; 8049 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8050 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8051 break; 8052 } 8053 case QuantizeCommand: 8054 { 8055 int 8056 status; 8057 8058 static char 8059 colors[MaxTextExtent] = "256"; 8060 8061 /* 8062 Query user for maximum number of colors. 8063 */ 8064 status=XDialogWidget(display,windows,"Quantize", 8065 "Maximum number of colors:",colors); 8066 if (*colors == '\0') 8067 break; 8068 /* 8069 Color reduce the image. 8070 */ 8071 XSetCursorState(display,windows,MagickTrue); 8072 XCheckRefreshWindows(display,windows); 8073 quantize_info.number_colors=StringToUnsignedLong(colors); 8074 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse; 8075 (void) QuantizeImage(&quantize_info,*image,exception); 8076 XSetCursorState(display,windows,MagickFalse); 8077 if (windows->image.orphan != MagickFalse) 8078 break; 8079 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8080 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8081 break; 8082 } 8083 case DespeckleCommand: 8084 { 8085 Image 8086 *despeckle_image; 8087 8088 /* 8089 Despeckle image. 8090 */ 8091 XSetCursorState(display,windows,MagickTrue); 8092 XCheckRefreshWindows(display,windows); 8093 despeckle_image=DespeckleImage(*image,exception); 8094 if (despeckle_image != (Image *) NULL) 8095 { 8096 *image=DestroyImage(*image); 8097 *image=despeckle_image; 8098 } 8099 CatchException(exception); 8100 XSetCursorState(display,windows,MagickFalse); 8101 if (windows->image.orphan != MagickFalse) 8102 break; 8103 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8104 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8105 break; 8106 } 8107 case EmbossCommand: 8108 { 8109 Image 8110 *emboss_image; 8111 8112 static char 8113 radius[MaxTextExtent] = "0.0x1.0"; 8114 8115 /* 8116 Query user for emboss radius. 8117 */ 8118 (void) XDialogWidget(display,windows,"Emboss", 8119 "Enter the emboss radius and standard deviation:",radius); 8120 if (*radius == '\0') 8121 break; 8122 /* 8123 Reduce noise in the image. 8124 */ 8125 XSetCursorState(display,windows,MagickTrue); 8126 XCheckRefreshWindows(display,windows); 8127 flags=ParseGeometry(radius,&geometry_info); 8128 if ((flags & SigmaValue) == 0) 8129 geometry_info.sigma=1.0; 8130 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma, 8131 exception); 8132 if (emboss_image != (Image *) NULL) 8133 { 8134 *image=DestroyImage(*image); 8135 *image=emboss_image; 8136 } 8137 CatchException(exception); 8138 XSetCursorState(display,windows,MagickFalse); 8139 if (windows->image.orphan != MagickFalse) 8140 break; 8141 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8142 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8143 break; 8144 } 8145 case ReduceNoiseCommand: 8146 { 8147 Image 8148 *noise_image; 8149 8150 static char 8151 radius[MaxTextExtent] = "0"; 8152 8153 /* 8154 Query user for noise radius. 8155 */ 8156 (void) XDialogWidget(display,windows,"Reduce Noise", 8157 "Enter the noise radius:",radius); 8158 if (*radius == '\0') 8159 break; 8160 /* 8161 Reduce noise in the image. 8162 */ 8163 XSetCursorState(display,windows,MagickTrue); 8164 XCheckRefreshWindows(display,windows); 8165 flags=ParseGeometry(radius,&geometry_info); 8166 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t) 8167 geometry_info.rho,(size_t) geometry_info.rho,exception); 8168 if (noise_image != (Image *) NULL) 8169 { 8170 *image=DestroyImage(*image); 8171 *image=noise_image; 8172 } 8173 CatchException(exception); 8174 XSetCursorState(display,windows,MagickFalse); 8175 if (windows->image.orphan != MagickFalse) 8176 break; 8177 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8178 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8179 break; 8180 } 8181 case AddNoiseCommand: 8182 { 8183 char 8184 **noises; 8185 8186 Image 8187 *noise_image; 8188 8189 static char 8190 noise_type[MaxTextExtent] = "Gaussian"; 8191 8192 /* 8193 Add noise to the image. 8194 */ 8195 noises=GetCommandOptions(MagickNoiseOptions); 8196 if (noises == (char **) NULL) 8197 break; 8198 XListBrowserWidget(display,windows,&windows->widget, 8199 (const char **) noises,"Add Noise", 8200 "Select a type of noise to add to your image:",noise_type); 8201 noises=DestroyStringList(noises); 8202 if (*noise_type == '\0') 8203 break; 8204 XSetCursorState(display,windows,MagickTrue); 8205 XCheckRefreshWindows(display,windows); 8206 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption( 8207 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception); 8208 if (noise_image != (Image *) NULL) 8209 { 8210 *image=DestroyImage(*image); 8211 *image=noise_image; 8212 } 8213 CatchException(exception); 8214 XSetCursorState(display,windows,MagickFalse); 8215 if (windows->image.orphan != MagickFalse) 8216 break; 8217 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8218 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8219 break; 8220 } 8221 case SharpenCommand: 8222 { 8223 Image 8224 *sharp_image; 8225 8226 static char 8227 radius[MaxTextExtent] = "0.0x1.0"; 8228 8229 /* 8230 Query user for sharpen radius. 8231 */ 8232 (void) XDialogWidget(display,windows,"Sharpen", 8233 "Enter the sharpen radius and standard deviation:",radius); 8234 if (*radius == '\0') 8235 break; 8236 /* 8237 Sharpen image scanlines. 8238 */ 8239 XSetCursorState(display,windows,MagickTrue); 8240 XCheckRefreshWindows(display,windows); 8241 flags=ParseGeometry(radius,&geometry_info); 8242 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma, 8243 geometry_info.xi,exception); 8244 if (sharp_image != (Image *) NULL) 8245 { 8246 *image=DestroyImage(*image); 8247 *image=sharp_image; 8248 } 8249 CatchException(exception); 8250 XSetCursorState(display,windows,MagickFalse); 8251 if (windows->image.orphan != MagickFalse) 8252 break; 8253 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8254 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8255 break; 8256 } 8257 case BlurCommand: 8258 { 8259 Image 8260 *blur_image; 8261 8262 static char 8263 radius[MaxTextExtent] = "0.0x1.0"; 8264 8265 /* 8266 Query user for blur radius. 8267 */ 8268 (void) XDialogWidget(display,windows,"Blur", 8269 "Enter the blur radius and standard deviation:",radius); 8270 if (*radius == '\0') 8271 break; 8272 /* 8273 Blur an image. 8274 */ 8275 XSetCursorState(display,windows,MagickTrue); 8276 XCheckRefreshWindows(display,windows); 8277 flags=ParseGeometry(radius,&geometry_info); 8278 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma, 8279 geometry_info.xi,exception); 8280 if (blur_image != (Image *) NULL) 8281 { 8282 *image=DestroyImage(*image); 8283 *image=blur_image; 8284 } 8285 CatchException(exception); 8286 XSetCursorState(display,windows,MagickFalse); 8287 if (windows->image.orphan != MagickFalse) 8288 break; 8289 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8290 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8291 break; 8292 } 8293 case ThresholdCommand: 8294 { 8295 double 8296 threshold; 8297 8298 static char 8299 factor[MaxTextExtent] = "128"; 8300 8301 /* 8302 Query user for threshold value. 8303 */ 8304 (void) XDialogWidget(display,windows,"Threshold", 8305 "Enter threshold value:",factor); 8306 if (*factor == '\0') 8307 break; 8308 /* 8309 Gamma correct image. 8310 */ 8311 XSetCursorState(display,windows,MagickTrue); 8312 XCheckRefreshWindows(display,windows); 8313 threshold=SiPrefixToDouble(factor,QuantumRange); 8314 (void) BilevelImage(*image,threshold,exception); 8315 XSetCursorState(display,windows,MagickFalse); 8316 if (windows->image.orphan != MagickFalse) 8317 break; 8318 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8319 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8320 break; 8321 } 8322 case EdgeDetectCommand: 8323 { 8324 Image 8325 *edge_image; 8326 8327 static char 8328 radius[MaxTextExtent] = "0"; 8329 8330 /* 8331 Query user for edge factor. 8332 */ 8333 (void) XDialogWidget(display,windows,"Detect Edges", 8334 "Enter the edge detect radius:",radius); 8335 if (*radius == '\0') 8336 break; 8337 /* 8338 Detect edge in image. 8339 */ 8340 XSetCursorState(display,windows,MagickTrue); 8341 XCheckRefreshWindows(display,windows); 8342 flags=ParseGeometry(radius,&geometry_info); 8343 edge_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8344 exception); 8345 if (edge_image != (Image *) NULL) 8346 { 8347 *image=DestroyImage(*image); 8348 *image=edge_image; 8349 } 8350 CatchException(exception); 8351 XSetCursorState(display,windows,MagickFalse); 8352 if (windows->image.orphan != MagickFalse) 8353 break; 8354 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8355 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8356 break; 8357 } 8358 case SpreadCommand: 8359 { 8360 Image 8361 *spread_image; 8362 8363 static char 8364 amount[MaxTextExtent] = "2"; 8365 8366 /* 8367 Query user for spread amount. 8368 */ 8369 (void) XDialogWidget(display,windows,"Spread", 8370 "Enter the displacement amount:",amount); 8371 if (*amount == '\0') 8372 break; 8373 /* 8374 Displace image pixels by a random amount. 8375 */ 8376 XSetCursorState(display,windows,MagickTrue); 8377 XCheckRefreshWindows(display,windows); 8378 flags=ParseGeometry(amount,&geometry_info); 8379 spread_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8380 exception); 8381 if (spread_image != (Image *) NULL) 8382 { 8383 *image=DestroyImage(*image); 8384 *image=spread_image; 8385 } 8386 CatchException(exception); 8387 XSetCursorState(display,windows,MagickFalse); 8388 if (windows->image.orphan != MagickFalse) 8389 break; 8390 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8391 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8392 break; 8393 } 8394 case ShadeCommand: 8395 { 8396 Image 8397 *shade_image; 8398 8399 int 8400 status; 8401 8402 static char 8403 geometry[MaxTextExtent] = "30x30"; 8404 8405 /* 8406 Query user for the shade geometry. 8407 */ 8408 status=XDialogWidget(display,windows,"Shade", 8409 "Enter the azimuth and elevation of the light source:",geometry); 8410 if (*geometry == '\0') 8411 break; 8412 /* 8413 Shade image pixels. 8414 */ 8415 XSetCursorState(display,windows,MagickTrue); 8416 XCheckRefreshWindows(display,windows); 8417 flags=ParseGeometry(geometry,&geometry_info); 8418 if ((flags & SigmaValue) == 0) 8419 geometry_info.sigma=1.0; 8420 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue, 8421 geometry_info.rho,geometry_info.sigma,exception); 8422 if (shade_image != (Image *) NULL) 8423 { 8424 *image=DestroyImage(*image); 8425 *image=shade_image; 8426 } 8427 CatchException(exception); 8428 XSetCursorState(display,windows,MagickFalse); 8429 if (windows->image.orphan != MagickFalse) 8430 break; 8431 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8432 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8433 break; 8434 } 8435 case RaiseCommand: 8436 { 8437 static char 8438 bevel_width[MaxTextExtent] = "10"; 8439 8440 /* 8441 Query user for bevel width. 8442 */ 8443 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8444 if (*bevel_width == '\0') 8445 break; 8446 /* 8447 Raise an image. 8448 */ 8449 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8450 exception); 8451 XSetCursorState(display,windows,MagickTrue); 8452 XCheckRefreshWindows(display,windows); 8453 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8454 exception); 8455 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception); 8456 XSetCursorState(display,windows,MagickFalse); 8457 if (windows->image.orphan != MagickFalse) 8458 break; 8459 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8460 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8461 break; 8462 } 8463 case SegmentCommand: 8464 { 8465 static char 8466 threshold[MaxTextExtent] = "1.0x1.5"; 8467 8468 /* 8469 Query user for smoothing threshold. 8470 */ 8471 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8472 threshold); 8473 if (*threshold == '\0') 8474 break; 8475 /* 8476 Segment an image. 8477 */ 8478 XSetCursorState(display,windows,MagickTrue); 8479 XCheckRefreshWindows(display,windows); 8480 flags=ParseGeometry(threshold,&geometry_info); 8481 if ((flags & SigmaValue) == 0) 8482 geometry_info.sigma=1.0; 8483 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho, 8484 geometry_info.sigma,exception); 8485 XSetCursorState(display,windows,MagickFalse); 8486 if (windows->image.orphan != MagickFalse) 8487 break; 8488 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8489 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8490 break; 8491 } 8492 case SepiaToneCommand: 8493 { 8494 double 8495 threshold; 8496 8497 Image 8498 *sepia_image; 8499 8500 static char 8501 factor[MaxTextExtent] = "80%"; 8502 8503 /* 8504 Query user for sepia-tone factor. 8505 */ 8506 (void) XDialogWidget(display,windows,"Sepia Tone", 8507 "Enter the sepia tone factor (0 - 99.9%):",factor); 8508 if (*factor == '\0') 8509 break; 8510 /* 8511 Sepia tone image pixels. 8512 */ 8513 XSetCursorState(display,windows,MagickTrue); 8514 XCheckRefreshWindows(display,windows); 8515 threshold=SiPrefixToDouble(factor,QuantumRange); 8516 sepia_image=SepiaToneImage(*image,threshold,exception); 8517 if (sepia_image != (Image *) NULL) 8518 { 8519 *image=DestroyImage(*image); 8520 *image=sepia_image; 8521 } 8522 CatchException(exception); 8523 XSetCursorState(display,windows,MagickFalse); 8524 if (windows->image.orphan != MagickFalse) 8525 break; 8526 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8527 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8528 break; 8529 } 8530 case SolarizeCommand: 8531 { 8532 double 8533 threshold; 8534 8535 static char 8536 factor[MaxTextExtent] = "60%"; 8537 8538 /* 8539 Query user for solarize factor. 8540 */ 8541 (void) XDialogWidget(display,windows,"Solarize", 8542 "Enter the solarize factor (0 - 99.9%):",factor); 8543 if (*factor == '\0') 8544 break; 8545 /* 8546 Solarize image pixels. 8547 */ 8548 XSetCursorState(display,windows,MagickTrue); 8549 XCheckRefreshWindows(display,windows); 8550 threshold=SiPrefixToDouble(factor,QuantumRange); 8551 (void) SolarizeImage(*image,threshold,exception); 8552 XSetCursorState(display,windows,MagickFalse); 8553 if (windows->image.orphan != MagickFalse) 8554 break; 8555 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8556 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8557 break; 8558 } 8559 case SwirlCommand: 8560 { 8561 Image 8562 *swirl_image; 8563 8564 static char 8565 degrees[MaxTextExtent] = "60"; 8566 8567 /* 8568 Query user for swirl angle. 8569 */ 8570 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8571 degrees); 8572 if (*degrees == '\0') 8573 break; 8574 /* 8575 Swirl image pixels about the center. 8576 */ 8577 XSetCursorState(display,windows,MagickTrue); 8578 XCheckRefreshWindows(display,windows); 8579 flags=ParseGeometry(degrees,&geometry_info); 8580 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate, 8581 exception); 8582 if (swirl_image != (Image *) NULL) 8583 { 8584 *image=DestroyImage(*image); 8585 *image=swirl_image; 8586 } 8587 CatchException(exception); 8588 XSetCursorState(display,windows,MagickFalse); 8589 if (windows->image.orphan != MagickFalse) 8590 break; 8591 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8592 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8593 break; 8594 } 8595 case ImplodeCommand: 8596 { 8597 Image 8598 *implode_image; 8599 8600 static char 8601 factor[MaxTextExtent] = "0.3"; 8602 8603 /* 8604 Query user for implode factor. 8605 */ 8606 (void) XDialogWidget(display,windows,"Implode", 8607 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8608 if (*factor == '\0') 8609 break; 8610 /* 8611 Implode image pixels about the center. 8612 */ 8613 XSetCursorState(display,windows,MagickTrue); 8614 XCheckRefreshWindows(display,windows); 8615 flags=ParseGeometry(factor,&geometry_info); 8616 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate, 8617 exception); 8618 if (implode_image != (Image *) NULL) 8619 { 8620 *image=DestroyImage(*image); 8621 *image=implode_image; 8622 } 8623 CatchException(exception); 8624 XSetCursorState(display,windows,MagickFalse); 8625 if (windows->image.orphan != MagickFalse) 8626 break; 8627 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8628 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8629 break; 8630 } 8631 case VignetteCommand: 8632 { 8633 Image 8634 *vignette_image; 8635 8636 static char 8637 geometry[MaxTextExtent] = "0x20"; 8638 8639 /* 8640 Query user for the vignette geometry. 8641 */ 8642 (void) XDialogWidget(display,windows,"Vignette", 8643 "Enter the radius, sigma, and x and y offsets:",geometry); 8644 if (*geometry == '\0') 8645 break; 8646 /* 8647 Soften the edges of the image in vignette style 8648 */ 8649 XSetCursorState(display,windows,MagickTrue); 8650 XCheckRefreshWindows(display,windows); 8651 flags=ParseGeometry(geometry,&geometry_info); 8652 if ((flags & SigmaValue) == 0) 8653 geometry_info.sigma=1.0; 8654 if ((flags & XiValue) == 0) 8655 geometry_info.xi=0.1*(*image)->columns; 8656 if ((flags & PsiValue) == 0) 8657 geometry_info.psi=0.1*(*image)->rows; 8658 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma, 8659 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi- 8660 0.5),exception); 8661 if (vignette_image != (Image *) NULL) 8662 { 8663 *image=DestroyImage(*image); 8664 *image=vignette_image; 8665 } 8666 CatchException(exception); 8667 XSetCursorState(display,windows,MagickFalse); 8668 if (windows->image.orphan != MagickFalse) 8669 break; 8670 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8671 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8672 break; 8673 } 8674 case WaveCommand: 8675 { 8676 Image 8677 *wave_image; 8678 8679 static char 8680 geometry[MaxTextExtent] = "25x150"; 8681 8682 /* 8683 Query user for the wave geometry. 8684 */ 8685 (void) XDialogWidget(display,windows,"Wave", 8686 "Enter the amplitude and length of the wave:",geometry); 8687 if (*geometry == '\0') 8688 break; 8689 /* 8690 Alter an image along a sine wave. 8691 */ 8692 XSetCursorState(display,windows,MagickTrue); 8693 XCheckRefreshWindows(display,windows); 8694 flags=ParseGeometry(geometry,&geometry_info); 8695 if ((flags & SigmaValue) == 0) 8696 geometry_info.sigma=1.0; 8697 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8698 (*image)->interpolate,exception); 8699 if (wave_image != (Image *) NULL) 8700 { 8701 *image=DestroyImage(*image); 8702 *image=wave_image; 8703 } 8704 CatchException(exception); 8705 XSetCursorState(display,windows,MagickFalse); 8706 if (windows->image.orphan != MagickFalse) 8707 break; 8708 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8709 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8710 break; 8711 } 8712 case OilPaintCommand: 8713 { 8714 Image 8715 *paint_image; 8716 8717 static char 8718 radius[MaxTextExtent] = "0"; 8719 8720 /* 8721 Query user for circular neighborhood radius. 8722 */ 8723 (void) XDialogWidget(display,windows,"Oil Paint", 8724 "Enter the mask radius:",radius); 8725 if (*radius == '\0') 8726 break; 8727 /* 8728 OilPaint image scanlines. 8729 */ 8730 XSetCursorState(display,windows,MagickTrue); 8731 XCheckRefreshWindows(display,windows); 8732 flags=ParseGeometry(radius,&geometry_info); 8733 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma, 8734 exception); 8735 if (paint_image != (Image *) NULL) 8736 { 8737 *image=DestroyImage(*image); 8738 *image=paint_image; 8739 } 8740 CatchException(exception); 8741 XSetCursorState(display,windows,MagickFalse); 8742 if (windows->image.orphan != MagickFalse) 8743 break; 8744 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8745 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8746 break; 8747 } 8748 case CharcoalDrawCommand: 8749 { 8750 Image 8751 *charcoal_image; 8752 8753 static char 8754 radius[MaxTextExtent] = "0x1"; 8755 8756 /* 8757 Query user for charcoal radius. 8758 */ 8759 (void) XDialogWidget(display,windows,"Charcoal Draw", 8760 "Enter the charcoal radius and sigma:",radius); 8761 if (*radius == '\0') 8762 break; 8763 /* 8764 Charcoal the image. 8765 */ 8766 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8767 exception); 8768 XSetCursorState(display,windows,MagickTrue); 8769 XCheckRefreshWindows(display,windows); 8770 flags=ParseGeometry(radius,&geometry_info); 8771 if ((flags & SigmaValue) == 0) 8772 geometry_info.sigma=geometry_info.rho; 8773 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8774 geometry_info.xi,exception); 8775 if (charcoal_image != (Image *) NULL) 8776 { 8777 *image=DestroyImage(*image); 8778 *image=charcoal_image; 8779 } 8780 CatchException(exception); 8781 XSetCursorState(display,windows,MagickFalse); 8782 if (windows->image.orphan != MagickFalse) 8783 break; 8784 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8785 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8786 break; 8787 } 8788 case AnnotateCommand: 8789 { 8790 /* 8791 Annotate the image with text. 8792 */ 8793 status=XAnnotateEditImage(display,resource_info,windows,*image,exception); 8794 if (status == MagickFalse) 8795 { 8796 XNoticeWidget(display,windows,"Unable to annotate X image", 8797 (*image)->filename); 8798 break; 8799 } 8800 break; 8801 } 8802 case DrawCommand: 8803 { 8804 /* 8805 Draw image. 8806 */ 8807 status=XDrawEditImage(display,resource_info,windows,image,exception); 8808 if (status == MagickFalse) 8809 { 8810 XNoticeWidget(display,windows,"Unable to draw on the X image", 8811 (*image)->filename); 8812 break; 8813 } 8814 break; 8815 } 8816 case ColorCommand: 8817 { 8818 /* 8819 Color edit. 8820 */ 8821 status=XColorEditImage(display,resource_info,windows,image,exception); 8822 if (status == MagickFalse) 8823 { 8824 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8825 (*image)->filename); 8826 break; 8827 } 8828 break; 8829 } 8830 case MatteCommand: 8831 { 8832 /* 8833 Matte edit. 8834 */ 8835 status=XMatteEditImage(display,resource_info,windows,image,exception); 8836 if (status == MagickFalse) 8837 { 8838 XNoticeWidget(display,windows,"Unable to matte edit X image", 8839 (*image)->filename); 8840 break; 8841 } 8842 break; 8843 } 8844 case CompositeCommand: 8845 { 8846 /* 8847 Composite image. 8848 */ 8849 status=XCompositeImage(display,resource_info,windows,*image, 8850 exception); 8851 if (status == MagickFalse) 8852 { 8853 XNoticeWidget(display,windows,"Unable to composite X image", 8854 (*image)->filename); 8855 break; 8856 } 8857 break; 8858 } 8859 case AddBorderCommand: 8860 { 8861 Image 8862 *border_image; 8863 8864 static char 8865 geometry[MaxTextExtent] = "6x6"; 8866 8867 /* 8868 Query user for border color and geometry. 8869 */ 8870 XColorBrowserWidget(display,windows,"Select",color); 8871 if (*color == '\0') 8872 break; 8873 (void) XDialogWidget(display,windows,"Add Border", 8874 "Enter border geometry:",geometry); 8875 if (*geometry == '\0') 8876 break; 8877 /* 8878 Add a border to the image. 8879 */ 8880 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8881 exception); 8882 XSetCursorState(display,windows,MagickTrue); 8883 XCheckRefreshWindows(display,windows); 8884 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color, 8885 exception); 8886 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8887 exception); 8888 border_image=BorderImage(*image,&page_geometry,(*image)->compose, 8889 exception); 8890 if (border_image != (Image *) NULL) 8891 { 8892 *image=DestroyImage(*image); 8893 *image=border_image; 8894 } 8895 CatchException(exception); 8896 XSetCursorState(display,windows,MagickFalse); 8897 if (windows->image.orphan != MagickFalse) 8898 break; 8899 windows->image.window_changes.width=(int) (*image)->columns; 8900 windows->image.window_changes.height=(int) (*image)->rows; 8901 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8902 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8903 break; 8904 } 8905 case AddFrameCommand: 8906 { 8907 FrameInfo 8908 frame_info; 8909 8910 Image 8911 *frame_image; 8912 8913 static char 8914 geometry[MaxTextExtent] = "6x6"; 8915 8916 /* 8917 Query user for frame color and geometry. 8918 */ 8919 XColorBrowserWidget(display,windows,"Select",color); 8920 if (*color == '\0') 8921 break; 8922 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8923 geometry); 8924 if (*geometry == '\0') 8925 break; 8926 /* 8927 Surround image with an ornamental border. 8928 */ 8929 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8930 exception); 8931 XSetCursorState(display,windows,MagickTrue); 8932 XCheckRefreshWindows(display,windows); 8933 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color, 8934 exception); 8935 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8936 exception); 8937 frame_info.width=page_geometry.width; 8938 frame_info.height=page_geometry.height; 8939 frame_info.outer_bevel=page_geometry.x; 8940 frame_info.inner_bevel=page_geometry.y; 8941 frame_info.x=(ssize_t) frame_info.width; 8942 frame_info.y=(ssize_t) frame_info.height; 8943 frame_info.width=(*image)->columns+2*frame_info.width; 8944 frame_info.height=(*image)->rows+2*frame_info.height; 8945 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception); 8946 if (frame_image != (Image *) NULL) 8947 { 8948 *image=DestroyImage(*image); 8949 *image=frame_image; 8950 } 8951 CatchException(exception); 8952 XSetCursorState(display,windows,MagickFalse); 8953 if (windows->image.orphan != MagickFalse) 8954 break; 8955 windows->image.window_changes.width=(int) (*image)->columns; 8956 windows->image.window_changes.height=(int) (*image)->rows; 8957 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8958 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8959 break; 8960 } 8961 case CommentCommand: 8962 { 8963 const char 8964 *value; 8965 8966 FILE 8967 *file; 8968 8969 int 8970 unique_file; 8971 8972 /* 8973 Edit image comment. 8974 */ 8975 unique_file=AcquireUniqueFileResource(image_info->filename); 8976 if (unique_file == -1) 8977 XNoticeWidget(display,windows,"Unable to edit image comment", 8978 image_info->filename); 8979 value=GetImageProperty(*image,"comment",exception); 8980 if (value == (char *) NULL) 8981 unique_file=close(unique_file)-1; 8982 else 8983 { 8984 register const char 8985 *p; 8986 8987 file=fdopen(unique_file,"w"); 8988 if (file == (FILE *) NULL) 8989 { 8990 XNoticeWidget(display,windows,"Unable to edit image comment", 8991 image_info->filename); 8992 break; 8993 } 8994 for (p=value; *p != '\0'; p++) 8995 (void) fputc((int) *p,file); 8996 (void) fputc('\n',file); 8997 (void) fclose(file); 8998 } 8999 XSetCursorState(display,windows,MagickTrue); 9000 XCheckRefreshWindows(display,windows); 9001 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 9002 exception); 9003 if (status == MagickFalse) 9004 XNoticeWidget(display,windows,"Unable to edit image comment", 9005 (char *) NULL); 9006 else 9007 { 9008 char 9009 *comment; 9010 9011 comment=FileToString(image_info->filename,~0UL,exception); 9012 if (comment != (char *) NULL) 9013 { 9014 (void) SetImageProperty(*image,"comment",comment,exception); 9015 (*image)->taint=MagickTrue; 9016 } 9017 } 9018 (void) RelinquishUniqueFileResource(image_info->filename); 9019 XSetCursorState(display,windows,MagickFalse); 9020 break; 9021 } 9022 case LaunchCommand: 9023 { 9024 /* 9025 Launch program. 9026 */ 9027 XSetCursorState(display,windows,MagickTrue); 9028 XCheckRefreshWindows(display,windows); 9029 (void) AcquireUniqueFilename(filename); 9030 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s", 9031 filename); 9032 status=WriteImage(image_info,*image,exception); 9033 if (status == MagickFalse) 9034 XNoticeWidget(display,windows,"Unable to launch image editor", 9035 (char *) NULL); 9036 else 9037 { 9038 nexus=ReadImage(resource_info->image_info,exception); 9039 CatchException(exception); 9040 XClientMessage(display,windows->image.id,windows->im_protocols, 9041 windows->im_next_image,CurrentTime); 9042 } 9043 (void) RelinquishUniqueFileResource(filename); 9044 XSetCursorState(display,windows,MagickFalse); 9045 break; 9046 } 9047 case RegionofInterestCommand: 9048 { 9049 /* 9050 Apply an image processing technique to a region of interest. 9051 */ 9052 (void) XROIImage(display,resource_info,windows,image,exception); 9053 break; 9054 } 9055 case InfoCommand: 9056 break; 9057 case ZoomCommand: 9058 { 9059 /* 9060 Zoom image. 9061 */ 9062 if (windows->magnify.mapped != MagickFalse) 9063 (void) XRaiseWindow(display,windows->magnify.id); 9064 else 9065 { 9066 /* 9067 Make magnify image. 9068 */ 9069 XSetCursorState(display,windows,MagickTrue); 9070 (void) XMapRaised(display,windows->magnify.id); 9071 XSetCursorState(display,windows,MagickFalse); 9072 } 9073 break; 9074 } 9075 case ShowPreviewCommand: 9076 { 9077 char 9078 **previews; 9079 9080 Image 9081 *preview_image; 9082 9083 static char 9084 preview_type[MaxTextExtent] = "Gamma"; 9085 9086 /* 9087 Select preview type from menu. 9088 */ 9089 previews=GetCommandOptions(MagickPreviewOptions); 9090 if (previews == (char **) NULL) 9091 break; 9092 XListBrowserWidget(display,windows,&windows->widget, 9093 (const char **) previews,"Preview", 9094 "Select an enhancement, effect, or F/X:",preview_type); 9095 previews=DestroyStringList(previews); 9096 if (*preview_type == '\0') 9097 break; 9098 /* 9099 Show image preview. 9100 */ 9101 XSetCursorState(display,windows,MagickTrue); 9102 XCheckRefreshWindows(display,windows); 9103 image_info->preview_type=(PreviewType) 9104 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type); 9105 image_info->group=(ssize_t) windows->image.id; 9106 (void) DeleteImageProperty(*image,"label"); 9107 (void) SetImageProperty(*image,"label","Preview",exception); 9108 (void) AcquireUniqueFilename(filename); 9109 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s", 9110 filename); 9111 status=WriteImage(image_info,*image,exception); 9112 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9113 preview_image=ReadImage(image_info,exception); 9114 (void) RelinquishUniqueFileResource(filename); 9115 if (preview_image == (Image *) NULL) 9116 break; 9117 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s", 9118 filename); 9119 status=WriteImage(image_info,preview_image,exception); 9120 preview_image=DestroyImage(preview_image); 9121 if (status == MagickFalse) 9122 XNoticeWidget(display,windows,"Unable to show image preview", 9123 (*image)->filename); 9124 XDelay(display,1500); 9125 XSetCursorState(display,windows,MagickFalse); 9126 break; 9127 } 9128 case ShowHistogramCommand: 9129 { 9130 Image 9131 *histogram_image; 9132 9133 /* 9134 Show image histogram. 9135 */ 9136 XSetCursorState(display,windows,MagickTrue); 9137 XCheckRefreshWindows(display,windows); 9138 image_info->group=(ssize_t) windows->image.id; 9139 (void) DeleteImageProperty(*image,"label"); 9140 (void) SetImageProperty(*image,"label","Histogram",exception); 9141 (void) AcquireUniqueFilename(filename); 9142 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s", 9143 filename); 9144 status=WriteImage(image_info,*image,exception); 9145 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9146 histogram_image=ReadImage(image_info,exception); 9147 (void) RelinquishUniqueFileResource(filename); 9148 if (histogram_image == (Image *) NULL) 9149 break; 9150 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent, 9151 "show:%s",filename); 9152 status=WriteImage(image_info,histogram_image,exception); 9153 histogram_image=DestroyImage(histogram_image); 9154 if (status == MagickFalse) 9155 XNoticeWidget(display,windows,"Unable to show histogram", 9156 (*image)->filename); 9157 XDelay(display,1500); 9158 XSetCursorState(display,windows,MagickFalse); 9159 break; 9160 } 9161 case ShowMatteCommand: 9162 { 9163 Image 9164 *matte_image; 9165 9166 if ((*image)->matte == MagickFalse) 9167 { 9168 XNoticeWidget(display,windows, 9169 "Image does not have any matte information",(*image)->filename); 9170 break; 9171 } 9172 /* 9173 Show image matte. 9174 */ 9175 XSetCursorState(display,windows,MagickTrue); 9176 XCheckRefreshWindows(display,windows); 9177 image_info->group=(ssize_t) windows->image.id; 9178 (void) DeleteImageProperty(*image,"label"); 9179 (void) SetImageProperty(*image,"label","Matte",exception); 9180 (void) AcquireUniqueFilename(filename); 9181 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s", 9182 filename); 9183 status=WriteImage(image_info,*image,exception); 9184 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9185 matte_image=ReadImage(image_info,exception); 9186 (void) RelinquishUniqueFileResource(filename); 9187 if (matte_image == (Image *) NULL) 9188 break; 9189 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s", 9190 filename); 9191 status=WriteImage(image_info,matte_image,exception); 9192 matte_image=DestroyImage(matte_image); 9193 if (status == MagickFalse) 9194 XNoticeWidget(display,windows,"Unable to show matte", 9195 (*image)->filename); 9196 XDelay(display,1500); 9197 XSetCursorState(display,windows,MagickFalse); 9198 break; 9199 } 9200 case BackgroundCommand: 9201 { 9202 /* 9203 Background image. 9204 */ 9205 status=XBackgroundImage(display,resource_info,windows,image,exception); 9206 if (status == MagickFalse) 9207 break; 9208 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9209 if (nexus != (Image *) NULL) 9210 XClientMessage(display,windows->image.id,windows->im_protocols, 9211 windows->im_next_image,CurrentTime); 9212 break; 9213 } 9214 case SlideShowCommand: 9215 { 9216 static char 9217 delay[MaxTextExtent] = "5"; 9218 9219 /* 9220 Display next image after pausing. 9221 */ 9222 (void) XDialogWidget(display,windows,"Slide Show", 9223 "Pause how many 1/100ths of a second between images:",delay); 9224 if (*delay == '\0') 9225 break; 9226 resource_info->delay=StringToUnsignedLong(delay); 9227 XClientMessage(display,windows->image.id,windows->im_protocols, 9228 windows->im_next_image,CurrentTime); 9229 break; 9230 } 9231 case PreferencesCommand: 9232 { 9233 /* 9234 Set user preferences. 9235 */ 9236 status=XPreferencesWidget(display,resource_info,windows); 9237 if (status == MagickFalse) 9238 break; 9239 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9240 if (nexus != (Image *) NULL) 9241 XClientMessage(display,windows->image.id,windows->im_protocols, 9242 windows->im_next_image,CurrentTime); 9243 break; 9244 } 9245 case HelpCommand: 9246 { 9247 /* 9248 User requested help. 9249 */ 9250 XTextViewWidget(display,resource_info,windows,MagickFalse, 9251 "Help Viewer - Display",DisplayHelp); 9252 break; 9253 } 9254 case BrowseDocumentationCommand: 9255 { 9256 Atom 9257 mozilla_atom; 9258 9259 Window 9260 mozilla_window, 9261 root_window; 9262 9263 /* 9264 Browse the ImageMagick documentation. 9265 */ 9266 root_window=XRootWindow(display,XDefaultScreen(display)); 9267 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); 9268 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); 9269 if (mozilla_window != (Window) NULL) 9270 { 9271 char 9272 command[MaxTextExtent], 9273 *url; 9274 9275 /* 9276 Display documentation using Netscape remote control. 9277 */ 9278 url=GetMagickHomeURL(); 9279 (void) FormatLocaleString(command,MaxTextExtent, 9280 "openurl(%s,new-tab)",url); 9281 url=DestroyString(url); 9282 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); 9283 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING, 9284 8,PropModeReplace,(unsigned char *) command,(int) strlen(command)); 9285 XSetCursorState(display,windows,MagickFalse); 9286 break; 9287 } 9288 XSetCursorState(display,windows,MagickTrue); 9289 XCheckRefreshWindows(display,windows); 9290 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL, 9291 exception); 9292 if (status == MagickFalse) 9293 XNoticeWidget(display,windows,"Unable to browse documentation", 9294 (char *) NULL); 9295 XDelay(display,1500); 9296 XSetCursorState(display,windows,MagickFalse); 9297 break; 9298 } 9299 case VersionCommand: 9300 { 9301 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), 9302 GetMagickCopyright()); 9303 break; 9304 } 9305 case SaveToUndoBufferCommand: 9306 break; 9307 default: 9308 { 9309 (void) XBell(display,0); 9310 break; 9311 } 9312 } 9313 image_info=DestroyImageInfo(image_info); 9314 return(nexus); 9315} 9316 9317/* 9318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9319% % 9320% % 9321% % 9322+ X M a g n i f y I m a g e % 9323% % 9324% % 9325% % 9326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9327% 9328% XMagnifyImage() magnifies portions of the image as indicated by the pointer. 9329% The magnified portion is displayed in a separate window. 9330% 9331% The format of the XMagnifyImage method is: 9332% 9333% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9334% ExceptionInfo *exception) 9335% 9336% A description of each parameter follows: 9337% 9338% o display: Specifies a connection to an X server; returned from 9339% XOpenDisplay. 9340% 9341% o windows: Specifies a pointer to a XWindows structure. 9342% 9343% o event: Specifies a pointer to a XEvent structure. If it is NULL, 9344% the entire image is refreshed. 9345% 9346% o exception: return any errors or warnings in this structure. 9347% 9348*/ 9349static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9350 ExceptionInfo *exception) 9351{ 9352 char 9353 text[MaxTextExtent]; 9354 9355 register int 9356 x, 9357 y; 9358 9359 size_t 9360 state; 9361 9362 /* 9363 Update magnified image until the mouse button is released. 9364 */ 9365 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor); 9366 state=DefaultState; 9367 x=event->xbutton.x; 9368 y=event->xbutton.y; 9369 windows->magnify.x=(int) windows->image.x+x; 9370 windows->magnify.y=(int) windows->image.y+y; 9371 do 9372 { 9373 /* 9374 Map and unmap Info widget as text cursor crosses its boundaries. 9375 */ 9376 if (windows->info.mapped != MagickFalse) 9377 { 9378 if ((x < (int) (windows->info.x+windows->info.width)) && 9379 (y < (int) (windows->info.y+windows->info.height))) 9380 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 9381 } 9382 else 9383 if ((x > (int) (windows->info.x+windows->info.width)) || 9384 (y > (int) (windows->info.y+windows->info.height))) 9385 (void) XMapWindow(display,windows->info.id); 9386 if (windows->info.mapped != MagickFalse) 9387 { 9388 /* 9389 Display pointer position. 9390 */ 9391 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9392 windows->magnify.x,windows->magnify.y); 9393 XInfoWidget(display,windows,text); 9394 } 9395 /* 9396 Wait for next event. 9397 */ 9398 XScreenEvent(display,windows,event,exception); 9399 switch (event->type) 9400 { 9401 case ButtonPress: 9402 break; 9403 case ButtonRelease: 9404 { 9405 /* 9406 User has finished magnifying image. 9407 */ 9408 x=event->xbutton.x; 9409 y=event->xbutton.y; 9410 state|=ExitState; 9411 break; 9412 } 9413 case Expose: 9414 break; 9415 case MotionNotify: 9416 { 9417 x=event->xmotion.x; 9418 y=event->xmotion.y; 9419 break; 9420 } 9421 default: 9422 break; 9423 } 9424 /* 9425 Check boundary conditions. 9426 */ 9427 if (x < 0) 9428 x=0; 9429 else 9430 if (x >= (int) windows->image.width) 9431 x=(int) windows->image.width-1; 9432 if (y < 0) 9433 y=0; 9434 else 9435 if (y >= (int) windows->image.height) 9436 y=(int) windows->image.height-1; 9437 } while ((state & ExitState) == 0); 9438 /* 9439 Display magnified image. 9440 */ 9441 XSetCursorState(display,windows,MagickFalse); 9442} 9443 9444/* 9445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9446% % 9447% % 9448% % 9449+ X M a g n i f y W i n d o w C o m m a n d % 9450% % 9451% % 9452% % 9453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9454% 9455% XMagnifyWindowCommand() moves the image within an Magnify window by one 9456% pixel as specified by the key symbol. 9457% 9458% The format of the XMagnifyWindowCommand method is: 9459% 9460% void XMagnifyWindowCommand(Display *display,XWindows *windows, 9461% const MagickStatusType state,const KeySym key_symbol, 9462% ExceptionInfo *exception) 9463% 9464% A description of each parameter follows: 9465% 9466% o display: Specifies a connection to an X server; returned from 9467% XOpenDisplay. 9468% 9469% o windows: Specifies a pointer to a XWindows structure. 9470% 9471% o state: key mask. 9472% 9473% o key_symbol: Specifies a KeySym which indicates which side of the image 9474% to trim. 9475% 9476% o exception: return any errors or warnings in this structure. 9477% 9478*/ 9479static void XMagnifyWindowCommand(Display *display,XWindows *windows, 9480 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception) 9481{ 9482 unsigned int 9483 quantum; 9484 9485 /* 9486 User specified a magnify factor or position. 9487 */ 9488 quantum=1; 9489 if ((state & Mod1Mask) != 0) 9490 quantum=10; 9491 switch ((int) key_symbol) 9492 { 9493 case QuitCommand: 9494 { 9495 (void) XWithdrawWindow(display,windows->magnify.id, 9496 windows->magnify.screen); 9497 break; 9498 } 9499 case XK_Home: 9500 case XK_KP_Home: 9501 { 9502 windows->magnify.x=(int) windows->image.width/2; 9503 windows->magnify.y=(int) windows->image.height/2; 9504 break; 9505 } 9506 case XK_Left: 9507 case XK_KP_Left: 9508 { 9509 if (windows->magnify.x > 0) 9510 windows->magnify.x-=quantum; 9511 break; 9512 } 9513 case XK_Up: 9514 case XK_KP_Up: 9515 { 9516 if (windows->magnify.y > 0) 9517 windows->magnify.y-=quantum; 9518 break; 9519 } 9520 case XK_Right: 9521 case XK_KP_Right: 9522 { 9523 if (windows->magnify.x < (int) (windows->image.ximage->width-1)) 9524 windows->magnify.x+=quantum; 9525 break; 9526 } 9527 case XK_Down: 9528 case XK_KP_Down: 9529 { 9530 if (windows->magnify.y < (int) (windows->image.ximage->height-1)) 9531 windows->magnify.y+=quantum; 9532 break; 9533 } 9534 case XK_0: 9535 case XK_1: 9536 case XK_2: 9537 case XK_3: 9538 case XK_4: 9539 case XK_5: 9540 case XK_6: 9541 case XK_7: 9542 case XK_8: 9543 case XK_9: 9544 { 9545 windows->magnify.data=(key_symbol-XK_0); 9546 break; 9547 } 9548 case XK_KP_0: 9549 case XK_KP_1: 9550 case XK_KP_2: 9551 case XK_KP_3: 9552 case XK_KP_4: 9553 case XK_KP_5: 9554 case XK_KP_6: 9555 case XK_KP_7: 9556 case XK_KP_8: 9557 case XK_KP_9: 9558 { 9559 windows->magnify.data=(key_symbol-XK_KP_0); 9560 break; 9561 } 9562 default: 9563 break; 9564 } 9565 XMakeMagnifyImage(display,windows,exception); 9566} 9567 9568/* 9569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9570% % 9571% % 9572% % 9573+ X M a k e P a n I m a g e % 9574% % 9575% % 9576% % 9577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9578% 9579% XMakePanImage() creates a thumbnail of the image and displays it in the Pan 9580% icon window. 9581% 9582% The format of the XMakePanImage method is: 9583% 9584% void XMakePanImage(Display *display,XResourceInfo *resource_info, 9585% XWindows *windows,Image *image,ExceptionInfo *exception) 9586% 9587% A description of each parameter follows: 9588% 9589% o display: Specifies a connection to an X server; returned from 9590% XOpenDisplay. 9591% 9592% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9593% 9594% o windows: Specifies a pointer to a XWindows structure. 9595% 9596% o image: the image. 9597% 9598% o exception: return any errors or warnings in this structure. 9599% 9600*/ 9601static void XMakePanImage(Display *display,XResourceInfo *resource_info, 9602 XWindows *windows,Image *image,ExceptionInfo *exception) 9603{ 9604 MagickStatusType 9605 status; 9606 9607 /* 9608 Create and display image for panning icon. 9609 */ 9610 XSetCursorState(display,windows,MagickTrue); 9611 XCheckRefreshWindows(display,windows); 9612 windows->pan.x=(int) windows->image.x; 9613 windows->pan.y=(int) windows->image.y; 9614 status=XMakeImage(display,resource_info,&windows->pan,image, 9615 windows->pan.width,windows->pan.height,exception); 9616 if (status == MagickFalse) 9617 ThrowXWindowFatalException(ResourceLimitError, 9618 "MemoryAllocationFailed",image->filename); 9619 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 9620 windows->pan.pixmap); 9621 (void) XClearWindow(display,windows->pan.id); 9622 XDrawPanRectangle(display,windows); 9623 XSetCursorState(display,windows,MagickFalse); 9624} 9625 9626/* 9627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9628% % 9629% % 9630% % 9631+ X M a t t a E d i t I m a g e % 9632% % 9633% % 9634% % 9635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9636% 9637% XMatteEditImage() allows the user to interactively change the Matte channel 9638% of an image. If the image is PseudoClass it is promoted to DirectClass 9639% before the matte information is stored. 9640% 9641% The format of the XMatteEditImage method is: 9642% 9643% MagickBooleanType XMatteEditImage(Display *display, 9644% XResourceInfo *resource_info,XWindows *windows,Image **image, 9645% ExceptionInfo *exception) 9646% 9647% A description of each parameter follows: 9648% 9649% o display: Specifies a connection to an X server; returned from 9650% XOpenDisplay. 9651% 9652% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9653% 9654% o windows: Specifies a pointer to a XWindows structure. 9655% 9656% o image: the image; returned from ReadImage. 9657% 9658% o exception: return any errors or warnings in this structure. 9659% 9660*/ 9661static MagickBooleanType XMatteEditImage(Display *display, 9662 XResourceInfo *resource_info,XWindows *windows,Image **image, 9663 ExceptionInfo *exception) 9664{ 9665 static char 9666 matte[MaxTextExtent] = "0"; 9667 9668 static const char 9669 *MatteEditMenu[] = 9670 { 9671 "Method", 9672 "Border Color", 9673 "Fuzz", 9674 "Matte Value", 9675 "Undo", 9676 "Help", 9677 "Dismiss", 9678 (char *) NULL 9679 }; 9680 9681 static const ModeType 9682 MatteEditCommands[] = 9683 { 9684 MatteEditMethod, 9685 MatteEditBorderCommand, 9686 MatteEditFuzzCommand, 9687 MatteEditValueCommand, 9688 MatteEditUndoCommand, 9689 MatteEditHelpCommand, 9690 MatteEditDismissCommand 9691 }; 9692 9693 static PaintMethod 9694 method = PointMethod; 9695 9696 static XColor 9697 border_color = { 0, 0, 0, 0, 0, 0 }; 9698 9699 char 9700 command[MaxTextExtent], 9701 text[MaxTextExtent]; 9702 9703 Cursor 9704 cursor; 9705 9706 int 9707 entry, 9708 id, 9709 x, 9710 x_offset, 9711 y, 9712 y_offset; 9713 9714 register int 9715 i; 9716 9717 register Quantum 9718 *q; 9719 9720 unsigned int 9721 height, 9722 width; 9723 9724 size_t 9725 state; 9726 9727 XEvent 9728 event; 9729 9730 /* 9731 Map Command widget. 9732 */ 9733 (void) CloneString(&windows->command.name,"Matte Edit"); 9734 windows->command.data=4; 9735 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL); 9736 (void) XMapRaised(display,windows->command.id); 9737 XClientMessage(display,windows->image.id,windows->im_protocols, 9738 windows->im_update_widget,CurrentTime); 9739 /* 9740 Make cursor. 9741 */ 9742 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 9743 resource_info->background_color,resource_info->foreground_color); 9744 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9745 /* 9746 Track pointer until button 1 is pressed. 9747 */ 9748 XQueryPosition(display,windows->image.id,&x,&y); 9749 (void) XSelectInput(display,windows->image.id, 9750 windows->image.attributes.event_mask | PointerMotionMask); 9751 state=DefaultState; 9752 do 9753 { 9754 if (windows->info.mapped != MagickFalse) 9755 { 9756 /* 9757 Display pointer position. 9758 */ 9759 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9760 x+windows->image.x,y+windows->image.y); 9761 XInfoWidget(display,windows,text); 9762 } 9763 /* 9764 Wait for next event. 9765 */ 9766 XScreenEvent(display,windows,&event,exception); 9767 if (event.xany.window == windows->command.id) 9768 { 9769 /* 9770 Select a command from the Command widget. 9771 */ 9772 id=XCommandWidget(display,windows,MatteEditMenu,&event); 9773 if (id < 0) 9774 { 9775 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9776 continue; 9777 } 9778 switch (MatteEditCommands[id]) 9779 { 9780 case MatteEditMethod: 9781 { 9782 char 9783 **methods; 9784 9785 /* 9786 Select a method from the pop-up menu. 9787 */ 9788 methods=GetCommandOptions(MagickMethodOptions); 9789 if (methods == (char **) NULL) 9790 break; 9791 entry=XMenuWidget(display,windows,MatteEditMenu[id], 9792 (const char **) methods,command); 9793 if (entry >= 0) 9794 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 9795 MagickFalse,methods[entry]); 9796 methods=DestroyStringList(methods); 9797 break; 9798 } 9799 case MatteEditBorderCommand: 9800 { 9801 const char 9802 *ColorMenu[MaxNumberPens]; 9803 9804 int 9805 pen_number; 9806 9807 /* 9808 Initialize menu selections. 9809 */ 9810 for (i=0; i < (int) (MaxNumberPens-2); i++) 9811 ColorMenu[i]=resource_info->pen_colors[i]; 9812 ColorMenu[MaxNumberPens-2]="Browser..."; 9813 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 9814 /* 9815 Select a pen color from the pop-up menu. 9816 */ 9817 pen_number=XMenuWidget(display,windows,MatteEditMenu[id], 9818 (const char **) ColorMenu,command); 9819 if (pen_number < 0) 9820 break; 9821 if (pen_number == (MaxNumberPens-2)) 9822 { 9823 static char 9824 color_name[MaxTextExtent] = "gray"; 9825 9826 /* 9827 Select a pen color from a dialog. 9828 */ 9829 resource_info->pen_colors[pen_number]=color_name; 9830 XColorBrowserWidget(display,windows,"Select",color_name); 9831 if (*color_name == '\0') 9832 break; 9833 } 9834 /* 9835 Set border color. 9836 */ 9837 (void) XParseColor(display,windows->map_info->colormap, 9838 resource_info->pen_colors[pen_number],&border_color); 9839 break; 9840 } 9841 case MatteEditFuzzCommand: 9842 { 9843 static char 9844 fuzz[MaxTextExtent]; 9845 9846 static const char 9847 *FuzzMenu[] = 9848 { 9849 "0%", 9850 "2%", 9851 "5%", 9852 "10%", 9853 "15%", 9854 "Dialog...", 9855 (char *) NULL, 9856 }; 9857 9858 /* 9859 Select a command from the pop-up menu. 9860 */ 9861 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu, 9862 command); 9863 if (entry < 0) 9864 break; 9865 if (entry != 5) 9866 { 9867 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],(double) 9868 QuantumRange+1.0); 9869 break; 9870 } 9871 (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 9872 (void) XDialogWidget(display,windows,"Ok", 9873 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 9874 if (*fuzz == '\0') 9875 break; 9876 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 9877 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0); 9878 break; 9879 } 9880 case MatteEditValueCommand: 9881 { 9882 static char 9883 message[MaxTextExtent]; 9884 9885 static const char 9886 *MatteMenu[] = 9887 { 9888 "Opaque", 9889 "Transparent", 9890 "Dialog...", 9891 (char *) NULL, 9892 }; 9893 9894 /* 9895 Select a command from the pop-up menu. 9896 */ 9897 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu, 9898 command); 9899 if (entry < 0) 9900 break; 9901 if (entry != 2) 9902 { 9903 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9904 OpaqueAlpha); 9905 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9906 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9907 (Quantum) TransparentAlpha); 9908 break; 9909 } 9910 (void) FormatLocaleString(message,MaxTextExtent, 9911 "Enter matte value (0 - " QuantumFormat "):",(Quantum) 9912 QuantumRange); 9913 (void) XDialogWidget(display,windows,"Matte",message,matte); 9914 if (*matte == '\0') 9915 break; 9916 break; 9917 } 9918 case MatteEditUndoCommand: 9919 { 9920 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 9921 image,exception); 9922 break; 9923 } 9924 case MatteEditHelpCommand: 9925 { 9926 XTextViewWidget(display,resource_info,windows,MagickFalse, 9927 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9928 break; 9929 } 9930 case MatteEditDismissCommand: 9931 { 9932 /* 9933 Prematurely exit. 9934 */ 9935 state|=EscapeState; 9936 state|=ExitState; 9937 break; 9938 } 9939 default: 9940 break; 9941 } 9942 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9943 continue; 9944 } 9945 switch (event.type) 9946 { 9947 case ButtonPress: 9948 { 9949 if (event.xbutton.button != Button1) 9950 break; 9951 if ((event.xbutton.window != windows->image.id) && 9952 (event.xbutton.window != windows->magnify.id)) 9953 break; 9954 /* 9955 Update matte data. 9956 */ 9957 x=event.xbutton.x; 9958 y=event.xbutton.y; 9959 (void) XMagickCommand(display,resource_info,windows, 9960 SaveToUndoBufferCommand,image,exception); 9961 state|=UpdateConfigurationState; 9962 break; 9963 } 9964 case ButtonRelease: 9965 { 9966 if (event.xbutton.button != Button1) 9967 break; 9968 if ((event.xbutton.window != windows->image.id) && 9969 (event.xbutton.window != windows->magnify.id)) 9970 break; 9971 /* 9972 Update colormap information. 9973 */ 9974 x=event.xbutton.x; 9975 y=event.xbutton.y; 9976 XConfigureImageColormap(display,resource_info,windows,*image,exception); 9977 (void) XConfigureImage(display,resource_info,windows,*image,exception); 9978 XInfoWidget(display,windows,text); 9979 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9980 state&=(~UpdateConfigurationState); 9981 break; 9982 } 9983 case Expose: 9984 break; 9985 case KeyPress: 9986 { 9987 char 9988 command[MaxTextExtent]; 9989 9990 KeySym 9991 key_symbol; 9992 9993 if (event.xkey.window == windows->magnify.id) 9994 { 9995 Window 9996 window; 9997 9998 window=windows->magnify.id; 9999 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 10000 } 10001 if (event.xkey.window != windows->image.id) 10002 break; 10003 /* 10004 Respond to a user key press. 10005 */ 10006 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 10007 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10008 switch ((int) key_symbol) 10009 { 10010 case XK_Escape: 10011 case XK_F20: 10012 { 10013 /* 10014 Prematurely exit. 10015 */ 10016 state|=ExitState; 10017 break; 10018 } 10019 case XK_F1: 10020 case XK_Help: 10021 { 10022 XTextViewWidget(display,resource_info,windows,MagickFalse, 10023 "Help Viewer - Matte Edit",ImageMatteEditHelp); 10024 break; 10025 } 10026 default: 10027 { 10028 (void) XBell(display,0); 10029 break; 10030 } 10031 } 10032 break; 10033 } 10034 case MotionNotify: 10035 { 10036 /* 10037 Map and unmap Info widget as cursor crosses its boundaries. 10038 */ 10039 x=event.xmotion.x; 10040 y=event.xmotion.y; 10041 if (windows->info.mapped != MagickFalse) 10042 { 10043 if ((x < (int) (windows->info.x+windows->info.width)) && 10044 (y < (int) (windows->info.y+windows->info.height))) 10045 (void) XWithdrawWindow(display,windows->info.id, 10046 windows->info.screen); 10047 } 10048 else 10049 if ((x > (int) (windows->info.x+windows->info.width)) || 10050 (y > (int) (windows->info.y+windows->info.height))) 10051 (void) XMapWindow(display,windows->info.id); 10052 break; 10053 } 10054 default: 10055 break; 10056 } 10057 if (event.xany.window == windows->magnify.id) 10058 { 10059 x=windows->magnify.x-windows->image.x; 10060 y=windows->magnify.y-windows->image.y; 10061 } 10062 x_offset=x; 10063 y_offset=y; 10064 if ((state & UpdateConfigurationState) != 0) 10065 { 10066 CacheView 10067 *image_view; 10068 10069 int 10070 x, 10071 y; 10072 10073 /* 10074 Matte edit is relative to image configuration. 10075 */ 10076 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 10077 MagickTrue); 10078 XPutPixel(windows->image.ximage,x_offset,y_offset, 10079 windows->pixel_info->background_color.pixel); 10080 width=(unsigned int) (*image)->columns; 10081 height=(unsigned int) (*image)->rows; 10082 x=0; 10083 y=0; 10084 if (windows->image.crop_geometry != (char *) NULL) 10085 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width, 10086 &height); 10087 x_offset=(int) (width*(windows->image.x+x_offset)/ 10088 windows->image.ximage->width+x); 10089 y_offset=(int) (height*(windows->image.y+y_offset)/ 10090 windows->image.ximage->height+y); 10091 if ((x_offset < 0) || (y_offset < 0)) 10092 continue; 10093 if ((x_offset >= (int) (*image)->columns) || 10094 (y_offset >= (int) (*image)->rows)) 10095 continue; 10096 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10097 return(MagickFalse); 10098 (*image)->matte=MagickTrue; 10099 image_view=AcquireCacheView(*image); 10100 switch (method) 10101 { 10102 case PointMethod: 10103 default: 10104 { 10105 /* 10106 Update matte information using point algorithm. 10107 */ 10108 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset, 10109 (ssize_t) y_offset,1,1,exception); 10110 if (q == (Quantum *) NULL) 10111 break; 10112 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10113 (void) SyncCacheViewAuthenticPixels(image_view,exception); 10114 break; 10115 } 10116 case ReplaceMethod: 10117 { 10118 PixelInfo 10119 pixel, 10120 target; 10121 10122 Quantum 10123 virtual_pixel[CompositePixelChannel]; 10124 10125 /* 10126 Update matte information using replace algorithm. 10127 */ 10128 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 10129 (ssize_t) y_offset,virtual_pixel,exception); 10130 target.red=virtual_pixel[RedPixelChannel]; 10131 target.green=virtual_pixel[GreenPixelChannel]; 10132 target.blue=virtual_pixel[BluePixelChannel]; 10133 target.alpha=virtual_pixel[AlphaPixelChannel]; 10134 for (y=0; y < (int) (*image)->rows; y++) 10135 { 10136 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10137 (*image)->columns,1,exception); 10138 if (q == (Quantum *) NULL) 10139 break; 10140 for (x=0; x < (int) (*image)->columns; x++) 10141 { 10142 GetPixelInfoPixel(*image,q,&pixel); 10143 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 10144 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10145 q+=GetPixelChannels(*image); 10146 } 10147 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10148 break; 10149 } 10150 break; 10151 } 10152 case FloodfillMethod: 10153 case FillToBorderMethod: 10154 { 10155 ChannelType 10156 channel_mask; 10157 10158 DrawInfo 10159 *draw_info; 10160 10161 PixelInfo 10162 target; 10163 10164 /* 10165 Update matte information using floodfill algorithm. 10166 */ 10167 (void) GetOneVirtualMagickPixel(*image, 10168 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 10169 y_offset,&target,exception); 10170 if (method == FillToBorderMethod) 10171 { 10172 target.red=(MagickRealType) ScaleShortToQuantum( 10173 border_color.red); 10174 target.green=(MagickRealType) ScaleShortToQuantum( 10175 border_color.green); 10176 target.blue=(MagickRealType) ScaleShortToQuantum( 10177 border_color.blue); 10178 } 10179 draw_info=CloneDrawInfo(resource_info->image_info, 10180 (DrawInfo *) NULL); 10181 draw_info->fill.alpha=ClampToQuantum(InterpretLocaleValue(matte, 10182 (char **) NULL)); 10183 channel_mask=SetPixelChannelMask(*image,AlphaChannel); 10184 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 10185 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 10186 MagickFalse : MagickTrue,exception); 10187 (void) SetPixelChannelMap(*image,channel_mask); 10188 draw_info=DestroyDrawInfo(draw_info); 10189 break; 10190 } 10191 case ResetMethod: 10192 { 10193 /* 10194 Update matte information using reset algorithm. 10195 */ 10196 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10197 return(MagickFalse); 10198 for (y=0; y < (int) (*image)->rows; y++) 10199 { 10200 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10201 (*image)->columns,1,exception); 10202 if (q == (Quantum *) NULL) 10203 break; 10204 for (x=0; x < (int) (*image)->columns; x++) 10205 { 10206 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10207 q+=GetPixelChannels(*image); 10208 } 10209 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10210 break; 10211 } 10212 if (StringToLong(matte) == (long) OpaqueAlpha) 10213 (*image)->matte=MagickFalse; 10214 break; 10215 } 10216 } 10217 image_view=DestroyCacheView(image_view); 10218 state&=(~UpdateConfigurationState); 10219 } 10220 } while ((state & ExitState) == 0); 10221 (void) XSelectInput(display,windows->image.id, 10222 windows->image.attributes.event_mask); 10223 XSetCursorState(display,windows,MagickFalse); 10224 (void) XFreeCursor(display,cursor); 10225 return(MagickTrue); 10226} 10227 10228/* 10229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10230% % 10231% % 10232% % 10233+ X O p e n I m a g e % 10234% % 10235% % 10236% % 10237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10238% 10239% XOpenImage() loads an image from a file. 10240% 10241% The format of the XOpenImage method is: 10242% 10243% Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10244% XWindows *windows,const unsigned int command) 10245% 10246% A description of each parameter follows: 10247% 10248% o display: Specifies a connection to an X server; returned from 10249% XOpenDisplay. 10250% 10251% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10252% 10253% o windows: Specifies a pointer to a XWindows structure. 10254% 10255% o command: A value other than zero indicates that the file is selected 10256% from the command line argument list. 10257% 10258*/ 10259static Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10260 XWindows *windows,const MagickBooleanType command) 10261{ 10262 const MagickInfo 10263 *magick_info; 10264 10265 ExceptionInfo 10266 *exception; 10267 10268 Image 10269 *nexus; 10270 10271 ImageInfo 10272 *image_info; 10273 10274 static char 10275 filename[MaxTextExtent] = "\0"; 10276 10277 /* 10278 Request file name from user. 10279 */ 10280 if (command == MagickFalse) 10281 XFileBrowserWidget(display,windows,"Open",filename); 10282 else 10283 { 10284 char 10285 **filelist, 10286 **files; 10287 10288 int 10289 count, 10290 status; 10291 10292 register int 10293 i, 10294 j; 10295 10296 /* 10297 Select next image from the command line. 10298 */ 10299 status=XGetCommand(display,windows->image.id,&files,&count); 10300 if (status == 0) 10301 { 10302 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","..."); 10303 return((Image *) NULL); 10304 } 10305 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10306 if (filelist == (char **) NULL) 10307 { 10308 ThrowXWindowFatalException(ResourceLimitError, 10309 "MemoryAllocationFailed","..."); 10310 (void) XFreeStringList(files); 10311 return((Image *) NULL); 10312 } 10313 j=0; 10314 for (i=1; i < count; i++) 10315 if (*files[i] != '-') 10316 filelist[j++]=files[i]; 10317 filelist[j]=(char *) NULL; 10318 XListBrowserWidget(display,windows,&windows->widget, 10319 (const char **) filelist,"Load","Select Image to Load:",filename); 10320 filelist=(char **) RelinquishMagickMemory(filelist); 10321 (void) XFreeStringList(files); 10322 } 10323 if (*filename == '\0') 10324 return((Image *) NULL); 10325 image_info=CloneImageInfo(resource_info->image_info); 10326 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL, 10327 (void *) NULL); 10328 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10329 exception=AcquireExceptionInfo(); 10330 (void) SetImageInfo(image_info,0,exception); 10331 if (LocaleCompare(image_info->magick,"X") == 0) 10332 { 10333 char 10334 seconds[MaxTextExtent]; 10335 10336 /* 10337 User may want to delay the X server screen grab. 10338 */ 10339 (void) CopyMagickString(seconds,"0",MaxTextExtent); 10340 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:", 10341 seconds); 10342 if (*seconds == '\0') 10343 return((Image *) NULL); 10344 XDelay(display,(size_t) (1000*StringToLong(seconds))); 10345 } 10346 magick_info=GetMagickInfo(image_info->magick,exception); 10347 if ((magick_info != (const MagickInfo *) NULL) && 10348 (magick_info->raw != MagickFalse)) 10349 { 10350 char 10351 geometry[MaxTextExtent]; 10352 10353 /* 10354 Request image size from the user. 10355 */ 10356 (void) CopyMagickString(geometry,"512x512",MaxTextExtent); 10357 if (image_info->size != (char *) NULL) 10358 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent); 10359 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:", 10360 geometry); 10361 (void) CloneString(&image_info->size,geometry); 10362 } 10363 /* 10364 Load the image. 10365 */ 10366 XSetCursorState(display,windows,MagickTrue); 10367 XCheckRefreshWindows(display,windows); 10368 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10369 nexus=ReadImage(image_info,exception); 10370 CatchException(exception); 10371 XSetCursorState(display,windows,MagickFalse); 10372 if (nexus != (Image *) NULL) 10373 XClientMessage(display,windows->image.id,windows->im_protocols, 10374 windows->im_next_image,CurrentTime); 10375 else 10376 { 10377 char 10378 *text, 10379 **textlist; 10380 10381 /* 10382 Unknown image format. 10383 */ 10384 text=FileToString(filename,~0,exception); 10385 if (text == (char *) NULL) 10386 return((Image *) NULL); 10387 textlist=StringToList(text); 10388 if (textlist != (char **) NULL) 10389 { 10390 char 10391 title[MaxTextExtent]; 10392 10393 register int 10394 i; 10395 10396 (void) FormatLocaleString(title,MaxTextExtent, 10397 "Unknown format: %s",filename); 10398 XTextViewWidget(display,resource_info,windows,MagickTrue,title, 10399 (const char **) textlist); 10400 for (i=0; textlist[i] != (char *) NULL; i++) 10401 textlist[i]=DestroyString(textlist[i]); 10402 textlist=(char **) RelinquishMagickMemory(textlist); 10403 } 10404 text=DestroyString(text); 10405 } 10406 exception=DestroyExceptionInfo(exception); 10407 image_info=DestroyImageInfo(image_info); 10408 return(nexus); 10409} 10410 10411/* 10412%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10413% % 10414% % 10415% % 10416+ X P a n I m a g e % 10417% % 10418% % 10419% % 10420%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10421% 10422% XPanImage() pans the image until the mouse button is released. 10423% 10424% The format of the XPanImage method is: 10425% 10426% void XPanImage(Display *display,XWindows *windows,XEvent *event, 10427% ExceptionInfo *exception) 10428% 10429% A description of each parameter follows: 10430% 10431% o display: Specifies a connection to an X server; returned from 10432% XOpenDisplay. 10433% 10434% o windows: Specifies a pointer to a XWindows structure. 10435% 10436% o event: Specifies a pointer to a XEvent structure. If it is NULL, 10437% the entire image is refreshed. 10438% 10439% o exception: return any errors or warnings in this structure. 10440% 10441*/ 10442static void XPanImage(Display *display,XWindows *windows,XEvent *event, 10443 ExceptionInfo *exception) 10444{ 10445 char 10446 text[MaxTextExtent]; 10447 10448 Cursor 10449 cursor; 10450 10451 MagickRealType 10452 x_factor, 10453 y_factor; 10454 10455 RectangleInfo 10456 pan_info; 10457 10458 size_t 10459 state; 10460 10461 /* 10462 Define cursor. 10463 */ 10464 if ((windows->image.ximage->width > (int) windows->image.width) && 10465 (windows->image.ximage->height > (int) windows->image.height)) 10466 cursor=XCreateFontCursor(display,XC_fleur); 10467 else 10468 if (windows->image.ximage->width > (int) windows->image.width) 10469 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow); 10470 else 10471 if (windows->image.ximage->height > (int) windows->image.height) 10472 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow); 10473 else 10474 cursor=XCreateFontCursor(display,XC_arrow); 10475 (void) XCheckDefineCursor(display,windows->pan.id,cursor); 10476 /* 10477 Pan image as pointer moves until the mouse button is released. 10478 */ 10479 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width; 10480 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height; 10481 pan_info.width=windows->pan.width*windows->image.width/ 10482 windows->image.ximage->width; 10483 pan_info.height=windows->pan.height*windows->image.height/ 10484 windows->image.ximage->height; 10485 pan_info.x=0; 10486 pan_info.y=0; 10487 state=UpdateConfigurationState; 10488 do 10489 { 10490 switch (event->type) 10491 { 10492 case ButtonPress: 10493 { 10494 /* 10495 User choose an initial pan location. 10496 */ 10497 pan_info.x=(ssize_t) event->xbutton.x; 10498 pan_info.y=(ssize_t) event->xbutton.y; 10499 state|=UpdateConfigurationState; 10500 break; 10501 } 10502 case ButtonRelease: 10503 { 10504 /* 10505 User has finished panning the image. 10506 */ 10507 pan_info.x=(ssize_t) event->xbutton.x; 10508 pan_info.y=(ssize_t) event->xbutton.y; 10509 state|=UpdateConfigurationState | ExitState; 10510 break; 10511 } 10512 case MotionNotify: 10513 { 10514 pan_info.x=(ssize_t) event->xmotion.x; 10515 pan_info.y=(ssize_t) event->xmotion.y; 10516 state|=UpdateConfigurationState; 10517 } 10518 default: 10519 break; 10520 } 10521 if ((state & UpdateConfigurationState) != 0) 10522 { 10523 /* 10524 Check boundary conditions. 10525 */ 10526 if (pan_info.x < (ssize_t) (pan_info.width/2)) 10527 pan_info.x=0; 10528 else 10529 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2))); 10530 if (pan_info.x < 0) 10531 pan_info.x=0; 10532 else 10533 if ((int) (pan_info.x+windows->image.width) > 10534 windows->image.ximage->width) 10535 pan_info.x=(ssize_t) 10536 (windows->image.ximage->width-windows->image.width); 10537 if (pan_info.y < (ssize_t) (pan_info.height/2)) 10538 pan_info.y=0; 10539 else 10540 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2))); 10541 if (pan_info.y < 0) 10542 pan_info.y=0; 10543 else 10544 if ((int) (pan_info.y+windows->image.height) > 10545 windows->image.ximage->height) 10546 pan_info.y=(ssize_t) 10547 (windows->image.ximage->height-windows->image.height); 10548 if ((windows->image.x != (int) pan_info.x) || 10549 (windows->image.y != (int) pan_info.y)) 10550 { 10551 /* 10552 Display image pan offset. 10553 */ 10554 windows->image.x=(int) pan_info.x; 10555 windows->image.y=(int) pan_info.y; 10556 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 10557 windows->image.width,windows->image.height,windows->image.x, 10558 windows->image.y); 10559 XInfoWidget(display,windows,text); 10560 /* 10561 Refresh Image window. 10562 */ 10563 XDrawPanRectangle(display,windows); 10564 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 10565 } 10566 state&=(~UpdateConfigurationState); 10567 } 10568 /* 10569 Wait for next event. 10570 */ 10571 if ((state & ExitState) == 0) 10572 XScreenEvent(display,windows,event,exception); 10573 } while ((state & ExitState) == 0); 10574 /* 10575 Restore cursor. 10576 */ 10577 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor); 10578 (void) XFreeCursor(display,cursor); 10579 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 10580} 10581 10582/* 10583%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10584% % 10585% % 10586% % 10587+ X P a s t e I m a g e % 10588% % 10589% % 10590% % 10591%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10592% 10593% XPasteImage() pastes an image previously saved with XCropImage in the X 10594% window image at a location the user chooses with the pointer. 10595% 10596% The format of the XPasteImage method is: 10597% 10598% MagickBooleanType XPasteImage(Display *display, 10599% XResourceInfo *resource_info,XWindows *windows,Image *image, 10600% ExceptionInfo *exception) 10601% 10602% A description of each parameter follows: 10603% 10604% o display: Specifies a connection to an X server; returned from 10605% XOpenDisplay. 10606% 10607% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10608% 10609% o windows: Specifies a pointer to a XWindows structure. 10610% 10611% o image: the image; returned from ReadImage. 10612% 10613% o exception: return any errors or warnings in this structure. 10614% 10615*/ 10616static MagickBooleanType XPasteImage(Display *display, 10617 XResourceInfo *resource_info,XWindows *windows,Image *image, 10618 ExceptionInfo *exception) 10619{ 10620 static const char 10621 *PasteMenu[] = 10622 { 10623 "Operator", 10624 "Help", 10625 "Dismiss", 10626 (char *) NULL 10627 }; 10628 10629 static const ModeType 10630 PasteCommands[] = 10631 { 10632 PasteOperatorsCommand, 10633 PasteHelpCommand, 10634 PasteDismissCommand 10635 }; 10636 10637 static CompositeOperator 10638 compose = CopyCompositeOp; 10639 10640 char 10641 text[MaxTextExtent]; 10642 10643 Cursor 10644 cursor; 10645 10646 Image 10647 *paste_image; 10648 10649 int 10650 entry, 10651 id, 10652 x, 10653 y; 10654 10655 MagickRealType 10656 scale_factor; 10657 10658 RectangleInfo 10659 highlight_info, 10660 paste_info; 10661 10662 unsigned int 10663 height, 10664 width; 10665 10666 size_t 10667 state; 10668 10669 XEvent 10670 event; 10671 10672 /* 10673 Copy image. 10674 */ 10675 if (resource_info->copy_image == (Image *) NULL) 10676 return(MagickFalse); 10677 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception); 10678 /* 10679 Map Command widget. 10680 */ 10681 (void) CloneString(&windows->command.name,"Paste"); 10682 windows->command.data=1; 10683 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL); 10684 (void) XMapRaised(display,windows->command.id); 10685 XClientMessage(display,windows->image.id,windows->im_protocols, 10686 windows->im_update_widget,CurrentTime); 10687 /* 10688 Track pointer until button 1 is pressed. 10689 */ 10690 XSetCursorState(display,windows,MagickFalse); 10691 XQueryPosition(display,windows->image.id,&x,&y); 10692 (void) XSelectInput(display,windows->image.id, 10693 windows->image.attributes.event_mask | PointerMotionMask); 10694 paste_info.x=(ssize_t) windows->image.x+x; 10695 paste_info.y=(ssize_t) windows->image.y+y; 10696 paste_info.width=0; 10697 paste_info.height=0; 10698 cursor=XCreateFontCursor(display,XC_ul_angle); 10699 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 10700 state=DefaultState; 10701 do 10702 { 10703 if (windows->info.mapped != MagickFalse) 10704 { 10705 /* 10706 Display pointer position. 10707 */ 10708 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 10709 (long) paste_info.x,(long) paste_info.y); 10710 XInfoWidget(display,windows,text); 10711 } 10712 highlight_info=paste_info; 10713 highlight_info.x=paste_info.x-windows->image.x; 10714 highlight_info.y=paste_info.y-windows->image.y; 10715 XHighlightRectangle(display,windows->image.id, 10716 windows->image.highlight_context,&highlight_info); 10717 /* 10718 Wait for next event. 10719 */ 10720 XScreenEvent(display,windows,&event,exception); 10721 XHighlightRectangle(display,windows->image.id, 10722 windows->image.highlight_context,&highlight_info); 10723 if (event.xany.window == windows->command.id) 10724 { 10725 /* 10726 Select a command from the Command widget. 10727 */ 10728 id=XCommandWidget(display,windows,PasteMenu,&event); 10729 if (id < 0) 10730 continue; 10731 switch (PasteCommands[id]) 10732 { 10733 case PasteOperatorsCommand: 10734 { 10735 char 10736 command[MaxTextExtent], 10737 **operators; 10738 10739 /* 10740 Select a command from the pop-up menu. 10741 */ 10742 operators=GetCommandOptions(MagickComposeOptions); 10743 if (operators == (char **) NULL) 10744 break; 10745 entry=XMenuWidget(display,windows,PasteMenu[id], 10746 (const char **) operators,command); 10747 if (entry >= 0) 10748 compose=(CompositeOperator) ParseCommandOption( 10749 MagickComposeOptions,MagickFalse,operators[entry]); 10750 operators=DestroyStringList(operators); 10751 break; 10752 } 10753 case PasteHelpCommand: 10754 { 10755 XTextViewWidget(display,resource_info,windows,MagickFalse, 10756 "Help Viewer - Image Composite",ImagePasteHelp); 10757 break; 10758 } 10759 case PasteDismissCommand: 10760 { 10761 /* 10762 Prematurely exit. 10763 */ 10764 state|=EscapeState; 10765 state|=ExitState; 10766 break; 10767 } 10768 default: 10769 break; 10770 } 10771 continue; 10772 } 10773 switch (event.type) 10774 { 10775 case ButtonPress: 10776 { 10777 if (image->debug != MagickFalse) 10778 (void) LogMagickEvent(X11Event,GetMagickModule(), 10779 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 10780 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10781 if (event.xbutton.button != Button1) 10782 break; 10783 if (event.xbutton.window != windows->image.id) 10784 break; 10785 /* 10786 Paste rectangle is relative to image configuration. 10787 */ 10788 width=(unsigned int) image->columns; 10789 height=(unsigned int) image->rows; 10790 x=0; 10791 y=0; 10792 if (windows->image.crop_geometry != (char *) NULL) 10793 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 10794 &width,&height); 10795 scale_factor=(MagickRealType) windows->image.ximage->width/width; 10796 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5); 10797 scale_factor=(MagickRealType) windows->image.ximage->height/height; 10798 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5); 10799 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10800 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10801 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10802 break; 10803 } 10804 case ButtonRelease: 10805 { 10806 if (image->debug != MagickFalse) 10807 (void) LogMagickEvent(X11Event,GetMagickModule(), 10808 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 10809 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10810 if (event.xbutton.button != Button1) 10811 break; 10812 if (event.xbutton.window != windows->image.id) 10813 break; 10814 if ((paste_info.width != 0) && (paste_info.height != 0)) 10815 { 10816 /* 10817 User has selected the location of the paste image. 10818 */ 10819 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10820 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10821 state|=ExitState; 10822 } 10823 break; 10824 } 10825 case Expose: 10826 break; 10827 case KeyPress: 10828 { 10829 char 10830 command[MaxTextExtent]; 10831 10832 KeySym 10833 key_symbol; 10834 10835 int 10836 length; 10837 10838 if (event.xkey.window != windows->image.id) 10839 break; 10840 /* 10841 Respond to a user key press. 10842 */ 10843 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 10844 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10845 *(command+length)='\0'; 10846 if (image->debug != MagickFalse) 10847 (void) LogMagickEvent(X11Event,GetMagickModule(), 10848 "Key press: 0x%lx (%s)",(long) key_symbol,command); 10849 switch ((int) key_symbol) 10850 { 10851 case XK_Escape: 10852 case XK_F20: 10853 { 10854 /* 10855 Prematurely exit. 10856 */ 10857 paste_image=DestroyImage(paste_image); 10858 state|=EscapeState; 10859 state|=ExitState; 10860 break; 10861 } 10862 case XK_F1: 10863 case XK_Help: 10864 { 10865 (void) XSetFunction(display,windows->image.highlight_context, 10866 GXcopy); 10867 XTextViewWidget(display,resource_info,windows,MagickFalse, 10868 "Help Viewer - Image Composite",ImagePasteHelp); 10869 (void) XSetFunction(display,windows->image.highlight_context, 10870 GXinvert); 10871 break; 10872 } 10873 default: 10874 { 10875 (void) XBell(display,0); 10876 break; 10877 } 10878 } 10879 break; 10880 } 10881 case MotionNotify: 10882 { 10883 /* 10884 Map and unmap Info widget as text cursor crosses its boundaries. 10885 */ 10886 x=event.xmotion.x; 10887 y=event.xmotion.y; 10888 if (windows->info.mapped != MagickFalse) 10889 { 10890 if ((x < (int) (windows->info.x+windows->info.width)) && 10891 (y < (int) (windows->info.y+windows->info.height))) 10892 (void) XWithdrawWindow(display,windows->info.id, 10893 windows->info.screen); 10894 } 10895 else 10896 if ((x > (int) (windows->info.x+windows->info.width)) || 10897 (y > (int) (windows->info.y+windows->info.height))) 10898 (void) XMapWindow(display,windows->info.id); 10899 paste_info.x=(ssize_t) windows->image.x+x; 10900 paste_info.y=(ssize_t) windows->image.y+y; 10901 break; 10902 } 10903 default: 10904 { 10905 if (image->debug != MagickFalse) 10906 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 10907 event.type); 10908 break; 10909 } 10910 } 10911 } while ((state & ExitState) == 0); 10912 (void) XSelectInput(display,windows->image.id, 10913 windows->image.attributes.event_mask); 10914 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 10915 XSetCursorState(display,windows,MagickFalse); 10916 (void) XFreeCursor(display,cursor); 10917 if ((state & EscapeState) != 0) 10918 return(MagickTrue); 10919 /* 10920 Image pasting is relative to image configuration. 10921 */ 10922 XSetCursorState(display,windows,MagickTrue); 10923 XCheckRefreshWindows(display,windows); 10924 width=(unsigned int) image->columns; 10925 height=(unsigned int) image->rows; 10926 x=0; 10927 y=0; 10928 if (windows->image.crop_geometry != (char *) NULL) 10929 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 10930 scale_factor=(MagickRealType) width/windows->image.ximage->width; 10931 paste_info.x+=x; 10932 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5); 10933 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5); 10934 scale_factor=(MagickRealType) height/windows->image.ximage->height; 10935 paste_info.y+=y; 10936 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5); 10937 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5); 10938 /* 10939 Paste image with X Image window. 10940 */ 10941 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y, 10942 exception); 10943 paste_image=DestroyImage(paste_image); 10944 XSetCursorState(display,windows,MagickFalse); 10945 /* 10946 Update image colormap. 10947 */ 10948 XConfigureImageColormap(display,resource_info,windows,image,exception); 10949 (void) XConfigureImage(display,resource_info,windows,image,exception); 10950 return(MagickTrue); 10951} 10952 10953/* 10954%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10955% % 10956% % 10957% % 10958+ X P r i n t I m a g e % 10959% % 10960% % 10961% % 10962%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10963% 10964% XPrintImage() prints an image to a Postscript printer. 10965% 10966% The format of the XPrintImage method is: 10967% 10968% MagickBooleanType XPrintImage(Display *display, 10969% XResourceInfo *resource_info,XWindows *windows,Image *image, 10970% ExceptionInfo *exception) 10971% 10972% A description of each parameter follows: 10973% 10974% o display: Specifies a connection to an X server; returned from 10975% XOpenDisplay. 10976% 10977% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10978% 10979% o windows: Specifies a pointer to a XWindows structure. 10980% 10981% o image: the image. 10982% 10983% o exception: return any errors or warnings in this structure. 10984% 10985*/ 10986static MagickBooleanType XPrintImage(Display *display, 10987 XResourceInfo *resource_info,XWindows *windows,Image *image, 10988 ExceptionInfo *exception) 10989{ 10990 char 10991 filename[MaxTextExtent], 10992 geometry[MaxTextExtent]; 10993 10994 Image 10995 *print_image; 10996 10997 ImageInfo 10998 *image_info; 10999 11000 MagickStatusType 11001 status; 11002 11003 /* 11004 Request Postscript page geometry from user. 11005 */ 11006 image_info=CloneImageInfo(resource_info->image_info); 11007 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter"); 11008 if (image_info->page != (char *) NULL) 11009 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 11010 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 11011 "Select Postscript Page Geometry:",geometry); 11012 if (*geometry == '\0') 11013 return(MagickTrue); 11014 image_info->page=GetPageGeometry(geometry); 11015 /* 11016 Apply image transforms. 11017 */ 11018 XSetCursorState(display,windows,MagickTrue); 11019 XCheckRefreshWindows(display,windows); 11020 print_image=CloneImage(image,0,0,MagickTrue,exception); 11021 if (print_image == (Image *) NULL) 11022 return(MagickFalse); 11023 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 11024 windows->image.ximage->width,windows->image.ximage->height); 11025 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry, 11026 exception); 11027 /* 11028 Print image. 11029 */ 11030 (void) AcquireUniqueFilename(filename); 11031 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s", 11032 filename); 11033 status=WriteImage(image_info,print_image,exception); 11034 (void) RelinquishUniqueFileResource(filename); 11035 print_image=DestroyImage(print_image); 11036 image_info=DestroyImageInfo(image_info); 11037 XSetCursorState(display,windows,MagickFalse); 11038 return(status != 0 ? MagickTrue : MagickFalse); 11039} 11040 11041/* 11042%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11043% % 11044% % 11045% % 11046+ X R O I I m a g e % 11047% % 11048% % 11049% % 11050%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11051% 11052% XROIImage() applies an image processing technique to a region of interest. 11053% 11054% The format of the XROIImage method is: 11055% 11056% MagickBooleanType XROIImage(Display *display, 11057% XResourceInfo *resource_info,XWindows *windows,Image **image, 11058% ExceptionInfo *exception) 11059% 11060% A description of each parameter follows: 11061% 11062% o display: Specifies a connection to an X server; returned from 11063% XOpenDisplay. 11064% 11065% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11066% 11067% o windows: Specifies a pointer to a XWindows structure. 11068% 11069% o image: the image; returned from ReadImage. 11070% 11071% o exception: return any errors or warnings in this structure. 11072% 11073*/ 11074static MagickBooleanType XROIImage(Display *display, 11075 XResourceInfo *resource_info,XWindows *windows,Image **image, 11076 ExceptionInfo *exception) 11077{ 11078#define ApplyMenus 7 11079 11080 static const char 11081 *ROIMenu[] = 11082 { 11083 "Help", 11084 "Dismiss", 11085 (char *) NULL 11086 }, 11087 *ApplyMenu[] = 11088 { 11089 "File", 11090 "Edit", 11091 "Transform", 11092 "Enhance", 11093 "Effects", 11094 "F/X", 11095 "Miscellany", 11096 "Help", 11097 "Dismiss", 11098 (char *) NULL 11099 }, 11100 *FileMenu[] = 11101 { 11102 "Save...", 11103 "Print...", 11104 (char *) NULL 11105 }, 11106 *EditMenu[] = 11107 { 11108 "Undo", 11109 "Redo", 11110 (char *) NULL 11111 }, 11112 *TransformMenu[] = 11113 { 11114 "Flop", 11115 "Flip", 11116 "Rotate Right", 11117 "Rotate Left", 11118 (char *) NULL 11119 }, 11120 *EnhanceMenu[] = 11121 { 11122 "Hue...", 11123 "Saturation...", 11124 "Brightness...", 11125 "Gamma...", 11126 "Spiff", 11127 "Dull", 11128 "Contrast Stretch...", 11129 "Sigmoidal Contrast...", 11130 "Normalize", 11131 "Equalize", 11132 "Negate", 11133 "Grayscale", 11134 "Map...", 11135 "Quantize...", 11136 (char *) NULL 11137 }, 11138 *EffectsMenu[] = 11139 { 11140 "Despeckle", 11141 "Emboss", 11142 "Reduce Noise", 11143 "Add Noise", 11144 "Sharpen...", 11145 "Blur...", 11146 "Threshold...", 11147 "Edge Detect...", 11148 "Spread...", 11149 "Shade...", 11150 "Raise...", 11151 "Segment...", 11152 (char *) NULL 11153 }, 11154 *FXMenu[] = 11155 { 11156 "Solarize...", 11157 "Sepia Tone...", 11158 "Swirl...", 11159 "Implode...", 11160 "Vignette...", 11161 "Wave...", 11162 "Oil Paint...", 11163 "Charcoal Draw...", 11164 (char *) NULL 11165 }, 11166 *MiscellanyMenu[] = 11167 { 11168 "Image Info", 11169 "Zoom Image", 11170 "Show Preview...", 11171 "Show Histogram", 11172 "Show Matte", 11173 (char *) NULL 11174 }; 11175 11176 static const char 11177 **Menus[ApplyMenus] = 11178 { 11179 FileMenu, 11180 EditMenu, 11181 TransformMenu, 11182 EnhanceMenu, 11183 EffectsMenu, 11184 FXMenu, 11185 MiscellanyMenu 11186 }; 11187 11188 static const CommandType 11189 ApplyCommands[] = 11190 { 11191 NullCommand, 11192 NullCommand, 11193 NullCommand, 11194 NullCommand, 11195 NullCommand, 11196 NullCommand, 11197 NullCommand, 11198 HelpCommand, 11199 QuitCommand 11200 }, 11201 FileCommands[] = 11202 { 11203 SaveCommand, 11204 PrintCommand 11205 }, 11206 EditCommands[] = 11207 { 11208 UndoCommand, 11209 RedoCommand 11210 }, 11211 TransformCommands[] = 11212 { 11213 FlopCommand, 11214 FlipCommand, 11215 RotateRightCommand, 11216 RotateLeftCommand 11217 }, 11218 EnhanceCommands[] = 11219 { 11220 HueCommand, 11221 SaturationCommand, 11222 BrightnessCommand, 11223 GammaCommand, 11224 SpiffCommand, 11225 DullCommand, 11226 ContrastStretchCommand, 11227 SigmoidalContrastCommand, 11228 NormalizeCommand, 11229 EqualizeCommand, 11230 NegateCommand, 11231 GrayscaleCommand, 11232 MapCommand, 11233 QuantizeCommand 11234 }, 11235 EffectsCommands[] = 11236 { 11237 DespeckleCommand, 11238 EmbossCommand, 11239 ReduceNoiseCommand, 11240 AddNoiseCommand, 11241 SharpenCommand, 11242 BlurCommand, 11243 EdgeDetectCommand, 11244 SpreadCommand, 11245 ShadeCommand, 11246 RaiseCommand, 11247 SegmentCommand 11248 }, 11249 FXCommands[] = 11250 { 11251 SolarizeCommand, 11252 SepiaToneCommand, 11253 SwirlCommand, 11254 ImplodeCommand, 11255 VignetteCommand, 11256 WaveCommand, 11257 OilPaintCommand, 11258 CharcoalDrawCommand 11259 }, 11260 MiscellanyCommands[] = 11261 { 11262 InfoCommand, 11263 ZoomCommand, 11264 ShowPreviewCommand, 11265 ShowHistogramCommand, 11266 ShowMatteCommand 11267 }, 11268 ROICommands[] = 11269 { 11270 ROIHelpCommand, 11271 ROIDismissCommand 11272 }; 11273 11274 static const CommandType 11275 *Commands[ApplyMenus] = 11276 { 11277 FileCommands, 11278 EditCommands, 11279 TransformCommands, 11280 EnhanceCommands, 11281 EffectsCommands, 11282 FXCommands, 11283 MiscellanyCommands 11284 }; 11285 11286 char 11287 command[MaxTextExtent], 11288 text[MaxTextExtent]; 11289 11290 CommandType 11291 command_type; 11292 11293 Cursor 11294 cursor; 11295 11296 Image 11297 *roi_image; 11298 11299 int 11300 entry, 11301 id, 11302 x, 11303 y; 11304 11305 MagickRealType 11306 scale_factor; 11307 11308 MagickProgressMonitor 11309 progress_monitor; 11310 11311 RectangleInfo 11312 crop_info, 11313 highlight_info, 11314 roi_info; 11315 11316 unsigned int 11317 height, 11318 width; 11319 11320 size_t 11321 state; 11322 11323 XEvent 11324 event; 11325 11326 /* 11327 Map Command widget. 11328 */ 11329 (void) CloneString(&windows->command.name,"ROI"); 11330 windows->command.data=0; 11331 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL); 11332 (void) XMapRaised(display,windows->command.id); 11333 XClientMessage(display,windows->image.id,windows->im_protocols, 11334 windows->im_update_widget,CurrentTime); 11335 /* 11336 Track pointer until button 1 is pressed. 11337 */ 11338 XQueryPosition(display,windows->image.id,&x,&y); 11339 (void) XSelectInput(display,windows->image.id, 11340 windows->image.attributes.event_mask | PointerMotionMask); 11341 roi_info.x=(ssize_t) windows->image.x+x; 11342 roi_info.y=(ssize_t) windows->image.y+y; 11343 roi_info.width=0; 11344 roi_info.height=0; 11345 cursor=XCreateFontCursor(display,XC_fleur); 11346 state=DefaultState; 11347 do 11348 { 11349 if (windows->info.mapped != MagickFalse) 11350 { 11351 /* 11352 Display pointer position. 11353 */ 11354 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 11355 (long) roi_info.x,(long) roi_info.y); 11356 XInfoWidget(display,windows,text); 11357 } 11358 /* 11359 Wait for next event. 11360 */ 11361 XScreenEvent(display,windows,&event,exception); 11362 if (event.xany.window == windows->command.id) 11363 { 11364 /* 11365 Select a command from the Command widget. 11366 */ 11367 id=XCommandWidget(display,windows,ROIMenu,&event); 11368 if (id < 0) 11369 continue; 11370 switch (ROICommands[id]) 11371 { 11372 case ROIHelpCommand: 11373 { 11374 XTextViewWidget(display,resource_info,windows,MagickFalse, 11375 "Help Viewer - Region of Interest",ImageROIHelp); 11376 break; 11377 } 11378 case ROIDismissCommand: 11379 { 11380 /* 11381 Prematurely exit. 11382 */ 11383 state|=EscapeState; 11384 state|=ExitState; 11385 break; 11386 } 11387 default: 11388 break; 11389 } 11390 continue; 11391 } 11392 switch (event.type) 11393 { 11394 case ButtonPress: 11395 { 11396 if (event.xbutton.button != Button1) 11397 break; 11398 if (event.xbutton.window != windows->image.id) 11399 break; 11400 /* 11401 Note first corner of region of interest rectangle-- exit loop. 11402 */ 11403 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11404 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11405 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11406 state|=ExitState; 11407 break; 11408 } 11409 case ButtonRelease: 11410 break; 11411 case Expose: 11412 break; 11413 case KeyPress: 11414 { 11415 KeySym 11416 key_symbol; 11417 11418 if (event.xkey.window != windows->image.id) 11419 break; 11420 /* 11421 Respond to a user key press. 11422 */ 11423 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11424 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11425 switch ((int) key_symbol) 11426 { 11427 case XK_Escape: 11428 case XK_F20: 11429 { 11430 /* 11431 Prematurely exit. 11432 */ 11433 state|=EscapeState; 11434 state|=ExitState; 11435 break; 11436 } 11437 case XK_F1: 11438 case XK_Help: 11439 { 11440 XTextViewWidget(display,resource_info,windows,MagickFalse, 11441 "Help Viewer - Region of Interest",ImageROIHelp); 11442 break; 11443 } 11444 default: 11445 { 11446 (void) XBell(display,0); 11447 break; 11448 } 11449 } 11450 break; 11451 } 11452 case MotionNotify: 11453 { 11454 /* 11455 Map and unmap Info widget as text cursor crosses its boundaries. 11456 */ 11457 x=event.xmotion.x; 11458 y=event.xmotion.y; 11459 if (windows->info.mapped != MagickFalse) 11460 { 11461 if ((x < (int) (windows->info.x+windows->info.width)) && 11462 (y < (int) (windows->info.y+windows->info.height))) 11463 (void) XWithdrawWindow(display,windows->info.id, 11464 windows->info.screen); 11465 } 11466 else 11467 if ((x > (int) (windows->info.x+windows->info.width)) || 11468 (y > (int) (windows->info.y+windows->info.height))) 11469 (void) XMapWindow(display,windows->info.id); 11470 roi_info.x=(ssize_t) windows->image.x+x; 11471 roi_info.y=(ssize_t) windows->image.y+y; 11472 break; 11473 } 11474 default: 11475 break; 11476 } 11477 } while ((state & ExitState) == 0); 11478 (void) XSelectInput(display,windows->image.id, 11479 windows->image.attributes.event_mask); 11480 if ((state & EscapeState) != 0) 11481 { 11482 /* 11483 User want to exit without region of interest. 11484 */ 11485 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11486 (void) XFreeCursor(display,cursor); 11487 return(MagickTrue); 11488 } 11489 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11490 do 11491 { 11492 /* 11493 Size rectangle as pointer moves until the mouse button is released. 11494 */ 11495 x=(int) roi_info.x; 11496 y=(int) roi_info.y; 11497 roi_info.width=0; 11498 roi_info.height=0; 11499 state=DefaultState; 11500 do 11501 { 11502 highlight_info=roi_info; 11503 highlight_info.x=roi_info.x-windows->image.x; 11504 highlight_info.y=roi_info.y-windows->image.y; 11505 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11506 { 11507 /* 11508 Display info and draw region of interest rectangle. 11509 */ 11510 if (windows->info.mapped == MagickFalse) 11511 (void) XMapWindow(display,windows->info.id); 11512 (void) FormatLocaleString(text,MaxTextExtent, 11513 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11514 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11515 XInfoWidget(display,windows,text); 11516 XHighlightRectangle(display,windows->image.id, 11517 windows->image.highlight_context,&highlight_info); 11518 } 11519 else 11520 if (windows->info.mapped != MagickFalse) 11521 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11522 /* 11523 Wait for next event. 11524 */ 11525 XScreenEvent(display,windows,&event,exception); 11526 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11527 XHighlightRectangle(display,windows->image.id, 11528 windows->image.highlight_context,&highlight_info); 11529 switch (event.type) 11530 { 11531 case ButtonPress: 11532 { 11533 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11534 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11535 break; 11536 } 11537 case ButtonRelease: 11538 { 11539 /* 11540 User has committed to region of interest rectangle. 11541 */ 11542 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11543 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11544 XSetCursorState(display,windows,MagickFalse); 11545 state|=ExitState; 11546 if (LocaleCompare(windows->command.name,"Apply") == 0) 11547 break; 11548 (void) CloneString(&windows->command.name,"Apply"); 11549 windows->command.data=ApplyMenus; 11550 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL); 11551 break; 11552 } 11553 case Expose: 11554 break; 11555 case MotionNotify: 11556 { 11557 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11558 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11559 } 11560 default: 11561 break; 11562 } 11563 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) || 11564 ((state & ExitState) != 0)) 11565 { 11566 /* 11567 Check boundary conditions. 11568 */ 11569 if (roi_info.x < 0) 11570 roi_info.x=0; 11571 else 11572 if (roi_info.x > (ssize_t) windows->image.ximage->width) 11573 roi_info.x=(ssize_t) windows->image.ximage->width; 11574 if ((int) roi_info.x < x) 11575 roi_info.width=(unsigned int) (x-roi_info.x); 11576 else 11577 { 11578 roi_info.width=(unsigned int) (roi_info.x-x); 11579 roi_info.x=(ssize_t) x; 11580 } 11581 if (roi_info.y < 0) 11582 roi_info.y=0; 11583 else 11584 if (roi_info.y > (ssize_t) windows->image.ximage->height) 11585 roi_info.y=(ssize_t) windows->image.ximage->height; 11586 if ((int) roi_info.y < y) 11587 roi_info.height=(unsigned int) (y-roi_info.y); 11588 else 11589 { 11590 roi_info.height=(unsigned int) (roi_info.y-y); 11591 roi_info.y=(ssize_t) y; 11592 } 11593 } 11594 } while ((state & ExitState) == 0); 11595 /* 11596 Wait for user to grab a corner of the rectangle or press return. 11597 */ 11598 state=DefaultState; 11599 command_type=NullCommand; 11600 (void) XMapWindow(display,windows->info.id); 11601 do 11602 { 11603 if (windows->info.mapped != MagickFalse) 11604 { 11605 /* 11606 Display pointer position. 11607 */ 11608 (void) FormatLocaleString(text,MaxTextExtent, 11609 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11610 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11611 XInfoWidget(display,windows,text); 11612 } 11613 highlight_info=roi_info; 11614 highlight_info.x=roi_info.x-windows->image.x; 11615 highlight_info.y=roi_info.y-windows->image.y; 11616 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11617 { 11618 state|=EscapeState; 11619 state|=ExitState; 11620 break; 11621 } 11622 if ((state & UpdateRegionState) != 0) 11623 { 11624 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11625 switch (command_type) 11626 { 11627 case UndoCommand: 11628 case RedoCommand: 11629 { 11630 (void) XMagickCommand(display,resource_info,windows,command_type, 11631 image,exception); 11632 break; 11633 } 11634 default: 11635 { 11636 /* 11637 Region of interest is relative to image configuration. 11638 */ 11639 progress_monitor=SetImageProgressMonitor(*image, 11640 (MagickProgressMonitor) NULL,(*image)->client_data); 11641 crop_info=roi_info; 11642 width=(unsigned int) (*image)->columns; 11643 height=(unsigned int) (*image)->rows; 11644 x=0; 11645 y=0; 11646 if (windows->image.crop_geometry != (char *) NULL) 11647 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11648 &width,&height); 11649 scale_factor=(MagickRealType) width/windows->image.ximage->width; 11650 crop_info.x+=x; 11651 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11652 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11653 scale_factor=(MagickRealType) 11654 height/windows->image.ximage->height; 11655 crop_info.y+=y; 11656 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11657 crop_info.height=(unsigned int) 11658 (scale_factor*crop_info.height+0.5); 11659 roi_image=CropImage(*image,&crop_info,exception); 11660 (void) SetImageProgressMonitor(*image,progress_monitor, 11661 (*image)->client_data); 11662 if (roi_image == (Image *) NULL) 11663 continue; 11664 /* 11665 Apply image processing technique to the region of interest. 11666 */ 11667 windows->image.orphan=MagickTrue; 11668 (void) XMagickCommand(display,resource_info,windows,command_type, 11669 &roi_image,exception); 11670 progress_monitor=SetImageProgressMonitor(*image, 11671 (MagickProgressMonitor) NULL,(*image)->client_data); 11672 (void) XMagickCommand(display,resource_info,windows, 11673 SaveToUndoBufferCommand,image,exception); 11674 windows->image.orphan=MagickFalse; 11675 (void) CompositeImage(*image,CopyCompositeOp,roi_image, 11676 crop_info.x,crop_info.y,exception); 11677 roi_image=DestroyImage(roi_image); 11678 (void) SetImageProgressMonitor(*image,progress_monitor, 11679 (*image)->client_data); 11680 break; 11681 } 11682 } 11683 if (command_type != InfoCommand) 11684 { 11685 XConfigureImageColormap(display,resource_info,windows,*image, 11686 exception); 11687 (void) XConfigureImage(display,resource_info,windows,*image, 11688 exception); 11689 } 11690 XCheckRefreshWindows(display,windows); 11691 XInfoWidget(display,windows,text); 11692 (void) XSetFunction(display,windows->image.highlight_context, 11693 GXinvert); 11694 state&=(~UpdateRegionState); 11695 } 11696 XHighlightRectangle(display,windows->image.id, 11697 windows->image.highlight_context,&highlight_info); 11698 XScreenEvent(display,windows,&event,exception); 11699 if (event.xany.window == windows->command.id) 11700 { 11701 /* 11702 Select a command from the Command widget. 11703 */ 11704 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11705 command_type=NullCommand; 11706 id=XCommandWidget(display,windows,ApplyMenu,&event); 11707 if (id >= 0) 11708 { 11709 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent); 11710 command_type=ApplyCommands[id]; 11711 if (id < ApplyMenus) 11712 { 11713 /* 11714 Select a command from a pop-up menu. 11715 */ 11716 entry=XMenuWidget(display,windows,ApplyMenu[id], 11717 (const char **) Menus[id],command); 11718 if (entry >= 0) 11719 { 11720 (void) CopyMagickString(command,Menus[id][entry], 11721 MaxTextExtent); 11722 command_type=Commands[id][entry]; 11723 } 11724 } 11725 } 11726 (void) XSetFunction(display,windows->image.highlight_context, 11727 GXinvert); 11728 XHighlightRectangle(display,windows->image.id, 11729 windows->image.highlight_context,&highlight_info); 11730 if (command_type == HelpCommand) 11731 { 11732 (void) XSetFunction(display,windows->image.highlight_context, 11733 GXcopy); 11734 XTextViewWidget(display,resource_info,windows,MagickFalse, 11735 "Help Viewer - Region of Interest",ImageROIHelp); 11736 (void) XSetFunction(display,windows->image.highlight_context, 11737 GXinvert); 11738 continue; 11739 } 11740 if (command_type == QuitCommand) 11741 { 11742 /* 11743 exit. 11744 */ 11745 state|=EscapeState; 11746 state|=ExitState; 11747 continue; 11748 } 11749 if (command_type != NullCommand) 11750 state|=UpdateRegionState; 11751 continue; 11752 } 11753 XHighlightRectangle(display,windows->image.id, 11754 windows->image.highlight_context,&highlight_info); 11755 switch (event.type) 11756 { 11757 case ButtonPress: 11758 { 11759 x=windows->image.x; 11760 y=windows->image.y; 11761 if (event.xbutton.button != Button1) 11762 break; 11763 if (event.xbutton.window != windows->image.id) 11764 break; 11765 x=windows->image.x+event.xbutton.x; 11766 y=windows->image.y+event.xbutton.y; 11767 if ((x < (int) (roi_info.x+RoiDelta)) && 11768 (x > (int) (roi_info.x-RoiDelta)) && 11769 (y < (int) (roi_info.y+RoiDelta)) && 11770 (y > (int) (roi_info.y-RoiDelta))) 11771 { 11772 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11773 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11774 state|=UpdateConfigurationState; 11775 break; 11776 } 11777 if ((x < (int) (roi_info.x+RoiDelta)) && 11778 (x > (int) (roi_info.x-RoiDelta)) && 11779 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11780 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11781 { 11782 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11783 state|=UpdateConfigurationState; 11784 break; 11785 } 11786 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11787 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11788 (y < (int) (roi_info.y+RoiDelta)) && 11789 (y > (int) (roi_info.y-RoiDelta))) 11790 { 11791 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11792 state|=UpdateConfigurationState; 11793 break; 11794 } 11795 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11796 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11797 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11798 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11799 { 11800 state|=UpdateConfigurationState; 11801 break; 11802 } 11803 } 11804 case ButtonRelease: 11805 { 11806 if (event.xbutton.window == windows->pan.id) 11807 if ((highlight_info.x != crop_info.x-windows->image.x) || 11808 (highlight_info.y != crop_info.y-windows->image.y)) 11809 XHighlightRectangle(display,windows->image.id, 11810 windows->image.highlight_context,&highlight_info); 11811 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11812 event.xbutton.time); 11813 break; 11814 } 11815 case Expose: 11816 { 11817 if (event.xexpose.window == windows->image.id) 11818 if (event.xexpose.count == 0) 11819 { 11820 event.xexpose.x=(int) highlight_info.x; 11821 event.xexpose.y=(int) highlight_info.y; 11822 event.xexpose.width=(int) highlight_info.width; 11823 event.xexpose.height=(int) highlight_info.height; 11824 XRefreshWindow(display,&windows->image,&event); 11825 } 11826 if (event.xexpose.window == windows->info.id) 11827 if (event.xexpose.count == 0) 11828 XInfoWidget(display,windows,text); 11829 break; 11830 } 11831 case KeyPress: 11832 { 11833 KeySym 11834 key_symbol; 11835 11836 if (event.xkey.window != windows->image.id) 11837 break; 11838 /* 11839 Respond to a user key press. 11840 */ 11841 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11842 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11843 switch ((int) key_symbol) 11844 { 11845 case XK_Shift_L: 11846 case XK_Shift_R: 11847 break; 11848 case XK_Escape: 11849 case XK_F20: 11850 state|=EscapeState; 11851 case XK_Return: 11852 { 11853 state|=ExitState; 11854 break; 11855 } 11856 case XK_Home: 11857 case XK_KP_Home: 11858 { 11859 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11860 roi_info.y=(ssize_t) (windows->image.height/2L- 11861 roi_info.height/2L); 11862 break; 11863 } 11864 case XK_Left: 11865 case XK_KP_Left: 11866 { 11867 roi_info.x--; 11868 break; 11869 } 11870 case XK_Up: 11871 case XK_KP_Up: 11872 case XK_Next: 11873 { 11874 roi_info.y--; 11875 break; 11876 } 11877 case XK_Right: 11878 case XK_KP_Right: 11879 { 11880 roi_info.x++; 11881 break; 11882 } 11883 case XK_Prior: 11884 case XK_Down: 11885 case XK_KP_Down: 11886 { 11887 roi_info.y++; 11888 break; 11889 } 11890 case XK_F1: 11891 case XK_Help: 11892 { 11893 (void) XSetFunction(display,windows->image.highlight_context, 11894 GXcopy); 11895 XTextViewWidget(display,resource_info,windows,MagickFalse, 11896 "Help Viewer - Region of Interest",ImageROIHelp); 11897 (void) XSetFunction(display,windows->image.highlight_context, 11898 GXinvert); 11899 break; 11900 } 11901 default: 11902 { 11903 command_type=XImageWindowCommand(display,resource_info,windows, 11904 event.xkey.state,key_symbol,image,exception); 11905 if (command_type != NullCommand) 11906 state|=UpdateRegionState; 11907 break; 11908 } 11909 } 11910 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11911 event.xkey.time); 11912 break; 11913 } 11914 case KeyRelease: 11915 break; 11916 case MotionNotify: 11917 { 11918 if (event.xbutton.window != windows->image.id) 11919 break; 11920 /* 11921 Map and unmap Info widget as text cursor crosses its boundaries. 11922 */ 11923 x=event.xmotion.x; 11924 y=event.xmotion.y; 11925 if (windows->info.mapped != MagickFalse) 11926 { 11927 if ((x < (int) (windows->info.x+windows->info.width)) && 11928 (y < (int) (windows->info.y+windows->info.height))) 11929 (void) XWithdrawWindow(display,windows->info.id, 11930 windows->info.screen); 11931 } 11932 else 11933 if ((x > (int) (windows->info.x+windows->info.width)) || 11934 (y > (int) (windows->info.y+windows->info.height))) 11935 (void) XMapWindow(display,windows->info.id); 11936 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11937 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11938 break; 11939 } 11940 case SelectionRequest: 11941 { 11942 XSelectionEvent 11943 notify; 11944 11945 XSelectionRequestEvent 11946 *request; 11947 11948 /* 11949 Set primary selection. 11950 */ 11951 (void) FormatLocaleString(text,MaxTextExtent, 11952 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11953 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11954 request=(&(event.xselectionrequest)); 11955 (void) XChangeProperty(request->display,request->requestor, 11956 request->property,request->target,8,PropModeReplace, 11957 (unsigned char *) text,(int) strlen(text)); 11958 notify.type=SelectionNotify; 11959 notify.display=request->display; 11960 notify.requestor=request->requestor; 11961 notify.selection=request->selection; 11962 notify.target=request->target; 11963 notify.time=request->time; 11964 if (request->property == None) 11965 notify.property=request->target; 11966 else 11967 notify.property=request->property; 11968 (void) XSendEvent(request->display,request->requestor,False,0, 11969 (XEvent *) ¬ify); 11970 } 11971 default: 11972 break; 11973 } 11974 if ((state & UpdateConfigurationState) != 0) 11975 { 11976 (void) XPutBackEvent(display,&event); 11977 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11978 break; 11979 } 11980 } while ((state & ExitState) == 0); 11981 } while ((state & ExitState) == 0); 11982 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11983 XSetCursorState(display,windows,MagickFalse); 11984 if ((state & EscapeState) != 0) 11985 return(MagickTrue); 11986 return(MagickTrue); 11987} 11988 11989/* 11990%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11991% % 11992% % 11993% % 11994+ X R o t a t e I m a g e % 11995% % 11996% % 11997% % 11998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11999% 12000% XRotateImage() rotates the X image. If the degrees parameter if zero, the 12001% rotation angle is computed from the slope of a line drawn by the user. 12002% 12003% The format of the XRotateImage method is: 12004% 12005% MagickBooleanType XRotateImage(Display *display, 12006% XResourceInfo *resource_info,XWindows *windows,double degrees, 12007% Image **image,ExceptionInfo *exception) 12008% 12009% A description of each parameter follows: 12010% 12011% o display: Specifies a connection to an X server; returned from 12012% XOpenDisplay. 12013% 12014% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12015% 12016% o windows: Specifies a pointer to a XWindows structure. 12017% 12018% o degrees: Specifies the number of degrees to rotate the image. 12019% 12020% o image: the image. 12021% 12022% o exception: return any errors or warnings in this structure. 12023% 12024*/ 12025static MagickBooleanType XRotateImage(Display *display, 12026 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image, 12027 ExceptionInfo *exception) 12028{ 12029 static const char 12030 *RotateMenu[] = 12031 { 12032 "Pixel Color", 12033 "Direction", 12034 "Help", 12035 "Dismiss", 12036 (char *) NULL 12037 }; 12038 12039 static ModeType 12040 direction = HorizontalRotateCommand; 12041 12042 static const ModeType 12043 DirectionCommands[] = 12044 { 12045 HorizontalRotateCommand, 12046 VerticalRotateCommand 12047 }, 12048 RotateCommands[] = 12049 { 12050 RotateColorCommand, 12051 RotateDirectionCommand, 12052 RotateHelpCommand, 12053 RotateDismissCommand 12054 }; 12055 12056 static unsigned int 12057 pen_id = 0; 12058 12059 char 12060 command[MaxTextExtent], 12061 text[MaxTextExtent]; 12062 12063 Image 12064 *rotate_image; 12065 12066 int 12067 id, 12068 x, 12069 y; 12070 12071 MagickRealType 12072 normalized_degrees; 12073 12074 register int 12075 i; 12076 12077 unsigned int 12078 height, 12079 rotations, 12080 width; 12081 12082 if (degrees == 0.0) 12083 { 12084 unsigned int 12085 distance; 12086 12087 size_t 12088 state; 12089 12090 XEvent 12091 event; 12092 12093 XSegment 12094 rotate_info; 12095 12096 /* 12097 Map Command widget. 12098 */ 12099 (void) CloneString(&windows->command.name,"Rotate"); 12100 windows->command.data=2; 12101 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 12102 (void) XMapRaised(display,windows->command.id); 12103 XClientMessage(display,windows->image.id,windows->im_protocols, 12104 windows->im_update_widget,CurrentTime); 12105 /* 12106 Wait for first button press. 12107 */ 12108 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12109 XQueryPosition(display,windows->image.id,&x,&y); 12110 rotate_info.x1=x; 12111 rotate_info.y1=y; 12112 rotate_info.x2=x; 12113 rotate_info.y2=y; 12114 state=DefaultState; 12115 do 12116 { 12117 XHighlightLine(display,windows->image.id, 12118 windows->image.highlight_context,&rotate_info); 12119 /* 12120 Wait for next event. 12121 */ 12122 XScreenEvent(display,windows,&event,exception); 12123 XHighlightLine(display,windows->image.id, 12124 windows->image.highlight_context,&rotate_info); 12125 if (event.xany.window == windows->command.id) 12126 { 12127 /* 12128 Select a command from the Command widget. 12129 */ 12130 id=XCommandWidget(display,windows,RotateMenu,&event); 12131 if (id < 0) 12132 continue; 12133 (void) XSetFunction(display,windows->image.highlight_context, 12134 GXcopy); 12135 switch (RotateCommands[id]) 12136 { 12137 case RotateColorCommand: 12138 { 12139 const char 12140 *ColorMenu[MaxNumberPens]; 12141 12142 int 12143 pen_number; 12144 12145 XColor 12146 color; 12147 12148 /* 12149 Initialize menu selections. 12150 */ 12151 for (i=0; i < (int) (MaxNumberPens-2); i++) 12152 ColorMenu[i]=resource_info->pen_colors[i]; 12153 ColorMenu[MaxNumberPens-2]="Browser..."; 12154 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12155 /* 12156 Select a pen color from the pop-up menu. 12157 */ 12158 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12159 (const char **) ColorMenu,command); 12160 if (pen_number < 0) 12161 break; 12162 if (pen_number == (MaxNumberPens-2)) 12163 { 12164 static char 12165 color_name[MaxTextExtent] = "gray"; 12166 12167 /* 12168 Select a pen color from a dialog. 12169 */ 12170 resource_info->pen_colors[pen_number]=color_name; 12171 XColorBrowserWidget(display,windows,"Select",color_name); 12172 if (*color_name == '\0') 12173 break; 12174 } 12175 /* 12176 Set pen color. 12177 */ 12178 (void) XParseColor(display,windows->map_info->colormap, 12179 resource_info->pen_colors[pen_number],&color); 12180 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12181 (unsigned int) MaxColors,&color); 12182 windows->pixel_info->pen_colors[pen_number]=color; 12183 pen_id=(unsigned int) pen_number; 12184 break; 12185 } 12186 case RotateDirectionCommand: 12187 { 12188 static const char 12189 *Directions[] = 12190 { 12191 "horizontal", 12192 "vertical", 12193 (char *) NULL, 12194 }; 12195 12196 /* 12197 Select a command from the pop-up menu. 12198 */ 12199 id=XMenuWidget(display,windows,RotateMenu[id], 12200 Directions,command); 12201 if (id >= 0) 12202 direction=DirectionCommands[id]; 12203 break; 12204 } 12205 case RotateHelpCommand: 12206 { 12207 XTextViewWidget(display,resource_info,windows,MagickFalse, 12208 "Help Viewer - Image Rotation",ImageRotateHelp); 12209 break; 12210 } 12211 case RotateDismissCommand: 12212 { 12213 /* 12214 Prematurely exit. 12215 */ 12216 state|=EscapeState; 12217 state|=ExitState; 12218 break; 12219 } 12220 default: 12221 break; 12222 } 12223 (void) XSetFunction(display,windows->image.highlight_context, 12224 GXinvert); 12225 continue; 12226 } 12227 switch (event.type) 12228 { 12229 case ButtonPress: 12230 { 12231 if (event.xbutton.button != Button1) 12232 break; 12233 if (event.xbutton.window != windows->image.id) 12234 break; 12235 /* 12236 exit loop. 12237 */ 12238 (void) XSetFunction(display,windows->image.highlight_context, 12239 GXcopy); 12240 rotate_info.x1=event.xbutton.x; 12241 rotate_info.y1=event.xbutton.y; 12242 state|=ExitState; 12243 break; 12244 } 12245 case ButtonRelease: 12246 break; 12247 case Expose: 12248 break; 12249 case KeyPress: 12250 { 12251 char 12252 command[MaxTextExtent]; 12253 12254 KeySym 12255 key_symbol; 12256 12257 if (event.xkey.window != windows->image.id) 12258 break; 12259 /* 12260 Respond to a user key press. 12261 */ 12262 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12263 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12264 switch ((int) key_symbol) 12265 { 12266 case XK_Escape: 12267 case XK_F20: 12268 { 12269 /* 12270 Prematurely exit. 12271 */ 12272 state|=EscapeState; 12273 state|=ExitState; 12274 break; 12275 } 12276 case XK_F1: 12277 case XK_Help: 12278 { 12279 (void) XSetFunction(display,windows->image.highlight_context, 12280 GXcopy); 12281 XTextViewWidget(display,resource_info,windows,MagickFalse, 12282 "Help Viewer - Image Rotation",ImageRotateHelp); 12283 (void) XSetFunction(display,windows->image.highlight_context, 12284 GXinvert); 12285 break; 12286 } 12287 default: 12288 { 12289 (void) XBell(display,0); 12290 break; 12291 } 12292 } 12293 break; 12294 } 12295 case MotionNotify: 12296 { 12297 rotate_info.x1=event.xmotion.x; 12298 rotate_info.y1=event.xmotion.y; 12299 } 12300 } 12301 rotate_info.x2=rotate_info.x1; 12302 rotate_info.y2=rotate_info.y1; 12303 if (direction == HorizontalRotateCommand) 12304 rotate_info.x2+=32; 12305 else 12306 rotate_info.y2-=32; 12307 } while ((state & ExitState) == 0); 12308 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12309 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12310 if ((state & EscapeState) != 0) 12311 return(MagickTrue); 12312 /* 12313 Draw line as pointer moves until the mouse button is released. 12314 */ 12315 distance=0; 12316 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12317 state=DefaultState; 12318 do 12319 { 12320 if (distance > 9) 12321 { 12322 /* 12323 Display info and draw rotation line. 12324 */ 12325 if (windows->info.mapped == MagickFalse) 12326 (void) XMapWindow(display,windows->info.id); 12327 (void) FormatLocaleString(text,MaxTextExtent," %g", 12328 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12329 XInfoWidget(display,windows,text); 12330 XHighlightLine(display,windows->image.id, 12331 windows->image.highlight_context,&rotate_info); 12332 } 12333 else 12334 if (windows->info.mapped != MagickFalse) 12335 (void) XWithdrawWindow(display,windows->info.id, 12336 windows->info.screen); 12337 /* 12338 Wait for next event. 12339 */ 12340 XScreenEvent(display,windows,&event,exception); 12341 if (distance > 9) 12342 XHighlightLine(display,windows->image.id, 12343 windows->image.highlight_context,&rotate_info); 12344 switch (event.type) 12345 { 12346 case ButtonPress: 12347 break; 12348 case ButtonRelease: 12349 { 12350 /* 12351 User has committed to rotation line. 12352 */ 12353 rotate_info.x2=event.xbutton.x; 12354 rotate_info.y2=event.xbutton.y; 12355 state|=ExitState; 12356 break; 12357 } 12358 case Expose: 12359 break; 12360 case MotionNotify: 12361 { 12362 rotate_info.x2=event.xmotion.x; 12363 rotate_info.y2=event.xmotion.y; 12364 } 12365 default: 12366 break; 12367 } 12368 /* 12369 Check boundary conditions. 12370 */ 12371 if (rotate_info.x2 < 0) 12372 rotate_info.x2=0; 12373 else 12374 if (rotate_info.x2 > (int) windows->image.width) 12375 rotate_info.x2=(short) windows->image.width; 12376 if (rotate_info.y2 < 0) 12377 rotate_info.y2=0; 12378 else 12379 if (rotate_info.y2 > (int) windows->image.height) 12380 rotate_info.y2=(short) windows->image.height; 12381 /* 12382 Compute rotation angle from the slope of the line. 12383 */ 12384 degrees=0.0; 12385 distance=(unsigned int) 12386 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12387 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12388 if (distance > 9) 12389 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12390 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12391 } while ((state & ExitState) == 0); 12392 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12393 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12394 if (distance <= 9) 12395 return(MagickTrue); 12396 } 12397 if (direction == VerticalRotateCommand) 12398 degrees-=90.0; 12399 if (degrees == 0.0) 12400 return(MagickTrue); 12401 /* 12402 Rotate image. 12403 */ 12404 normalized_degrees=degrees; 12405 while (normalized_degrees < -45.0) 12406 normalized_degrees+=360.0; 12407 for (rotations=0; normalized_degrees > 45.0; rotations++) 12408 normalized_degrees-=90.0; 12409 if (normalized_degrees != 0.0) 12410 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 12411 exception); 12412 XSetCursorState(display,windows,MagickTrue); 12413 XCheckRefreshWindows(display,windows); 12414 (*image)->background_color.red=ScaleShortToQuantum( 12415 windows->pixel_info->pen_colors[pen_id].red); 12416 (*image)->background_color.green=ScaleShortToQuantum( 12417 windows->pixel_info->pen_colors[pen_id].green); 12418 (*image)->background_color.blue=ScaleShortToQuantum( 12419 windows->pixel_info->pen_colors[pen_id].blue); 12420 rotate_image=RotateImage(*image,degrees,exception); 12421 XSetCursorState(display,windows,MagickFalse); 12422 if (rotate_image == (Image *) NULL) 12423 return(MagickFalse); 12424 *image=DestroyImage(*image); 12425 *image=rotate_image; 12426 if (windows->image.crop_geometry != (char *) NULL) 12427 { 12428 /* 12429 Rotate crop geometry. 12430 */ 12431 width=(unsigned int) (*image)->columns; 12432 height=(unsigned int) (*image)->rows; 12433 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12434 switch (rotations % 4) 12435 { 12436 default: 12437 case 0: 12438 break; 12439 case 1: 12440 { 12441 /* 12442 Rotate 90 degrees. 12443 */ 12444 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12445 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12446 (int) height-y,x); 12447 break; 12448 } 12449 case 2: 12450 { 12451 /* 12452 Rotate 180 degrees. 12453 */ 12454 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12455 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12456 break; 12457 } 12458 case 3: 12459 { 12460 /* 12461 Rotate 270 degrees. 12462 */ 12463 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12464 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12465 break; 12466 } 12467 } 12468 } 12469 if (windows->image.orphan != MagickFalse) 12470 return(MagickTrue); 12471 if (normalized_degrees != 0.0) 12472 { 12473 /* 12474 Update image colormap. 12475 */ 12476 windows->image.window_changes.width=(int) (*image)->columns; 12477 windows->image.window_changes.height=(int) (*image)->rows; 12478 if (windows->image.crop_geometry != (char *) NULL) 12479 { 12480 /* 12481 Obtain dimensions of image from crop geometry. 12482 */ 12483 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12484 &width,&height); 12485 windows->image.window_changes.width=(int) width; 12486 windows->image.window_changes.height=(int) height; 12487 } 12488 XConfigureImageColormap(display,resource_info,windows,*image,exception); 12489 } 12490 else 12491 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12492 { 12493 windows->image.window_changes.width=windows->image.ximage->height; 12494 windows->image.window_changes.height=windows->image.ximage->width; 12495 } 12496 /* 12497 Update image configuration. 12498 */ 12499 (void) XConfigureImage(display,resource_info,windows,*image,exception); 12500 return(MagickTrue); 12501} 12502 12503/* 12504%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12505% % 12506% % 12507% % 12508+ X S a v e I m a g e % 12509% % 12510% % 12511% % 12512%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12513% 12514% XSaveImage() saves an image to a file. 12515% 12516% The format of the XSaveImage method is: 12517% 12518% MagickBooleanType XSaveImage(Display *display, 12519% XResourceInfo *resource_info,XWindows *windows,Image *image, 12520% ExceptionInfo *exception) 12521% 12522% A description of each parameter follows: 12523% 12524% o display: Specifies a connection to an X server; returned from 12525% XOpenDisplay. 12526% 12527% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12528% 12529% o windows: Specifies a pointer to a XWindows structure. 12530% 12531% o image: the image. 12532% 12533% o exception: return any errors or warnings in this structure. 12534% 12535*/ 12536static MagickBooleanType XSaveImage(Display *display, 12537 XResourceInfo *resource_info,XWindows *windows,Image *image, 12538 ExceptionInfo *exception) 12539{ 12540 char 12541 filename[MaxTextExtent], 12542 geometry[MaxTextExtent]; 12543 12544 Image 12545 *save_image; 12546 12547 ImageInfo 12548 *image_info; 12549 12550 MagickStatusType 12551 status; 12552 12553 /* 12554 Request file name from user. 12555 */ 12556 if (resource_info->write_filename != (char *) NULL) 12557 (void) CopyMagickString(filename,resource_info->write_filename, 12558 MaxTextExtent); 12559 else 12560 { 12561 char 12562 path[MaxTextExtent]; 12563 12564 int 12565 status; 12566 12567 GetPathComponent(image->filename,HeadPath,path); 12568 GetPathComponent(image->filename,TailPath,filename); 12569 if (*path != '\0') 12570 { 12571 status=chdir(path); 12572 if (status == -1) 12573 (void) ThrowMagickException(exception,GetMagickModule(), 12574 FileOpenError,"UnableToOpenFile","%s",path); 12575 } 12576 } 12577 XFileBrowserWidget(display,windows,"Save",filename); 12578 if (*filename == '\0') 12579 return(MagickTrue); 12580 if (IsPathAccessible(filename) != MagickFalse) 12581 { 12582 int 12583 status; 12584 12585 /* 12586 File exists-- seek user's permission before overwriting. 12587 */ 12588 status=XConfirmWidget(display,windows,"Overwrite",filename); 12589 if (status <= 0) 12590 return(MagickTrue); 12591 } 12592 image_info=CloneImageInfo(resource_info->image_info); 12593 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 12594 (void) SetImageInfo(image_info,1,exception); 12595 if ((LocaleCompare(image_info->magick,"JPEG") == 0) || 12596 (LocaleCompare(image_info->magick,"JPG") == 0)) 12597 { 12598 char 12599 quality[MaxTextExtent]; 12600 12601 int 12602 status; 12603 12604 /* 12605 Request JPEG quality from user. 12606 */ 12607 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double) 12608 image->quality); 12609 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", 12610 quality); 12611 if (*quality == '\0') 12612 return(MagickTrue); 12613 image->quality=StringToUnsignedLong(quality); 12614 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace; 12615 } 12616 if ((LocaleCompare(image_info->magick,"EPS") == 0) || 12617 (LocaleCompare(image_info->magick,"PDF") == 0) || 12618 (LocaleCompare(image_info->magick,"PS") == 0) || 12619 (LocaleCompare(image_info->magick,"PS2") == 0)) 12620 { 12621 char 12622 geometry[MaxTextExtent]; 12623 12624 /* 12625 Request page geometry from user. 12626 */ 12627 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12628 if (LocaleCompare(image_info->magick,"PDF") == 0) 12629 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12630 if (image_info->page != (char *) NULL) 12631 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 12632 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 12633 "Select page geometry:",geometry); 12634 if (*geometry != '\0') 12635 image_info->page=GetPageGeometry(geometry); 12636 } 12637 /* 12638 Apply image transforms. 12639 */ 12640 XSetCursorState(display,windows,MagickTrue); 12641 XCheckRefreshWindows(display,windows); 12642 save_image=CloneImage(image,0,0,MagickTrue,exception); 12643 if (save_image == (Image *) NULL) 12644 return(MagickFalse); 12645 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 12646 windows->image.ximage->width,windows->image.ximage->height); 12647 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry, 12648 exception); 12649 /* 12650 Write image. 12651 */ 12652 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent); 12653 status=WriteImage(image_info,save_image,exception); 12654 if (status != MagickFalse) 12655 image->taint=MagickFalse; 12656 save_image=DestroyImage(save_image); 12657 image_info=DestroyImageInfo(image_info); 12658 XSetCursorState(display,windows,MagickFalse); 12659 return(status != 0 ? MagickTrue : MagickFalse); 12660} 12661 12662/* 12663%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12664% % 12665% % 12666% % 12667+ X S c r e e n E v e n t % 12668% % 12669% % 12670% % 12671%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12672% 12673% XScreenEvent() handles global events associated with the Pan and Magnify 12674% windows. 12675% 12676% The format of the XScreenEvent function is: 12677% 12678% void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12679% ExceptionInfo *exception) 12680% 12681% A description of each parameter follows: 12682% 12683% o display: Specifies a pointer to the Display structure; returned from 12684% XOpenDisplay. 12685% 12686% o windows: Specifies a pointer to a XWindows structure. 12687% 12688% o event: Specifies a pointer to a X11 XEvent structure. 12689% 12690% o exception: return any errors or warnings in this structure. 12691% 12692*/ 12693 12694#if defined(__cplusplus) || defined(c_plusplus) 12695extern "C" { 12696#endif 12697 12698static int XPredicate(Display *magick_unused(display),XEvent *event,char *data) 12699{ 12700 register XWindows 12701 *windows; 12702 12703 windows=(XWindows *) data; 12704 if ((event->type == ClientMessage) && 12705 (event->xclient.window == windows->image.id)) 12706 return(MagickFalse); 12707 return(MagickTrue); 12708} 12709 12710#if defined(__cplusplus) || defined(c_plusplus) 12711} 12712#endif 12713 12714static void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12715 ExceptionInfo *exception) 12716{ 12717 register int 12718 x, 12719 y; 12720 12721 (void) XIfEvent(display,event,XPredicate,(char *) windows); 12722 if (event->xany.window == windows->command.id) 12723 return; 12724 switch (event->type) 12725 { 12726 case ButtonPress: 12727 case ButtonRelease: 12728 { 12729 if ((event->xbutton.button == Button3) && 12730 (event->xbutton.state & Mod1Mask)) 12731 { 12732 /* 12733 Convert Alt-Button3 to Button2. 12734 */ 12735 event->xbutton.button=Button2; 12736 event->xbutton.state&=(~Mod1Mask); 12737 } 12738 if (event->xbutton.window == windows->backdrop.id) 12739 { 12740 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent, 12741 event->xbutton.time); 12742 break; 12743 } 12744 if (event->xbutton.window == windows->pan.id) 12745 { 12746 XPanImage(display,windows,event,exception); 12747 break; 12748 } 12749 if (event->xbutton.window == windows->image.id) 12750 if (event->xbutton.button == Button2) 12751 { 12752 /* 12753 Update magnified image. 12754 */ 12755 x=event->xbutton.x; 12756 y=event->xbutton.y; 12757 if (x < 0) 12758 x=0; 12759 else 12760 if (x >= (int) windows->image.width) 12761 x=(int) (windows->image.width-1); 12762 windows->magnify.x=(int) windows->image.x+x; 12763 if (y < 0) 12764 y=0; 12765 else 12766 if (y >= (int) windows->image.height) 12767 y=(int) (windows->image.height-1); 12768 windows->magnify.y=windows->image.y+y; 12769 if (windows->magnify.mapped == MagickFalse) 12770 (void) XMapRaised(display,windows->magnify.id); 12771 XMakeMagnifyImage(display,windows,exception); 12772 if (event->type == ButtonRelease) 12773 (void) XWithdrawWindow(display,windows->info.id, 12774 windows->info.screen); 12775 break; 12776 } 12777 break; 12778 } 12779 case ClientMessage: 12780 { 12781 /* 12782 If client window delete message, exit. 12783 */ 12784 if (event->xclient.message_type != windows->wm_protocols) 12785 break; 12786 if (*event->xclient.data.l != (long) windows->wm_delete_window) 12787 break; 12788 if (event->xclient.window == windows->magnify.id) 12789 { 12790 (void) XWithdrawWindow(display,windows->magnify.id, 12791 windows->magnify.screen); 12792 break; 12793 } 12794 break; 12795 } 12796 case ConfigureNotify: 12797 { 12798 if (event->xconfigure.window == windows->magnify.id) 12799 { 12800 unsigned int 12801 magnify; 12802 12803 /* 12804 Magnify window has a new configuration. 12805 */ 12806 windows->magnify.width=(unsigned int) event->xconfigure.width; 12807 windows->magnify.height=(unsigned int) event->xconfigure.height; 12808 if (windows->magnify.mapped == MagickFalse) 12809 break; 12810 magnify=1; 12811 while ((int) magnify <= event->xconfigure.width) 12812 magnify<<=1; 12813 while ((int) magnify <= event->xconfigure.height) 12814 magnify<<=1; 12815 magnify>>=1; 12816 if (((int) magnify != event->xconfigure.width) || 12817 ((int) magnify != event->xconfigure.height)) 12818 { 12819 XWindowChanges 12820 window_changes; 12821 12822 window_changes.width=(int) magnify; 12823 window_changes.height=(int) magnify; 12824 (void) XReconfigureWMWindow(display,windows->magnify.id, 12825 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 12826 &window_changes); 12827 break; 12828 } 12829 XMakeMagnifyImage(display,windows,exception); 12830 break; 12831 } 12832 break; 12833 } 12834 case Expose: 12835 { 12836 if (event->xexpose.window == windows->image.id) 12837 { 12838 XRefreshWindow(display,&windows->image,event); 12839 break; 12840 } 12841 if (event->xexpose.window == windows->pan.id) 12842 if (event->xexpose.count == 0) 12843 { 12844 XDrawPanRectangle(display,windows); 12845 break; 12846 } 12847 if (event->xexpose.window == windows->magnify.id) 12848 if (event->xexpose.count == 0) 12849 { 12850 XMakeMagnifyImage(display,windows,exception); 12851 break; 12852 } 12853 break; 12854 } 12855 case KeyPress: 12856 { 12857 char 12858 command[MaxTextExtent]; 12859 12860 KeySym 12861 key_symbol; 12862 12863 if (event->xkey.window != windows->magnify.id) 12864 break; 12865 /* 12866 Respond to a user key press. 12867 */ 12868 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int) 12869 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12870 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol, 12871 exception); 12872 break; 12873 } 12874 case MapNotify: 12875 { 12876 if (event->xmap.window == windows->magnify.id) 12877 { 12878 windows->magnify.mapped=MagickTrue; 12879 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12880 break; 12881 } 12882 if (event->xmap.window == windows->info.id) 12883 { 12884 windows->info.mapped=MagickTrue; 12885 break; 12886 } 12887 break; 12888 } 12889 case MotionNotify: 12890 { 12891 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; 12892 if (event->xmotion.window == windows->image.id) 12893 if (windows->magnify.mapped != MagickFalse) 12894 { 12895 /* 12896 Update magnified image. 12897 */ 12898 x=event->xmotion.x; 12899 y=event->xmotion.y; 12900 if (x < 0) 12901 x=0; 12902 else 12903 if (x >= (int) windows->image.width) 12904 x=(int) (windows->image.width-1); 12905 windows->magnify.x=(int) windows->image.x+x; 12906 if (y < 0) 12907 y=0; 12908 else 12909 if (y >= (int) windows->image.height) 12910 y=(int) (windows->image.height-1); 12911 windows->magnify.y=windows->image.y+y; 12912 XMakeMagnifyImage(display,windows,exception); 12913 } 12914 break; 12915 } 12916 case UnmapNotify: 12917 { 12918 if (event->xunmap.window == windows->magnify.id) 12919 { 12920 windows->magnify.mapped=MagickFalse; 12921 break; 12922 } 12923 if (event->xunmap.window == windows->info.id) 12924 { 12925 windows->info.mapped=MagickFalse; 12926 break; 12927 } 12928 break; 12929 } 12930 default: 12931 break; 12932 } 12933} 12934 12935/* 12936%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12937% % 12938% % 12939% % 12940+ X S e t C r o p G e o m e t r y % 12941% % 12942% % 12943% % 12944%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12945% 12946% XSetCropGeometry() accepts a cropping geometry relative to the Image window 12947% and translates it to a cropping geometry relative to the image. 12948% 12949% The format of the XSetCropGeometry method is: 12950% 12951% void XSetCropGeometry(Display *display,XWindows *windows, 12952% RectangleInfo *crop_info,Image *image) 12953% 12954% A description of each parameter follows: 12955% 12956% o display: Specifies a connection to an X server; returned from 12957% XOpenDisplay. 12958% 12959% o windows: Specifies a pointer to a XWindows structure. 12960% 12961% o crop_info: A pointer to a RectangleInfo that defines a region of the 12962% Image window to crop. 12963% 12964% o image: the image. 12965% 12966*/ 12967static void XSetCropGeometry(Display *display,XWindows *windows, 12968 RectangleInfo *crop_info,Image *image) 12969{ 12970 char 12971 text[MaxTextExtent]; 12972 12973 int 12974 x, 12975 y; 12976 12977 MagickRealType 12978 scale_factor; 12979 12980 unsigned int 12981 height, 12982 width; 12983 12984 if (windows->info.mapped != MagickFalse) 12985 { 12986 /* 12987 Display info on cropping rectangle. 12988 */ 12989 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g", 12990 (double) crop_info->width,(double) crop_info->height,(double) 12991 crop_info->x,(double) crop_info->y); 12992 XInfoWidget(display,windows,text); 12993 } 12994 /* 12995 Cropping geometry is relative to any previous crop geometry. 12996 */ 12997 x=0; 12998 y=0; 12999 width=(unsigned int) image->columns; 13000 height=(unsigned int) image->rows; 13001 if (windows->image.crop_geometry != (char *) NULL) 13002 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13003 else 13004 windows->image.crop_geometry=AcquireString((char *) NULL); 13005 /* 13006 Define the crop geometry string from the cropping rectangle. 13007 */ 13008 scale_factor=(MagickRealType) width/windows->image.ximage->width; 13009 if (crop_info->x > 0) 13010 x+=(int) (scale_factor*crop_info->x+0.5); 13011 width=(unsigned int) (scale_factor*crop_info->width+0.5); 13012 if (width == 0) 13013 width=1; 13014 scale_factor=(MagickRealType) height/windows->image.ximage->height; 13015 if (crop_info->y > 0) 13016 y+=(int) (scale_factor*crop_info->y+0.5); 13017 height=(unsigned int) (scale_factor*crop_info->height+0.5); 13018 if (height == 0) 13019 height=1; 13020 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 13021 "%ux%u%+d%+d",width,height,x,y); 13022} 13023 13024/* 13025%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13026% % 13027% % 13028% % 13029+ X T i l e I m a g e % 13030% % 13031% % 13032% % 13033%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13034% 13035% XTileImage() loads or deletes a selected tile from a visual image directory. 13036% The load or delete command is chosen from a menu. 13037% 13038% The format of the XTileImage method is: 13039% 13040% Image *XTileImage(Display *display,XResourceInfo *resource_info, 13041% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13042% 13043% A description of each parameter follows: 13044% 13045% o tile_image: XTileImage reads or deletes the tile image 13046% and returns it. A null image is returned if an error occurs. 13047% 13048% o display: Specifies a connection to an X server; returned from 13049% XOpenDisplay. 13050% 13051% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13052% 13053% o windows: Specifies a pointer to a XWindows structure. 13054% 13055% o image: the image; returned from ReadImage. 13056% 13057% o event: Specifies a pointer to a XEvent structure. If it is NULL, 13058% the entire image is refreshed. 13059% 13060% o exception: return any errors or warnings in this structure. 13061% 13062*/ 13063static Image *XTileImage(Display *display,XResourceInfo *resource_info, 13064 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13065{ 13066 static const char 13067 *VerbMenu[] = 13068 { 13069 "Load", 13070 "Next", 13071 "Former", 13072 "Delete", 13073 "Update", 13074 (char *) NULL, 13075 }; 13076 13077 static const ModeType 13078 TileCommands[] = 13079 { 13080 TileLoadCommand, 13081 TileNextCommand, 13082 TileFormerCommand, 13083 TileDeleteCommand, 13084 TileUpdateCommand 13085 }; 13086 13087 char 13088 command[MaxTextExtent], 13089 filename[MaxTextExtent]; 13090 13091 Image 13092 *tile_image; 13093 13094 int 13095 id, 13096 status, 13097 tile, 13098 x, 13099 y; 13100 13101 MagickRealType 13102 scale_factor; 13103 13104 register char 13105 *p, 13106 *q; 13107 13108 register int 13109 i; 13110 13111 unsigned int 13112 height, 13113 width; 13114 13115 /* 13116 Tile image is relative to montage image configuration. 13117 */ 13118 x=0; 13119 y=0; 13120 width=(unsigned int) image->columns; 13121 height=(unsigned int) image->rows; 13122 if (windows->image.crop_geometry != (char *) NULL) 13123 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13124 scale_factor=(MagickRealType) width/windows->image.ximage->width; 13125 event->xbutton.x+=windows->image.x; 13126 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5); 13127 scale_factor=(MagickRealType) height/windows->image.ximage->height; 13128 event->xbutton.y+=windows->image.y; 13129 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5); 13130 /* 13131 Determine size and location of each tile in the visual image directory. 13132 */ 13133 width=(unsigned int) image->columns; 13134 height=(unsigned int) image->rows; 13135 x=0; 13136 y=0; 13137 (void) XParseGeometry(image->montage,&x,&y,&width,&height); 13138 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+ 13139 (event->xbutton.x-x)/width; 13140 if (tile < 0) 13141 { 13142 /* 13143 Button press is outside any tile. 13144 */ 13145 (void) XBell(display,0); 13146 return((Image *) NULL); 13147 } 13148 /* 13149 Determine file name from the tile directory. 13150 */ 13151 p=image->directory; 13152 for (i=tile; (i != 0) && (*p != '\0'); ) 13153 { 13154 if (*p == '\n') 13155 i--; 13156 p++; 13157 } 13158 if (*p == '\0') 13159 { 13160 /* 13161 Button press is outside any tile. 13162 */ 13163 (void) XBell(display,0); 13164 return((Image *) NULL); 13165 } 13166 /* 13167 Select a command from the pop-up menu. 13168 */ 13169 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command); 13170 if (id < 0) 13171 return((Image *) NULL); 13172 q=p; 13173 while ((*q != '\n') && (*q != '\0')) 13174 q++; 13175 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13176 /* 13177 Perform command for the selected tile. 13178 */ 13179 XSetCursorState(display,windows,MagickTrue); 13180 XCheckRefreshWindows(display,windows); 13181 tile_image=NewImageList(); 13182 switch (TileCommands[id]) 13183 { 13184 case TileLoadCommand: 13185 { 13186 /* 13187 Load tile image. 13188 */ 13189 XCheckRefreshWindows(display,windows); 13190 (void) CopyMagickString(resource_info->image_info->magick,"MIFF", 13191 MaxTextExtent); 13192 (void) CopyMagickString(resource_info->image_info->filename,filename, 13193 MaxTextExtent); 13194 tile_image=ReadImage(resource_info->image_info,exception); 13195 CatchException(exception); 13196 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13197 break; 13198 } 13199 case TileNextCommand: 13200 { 13201 /* 13202 Display next image. 13203 */ 13204 XClientMessage(display,windows->image.id,windows->im_protocols, 13205 windows->im_next_image,CurrentTime); 13206 break; 13207 } 13208 case TileFormerCommand: 13209 { 13210 /* 13211 Display former image. 13212 */ 13213 XClientMessage(display,windows->image.id,windows->im_protocols, 13214 windows->im_former_image,CurrentTime); 13215 break; 13216 } 13217 case TileDeleteCommand: 13218 { 13219 /* 13220 Delete tile image. 13221 */ 13222 if (IsPathAccessible(filename) == MagickFalse) 13223 { 13224 XNoticeWidget(display,windows,"Image file does not exist:",filename); 13225 break; 13226 } 13227 status=XConfirmWidget(display,windows,"Really delete tile",filename); 13228 if (status <= 0) 13229 break; 13230 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse; 13231 if (status != MagickFalse) 13232 { 13233 XNoticeWidget(display,windows,"Unable to delete image file:", 13234 filename); 13235 break; 13236 } 13237 } 13238 case TileUpdateCommand: 13239 { 13240 int 13241 x_offset, 13242 y_offset; 13243 13244 PixelInfo 13245 pixel; 13246 13247 Quantum 13248 virtual_pixel[CompositePixelChannel]; 13249 13250 register int 13251 j; 13252 13253 register Quantum 13254 *s; 13255 13256 /* 13257 Ensure all the images exist. 13258 */ 13259 tile=0; 13260 GetPixelInfo(image,&pixel); 13261 for (p=image->directory; *p != '\0'; p++) 13262 { 13263 CacheView 13264 *image_view; 13265 13266 q=p; 13267 while ((*q != '\n') && (*q != '\0')) 13268 q++; 13269 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13270 p=q; 13271 if (IsPathAccessible(filename) != MagickFalse) 13272 { 13273 tile++; 13274 continue; 13275 } 13276 /* 13277 Overwrite tile with background color. 13278 */ 13279 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x); 13280 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y); 13281 image_view=AcquireCacheView(image); 13282 (void) GetOneCacheViewVirtualPixel(image_view,0,0,virtual_pixel, 13283 exception); 13284 pixel.red=virtual_pixel[RedPixelChannel]; 13285 pixel.green=virtual_pixel[GreenPixelChannel]; 13286 pixel.blue=virtual_pixel[BluePixelChannel]; 13287 pixel.alpha=virtual_pixel[AlphaPixelChannel]; 13288 for (i=0; i < (int) height; i++) 13289 { 13290 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t) 13291 y_offset+i,width,1,exception); 13292 if (s == (Quantum *) NULL) 13293 break; 13294 for (j=0; j < (int) width; j++) 13295 { 13296 SetPixelPixelInfo(image,&pixel,s); 13297 s+=GetPixelChannels(image); 13298 } 13299 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 13300 break; 13301 } 13302 image_view=DestroyCacheView(image_view); 13303 tile++; 13304 } 13305 windows->image.window_changes.width=(int) image->columns; 13306 windows->image.window_changes.height=(int) image->rows; 13307 XConfigureImageColormap(display,resource_info,windows,image,exception); 13308 (void) XConfigureImage(display,resource_info,windows,image,exception); 13309 break; 13310 } 13311 default: 13312 break; 13313 } 13314 XSetCursorState(display,windows,MagickFalse); 13315 return(tile_image); 13316} 13317 13318/* 13319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13320% % 13321% % 13322% % 13323+ X T r a n s l a t e I m a g e % 13324% % 13325% % 13326% % 13327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13328% 13329% XTranslateImage() translates the image within an Image window by one pixel 13330% as specified by the key symbol. If the image has a `montage string the 13331% translation is respect to the width and height contained within the string. 13332% 13333% The format of the XTranslateImage method is: 13334% 13335% void XTranslateImage(Display *display,XWindows *windows, 13336% Image *image,const KeySym key_symbol) 13337% 13338% A description of each parameter follows: 13339% 13340% o display: Specifies a connection to an X server; returned from 13341% XOpenDisplay. 13342% 13343% o windows: Specifies a pointer to a XWindows structure. 13344% 13345% o image: the image. 13346% 13347% o key_symbol: Specifies a KeySym which indicates which side of the image 13348% to trim. 13349% 13350*/ 13351static void XTranslateImage(Display *display,XWindows *windows, 13352 Image *image,const KeySym key_symbol) 13353{ 13354 char 13355 text[MaxTextExtent]; 13356 13357 int 13358 x, 13359 y; 13360 13361 unsigned int 13362 x_offset, 13363 y_offset; 13364 13365 /* 13366 User specified a pan position offset. 13367 */ 13368 x_offset=windows->image.width; 13369 y_offset=windows->image.height; 13370 if (image->montage != (char *) NULL) 13371 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset); 13372 switch ((int) key_symbol) 13373 { 13374 case XK_Home: 13375 case XK_KP_Home: 13376 { 13377 windows->image.x=(int) windows->image.width/2; 13378 windows->image.y=(int) windows->image.height/2; 13379 break; 13380 } 13381 case XK_Left: 13382 case XK_KP_Left: 13383 { 13384 windows->image.x-=x_offset; 13385 break; 13386 } 13387 case XK_Next: 13388 case XK_Up: 13389 case XK_KP_Up: 13390 { 13391 windows->image.y-=y_offset; 13392 break; 13393 } 13394 case XK_Right: 13395 case XK_KP_Right: 13396 { 13397 windows->image.x+=x_offset; 13398 break; 13399 } 13400 case XK_Prior: 13401 case XK_Down: 13402 case XK_KP_Down: 13403 { 13404 windows->image.y+=y_offset; 13405 break; 13406 } 13407 default: 13408 return; 13409 } 13410 /* 13411 Check boundary conditions. 13412 */ 13413 if (windows->image.x < 0) 13414 windows->image.x=0; 13415 else 13416 if ((int) (windows->image.x+windows->image.width) > 13417 windows->image.ximage->width) 13418 windows->image.x=(int) windows->image.ximage->width-windows->image.width; 13419 if (windows->image.y < 0) 13420 windows->image.y=0; 13421 else 13422 if ((int) (windows->image.y+windows->image.height) > 13423 windows->image.ximage->height) 13424 windows->image.y=(int) windows->image.ximage->height-windows->image.height; 13425 /* 13426 Refresh Image window. 13427 */ 13428 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 13429 windows->image.width,windows->image.height,windows->image.x, 13430 windows->image.y); 13431 XInfoWidget(display,windows,text); 13432 XCheckRefreshWindows(display,windows); 13433 XDrawPanRectangle(display,windows); 13434 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 13435 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13436} 13437 13438/* 13439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13440% % 13441% % 13442% % 13443+ X T r i m I m a g e % 13444% % 13445% % 13446% % 13447%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13448% 13449% XTrimImage() trims the edges from the Image window. 13450% 13451% The format of the XTrimImage method is: 13452% 13453% MagickBooleanType XTrimImage(Display *display, 13454% XResourceInfo *resource_info,XWindows *windows,Image *image, 13455% ExceptionInfo *exception) 13456% 13457% A description of each parameter follows: 13458% 13459% o display: Specifies a connection to an X server; returned from 13460% XOpenDisplay. 13461% 13462% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13463% 13464% o windows: Specifies a pointer to a XWindows structure. 13465% 13466% o image: the image. 13467% 13468% o exception: return any errors or warnings in this structure. 13469% 13470*/ 13471static MagickBooleanType XTrimImage(Display *display, 13472 XResourceInfo *resource_info,XWindows *windows,Image *image, 13473 ExceptionInfo *exception) 13474{ 13475 RectangleInfo 13476 trim_info; 13477 13478 register int 13479 x, 13480 y; 13481 13482 size_t 13483 background, 13484 pixel; 13485 13486 /* 13487 Trim edges from image. 13488 */ 13489 XSetCursorState(display,windows,MagickTrue); 13490 XCheckRefreshWindows(display,windows); 13491 /* 13492 Crop the left edge. 13493 */ 13494 background=XGetPixel(windows->image.ximage,0,0); 13495 trim_info.width=(size_t) windows->image.ximage->width; 13496 for (x=0; x < windows->image.ximage->width; x++) 13497 { 13498 for (y=0; y < windows->image.ximage->height; y++) 13499 { 13500 pixel=XGetPixel(windows->image.ximage,x,y); 13501 if (pixel != background) 13502 break; 13503 } 13504 if (y < windows->image.ximage->height) 13505 break; 13506 } 13507 trim_info.x=(ssize_t) x; 13508 if (trim_info.x == (ssize_t) windows->image.ximage->width) 13509 { 13510 XSetCursorState(display,windows,MagickFalse); 13511 return(MagickFalse); 13512 } 13513 /* 13514 Crop the right edge. 13515 */ 13516 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0); 13517 for (x=windows->image.ximage->width-1; x != 0; x--) 13518 { 13519 for (y=0; y < windows->image.ximage->height; y++) 13520 { 13521 pixel=XGetPixel(windows->image.ximage,x,y); 13522 if (pixel != background) 13523 break; 13524 } 13525 if (y < windows->image.ximage->height) 13526 break; 13527 } 13528 trim_info.width=(size_t) (x-trim_info.x+1); 13529 /* 13530 Crop the top edge. 13531 */ 13532 background=XGetPixel(windows->image.ximage,0,0); 13533 trim_info.height=(size_t) windows->image.ximage->height; 13534 for (y=0; y < windows->image.ximage->height; y++) 13535 { 13536 for (x=0; x < windows->image.ximage->width; x++) 13537 { 13538 pixel=XGetPixel(windows->image.ximage,x,y); 13539 if (pixel != background) 13540 break; 13541 } 13542 if (x < windows->image.ximage->width) 13543 break; 13544 } 13545 trim_info.y=(ssize_t) y; 13546 /* 13547 Crop the bottom edge. 13548 */ 13549 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1); 13550 for (y=windows->image.ximage->height-1; y != 0; y--) 13551 { 13552 for (x=0; x < windows->image.ximage->width; x++) 13553 { 13554 pixel=XGetPixel(windows->image.ximage,x,y); 13555 if (pixel != background) 13556 break; 13557 } 13558 if (x < windows->image.ximage->width) 13559 break; 13560 } 13561 trim_info.height=(size_t) y-trim_info.y+1; 13562 if (((unsigned int) trim_info.width != windows->image.width) || 13563 ((unsigned int) trim_info.height != windows->image.height)) 13564 { 13565 /* 13566 Reconfigure Image window as defined by the trimming rectangle. 13567 */ 13568 XSetCropGeometry(display,windows,&trim_info,image); 13569 windows->image.window_changes.width=(int) trim_info.width; 13570 windows->image.window_changes.height=(int) trim_info.height; 13571 (void) XConfigureImage(display,resource_info,windows,image,exception); 13572 } 13573 XSetCursorState(display,windows,MagickFalse); 13574 return(MagickTrue); 13575} 13576 13577/* 13578%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13579% % 13580% % 13581% % 13582+ X V i s u a l D i r e c t o r y I m a g e % 13583% % 13584% % 13585% % 13586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13587% 13588% XVisualDirectoryImage() creates a Visual Image Directory. 13589% 13590% The format of the XVisualDirectoryImage method is: 13591% 13592% Image *XVisualDirectoryImage(Display *display, 13593% XResourceInfo *resource_info,XWindows *windows, 13594% ExceptionInfo *exception) 13595% 13596% A description of each parameter follows: 13597% 13598% o display: Specifies a connection to an X server; returned from 13599% XOpenDisplay. 13600% 13601% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13602% 13603% o windows: Specifies a pointer to a XWindows structure. 13604% 13605% o exception: return any errors or warnings in this structure. 13606% 13607*/ 13608static Image *XVisualDirectoryImage(Display *display, 13609 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception) 13610{ 13611#define TileImageTag "Scale/Image" 13612#define XClientName "montage" 13613 13614 char 13615 **filelist; 13616 13617 Image 13618 *images, 13619 *montage_image, 13620 *next_image, 13621 *thumbnail_image; 13622 13623 ImageInfo 13624 *read_info; 13625 13626 int 13627 number_files; 13628 13629 MagickBooleanType 13630 backdrop; 13631 13632 MagickStatusType 13633 status; 13634 13635 MontageInfo 13636 *montage_info; 13637 13638 RectangleInfo 13639 geometry; 13640 13641 register int 13642 i; 13643 13644 static char 13645 filename[MaxTextExtent] = "\0", 13646 filenames[MaxTextExtent] = "*"; 13647 13648 XResourceInfo 13649 background_resources; 13650 13651 /* 13652 Request file name from user. 13653 */ 13654 XFileBrowserWidget(display,windows,"Directory",filenames); 13655 if (*filenames == '\0') 13656 return((Image *) NULL); 13657 /* 13658 Expand the filenames. 13659 */ 13660 filelist=(char **) AcquireMagickMemory(sizeof(*filelist)); 13661 if (filelist == (char **) NULL) 13662 { 13663 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13664 filenames); 13665 return((Image *) NULL); 13666 } 13667 number_files=1; 13668 filelist[0]=filenames; 13669 status=ExpandFilenames(&number_files,&filelist); 13670 if ((status == MagickFalse) || (number_files == 0)) 13671 { 13672 if (number_files == 0) 13673 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames) 13674 else 13675 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13676 filenames); 13677 return((Image *) NULL); 13678 } 13679 /* 13680 Set image background resources. 13681 */ 13682 background_resources=(*resource_info); 13683 background_resources.window_id=AcquireString(""); 13684 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent, 13685 "0x%lx",windows->image.id); 13686 background_resources.backdrop=MagickTrue; 13687 /* 13688 Read each image and convert them to a tile. 13689 */ 13690 backdrop=(windows->visual_info->klass == TrueColor) || 13691 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse; 13692 read_info=CloneImageInfo(resource_info->image_info); 13693 (void) SetImageOption(read_info,"jpeg:size","120x120"); 13694 (void) CloneString(&read_info->size,DefaultTileGeometry); 13695 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 13696 (void *) NULL); 13697 images=NewImageList(); 13698 XSetCursorState(display,windows,MagickTrue); 13699 XCheckRefreshWindows(display,windows); 13700 for (i=0; i < (int) number_files; i++) 13701 { 13702 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent); 13703 filelist[i]=DestroyString(filelist[i]); 13704 *read_info->magick='\0'; 13705 next_image=ReadImage(read_info,exception); 13706 CatchException(exception); 13707 if (next_image != (Image *) NULL) 13708 { 13709 (void) DeleteImageProperty(next_image,"label"); 13710 (void) SetImageProperty(next_image,"label",InterpretImageProperties( 13711 read_info,next_image,DefaultTileLabel,exception),exception); 13712 (void) ParseRegionGeometry(next_image,read_info->size,&geometry, 13713 exception); 13714 thumbnail_image=ThumbnailImage(next_image,geometry.width, 13715 geometry.height,exception); 13716 if (thumbnail_image != (Image *) NULL) 13717 { 13718 next_image=DestroyImage(next_image); 13719 next_image=thumbnail_image; 13720 } 13721 if (backdrop) 13722 { 13723 (void) XDisplayBackgroundImage(display,&background_resources, 13724 next_image,exception); 13725 XSetCursorState(display,windows,MagickTrue); 13726 } 13727 AppendImageToList(&images,next_image); 13728 if (images->progress_monitor != (MagickProgressMonitor) NULL) 13729 { 13730 MagickBooleanType 13731 proceed; 13732 13733 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i, 13734 (MagickSizeType) number_files); 13735 if (proceed == MagickFalse) 13736 break; 13737 } 13738 } 13739 } 13740 filelist=(char **) RelinquishMagickMemory(filelist); 13741 if (images == (Image *) NULL) 13742 { 13743 read_info=DestroyImageInfo(read_info); 13744 XSetCursorState(display,windows,MagickFalse); 13745 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames); 13746 return((Image *) NULL); 13747 } 13748 /* 13749 Create the Visual Image Directory. 13750 */ 13751 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL); 13752 montage_info->pointsize=10; 13753 if (resource_info->font != (char *) NULL) 13754 (void) CloneString(&montage_info->font,resource_info->font); 13755 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent); 13756 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList( 13757 images),exception); 13758 images=DestroyImageList(images); 13759 montage_info=DestroyMontageInfo(montage_info); 13760 read_info=DestroyImageInfo(read_info); 13761 XSetCursorState(display,windows,MagickFalse); 13762 if (montage_image == (Image *) NULL) 13763 return(montage_image); 13764 XClientMessage(display,windows->image.id,windows->im_protocols, 13765 windows->im_next_image,CurrentTime); 13766 return(montage_image); 13767} 13768 13769/* 13770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13771% % 13772% % 13773% % 13774% X D i s p l a y B a c k g r o u n d I m a g e % 13775% % 13776% % 13777% % 13778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13779% 13780% XDisplayBackgroundImage() displays an image in the background of a window. 13781% 13782% The format of the XDisplayBackgroundImage method is: 13783% 13784% MagickBooleanType XDisplayBackgroundImage(Display *display, 13785% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13786% 13787% A description of each parameter follows: 13788% 13789% o display: Specifies a connection to an X server; returned from 13790% XOpenDisplay. 13791% 13792% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13793% 13794% o image: the image. 13795% 13796% o exception: return any errors or warnings in this structure. 13797% 13798*/ 13799MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display, 13800 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13801{ 13802 char 13803 geometry[MaxTextExtent], 13804 visual_type[MaxTextExtent]; 13805 13806 int 13807 height, 13808 status, 13809 width; 13810 13811 RectangleInfo 13812 geometry_info; 13813 13814 static XPixelInfo 13815 pixel; 13816 13817 static XStandardColormap 13818 *map_info; 13819 13820 static XVisualInfo 13821 *visual_info = (XVisualInfo *) NULL; 13822 13823 static XWindowInfo 13824 window_info; 13825 13826 size_t 13827 delay; 13828 13829 Window 13830 root_window; 13831 13832 XGCValues 13833 context_values; 13834 13835 XResourceInfo 13836 resources; 13837 13838 XWindowAttributes 13839 window_attributes; 13840 13841 /* 13842 Determine target window. 13843 */ 13844 assert(image != (Image *) NULL); 13845 assert(image->signature == MagickSignature); 13846 if (image->debug != MagickFalse) 13847 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 13848 resources=(*resource_info); 13849 window_info.id=(Window) NULL; 13850 root_window=XRootWindow(display,XDefaultScreen(display)); 13851 if (LocaleCompare(resources.window_id,"root") == 0) 13852 window_info.id=root_window; 13853 else 13854 { 13855 if (isdigit((unsigned char) *resources.window_id) != 0) 13856 window_info.id=XWindowByID(display,root_window, 13857 (Window) strtol((char *) resources.window_id,(char **) NULL,0)); 13858 if (window_info.id == (Window) NULL) 13859 window_info.id=XWindowByName(display,root_window,resources.window_id); 13860 } 13861 if (window_info.id == (Window) NULL) 13862 { 13863 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists", 13864 resources.window_id); 13865 return(MagickFalse); 13866 } 13867 /* 13868 Determine window visual id. 13869 */ 13870 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); 13871 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); 13872 (void) CopyMagickString(visual_type,"default",MaxTextExtent); 13873 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13874 if (status != 0) 13875 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx", 13876 XVisualIDFromVisual(window_attributes.visual)); 13877 if (visual_info == (XVisualInfo *) NULL) 13878 { 13879 /* 13880 Allocate standard colormap. 13881 */ 13882 map_info=XAllocStandardColormap(); 13883 if (map_info == (XStandardColormap *) NULL) 13884 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", 13885 image->filename); 13886 map_info->colormap=(Colormap) NULL; 13887 pixel.pixels=(unsigned long *) NULL; 13888 /* 13889 Initialize visual info. 13890 */ 13891 resources.map_type=(char *) NULL; 13892 resources.visual_type=visual_type; 13893 visual_info=XBestVisualInfo(display,map_info,&resources); 13894 if (visual_info == (XVisualInfo *) NULL) 13895 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", 13896 resources.visual_type); 13897 /* 13898 Initialize window info. 13899 */ 13900 window_info.ximage=(XImage *) NULL; 13901 window_info.matte_image=(XImage *) NULL; 13902 window_info.pixmap=(Pixmap) NULL; 13903 window_info.matte_pixmap=(Pixmap) NULL; 13904 } 13905 /* 13906 Free previous root colors. 13907 */ 13908 if (window_info.id == root_window) 13909 (void) XDestroyWindowColors(display,root_window); 13910 /* 13911 Initialize Standard Colormap. 13912 */ 13913 resources.colormap=SharedColormap; 13914 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel, 13915 exception); 13916 /* 13917 Graphic context superclass. 13918 */ 13919 context_values.background=pixel.background_color.pixel; 13920 context_values.foreground=pixel.foreground_color.pixel; 13921 pixel.annotate_context=XCreateGC(display,window_info.id, 13922 (size_t) (GCBackground | GCForeground),&context_values); 13923 if (pixel.annotate_context == (GC) NULL) 13924 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 13925 image->filename); 13926 /* 13927 Initialize Image window attributes. 13928 */ 13929 window_info.name=AcquireString("\0"); 13930 window_info.icon_name=AcquireString("\0"); 13931 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, 13932 &resources,&window_info); 13933 /* 13934 Create the X image. 13935 */ 13936 window_info.width=(unsigned int) image->columns; 13937 window_info.height=(unsigned int) image->rows; 13938 if ((image->columns != window_info.width) || 13939 (image->rows != window_info.height)) 13940 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13941 image->filename); 13942 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>", 13943 window_attributes.width,window_attributes.height); 13944 geometry_info.width=window_info.width; 13945 geometry_info.height=window_info.height; 13946 geometry_info.x=(ssize_t) window_info.x; 13947 geometry_info.y=(ssize_t) window_info.y; 13948 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 13949 &geometry_info.width,&geometry_info.height); 13950 window_info.width=(unsigned int) geometry_info.width; 13951 window_info.height=(unsigned int) geometry_info.height; 13952 window_info.x=(int) geometry_info.x; 13953 window_info.y=(int) geometry_info.y; 13954 status=XMakeImage(display,&resources,&window_info,image,window_info.width, 13955 window_info.height,exception); 13956 if (status == MagickFalse) 13957 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13958 image->filename); 13959 window_info.x=0; 13960 window_info.y=0; 13961 if (image->debug != MagickFalse) 13962 { 13963 (void) LogMagickEvent(X11Event,GetMagickModule(), 13964 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene, 13965 (double) image->columns,(double) image->rows); 13966 if (image->colors != 0) 13967 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 13968 image->colors); 13969 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick); 13970 } 13971 /* 13972 Adjust image dimensions as specified by backdrop or geometry options. 13973 */ 13974 width=(int) window_info.width; 13975 height=(int) window_info.height; 13976 if (resources.backdrop != MagickFalse) 13977 { 13978 /* 13979 Center image on window. 13980 */ 13981 window_info.x=(window_attributes.width/2)- 13982 (window_info.ximage->width/2); 13983 window_info.y=(window_attributes.height/2)- 13984 (window_info.ximage->height/2); 13985 width=window_attributes.width; 13986 height=window_attributes.height; 13987 } 13988 if ((resources.image_geometry != (char *) NULL) && 13989 (*resources.image_geometry != '\0')) 13990 { 13991 char 13992 default_geometry[MaxTextExtent]; 13993 13994 int 13995 flags, 13996 gravity; 13997 13998 XSizeHints 13999 *size_hints; 14000 14001 /* 14002 User specified geometry. 14003 */ 14004 size_hints=XAllocSizeHints(); 14005 if (size_hints == (XSizeHints *) NULL) 14006 ThrowXWindowFatalException(ResourceLimitFatalError, 14007 "MemoryAllocationFailed",image->filename); 14008 size_hints->flags=0L; 14009 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d", 14010 width,height); 14011 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, 14012 default_geometry,window_info.border_width,size_hints,&window_info.x, 14013 &window_info.y,&width,&height,&gravity); 14014 if (flags & (XValue | YValue)) 14015 { 14016 width=window_attributes.width; 14017 height=window_attributes.height; 14018 } 14019 (void) XFree((void *) size_hints); 14020 } 14021 /* 14022 Create the X pixmap. 14023 */ 14024 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, 14025 (unsigned int) height,window_info.depth); 14026 if (window_info.pixmap == (Pixmap) NULL) 14027 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", 14028 image->filename); 14029 /* 14030 Display pixmap on the window. 14031 */ 14032 if (((unsigned int) width > window_info.width) || 14033 ((unsigned int) height > window_info.height)) 14034 (void) XFillRectangle(display,window_info.pixmap, 14035 window_info.annotate_context,0,0,(unsigned int) width, 14036 (unsigned int) height); 14037 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, 14038 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int) 14039 window_info.width,(unsigned int) window_info.height); 14040 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); 14041 (void) XClearWindow(display,window_info.id); 14042 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); 14043 XDelay(display,delay == 0UL ? 10UL : delay); 14044 (void) XSync(display,MagickFalse); 14045 return(window_info.id == root_window ? MagickTrue : MagickFalse); 14046} 14047 14048/* 14049%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14050% % 14051% % 14052% % 14053+ X D i s p l a y I m a g e % 14054% % 14055% % 14056% % 14057%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14058% 14059% XDisplayImage() displays an image via X11. A new image is created and 14060% returned if the user interactively transforms the displayed image. 14061% 14062% The format of the XDisplayImage method is: 14063% 14064% Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14065% char **argv,int argc,Image **image,size_t *state, 14066% ExceptionInfo *exception) 14067% 14068% A description of each parameter follows: 14069% 14070% o nexus: Method XDisplayImage returns an image when the 14071% user chooses 'Open Image' from the command menu or picks a tile 14072% from the image directory. Otherwise a null image is returned. 14073% 14074% o display: Specifies a connection to an X server; returned from 14075% XOpenDisplay. 14076% 14077% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 14078% 14079% o argv: Specifies the application's argument list. 14080% 14081% o argc: Specifies the number of arguments. 14082% 14083% o image: Specifies an address to an address of an Image structure; 14084% 14085% o exception: return any errors or warnings in this structure. 14086% 14087*/ 14088MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14089 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception) 14090{ 14091#define MagnifySize 256 /* must be a power of 2 */ 14092#define MagickMenus 10 14093#define MagickTitle "Commands" 14094 14095 static const char 14096 *CommandMenu[] = 14097 { 14098 "File", 14099 "Edit", 14100 "View", 14101 "Transform", 14102 "Enhance", 14103 "Effects", 14104 "F/X", 14105 "Image Edit", 14106 "Miscellany", 14107 "Help", 14108 (char *) NULL 14109 }, 14110 *FileMenu[] = 14111 { 14112 "Open...", 14113 "Next", 14114 "Former", 14115 "Select...", 14116 "Save...", 14117 "Print...", 14118 "Delete...", 14119 "New...", 14120 "Visual Directory...", 14121 "Quit", 14122 (char *) NULL 14123 }, 14124 *EditMenu[] = 14125 { 14126 "Undo", 14127 "Redo", 14128 "Cut", 14129 "Copy", 14130 "Paste", 14131 (char *) NULL 14132 }, 14133 *ViewMenu[] = 14134 { 14135 "Half Size", 14136 "Original Size", 14137 "Double Size", 14138 "Resize...", 14139 "Apply", 14140 "Refresh", 14141 "Restore", 14142 (char *) NULL 14143 }, 14144 *TransformMenu[] = 14145 { 14146 "Crop", 14147 "Chop", 14148 "Flop", 14149 "Flip", 14150 "Rotate Right", 14151 "Rotate Left", 14152 "Rotate...", 14153 "Shear...", 14154 "Roll...", 14155 "Trim Edges", 14156 (char *) NULL 14157 }, 14158 *EnhanceMenu[] = 14159 { 14160 "Hue...", 14161 "Saturation...", 14162 "Brightness...", 14163 "Gamma...", 14164 "Spiff", 14165 "Dull", 14166 "Contrast Stretch...", 14167 "Sigmoidal Contrast...", 14168 "Normalize", 14169 "Equalize", 14170 "Negate", 14171 "Grayscale", 14172 "Map...", 14173 "Quantize...", 14174 (char *) NULL 14175 }, 14176 *EffectsMenu[] = 14177 { 14178 "Despeckle", 14179 "Emboss", 14180 "Reduce Noise", 14181 "Add Noise...", 14182 "Sharpen...", 14183 "Blur...", 14184 "Threshold...", 14185 "Edge Detect...", 14186 "Spread...", 14187 "Shade...", 14188 "Raise...", 14189 "Segment...", 14190 (char *) NULL 14191 }, 14192 *FXMenu[] = 14193 { 14194 "Solarize...", 14195 "Sepia Tone...", 14196 "Swirl...", 14197 "Implode...", 14198 "Vignette...", 14199 "Wave...", 14200 "Oil Paint...", 14201 "Charcoal Draw...", 14202 (char *) NULL 14203 }, 14204 *ImageEditMenu[] = 14205 { 14206 "Annotate...", 14207 "Draw...", 14208 "Color...", 14209 "Matte...", 14210 "Composite...", 14211 "Add Border...", 14212 "Add Frame...", 14213 "Comment...", 14214 "Launch...", 14215 "Region of Interest...", 14216 (char *) NULL 14217 }, 14218 *MiscellanyMenu[] = 14219 { 14220 "Image Info", 14221 "Zoom Image", 14222 "Show Preview...", 14223 "Show Histogram", 14224 "Show Matte", 14225 "Background...", 14226 "Slide Show...", 14227 "Preferences...", 14228 (char *) NULL 14229 }, 14230 *HelpMenu[] = 14231 { 14232 "Overview", 14233 "Browse Documentation", 14234 "About Display", 14235 (char *) NULL 14236 }, 14237 *ShortCutsMenu[] = 14238 { 14239 "Next", 14240 "Former", 14241 "Open...", 14242 "Save...", 14243 "Print...", 14244 "Undo", 14245 "Restore", 14246 "Image Info", 14247 "Quit", 14248 (char *) NULL 14249 }, 14250 *VirtualMenu[] = 14251 { 14252 "Image Info", 14253 "Print", 14254 "Next", 14255 "Quit", 14256 (char *) NULL 14257 }; 14258 14259 static const char 14260 **Menus[MagickMenus] = 14261 { 14262 FileMenu, 14263 EditMenu, 14264 ViewMenu, 14265 TransformMenu, 14266 EnhanceMenu, 14267 EffectsMenu, 14268 FXMenu, 14269 ImageEditMenu, 14270 MiscellanyMenu, 14271 HelpMenu 14272 }; 14273 14274 static CommandType 14275 CommandMenus[] = 14276 { 14277 NullCommand, 14278 NullCommand, 14279 NullCommand, 14280 NullCommand, 14281 NullCommand, 14282 NullCommand, 14283 NullCommand, 14284 NullCommand, 14285 NullCommand, 14286 NullCommand, 14287 }, 14288 FileCommands[] = 14289 { 14290 OpenCommand, 14291 NextCommand, 14292 FormerCommand, 14293 SelectCommand, 14294 SaveCommand, 14295 PrintCommand, 14296 DeleteCommand, 14297 NewCommand, 14298 VisualDirectoryCommand, 14299 QuitCommand 14300 }, 14301 EditCommands[] = 14302 { 14303 UndoCommand, 14304 RedoCommand, 14305 CutCommand, 14306 CopyCommand, 14307 PasteCommand 14308 }, 14309 ViewCommands[] = 14310 { 14311 HalfSizeCommand, 14312 OriginalSizeCommand, 14313 DoubleSizeCommand, 14314 ResizeCommand, 14315 ApplyCommand, 14316 RefreshCommand, 14317 RestoreCommand 14318 }, 14319 TransformCommands[] = 14320 { 14321 CropCommand, 14322 ChopCommand, 14323 FlopCommand, 14324 FlipCommand, 14325 RotateRightCommand, 14326 RotateLeftCommand, 14327 RotateCommand, 14328 ShearCommand, 14329 RollCommand, 14330 TrimCommand 14331 }, 14332 EnhanceCommands[] = 14333 { 14334 HueCommand, 14335 SaturationCommand, 14336 BrightnessCommand, 14337 GammaCommand, 14338 SpiffCommand, 14339 DullCommand, 14340 ContrastStretchCommand, 14341 SigmoidalContrastCommand, 14342 NormalizeCommand, 14343 EqualizeCommand, 14344 NegateCommand, 14345 GrayscaleCommand, 14346 MapCommand, 14347 QuantizeCommand 14348 }, 14349 EffectsCommands[] = 14350 { 14351 DespeckleCommand, 14352 EmbossCommand, 14353 ReduceNoiseCommand, 14354 AddNoiseCommand, 14355 SharpenCommand, 14356 BlurCommand, 14357 ThresholdCommand, 14358 EdgeDetectCommand, 14359 SpreadCommand, 14360 ShadeCommand, 14361 RaiseCommand, 14362 SegmentCommand 14363 }, 14364 FXCommands[] = 14365 { 14366 SolarizeCommand, 14367 SepiaToneCommand, 14368 SwirlCommand, 14369 ImplodeCommand, 14370 VignetteCommand, 14371 WaveCommand, 14372 OilPaintCommand, 14373 CharcoalDrawCommand 14374 }, 14375 ImageEditCommands[] = 14376 { 14377 AnnotateCommand, 14378 DrawCommand, 14379 ColorCommand, 14380 MatteCommand, 14381 CompositeCommand, 14382 AddBorderCommand, 14383 AddFrameCommand, 14384 CommentCommand, 14385 LaunchCommand, 14386 RegionofInterestCommand 14387 }, 14388 MiscellanyCommands[] = 14389 { 14390 InfoCommand, 14391 ZoomCommand, 14392 ShowPreviewCommand, 14393 ShowHistogramCommand, 14394 ShowMatteCommand, 14395 BackgroundCommand, 14396 SlideShowCommand, 14397 PreferencesCommand 14398 }, 14399 HelpCommands[] = 14400 { 14401 HelpCommand, 14402 BrowseDocumentationCommand, 14403 VersionCommand 14404 }, 14405 ShortCutsCommands[] = 14406 { 14407 NextCommand, 14408 FormerCommand, 14409 OpenCommand, 14410 SaveCommand, 14411 PrintCommand, 14412 UndoCommand, 14413 RestoreCommand, 14414 InfoCommand, 14415 QuitCommand 14416 }, 14417 VirtualCommands[] = 14418 { 14419 InfoCommand, 14420 PrintCommand, 14421 NextCommand, 14422 QuitCommand 14423 }; 14424 14425 static CommandType 14426 *Commands[MagickMenus] = 14427 { 14428 FileCommands, 14429 EditCommands, 14430 ViewCommands, 14431 TransformCommands, 14432 EnhanceCommands, 14433 EffectsCommands, 14434 FXCommands, 14435 ImageEditCommands, 14436 MiscellanyCommands, 14437 HelpCommands 14438 }; 14439 14440 char 14441 command[MaxTextExtent], 14442 *directory, 14443 geometry[MaxTextExtent], 14444 resource_name[MaxTextExtent]; 14445 14446 CommandType 14447 command_type; 14448 14449 Image 14450 *display_image, 14451 *nexus; 14452 14453 int 14454 entry, 14455 id; 14456 14457 KeySym 14458 key_symbol; 14459 14460 MagickStatusType 14461 context_mask, 14462 status; 14463 14464 RectangleInfo 14465 geometry_info; 14466 14467 register int 14468 i; 14469 14470 static char 14471 working_directory[MaxTextExtent]; 14472 14473 static XPoint 14474 vid_info; 14475 14476 static XWindowInfo 14477 *magick_windows[MaxXWindows]; 14478 14479 static unsigned int 14480 number_windows; 14481 14482 struct stat 14483 attributes; 14484 14485 time_t 14486 timer, 14487 timestamp, 14488 update_time; 14489 14490 unsigned int 14491 height, 14492 width; 14493 14494 size_t 14495 delay; 14496 14497 WarningHandler 14498 warning_handler; 14499 14500 Window 14501 root_window; 14502 14503 XClassHint 14504 *class_hints; 14505 14506 XEvent 14507 event; 14508 14509 XFontStruct 14510 *font_info; 14511 14512 XGCValues 14513 context_values; 14514 14515 XPixelInfo 14516 *icon_pixel, 14517 *pixel; 14518 14519 XResourceInfo 14520 *icon_resources; 14521 14522 XStandardColormap 14523 *icon_map, 14524 *map_info; 14525 14526 XVisualInfo 14527 *icon_visual, 14528 *visual_info; 14529 14530 XWindowChanges 14531 window_changes; 14532 14533 XWindows 14534 *windows; 14535 14536 XWMHints 14537 *manager_hints; 14538 14539 assert(image != (Image **) NULL); 14540 assert((*image)->signature == MagickSignature); 14541 if ((*image)->debug != MagickFalse) 14542 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 14543 display_image=(*image); 14544 warning_handler=(WarningHandler) NULL; 14545 windows=XSetWindows((XWindows *) ~0); 14546 if (windows != (XWindows *) NULL) 14547 { 14548 int 14549 status; 14550 14551 status=chdir(working_directory); 14552 if (status == -1) 14553 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 14554 "UnableToOpenFile","%s",working_directory); 14555 warning_handler=resource_info->display_warnings ? 14556 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14557 warning_handler=resource_info->display_warnings ? 14558 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14559 } 14560 else 14561 { 14562 /* 14563 Allocate windows structure. 14564 */ 14565 resource_info->colors=display_image->colors; 14566 windows=XSetWindows(XInitializeWindows(display,resource_info)); 14567 if (windows == (XWindows *) NULL) 14568 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow", 14569 (*image)->filename); 14570 /* 14571 Initialize window id's. 14572 */ 14573 number_windows=0; 14574 magick_windows[number_windows++]=(&windows->icon); 14575 magick_windows[number_windows++]=(&windows->backdrop); 14576 magick_windows[number_windows++]=(&windows->image); 14577 magick_windows[number_windows++]=(&windows->info); 14578 magick_windows[number_windows++]=(&windows->command); 14579 magick_windows[number_windows++]=(&windows->widget); 14580 magick_windows[number_windows++]=(&windows->popup); 14581 magick_windows[number_windows++]=(&windows->magnify); 14582 magick_windows[number_windows++]=(&windows->pan); 14583 for (i=0; i < (int) number_windows; i++) 14584 magick_windows[i]->id=(Window) NULL; 14585 vid_info.x=0; 14586 vid_info.y=0; 14587 } 14588 /* 14589 Initialize font info. 14590 */ 14591 if (windows->font_info != (XFontStruct *) NULL) 14592 (void) XFreeFont(display,windows->font_info); 14593 windows->font_info=XBestFont(display,resource_info,MagickFalse); 14594 if (windows->font_info == (XFontStruct *) NULL) 14595 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", 14596 resource_info->font); 14597 /* 14598 Initialize Standard Colormap. 14599 */ 14600 map_info=windows->map_info; 14601 icon_map=windows->icon_map; 14602 visual_info=windows->visual_info; 14603 icon_visual=windows->icon_visual; 14604 pixel=windows->pixel_info; 14605 icon_pixel=windows->icon_pixel; 14606 font_info=windows->font_info; 14607 icon_resources=windows->icon_resources; 14608 class_hints=windows->class_hints; 14609 manager_hints=windows->manager_hints; 14610 root_window=XRootWindow(display,visual_info->screen); 14611 nexus=NewImageList(); 14612 if (display_image->debug != MagickFalse) 14613 { 14614 (void) LogMagickEvent(X11Event,GetMagickModule(), 14615 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename, 14616 (double) display_image->scene,(double) display_image->columns, 14617 (double) display_image->rows); 14618 if (display_image->colors != 0) 14619 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 14620 display_image->colors); 14621 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", 14622 display_image->magick); 14623 } 14624 XMakeStandardColormap(display,visual_info,resource_info,display_image, 14625 map_info,pixel,exception); 14626 display_image->taint=MagickFalse; 14627 /* 14628 Initialize graphic context. 14629 */ 14630 windows->context.id=(Window) NULL; 14631 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14632 resource_info,&windows->context); 14633 (void) CloneString(&class_hints->res_name,resource_info->client_name); 14634 (void) CloneString(&class_hints->res_class,resource_info->client_name); 14635 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]); 14636 manager_hints->flags=InputHint | StateHint; 14637 manager_hints->input=MagickFalse; 14638 manager_hints->initial_state=WithdrawnState; 14639 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14640 &windows->context); 14641 if (display_image->debug != MagickFalse) 14642 (void) LogMagickEvent(X11Event,GetMagickModule(), 14643 "Window id: 0x%lx (context)",windows->context.id); 14644 context_values.background=pixel->background_color.pixel; 14645 context_values.font=font_info->fid; 14646 context_values.foreground=pixel->foreground_color.pixel; 14647 context_values.graphics_exposures=MagickFalse; 14648 context_mask=(MagickStatusType) 14649 (GCBackground | GCFont | GCForeground | GCGraphicsExposures); 14650 if (pixel->annotate_context != (GC) NULL) 14651 (void) XFreeGC(display,pixel->annotate_context); 14652 pixel->annotate_context=XCreateGC(display,windows->context.id, 14653 context_mask,&context_values); 14654 if (pixel->annotate_context == (GC) NULL) 14655 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14656 display_image->filename); 14657 context_values.background=pixel->depth_color.pixel; 14658 if (pixel->widget_context != (GC) NULL) 14659 (void) XFreeGC(display,pixel->widget_context); 14660 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask, 14661 &context_values); 14662 if (pixel->widget_context == (GC) NULL) 14663 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14664 display_image->filename); 14665 context_values.background=pixel->foreground_color.pixel; 14666 context_values.foreground=pixel->background_color.pixel; 14667 context_values.plane_mask=context_values.background ^ 14668 context_values.foreground; 14669 if (pixel->highlight_context != (GC) NULL) 14670 (void) XFreeGC(display,pixel->highlight_context); 14671 pixel->highlight_context=XCreateGC(display,windows->context.id, 14672 (size_t) (context_mask | GCPlaneMask),&context_values); 14673 if (pixel->highlight_context == (GC) NULL) 14674 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14675 display_image->filename); 14676 (void) XDestroyWindow(display,windows->context.id); 14677 /* 14678 Initialize icon window. 14679 */ 14680 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, 14681 icon_resources,&windows->icon); 14682 windows->icon.geometry=resource_info->icon_geometry; 14683 XBestIconSize(display,&windows->icon,display_image); 14684 windows->icon.attributes.colormap=XDefaultColormap(display, 14685 icon_visual->screen); 14686 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; 14687 manager_hints->flags=InputHint | StateHint; 14688 manager_hints->input=MagickFalse; 14689 manager_hints->initial_state=IconicState; 14690 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14691 &windows->icon); 14692 if (display_image->debug != MagickFalse) 14693 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", 14694 windows->icon.id); 14695 /* 14696 Initialize graphic context for icon window. 14697 */ 14698 if (icon_pixel->annotate_context != (GC) NULL) 14699 (void) XFreeGC(display,icon_pixel->annotate_context); 14700 context_values.background=icon_pixel->background_color.pixel; 14701 context_values.foreground=icon_pixel->foreground_color.pixel; 14702 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, 14703 (size_t) (GCBackground | GCForeground),&context_values); 14704 if (icon_pixel->annotate_context == (GC) NULL) 14705 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14706 display_image->filename); 14707 windows->icon.annotate_context=icon_pixel->annotate_context; 14708 /* 14709 Initialize Image window. 14710 */ 14711 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14712 &windows->image); 14713 windows->image.shape=MagickTrue; /* non-rectangular shape hint */ 14714 if (resource_info->use_shared_memory == MagickFalse) 14715 windows->image.shared_memory=MagickFalse; 14716 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState)) 14717 { 14718 char 14719 *title; 14720 14721 title=InterpretImageProperties(resource_info->image_info,display_image, 14722 resource_info->title,exception); 14723 (void) CopyMagickString(windows->image.name,title,MaxTextExtent); 14724 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent); 14725 title=DestroyString(title); 14726 } 14727 else 14728 { 14729 char 14730 filename[MaxTextExtent]; 14731 14732 /* 14733 Window name is the base of the filename. 14734 */ 14735 GetPathComponent(display_image->magick_filename,TailPath,filename); 14736 if (display_image->scene == 0) 14737 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14738 "%s: %s",MagickPackageName,filename); 14739 else 14740 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14741 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename, 14742 (double) display_image->scene,(double) GetImageListLength( 14743 display_image)); 14744 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent); 14745 } 14746 if (resource_info->immutable) 14747 windows->image.immutable=MagickTrue; 14748 windows->image.use_pixmap=resource_info->use_pixmap; 14749 windows->image.geometry=resource_info->image_geometry; 14750 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 14751 XDisplayWidth(display,visual_info->screen), 14752 XDisplayHeight(display,visual_info->screen)); 14753 geometry_info.width=display_image->columns; 14754 geometry_info.height=display_image->rows; 14755 geometry_info.x=0; 14756 geometry_info.y=0; 14757 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 14758 &geometry_info.width,&geometry_info.height); 14759 windows->image.width=(unsigned int) geometry_info.width; 14760 windows->image.height=(unsigned int) geometry_info.height; 14761 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14762 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14763 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14764 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; 14765 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14766 resource_info,&windows->backdrop); 14767 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) 14768 { 14769 /* 14770 Initialize backdrop window. 14771 */ 14772 windows->backdrop.x=0; 14773 windows->backdrop.y=0; 14774 (void) CloneString(&windows->backdrop.name,"Backdrop"); 14775 windows->backdrop.flags=(size_t) (USSize | USPosition); 14776 windows->backdrop.width=(unsigned int) 14777 XDisplayWidth(display,visual_info->screen); 14778 windows->backdrop.height=(unsigned int) 14779 XDisplayHeight(display,visual_info->screen); 14780 windows->backdrop.border_width=0; 14781 windows->backdrop.immutable=MagickTrue; 14782 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | 14783 ButtonReleaseMask; 14784 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | 14785 StructureNotifyMask; 14786 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14787 manager_hints->icon_window=windows->icon.id; 14788 manager_hints->input=MagickTrue; 14789 manager_hints->initial_state=resource_info->iconic ? IconicState : 14790 NormalState; 14791 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14792 &windows->backdrop); 14793 if (display_image->debug != MagickFalse) 14794 (void) LogMagickEvent(X11Event,GetMagickModule(), 14795 "Window id: 0x%lx (backdrop)",windows->backdrop.id); 14796 (void) XMapWindow(display,windows->backdrop.id); 14797 (void) XClearWindow(display,windows->backdrop.id); 14798 if (windows->image.id != (Window) NULL) 14799 { 14800 (void) XDestroyWindow(display,windows->image.id); 14801 windows->image.id=(Window) NULL; 14802 } 14803 /* 14804 Position image in the center the backdrop. 14805 */ 14806 windows->image.flags|=USPosition; 14807 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- 14808 (windows->image.width/2); 14809 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- 14810 (windows->image.height/2); 14811 } 14812 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14813 manager_hints->icon_window=windows->icon.id; 14814 manager_hints->input=MagickTrue; 14815 manager_hints->initial_state=resource_info->iconic ? IconicState : 14816 NormalState; 14817 if (windows->group_leader.id != (Window) NULL) 14818 { 14819 /* 14820 Follow the leader. 14821 */ 14822 manager_hints->flags|=WindowGroupHint; 14823 manager_hints->window_group=windows->group_leader.id; 14824 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); 14825 if (display_image->debug != MagickFalse) 14826 (void) LogMagickEvent(X11Event,GetMagickModule(), 14827 "Window id: 0x%lx (group leader)",windows->group_leader.id); 14828 } 14829 XMakeWindow(display, 14830 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), 14831 argv,argc,class_hints,manager_hints,&windows->image); 14832 (void) XChangeProperty(display,windows->image.id,windows->im_protocols, 14833 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); 14834 if (windows->group_leader.id != (Window) NULL) 14835 (void) XSetTransientForHint(display,windows->image.id, 14836 windows->group_leader.id); 14837 if (display_image->debug != MagickFalse) 14838 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", 14839 windows->image.id); 14840 /* 14841 Initialize Info widget. 14842 */ 14843 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14844 &windows->info); 14845 (void) CloneString(&windows->info.name,"Info"); 14846 (void) CloneString(&windows->info.icon_name,"Info"); 14847 windows->info.border_width=1; 14848 windows->info.x=2; 14849 windows->info.y=2; 14850 windows->info.flags|=PPosition; 14851 windows->info.attributes.win_gravity=UnmapGravity; 14852 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | 14853 StructureNotifyMask; 14854 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14855 manager_hints->input=MagickFalse; 14856 manager_hints->initial_state=NormalState; 14857 manager_hints->window_group=windows->image.id; 14858 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, 14859 &windows->info); 14860 windows->info.highlight_stipple=XCreateBitmapFromData(display, 14861 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14862 windows->info.shadow_stipple=XCreateBitmapFromData(display, 14863 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14864 (void) XSetTransientForHint(display,windows->info.id,windows->image.id); 14865 if (windows->image.mapped != MagickFalse) 14866 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14867 if (display_image->debug != MagickFalse) 14868 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", 14869 windows->info.id); 14870 /* 14871 Initialize Command widget. 14872 */ 14873 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14874 resource_info,&windows->command); 14875 windows->command.data=MagickMenus; 14876 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); 14877 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command", 14878 resource_info->client_name); 14879 windows->command.geometry=XGetResourceClass(resource_info->resource_database, 14880 resource_name,"geometry",(char *) NULL); 14881 (void) CloneString(&windows->command.name,MagickTitle); 14882 windows->command.border_width=0; 14883 windows->command.flags|=PPosition; 14884 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14885 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | 14886 OwnerGrabButtonMask | StructureNotifyMask; 14887 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14888 manager_hints->input=MagickTrue; 14889 manager_hints->initial_state=NormalState; 14890 manager_hints->window_group=windows->image.id; 14891 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14892 &windows->command); 14893 windows->command.highlight_stipple=XCreateBitmapFromData(display, 14894 windows->command.id,(char *) HighlightBitmap,HighlightWidth, 14895 HighlightHeight); 14896 windows->command.shadow_stipple=XCreateBitmapFromData(display, 14897 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14898 (void) XSetTransientForHint(display,windows->command.id,windows->image.id); 14899 if (windows->command.mapped != MagickFalse) 14900 (void) XMapRaised(display,windows->command.id); 14901 if (display_image->debug != MagickFalse) 14902 (void) LogMagickEvent(X11Event,GetMagickModule(), 14903 "Window id: 0x%lx (command)",windows->command.id); 14904 /* 14905 Initialize Widget window. 14906 */ 14907 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14908 resource_info,&windows->widget); 14909 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget", 14910 resource_info->client_name); 14911 windows->widget.geometry=XGetResourceClass(resource_info->resource_database, 14912 resource_name,"geometry",(char *) NULL); 14913 windows->widget.border_width=0; 14914 windows->widget.flags|=PPosition; 14915 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14916 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14917 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14918 StructureNotifyMask; 14919 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14920 manager_hints->input=MagickTrue; 14921 manager_hints->initial_state=NormalState; 14922 manager_hints->window_group=windows->image.id; 14923 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14924 &windows->widget); 14925 windows->widget.highlight_stipple=XCreateBitmapFromData(display, 14926 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14927 windows->widget.shadow_stipple=XCreateBitmapFromData(display, 14928 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14929 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); 14930 if (display_image->debug != MagickFalse) 14931 (void) LogMagickEvent(X11Event,GetMagickModule(), 14932 "Window id: 0x%lx (widget)",windows->widget.id); 14933 /* 14934 Initialize popup window. 14935 */ 14936 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14937 resource_info,&windows->popup); 14938 windows->popup.border_width=0; 14939 windows->popup.flags|=PPosition; 14940 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14941 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14942 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask; 14943 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14944 manager_hints->input=MagickTrue; 14945 manager_hints->initial_state=NormalState; 14946 manager_hints->window_group=windows->image.id; 14947 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14948 &windows->popup); 14949 windows->popup.highlight_stipple=XCreateBitmapFromData(display, 14950 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14951 windows->popup.shadow_stipple=XCreateBitmapFromData(display, 14952 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14953 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); 14954 if (display_image->debug != MagickFalse) 14955 (void) LogMagickEvent(X11Event,GetMagickModule(), 14956 "Window id: 0x%lx (pop up)",windows->popup.id); 14957 /* 14958 Initialize Magnify window and cursor. 14959 */ 14960 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14961 resource_info,&windows->magnify); 14962 if (resource_info->use_shared_memory == MagickFalse) 14963 windows->magnify.shared_memory=MagickFalse; 14964 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify", 14965 resource_info->client_name); 14966 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database, 14967 resource_name,"geometry",(char *) NULL); 14968 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX", 14969 resource_info->magnify); 14970 if (windows->magnify.cursor != (Cursor) NULL) 14971 (void) XFreeCursor(display,windows->magnify.cursor); 14972 windows->magnify.cursor=XMakeCursor(display,windows->image.id, 14973 map_info->colormap,resource_info->background_color, 14974 resource_info->foreground_color); 14975 if (windows->magnify.cursor == (Cursor) NULL) 14976 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor", 14977 display_image->filename); 14978 windows->magnify.width=MagnifySize; 14979 windows->magnify.height=MagnifySize; 14980 windows->magnify.flags|=PPosition; 14981 windows->magnify.min_width=MagnifySize; 14982 windows->magnify.min_height=MagnifySize; 14983 windows->magnify.width_inc=MagnifySize; 14984 windows->magnify.height_inc=MagnifySize; 14985 windows->magnify.data=resource_info->magnify; 14986 windows->magnify.attributes.cursor=windows->magnify.cursor; 14987 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask | 14988 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask | 14989 StructureNotifyMask; 14990 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14991 manager_hints->input=MagickTrue; 14992 manager_hints->initial_state=NormalState; 14993 manager_hints->window_group=windows->image.id; 14994 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14995 &windows->magnify); 14996 if (display_image->debug != MagickFalse) 14997 (void) LogMagickEvent(X11Event,GetMagickModule(), 14998 "Window id: 0x%lx (magnify)",windows->magnify.id); 14999 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id); 15000 /* 15001 Initialize panning window. 15002 */ 15003 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 15004 resource_info,&windows->pan); 15005 (void) CloneString(&windows->pan.name,"Pan Icon"); 15006 windows->pan.width=windows->icon.width; 15007 windows->pan.height=windows->icon.height; 15008 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan", 15009 resource_info->client_name); 15010 windows->pan.geometry=XGetResourceClass(resource_info->resource_database, 15011 resource_name,"geometry",(char *) NULL); 15012 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 15013 &windows->pan.width,&windows->pan.height); 15014 windows->pan.flags|=PPosition; 15015 windows->pan.immutable=MagickTrue; 15016 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 15017 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask | 15018 StructureNotifyMask; 15019 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 15020 manager_hints->input=MagickFalse; 15021 manager_hints->initial_state=NormalState; 15022 manager_hints->window_group=windows->image.id; 15023 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 15024 &windows->pan); 15025 if (display_image->debug != MagickFalse) 15026 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)", 15027 windows->pan.id); 15028 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id); 15029 if (windows->info.mapped != MagickFalse) 15030 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15031 if ((windows->image.mapped == MagickFalse) || 15032 (windows->backdrop.id != (Window) NULL)) 15033 (void) XMapWindow(display,windows->image.id); 15034 /* 15035 Set our progress monitor and warning handlers. 15036 */ 15037 if (warning_handler == (WarningHandler) NULL) 15038 { 15039 warning_handler=resource_info->display_warnings ? 15040 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 15041 warning_handler=resource_info->display_warnings ? 15042 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 15043 } 15044 /* 15045 Initialize Image and Magnify X images. 15046 */ 15047 windows->image.x=0; 15048 windows->image.y=0; 15049 windows->magnify.shape=MagickFalse; 15050 width=(unsigned int) display_image->columns; 15051 height=(unsigned int) display_image->rows; 15052 if ((display_image->columns != width) || (display_image->rows != height)) 15053 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15054 display_image->filename); 15055 status=XMakeImage(display,resource_info,&windows->image,display_image, 15056 width,height,exception); 15057 if (status == MagickFalse) 15058 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15059 display_image->filename); 15060 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL, 15061 windows->magnify.width,windows->magnify.height,exception); 15062 if (status == MagickFalse) 15063 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15064 display_image->filename); 15065 if (windows->magnify.mapped != MagickFalse) 15066 (void) XMapRaised(display,windows->magnify.id); 15067 if (windows->pan.mapped != MagickFalse) 15068 (void) XMapRaised(display,windows->pan.id); 15069 windows->image.window_changes.width=(int) display_image->columns; 15070 windows->image.window_changes.height=(int) display_image->rows; 15071 (void) XConfigureImage(display,resource_info,windows,display_image,exception); 15072 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15073 (void) XSync(display,MagickFalse); 15074 /* 15075 Respond to events. 15076 */ 15077 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L); 15078 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15079 update_time=0; 15080 if (resource_info->update != MagickFalse) 15081 { 15082 MagickBooleanType 15083 status; 15084 15085 /* 15086 Determine when file data was last modified. 15087 */ 15088 status=GetPathAttributes(display_image->filename,&attributes); 15089 if (status != MagickFalse) 15090 update_time=attributes.st_mtime; 15091 } 15092 *state&=(~FormerImageState); 15093 *state&=(~MontageImageState); 15094 *state&=(~NextImageState); 15095 do 15096 { 15097 /* 15098 Handle a window event. 15099 */ 15100 if (windows->image.mapped != MagickFalse) 15101 if ((display_image->delay != 0) || (resource_info->update != 0)) 15102 { 15103 if (timer < time((time_t *) NULL)) 15104 { 15105 if (resource_info->update == MagickFalse) 15106 *state|=NextImageState | ExitState; 15107 else 15108 { 15109 MagickBooleanType 15110 status; 15111 15112 /* 15113 Determine if image file was modified. 15114 */ 15115 status=GetPathAttributes(display_image->filename,&attributes); 15116 if (status != MagickFalse) 15117 if (update_time != attributes.st_mtime) 15118 { 15119 /* 15120 Redisplay image. 15121 */ 15122 (void) FormatLocaleString( 15123 resource_info->image_info->filename,MaxTextExtent, 15124 "%s:%s",display_image->magick, 15125 display_image->filename); 15126 nexus=ReadImage(resource_info->image_info,exception); 15127 if (nexus != (Image *) NULL) 15128 { 15129 nexus=DestroyImage(nexus); 15130 *state|=NextImageState | ExitState; 15131 } 15132 } 15133 delay=display_image->delay/MagickMax( 15134 display_image->ticks_per_second,1L); 15135 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15136 } 15137 } 15138 if (XEventsQueued(display,QueuedAfterFlush) == 0) 15139 { 15140 /* 15141 Do not block if delay > 0. 15142 */ 15143 XDelay(display,SuspendTime << 2); 15144 continue; 15145 } 15146 } 15147 timestamp=time((time_t *) NULL); 15148 (void) XNextEvent(display,&event); 15149 if (windows->image.stasis == MagickFalse) 15150 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15151 MagickTrue : MagickFalse; 15152 if (windows->magnify.stasis == MagickFalse) 15153 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15154 MagickTrue : MagickFalse; 15155 if (event.xany.window == windows->command.id) 15156 { 15157 /* 15158 Select a command from the Command widget. 15159 */ 15160 id=XCommandWidget(display,windows,CommandMenu,&event); 15161 if (id < 0) 15162 continue; 15163 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent); 15164 command_type=CommandMenus[id]; 15165 if (id < MagickMenus) 15166 { 15167 /* 15168 Select a command from a pop-up menu. 15169 */ 15170 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15171 command); 15172 if (entry < 0) 15173 continue; 15174 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent); 15175 command_type=Commands[id][entry]; 15176 } 15177 if (command_type != NullCommand) 15178 nexus=XMagickCommand(display,resource_info,windows,command_type, 15179 &display_image,exception); 15180 continue; 15181 } 15182 switch (event.type) 15183 { 15184 case ButtonPress: 15185 { 15186 if (display_image->debug != MagickFalse) 15187 (void) LogMagickEvent(X11Event,GetMagickModule(), 15188 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15189 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15190 if ((event.xbutton.button == Button3) && 15191 (event.xbutton.state & Mod1Mask)) 15192 { 15193 /* 15194 Convert Alt-Button3 to Button2. 15195 */ 15196 event.xbutton.button=Button2; 15197 event.xbutton.state&=(~Mod1Mask); 15198 } 15199 if (event.xbutton.window == windows->backdrop.id) 15200 { 15201 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15202 event.xbutton.time); 15203 break; 15204 } 15205 if (event.xbutton.window == windows->image.id) 15206 { 15207 switch (event.xbutton.button) 15208 { 15209 case Button1: 15210 { 15211 if (resource_info->immutable) 15212 { 15213 /* 15214 Select a command from the Virtual menu. 15215 */ 15216 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15217 command); 15218 if (entry >= 0) 15219 nexus=XMagickCommand(display,resource_info,windows, 15220 VirtualCommands[entry],&display_image,exception); 15221 break; 15222 } 15223 /* 15224 Map/unmap Command widget. 15225 */ 15226 if (windows->command.mapped != MagickFalse) 15227 (void) XWithdrawWindow(display,windows->command.id, 15228 windows->command.screen); 15229 else 15230 { 15231 (void) XCommandWidget(display,windows,CommandMenu, 15232 (XEvent *) NULL); 15233 (void) XMapRaised(display,windows->command.id); 15234 } 15235 break; 15236 } 15237 case Button2: 15238 { 15239 /* 15240 User pressed the image magnify button. 15241 */ 15242 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15243 &display_image,exception); 15244 XMagnifyImage(display,windows,&event,exception); 15245 break; 15246 } 15247 case Button3: 15248 { 15249 if (resource_info->immutable) 15250 { 15251 /* 15252 Select a command from the Virtual menu. 15253 */ 15254 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15255 command); 15256 if (entry >= 0) 15257 nexus=XMagickCommand(display,resource_info,windows, 15258 VirtualCommands[entry],&display_image,exception); 15259 break; 15260 } 15261 if (display_image->montage != (char *) NULL) 15262 { 15263 /* 15264 Open or delete a tile from a visual image directory. 15265 */ 15266 nexus=XTileImage(display,resource_info,windows, 15267 display_image,&event,exception); 15268 if (nexus != (Image *) NULL) 15269 *state|=MontageImageState | NextImageState | ExitState; 15270 vid_info.x=(short int) windows->image.x; 15271 vid_info.y=(short int) windows->image.y; 15272 break; 15273 } 15274 /* 15275 Select a command from the Short Cuts menu. 15276 */ 15277 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15278 command); 15279 if (entry >= 0) 15280 nexus=XMagickCommand(display,resource_info,windows, 15281 ShortCutsCommands[entry],&display_image,exception); 15282 break; 15283 } 15284 case Button4: 15285 { 15286 /* 15287 Wheel up. 15288 */ 15289 XTranslateImage(display,windows,*image,XK_Up); 15290 break; 15291 } 15292 case Button5: 15293 { 15294 /* 15295 Wheel down. 15296 */ 15297 XTranslateImage(display,windows,*image,XK_Down); 15298 break; 15299 } 15300 default: 15301 break; 15302 } 15303 break; 15304 } 15305 if (event.xbutton.window == windows->magnify.id) 15306 { 15307 int 15308 factor; 15309 15310 static const char 15311 *MagnifyMenu[] = 15312 { 15313 "2", 15314 "4", 15315 "5", 15316 "6", 15317 "7", 15318 "8", 15319 "9", 15320 "3", 15321 (char *) NULL, 15322 }; 15323 15324 static KeySym 15325 MagnifyCommands[] = 15326 { 15327 XK_2, 15328 XK_4, 15329 XK_5, 15330 XK_6, 15331 XK_7, 15332 XK_8, 15333 XK_9, 15334 XK_3 15335 }; 15336 15337 /* 15338 Select a magnify factor from the pop-up menu. 15339 */ 15340 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15341 if (factor >= 0) 15342 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor], 15343 exception); 15344 break; 15345 } 15346 if (event.xbutton.window == windows->pan.id) 15347 { 15348 switch (event.xbutton.button) 15349 { 15350 case Button4: 15351 { 15352 /* 15353 Wheel up. 15354 */ 15355 XTranslateImage(display,windows,*image,XK_Up); 15356 break; 15357 } 15358 case Button5: 15359 { 15360 /* 15361 Wheel down. 15362 */ 15363 XTranslateImage(display,windows,*image,XK_Down); 15364 break; 15365 } 15366 default: 15367 { 15368 XPanImage(display,windows,&event,exception); 15369 break; 15370 } 15371 } 15372 break; 15373 } 15374 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15375 1L); 15376 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15377 break; 15378 } 15379 case ButtonRelease: 15380 { 15381 if (display_image->debug != MagickFalse) 15382 (void) LogMagickEvent(X11Event,GetMagickModule(), 15383 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15384 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15385 break; 15386 } 15387 case ClientMessage: 15388 { 15389 if (display_image->debug != MagickFalse) 15390 (void) LogMagickEvent(X11Event,GetMagickModule(), 15391 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15392 event.xclient.message_type,event.xclient.format,(unsigned long) 15393 event.xclient.data.l[0]); 15394 if (event.xclient.message_type == windows->im_protocols) 15395 { 15396 if (*event.xclient.data.l == (long) windows->im_update_widget) 15397 { 15398 (void) CloneString(&windows->command.name,MagickTitle); 15399 windows->command.data=MagickMenus; 15400 (void) XCommandWidget(display,windows,CommandMenu, 15401 (XEvent *) NULL); 15402 break; 15403 } 15404 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15405 { 15406 /* 15407 Update graphic context and window colormap. 15408 */ 15409 for (i=0; i < (int) number_windows; i++) 15410 { 15411 if (magick_windows[i]->id == windows->icon.id) 15412 continue; 15413 context_values.background=pixel->background_color.pixel; 15414 context_values.foreground=pixel->foreground_color.pixel; 15415 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15416 context_mask,&context_values); 15417 (void) XChangeGC(display,magick_windows[i]->widget_context, 15418 context_mask,&context_values); 15419 context_values.background=pixel->foreground_color.pixel; 15420 context_values.foreground=pixel->background_color.pixel; 15421 context_values.plane_mask=context_values.background ^ 15422 context_values.foreground; 15423 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15424 (size_t) (context_mask | GCPlaneMask), 15425 &context_values); 15426 magick_windows[i]->attributes.background_pixel= 15427 pixel->background_color.pixel; 15428 magick_windows[i]->attributes.border_pixel= 15429 pixel->border_color.pixel; 15430 magick_windows[i]->attributes.colormap=map_info->colormap; 15431 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15432 (unsigned long) magick_windows[i]->mask, 15433 &magick_windows[i]->attributes); 15434 } 15435 if (windows->pan.mapped != MagickFalse) 15436 { 15437 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15438 windows->pan.pixmap); 15439 (void) XClearWindow(display,windows->pan.id); 15440 XDrawPanRectangle(display,windows); 15441 } 15442 if (windows->backdrop.id != (Window) NULL) 15443 (void) XInstallColormap(display,map_info->colormap); 15444 break; 15445 } 15446 if (*event.xclient.data.l == (long) windows->im_former_image) 15447 { 15448 *state|=FormerImageState | ExitState; 15449 break; 15450 } 15451 if (*event.xclient.data.l == (long) windows->im_next_image) 15452 { 15453 *state|=NextImageState | ExitState; 15454 break; 15455 } 15456 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15457 { 15458 *state|=RetainColorsState; 15459 break; 15460 } 15461 if (*event.xclient.data.l == (long) windows->im_exit) 15462 { 15463 *state|=ExitState; 15464 break; 15465 } 15466 break; 15467 } 15468 if (event.xclient.message_type == windows->dnd_protocols) 15469 { 15470 Atom 15471 selection, 15472 type; 15473 15474 int 15475 format, 15476 status; 15477 15478 unsigned char 15479 *data; 15480 15481 unsigned long 15482 after, 15483 length; 15484 15485 /* 15486 Display image named by the Drag-and-Drop selection. 15487 */ 15488 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15489 break; 15490 selection=XInternAtom(display,"DndSelection",MagickFalse); 15491 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15492 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15493 &length,&after,&data); 15494 if ((status != Success) || (length == 0)) 15495 break; 15496 if (*event.xclient.data.l == 2) 15497 { 15498 /* 15499 Offix DND. 15500 */ 15501 (void) CopyMagickString(resource_info->image_info->filename, 15502 (char *) data,MaxTextExtent); 15503 } 15504 else 15505 { 15506 /* 15507 XDND. 15508 */ 15509 if (strncmp((char *) data, "file:", 5) != 0) 15510 { 15511 (void) XFree((void *) data); 15512 break; 15513 } 15514 (void) CopyMagickString(resource_info->image_info->filename, 15515 ((char *) data)+5,MaxTextExtent); 15516 } 15517 nexus=ReadImage(resource_info->image_info,exception); 15518 CatchException(exception); 15519 if (nexus != (Image *) NULL) 15520 *state|=NextImageState | ExitState; 15521 (void) XFree((void *) data); 15522 break; 15523 } 15524 /* 15525 If client window delete message, exit. 15526 */ 15527 if (event.xclient.message_type != windows->wm_protocols) 15528 break; 15529 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15530 break; 15531 (void) XWithdrawWindow(display,event.xclient.window, 15532 visual_info->screen); 15533 if (event.xclient.window == windows->image.id) 15534 { 15535 *state|=ExitState; 15536 break; 15537 } 15538 if (event.xclient.window == windows->pan.id) 15539 { 15540 /* 15541 Restore original image size when pan window is deleted. 15542 */ 15543 windows->image.window_changes.width=windows->image.ximage->width; 15544 windows->image.window_changes.height=windows->image.ximage->height; 15545 (void) XConfigureImage(display,resource_info,windows, 15546 display_image,exception); 15547 } 15548 break; 15549 } 15550 case ConfigureNotify: 15551 { 15552 if (display_image->debug != MagickFalse) 15553 (void) LogMagickEvent(X11Event,GetMagickModule(), 15554 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15555 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15556 event.xconfigure.y,event.xconfigure.send_event); 15557 if (event.xconfigure.window == windows->image.id) 15558 { 15559 /* 15560 Image window has a new configuration. 15561 */ 15562 if (event.xconfigure.send_event != 0) 15563 { 15564 XWindowChanges 15565 window_changes; 15566 15567 /* 15568 Position the transient windows relative of the Image window. 15569 */ 15570 if (windows->command.geometry == (char *) NULL) 15571 if (windows->command.mapped == MagickFalse) 15572 { 15573 windows->command.x=event.xconfigure.x- 15574 windows->command.width-25; 15575 windows->command.y=event.xconfigure.y; 15576 XConstrainWindowPosition(display,&windows->command); 15577 window_changes.x=windows->command.x; 15578 window_changes.y=windows->command.y; 15579 (void) XReconfigureWMWindow(display,windows->command.id, 15580 windows->command.screen,(unsigned int) (CWX | CWY), 15581 &window_changes); 15582 } 15583 if (windows->widget.geometry == (char *) NULL) 15584 if (windows->widget.mapped == MagickFalse) 15585 { 15586 windows->widget.x=event.xconfigure.x+ 15587 event.xconfigure.width/10; 15588 windows->widget.y=event.xconfigure.y+ 15589 event.xconfigure.height/10; 15590 XConstrainWindowPosition(display,&windows->widget); 15591 window_changes.x=windows->widget.x; 15592 window_changes.y=windows->widget.y; 15593 (void) XReconfigureWMWindow(display,windows->widget.id, 15594 windows->widget.screen,(unsigned int) (CWX | CWY), 15595 &window_changes); 15596 } 15597 if (windows->magnify.geometry == (char *) NULL) 15598 if (windows->magnify.mapped == MagickFalse) 15599 { 15600 windows->magnify.x=event.xconfigure.x+ 15601 event.xconfigure.width+25; 15602 windows->magnify.y=event.xconfigure.y; 15603 XConstrainWindowPosition(display,&windows->magnify); 15604 window_changes.x=windows->magnify.x; 15605 window_changes.y=windows->magnify.y; 15606 (void) XReconfigureWMWindow(display,windows->magnify.id, 15607 windows->magnify.screen,(unsigned int) (CWX | CWY), 15608 &window_changes); 15609 } 15610 if (windows->pan.geometry == (char *) NULL) 15611 if (windows->pan.mapped == MagickFalse) 15612 { 15613 windows->pan.x=event.xconfigure.x+ 15614 event.xconfigure.width+25; 15615 windows->pan.y=event.xconfigure.y+ 15616 windows->magnify.height+50; 15617 XConstrainWindowPosition(display,&windows->pan); 15618 window_changes.x=windows->pan.x; 15619 window_changes.y=windows->pan.y; 15620 (void) XReconfigureWMWindow(display,windows->pan.id, 15621 windows->pan.screen,(unsigned int) (CWX | CWY), 15622 &window_changes); 15623 } 15624 } 15625 if ((event.xconfigure.width == (int) windows->image.width) && 15626 (event.xconfigure.height == (int) windows->image.height)) 15627 break; 15628 windows->image.width=(unsigned int) event.xconfigure.width; 15629 windows->image.height=(unsigned int) event.xconfigure.height; 15630 windows->image.x=0; 15631 windows->image.y=0; 15632 if (display_image->montage != (char *) NULL) 15633 { 15634 windows->image.x=vid_info.x; 15635 windows->image.y=vid_info.y; 15636 } 15637 if ((windows->image.mapped != MagickFalse) && 15638 (windows->image.stasis != MagickFalse)) 15639 { 15640 /* 15641 Update image window configuration. 15642 */ 15643 windows->image.window_changes.width=event.xconfigure.width; 15644 windows->image.window_changes.height=event.xconfigure.height; 15645 (void) XConfigureImage(display,resource_info,windows, 15646 display_image,exception); 15647 } 15648 /* 15649 Update pan window configuration. 15650 */ 15651 if ((event.xconfigure.width < windows->image.ximage->width) || 15652 (event.xconfigure.height < windows->image.ximage->height)) 15653 { 15654 (void) XMapRaised(display,windows->pan.id); 15655 XDrawPanRectangle(display,windows); 15656 } 15657 else 15658 if (windows->pan.mapped != MagickFalse) 15659 (void) XWithdrawWindow(display,windows->pan.id, 15660 windows->pan.screen); 15661 break; 15662 } 15663 if (event.xconfigure.window == windows->magnify.id) 15664 { 15665 unsigned int 15666 magnify; 15667 15668 /* 15669 Magnify window has a new configuration. 15670 */ 15671 windows->magnify.width=(unsigned int) event.xconfigure.width; 15672 windows->magnify.height=(unsigned int) event.xconfigure.height; 15673 if (windows->magnify.mapped == MagickFalse) 15674 break; 15675 magnify=1; 15676 while ((int) magnify <= event.xconfigure.width) 15677 magnify<<=1; 15678 while ((int) magnify <= event.xconfigure.height) 15679 magnify<<=1; 15680 magnify>>=1; 15681 if (((int) magnify != event.xconfigure.width) || 15682 ((int) magnify != event.xconfigure.height)) 15683 { 15684 window_changes.width=(int) magnify; 15685 window_changes.height=(int) magnify; 15686 (void) XReconfigureWMWindow(display,windows->magnify.id, 15687 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15688 &window_changes); 15689 break; 15690 } 15691 if ((windows->magnify.mapped != MagickFalse) && 15692 (windows->magnify.stasis != MagickFalse)) 15693 { 15694 status=XMakeImage(display,resource_info,&windows->magnify, 15695 display_image,windows->magnify.width,windows->magnify.height, 15696 exception); 15697 XMakeMagnifyImage(display,windows,exception); 15698 } 15699 break; 15700 } 15701 if ((windows->magnify.mapped != MagickFalse) && 15702 (event.xconfigure.window == windows->pan.id)) 15703 { 15704 /* 15705 Pan icon window has a new configuration. 15706 */ 15707 if (event.xconfigure.send_event != 0) 15708 { 15709 windows->pan.x=event.xconfigure.x; 15710 windows->pan.y=event.xconfigure.y; 15711 } 15712 windows->pan.width=(unsigned int) event.xconfigure.width; 15713 windows->pan.height=(unsigned int) event.xconfigure.height; 15714 break; 15715 } 15716 if (event.xconfigure.window == windows->icon.id) 15717 { 15718 /* 15719 Icon window has a new configuration. 15720 */ 15721 windows->icon.width=(unsigned int) event.xconfigure.width; 15722 windows->icon.height=(unsigned int) event.xconfigure.height; 15723 break; 15724 } 15725 break; 15726 } 15727 case DestroyNotify: 15728 { 15729 /* 15730 Group leader has exited. 15731 */ 15732 if (display_image->debug != MagickFalse) 15733 (void) LogMagickEvent(X11Event,GetMagickModule(), 15734 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15735 if (event.xdestroywindow.window == windows->group_leader.id) 15736 { 15737 *state|=ExitState; 15738 break; 15739 } 15740 break; 15741 } 15742 case EnterNotify: 15743 { 15744 /* 15745 Selectively install colormap. 15746 */ 15747 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15748 if (event.xcrossing.mode != NotifyUngrab) 15749 XInstallColormap(display,map_info->colormap); 15750 break; 15751 } 15752 case Expose: 15753 { 15754 if (display_image->debug != MagickFalse) 15755 (void) LogMagickEvent(X11Event,GetMagickModule(), 15756 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15757 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15758 event.xexpose.y); 15759 /* 15760 Refresh windows that are now exposed. 15761 */ 15762 if ((event.xexpose.window == windows->image.id) && 15763 (windows->image.mapped != MagickFalse)) 15764 { 15765 XRefreshWindow(display,&windows->image,&event); 15766 delay=display_image->delay/MagickMax( 15767 display_image->ticks_per_second,1L); 15768 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15769 break; 15770 } 15771 if ((event.xexpose.window == windows->magnify.id) && 15772 (windows->magnify.mapped != MagickFalse)) 15773 { 15774 XMakeMagnifyImage(display,windows,exception); 15775 break; 15776 } 15777 if (event.xexpose.window == windows->pan.id) 15778 { 15779 XDrawPanRectangle(display,windows); 15780 break; 15781 } 15782 if (event.xexpose.window == windows->icon.id) 15783 { 15784 XRefreshWindow(display,&windows->icon,&event); 15785 break; 15786 } 15787 break; 15788 } 15789 case KeyPress: 15790 { 15791 int 15792 length; 15793 15794 /* 15795 Respond to a user key press. 15796 */ 15797 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15798 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15799 *(command+length)='\0'; 15800 if (display_image->debug != MagickFalse) 15801 (void) LogMagickEvent(X11Event,GetMagickModule(), 15802 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15803 key_symbol,command); 15804 if (event.xkey.window == windows->image.id) 15805 { 15806 command_type=XImageWindowCommand(display,resource_info,windows, 15807 event.xkey.state,key_symbol,&display_image,exception); 15808 if (command_type != NullCommand) 15809 nexus=XMagickCommand(display,resource_info,windows,command_type, 15810 &display_image,exception); 15811 } 15812 if (event.xkey.window == windows->magnify.id) 15813 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol, 15814 exception); 15815 if (event.xkey.window == windows->pan.id) 15816 { 15817 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15818 (void) XWithdrawWindow(display,windows->pan.id, 15819 windows->pan.screen); 15820 else 15821 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15822 XTextViewWidget(display,resource_info,windows,MagickFalse, 15823 "Help Viewer - Image Pan",ImagePanHelp); 15824 else 15825 XTranslateImage(display,windows,*image,key_symbol); 15826 } 15827 delay=display_image->delay/MagickMax( 15828 display_image->ticks_per_second,1L); 15829 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15830 break; 15831 } 15832 case KeyRelease: 15833 { 15834 /* 15835 Respond to a user key release. 15836 */ 15837 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15838 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15839 if (display_image->debug != MagickFalse) 15840 (void) LogMagickEvent(X11Event,GetMagickModule(), 15841 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15842 break; 15843 } 15844 case LeaveNotify: 15845 { 15846 /* 15847 Selectively uninstall colormap. 15848 */ 15849 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15850 if (event.xcrossing.mode != NotifyUngrab) 15851 XUninstallColormap(display,map_info->colormap); 15852 break; 15853 } 15854 case MapNotify: 15855 { 15856 if (display_image->debug != MagickFalse) 15857 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15858 event.xmap.window); 15859 if (event.xmap.window == windows->backdrop.id) 15860 { 15861 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15862 CurrentTime); 15863 windows->backdrop.mapped=MagickTrue; 15864 break; 15865 } 15866 if (event.xmap.window == windows->image.id) 15867 { 15868 if (windows->backdrop.id != (Window) NULL) 15869 (void) XInstallColormap(display,map_info->colormap); 15870 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15871 { 15872 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15873 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15874 } 15875 if (((int) windows->image.width < windows->image.ximage->width) || 15876 ((int) windows->image.height < windows->image.ximage->height)) 15877 (void) XMapRaised(display,windows->pan.id); 15878 windows->image.mapped=MagickTrue; 15879 break; 15880 } 15881 if (event.xmap.window == windows->magnify.id) 15882 { 15883 XMakeMagnifyImage(display,windows,exception); 15884 windows->magnify.mapped=MagickTrue; 15885 (void) XWithdrawWindow(display,windows->info.id, 15886 windows->info.screen); 15887 break; 15888 } 15889 if (event.xmap.window == windows->pan.id) 15890 { 15891 XMakePanImage(display,resource_info,windows,display_image, 15892 exception); 15893 windows->pan.mapped=MagickTrue; 15894 break; 15895 } 15896 if (event.xmap.window == windows->info.id) 15897 { 15898 windows->info.mapped=MagickTrue; 15899 break; 15900 } 15901 if (event.xmap.window == windows->icon.id) 15902 { 15903 MagickBooleanType 15904 taint; 15905 15906 /* 15907 Create an icon image. 15908 */ 15909 taint=display_image->taint; 15910 XMakeStandardColormap(display,icon_visual,icon_resources, 15911 display_image,icon_map,icon_pixel,exception); 15912 (void) XMakeImage(display,icon_resources,&windows->icon, 15913 display_image,windows->icon.width,windows->icon.height, 15914 exception); 15915 display_image->taint=taint; 15916 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15917 windows->icon.pixmap); 15918 (void) XClearWindow(display,windows->icon.id); 15919 (void) XWithdrawWindow(display,windows->info.id, 15920 windows->info.screen); 15921 windows->icon.mapped=MagickTrue; 15922 break; 15923 } 15924 if (event.xmap.window == windows->command.id) 15925 { 15926 windows->command.mapped=MagickTrue; 15927 break; 15928 } 15929 if (event.xmap.window == windows->popup.id) 15930 { 15931 windows->popup.mapped=MagickTrue; 15932 break; 15933 } 15934 if (event.xmap.window == windows->widget.id) 15935 { 15936 windows->widget.mapped=MagickTrue; 15937 break; 15938 } 15939 break; 15940 } 15941 case MappingNotify: 15942 { 15943 (void) XRefreshKeyboardMapping(&event.xmapping); 15944 break; 15945 } 15946 case NoExpose: 15947 break; 15948 case PropertyNotify: 15949 { 15950 Atom 15951 type; 15952 15953 int 15954 format, 15955 status; 15956 15957 unsigned char 15958 *data; 15959 15960 unsigned long 15961 after, 15962 length; 15963 15964 if (display_image->debug != MagickFalse) 15965 (void) LogMagickEvent(X11Event,GetMagickModule(), 15966 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15967 event.xproperty.atom,event.xproperty.state); 15968 if (event.xproperty.atom != windows->im_remote_command) 15969 break; 15970 /* 15971 Display image named by the remote command protocol. 15972 */ 15973 status=XGetWindowProperty(display,event.xproperty.window, 15974 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom) 15975 AnyPropertyType,&type,&format,&length,&after,&data); 15976 if ((status != Success) || (length == 0)) 15977 break; 15978 if (LocaleCompare((char *) data,"-quit") == 0) 15979 { 15980 XClientMessage(display,windows->image.id,windows->im_protocols, 15981 windows->im_exit,CurrentTime); 15982 (void) XFree((void *) data); 15983 break; 15984 } 15985 (void) CopyMagickString(resource_info->image_info->filename, 15986 (char *) data,MaxTextExtent); 15987 (void) XFree((void *) data); 15988 nexus=ReadImage(resource_info->image_info,exception); 15989 CatchException(exception); 15990 if (nexus != (Image *) NULL) 15991 *state|=NextImageState | ExitState; 15992 break; 15993 } 15994 case ReparentNotify: 15995 { 15996 if (display_image->debug != MagickFalse) 15997 (void) LogMagickEvent(X11Event,GetMagickModule(), 15998 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 15999 event.xreparent.window); 16000 break; 16001 } 16002 case UnmapNotify: 16003 { 16004 if (display_image->debug != MagickFalse) 16005 (void) LogMagickEvent(X11Event,GetMagickModule(), 16006 "Unmap Notify: 0x%lx",event.xunmap.window); 16007 if (event.xunmap.window == windows->backdrop.id) 16008 { 16009 windows->backdrop.mapped=MagickFalse; 16010 break; 16011 } 16012 if (event.xunmap.window == windows->image.id) 16013 { 16014 windows->image.mapped=MagickFalse; 16015 break; 16016 } 16017 if (event.xunmap.window == windows->magnify.id) 16018 { 16019 windows->magnify.mapped=MagickFalse; 16020 break; 16021 } 16022 if (event.xunmap.window == windows->pan.id) 16023 { 16024 windows->pan.mapped=MagickFalse; 16025 break; 16026 } 16027 if (event.xunmap.window == windows->info.id) 16028 { 16029 windows->info.mapped=MagickFalse; 16030 break; 16031 } 16032 if (event.xunmap.window == windows->icon.id) 16033 { 16034 if (map_info->colormap == icon_map->colormap) 16035 XConfigureImageColormap(display,resource_info,windows, 16036 display_image,exception); 16037 (void) XFreeStandardColormap(display,icon_visual,icon_map, 16038 icon_pixel); 16039 windows->icon.mapped=MagickFalse; 16040 break; 16041 } 16042 if (event.xunmap.window == windows->command.id) 16043 { 16044 windows->command.mapped=MagickFalse; 16045 break; 16046 } 16047 if (event.xunmap.window == windows->popup.id) 16048 { 16049 if (windows->backdrop.id != (Window) NULL) 16050 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16051 CurrentTime); 16052 windows->popup.mapped=MagickFalse; 16053 break; 16054 } 16055 if (event.xunmap.window == windows->widget.id) 16056 { 16057 if (windows->backdrop.id != (Window) NULL) 16058 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16059 CurrentTime); 16060 windows->widget.mapped=MagickFalse; 16061 break; 16062 } 16063 break; 16064 } 16065 default: 16066 { 16067 if (display_image->debug != MagickFalse) 16068 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 16069 event.type); 16070 break; 16071 } 16072 } 16073 } while (!(*state & ExitState)); 16074 if ((*state & ExitState) == 0) 16075 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 16076 &display_image,exception); 16077 else 16078 if (resource_info->confirm_edit != MagickFalse) 16079 { 16080 /* 16081 Query user if image has changed. 16082 */ 16083 if ((resource_info->immutable == MagickFalse) && 16084 (display_image->taint != MagickFalse)) 16085 { 16086 int 16087 status; 16088 16089 status=XConfirmWidget(display,windows,"Your image changed.", 16090 "Do you want to save it"); 16091 if (status == 0) 16092 *state&=(~ExitState); 16093 else 16094 if (status > 0) 16095 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 16096 &display_image,exception); 16097 } 16098 } 16099 if ((windows->visual_info->klass == GrayScale) || 16100 (windows->visual_info->klass == PseudoColor) || 16101 (windows->visual_info->klass == DirectColor)) 16102 { 16103 /* 16104 Withdraw pan and Magnify window. 16105 */ 16106 if (windows->info.mapped != MagickFalse) 16107 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 16108 if (windows->magnify.mapped != MagickFalse) 16109 (void) XWithdrawWindow(display,windows->magnify.id, 16110 windows->magnify.screen); 16111 if (windows->command.mapped != MagickFalse) 16112 (void) XWithdrawWindow(display,windows->command.id, 16113 windows->command.screen); 16114 } 16115 if (windows->pan.mapped != MagickFalse) 16116 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 16117 if (resource_info->backdrop == MagickFalse) 16118 if (windows->backdrop.mapped) 16119 { 16120 (void) XWithdrawWindow(display,windows->backdrop.id, 16121 windows->backdrop.screen); 16122 (void) XDestroyWindow(display,windows->backdrop.id); 16123 windows->backdrop.id=(Window) NULL; 16124 (void) XWithdrawWindow(display,windows->image.id, 16125 windows->image.screen); 16126 (void) XDestroyWindow(display,windows->image.id); 16127 windows->image.id=(Window) NULL; 16128 } 16129 XSetCursorState(display,windows,MagickTrue); 16130 XCheckRefreshWindows(display,windows); 16131 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 16132 *state&=(~ExitState); 16133 if (*state & ExitState) 16134 { 16135 /* 16136 Free Standard Colormap. 16137 */ 16138 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 16139 if (resource_info->map_type == (char *) NULL) 16140 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 16141 /* 16142 Free X resources. 16143 */ 16144 if (resource_info->copy_image != (Image *) NULL) 16145 { 16146 resource_info->copy_image=DestroyImage(resource_info->copy_image); 16147 resource_info->copy_image=NewImageList(); 16148 } 16149 DestroyXResources(); 16150 } 16151 (void) XSync(display,MagickFalse); 16152 /* 16153 Restore our progress monitor and warning handlers. 16154 */ 16155 (void) SetErrorHandler(warning_handler); 16156 (void) SetWarningHandler(warning_handler); 16157 /* 16158 Change to home directory. 16159 */ 16160 directory=getcwd(working_directory,MaxTextExtent); 16161 (void) directory; 16162 { 16163 int 16164 status; 16165 16166 status=chdir(resource_info->home_directory); 16167 if (status == -1) 16168 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 16169 "UnableToOpenFile","%s",resource_info->home_directory); 16170 } 16171 *image=display_image; 16172 return(nexus); 16173} 16174#else 16175 16176/* 16177%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16178% % 16179% % 16180% % 16181+ D i s p l a y I m a g e s % 16182% % 16183% % 16184% % 16185%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16186% 16187% DisplayImages() displays an image sequence to any X window screen. It 16188% returns a value other than 0 if successful. Check the exception member 16189% of image to determine the reason for any failure. 16190% 16191% The format of the DisplayImages method is: 16192% 16193% MagickBooleanType DisplayImages(const ImageInfo *image_info, 16194% Image *images,ExceptionInfo *exception) 16195% 16196% A description of each parameter follows: 16197% 16198% o image_info: the image info. 16199% 16200% o image: the image. 16201% 16202% o exception: return any errors or warnings in this structure. 16203% 16204*/ 16205MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16206 Image *image,ExceptionInfo *exception) 16207{ 16208 assert(image_info != (const ImageInfo *) NULL); 16209 assert(image_info->signature == MagickSignature); 16210 assert(image != (Image *) NULL); 16211 assert(image->signature == MagickSignature); 16212 if (image->debug != MagickFalse) 16213 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16214 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16215 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image->filename); 16216 return(MagickFalse); 16217} 16218 16219/* 16220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16221% % 16222% % 16223% % 16224+ R e m o t e D i s p l a y C o m m a n d % 16225% % 16226% % 16227% % 16228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16229% 16230% RemoteDisplayCommand() encourages a remote display program to display the 16231% specified image filename. 16232% 16233% The format of the RemoteDisplayCommand method is: 16234% 16235% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16236% const char *window,const char *filename,ExceptionInfo *exception) 16237% 16238% A description of each parameter follows: 16239% 16240% o image_info: the image info. 16241% 16242% o window: Specifies the name or id of an X window. 16243% 16244% o filename: the name of the image filename to display. 16245% 16246% o exception: return any errors or warnings in this structure. 16247% 16248*/ 16249MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16250 const char *window,const char *filename,ExceptionInfo *exception) 16251{ 16252 assert(image_info != (const ImageInfo *) NULL); 16253 assert(image_info->signature == MagickSignature); 16254 assert(filename != (char *) NULL); 16255 (void) window; 16256 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16257 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16258 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename); 16259 return(MagickFalse); 16260} 16261#endif 16262