display.c revision ea1a8aa04a9fe1500104284407c1cc06d20da699
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% DDDD IIIII SSSSS PPPP L AAA Y Y % 7% D D I SS P P L A A Y Y % 8% D D I SSS PPPP L AAAAA Y % 9% D D I SS P L A A Y % 10% DDDD IIIII SSSSS P LLLLL A A Y % 11% % 12% % 13% MagickCore Methods to Interactively Display and Edit an Image % 14% % 15% Software Design % 16% John Cristy % 17% July 1992 % 18% % 19% % 20% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization % 21% dedicated to making software imaging solutions freely available. % 22% % 23% You may not use this file except in compliance with the License. You may % 24% obtain a copy of the License at % 25% % 26% http://www.imagemagick.org/script/license.php % 27% % 28% Unless required by applicable law or agreed to in writing, software % 29% distributed under the License is distributed on an "AS IS" BASIS, % 30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31% See the License for the specific language governing permissions and % 32% limitations under the License. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 36% 37*/ 38 39/* 40 Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/artifact.h" 44#include "MagickCore/blob.h" 45#include "MagickCore/cache.h" 46#include "MagickCore/client.h" 47#include "MagickCore/color.h" 48#include "MagickCore/colorspace.h" 49#include "MagickCore/composite.h" 50#include "MagickCore/constitute.h" 51#include "MagickCore/decorate.h" 52#include "MagickCore/delegate.h" 53#include "MagickCore/display.h" 54#include "MagickCore/display-private.h" 55#include "MagickCore/draw.h" 56#include "MagickCore/effect.h" 57#include "MagickCore/enhance.h" 58#include "MagickCore/exception.h" 59#include "MagickCore/exception-private.h" 60#include "MagickCore/fx.h" 61#include "MagickCore/geometry.h" 62#include "MagickCore/image.h" 63#include "MagickCore/image-private.h" 64#include "MagickCore/list.h" 65#include "MagickCore/log.h" 66#include "MagickCore/magick.h" 67#include "MagickCore/memory_.h" 68#include "MagickCore/monitor.h" 69#include "MagickCore/monitor-private.h" 70#include "MagickCore/montage.h" 71#include "MagickCore/option.h" 72#include "MagickCore/paint.h" 73#include "MagickCore/pixel.h" 74#include "MagickCore/pixel-accessor.h" 75#include "MagickCore/PreRvIcccm.h" 76#include "MagickCore/property.h" 77#include "MagickCore/quantum.h" 78#include "MagickCore/quantum-private.h" 79#include "MagickCore/resize.h" 80#include "MagickCore/resource_.h" 81#include "MagickCore/shear.h" 82#include "MagickCore/segment.h" 83#include "MagickCore/string_.h" 84#include "MagickCore/string-private.h" 85#include "MagickCore/transform.h" 86#include "MagickCore/threshold.h" 87#include "MagickCore/utility.h" 88#include "MagickCore/utility-private.h" 89#include "MagickCore/version.h" 90#include "MagickCore/widget.h" 91#include "MagickCore/widget-private.h" 92#include "MagickCore/xwindow.h" 93#include "MagickCore/xwindow-private.h" 94 95#if defined(MAGICKCORE_X11_DELEGATE) 96/* 97 Define declarations. 98*/ 99#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L) 100 101/* 102 Constant declarations. 103*/ 104static const unsigned char 105 HighlightBitmap[8] = 106 { 107 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 108 }, 109 OpaqueBitmap[8] = 110 { 111 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 112 }, 113 ShadowBitmap[8] = 114 { 115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 116 }; 117 118static const char 119 *PageSizes[] = 120 { 121 "Letter", 122 "Tabloid", 123 "Ledger", 124 "Legal", 125 "Statement", 126 "Executive", 127 "A3", 128 "A4", 129 "A5", 130 "B4", 131 "B5", 132 "Folio", 133 "Quarto", 134 "10x14", 135 (char *) NULL 136 }; 137 138/* 139 Help widget declarations. 140*/ 141static const char 142 *ImageAnnotateHelp[] = 143 { 144 "In annotate mode, the Command widget has these options:", 145 "", 146 " Font Name", 147 " fixed", 148 " variable", 149 " 5x8", 150 " 6x10", 151 " 7x13bold", 152 " 8x13bold", 153 " 9x15bold", 154 " 10x20", 155 " 12x24", 156 " Browser...", 157 " Font Color", 158 " black", 159 " blue", 160 " cyan", 161 " green", 162 " gray", 163 " red", 164 " magenta", 165 " yellow", 166 " white", 167 " transparent", 168 " Browser...", 169 " Font Color", 170 " black", 171 " blue", 172 " cyan", 173 " green", 174 " gray", 175 " red", 176 " magenta", 177 " yellow", 178 " white", 179 " transparent", 180 " Browser...", 181 " Rotate Text", 182 " -90", 183 " -45", 184 " -30", 185 " 0", 186 " 30", 187 " 45", 188 " 90", 189 " 180", 190 " Dialog...", 191 " Help", 192 " Dismiss", 193 "", 194 "Choose a font name from the Font Name sub-menu. Additional", 195 "font names can be specified with the font browser. You can", 196 "change the menu names by setting the X resources font1", 197 "through font9.", 198 "", 199 "Choose a font color from the Font Color sub-menu.", 200 "Additional font colors can be specified with the color", 201 "browser. You can change the menu colors by setting the X", 202 "resources pen1 through pen9.", 203 "", 204 "If you select the color browser and press Grab, you can", 205 "choose the font color by moving the pointer to the desired", 206 "color on the screen and press any button.", 207 "", 208 "If you choose to rotate the text, choose Rotate Text from the", 209 "menu and select an angle. Typically you will only want to", 210 "rotate one line of text at a time. Depending on the angle you", 211 "choose, subsequent lines may end up overwriting each other.", 212 "", 213 "Choosing a font and its color is optional. The default font", 214 "is fixed and the default color is black. However, you must", 215 "choose a location to begin entering text and press button 1.", 216 "An underscore character will appear at the location of the", 217 "pointer. The cursor changes to a pencil to indicate you are", 218 "in text mode. To exit immediately, press Dismiss.", 219 "", 220 "In text mode, any key presses will display the character at", 221 "the location of the underscore and advance the underscore", 222 "cursor. Enter your text and once completed press Apply to", 223 "finish your image annotation. To correct errors press BACK", 224 "SPACE. To delete an entire line of text, press DELETE. Any", 225 "text that exceeds the boundaries of the image window is", 226 "automagically continued onto the next line.", 227 "", 228 "The actual color you request for the font is saved in the", 229 "image. However, the color that appears in your image window", 230 "may be different. For example, on a monochrome screen the", 231 "text will appear black or white even if you choose the color", 232 "red as the font color. However, the image saved to a file", 233 "with -write is written with red lettering. To assure the", 234 "correct color text in the final image, any PseudoClass image", 235 "is promoted to DirectClass (see miff(5)). To force a", 236 "PseudoClass image to remain PseudoClass, use -colors.", 237 (char *) NULL, 238 }, 239 *ImageChopHelp[] = 240 { 241 "In chop mode, the Command widget has these options:", 242 "", 243 " Direction", 244 " horizontal", 245 " vertical", 246 " Help", 247 " Dismiss", 248 "", 249 "If the you choose the horizontal direction (this the", 250 "default), the area of the image between the two horizontal", 251 "endpoints of the chop line is removed. Otherwise, the area", 252 "of the image between the two vertical endpoints of the chop", 253 "line is removed.", 254 "", 255 "Select a location within the image window to begin your chop,", 256 "press and hold any button. Next, move the pointer to", 257 "another location in the image. As you move a line will", 258 "connect the initial location and the pointer. When you", 259 "release the button, the area within the image to chop is", 260 "determined by which direction you choose from the Command", 261 "widget.", 262 "", 263 "To cancel the image chopping, move the pointer back to the", 264 "starting point of the line and release the button.", 265 (char *) NULL, 266 }, 267 *ImageColorEditHelp[] = 268 { 269 "In color edit mode, the Command widget has these options:", 270 "", 271 " Method", 272 " point", 273 " replace", 274 " floodfill", 275 " filltoborder", 276 " reset", 277 " Pixel Color", 278 " black", 279 " blue", 280 " cyan", 281 " green", 282 " gray", 283 " red", 284 " magenta", 285 " yellow", 286 " white", 287 " Browser...", 288 " Border Color", 289 " black", 290 " blue", 291 " cyan", 292 " green", 293 " gray", 294 " red", 295 " magenta", 296 " yellow", 297 " white", 298 " Browser...", 299 " Fuzz", 300 " 0%", 301 " 2%", 302 " 5%", 303 " 10%", 304 " 15%", 305 " Dialog...", 306 " Undo", 307 " Help", 308 " Dismiss", 309 "", 310 "Choose a color editing method from the Method sub-menu", 311 "of the Command widget. The point method recolors any pixel", 312 "selected with the pointer until the button is released. The", 313 "replace method recolors any pixel that matches the color of", 314 "the pixel you select with a button press. Floodfill recolors", 315 "any pixel that matches the color of the pixel you select with", 316 "a button press and is a neighbor. Whereas filltoborder recolors", 317 "any neighbor pixel that is not the border color. Finally reset", 318 "changes the entire image to the designated color.", 319 "", 320 "Next, choose a pixel color from the Pixel Color sub-menu.", 321 "Additional pixel colors can be specified with the color", 322 "browser. You can change the menu colors by setting the X", 323 "resources pen1 through pen9.", 324 "", 325 "Now press button 1 to select a pixel within the image window", 326 "to change its color. Additional pixels may be recolored as", 327 "prescribed by the method you choose.", 328 "", 329 "If the Magnify widget is mapped, it can be helpful in positioning", 330 "your pointer within the image (refer to button 2).", 331 "", 332 "The actual color you request for the pixels is saved in the", 333 "image. However, the color that appears in your image window", 334 "may be different. For example, on a monochrome screen the", 335 "pixel will appear black or white even if you choose the", 336 "color red as the pixel color. However, the image saved to a", 337 "file with -write is written with red pixels. To assure the", 338 "correct color text in the final image, any PseudoClass image", 339 "is promoted to DirectClass (see miff(5)). To force a", 340 "PseudoClass image to remain PseudoClass, use -colors.", 341 (char *) NULL, 342 }, 343 *ImageCompositeHelp[] = 344 { 345 "First a widget window is displayed requesting you to enter an", 346 "image name. Press Composite, Grab or type a file name.", 347 "Press Cancel if you choose not to create a composite image.", 348 "When you choose Grab, move the pointer to the desired window", 349 "and press any button.", 350 "", 351 "If the Composite image does not have any matte information,", 352 "you are informed and the file browser is displayed again.", 353 "Enter the name of a mask image. The image is typically", 354 "grayscale and the same size as the composite image. If the", 355 "image is not grayscale, it is converted to grayscale and the", 356 "resulting intensities are used as matte information.", 357 "", 358 "A small window appears showing the location of the cursor in", 359 "the image window. You are now in composite mode. To exit", 360 "immediately, press Dismiss. In composite mode, the Command", 361 "widget has these options:", 362 "", 363 " Operators", 364 " Over", 365 " In", 366 " Out", 367 " Atop", 368 " Xor", 369 " Plus", 370 " Minus", 371 " Add", 372 " Subtract", 373 " Difference", 374 " Multiply", 375 " Bumpmap", 376 " Copy", 377 " CopyRed", 378 " CopyGreen", 379 " CopyBlue", 380 " CopyOpacity", 381 " Clear", 382 " Dissolve", 383 " Displace", 384 " Help", 385 " Dismiss", 386 "", 387 "Choose a composite operation from the Operators sub-menu of", 388 "the Command widget. How each operator behaves is described", 389 "below. Image window is the image currently displayed on", 390 "your X server and image is the image obtained with the File", 391 "Browser widget.", 392 "", 393 "Over The result is the union of the two image shapes,", 394 " with image obscuring image window in the region of", 395 " overlap.", 396 "", 397 "In The result is simply image cut by the shape of", 398 " image window. None of the image data of image", 399 " window is in the result.", 400 "", 401 "Out The resulting image is image with the shape of", 402 " image window cut out.", 403 "", 404 "Atop The result is the same shape as image image window,", 405 " with image obscuring image window where the image", 406 " shapes overlap. Note this differs from over", 407 " because the portion of image outside image window's", 408 " shape does not appear in the result.", 409 "", 410 "Xor The result is the image data from both image and", 411 " image window that is outside the overlap region.", 412 " The overlap region is blank.", 413 "", 414 "Plus The result is just the sum of the image data.", 415 " Output values are cropped to QuantumRange (no overflow).", 416 "", 417 "Minus The result of image - image window, with underflow", 418 " cropped to zero.", 419 "", 420 "Add The result of image + image window, with overflow", 421 " wrapping around (mod 256).", 422 "", 423 "Subtract The result of image - image window, with underflow", 424 " wrapping around (mod 256). The add and subtract", 425 " operators can be used to perform reversible", 426 " transformations.", 427 "", 428 "Difference", 429 " The result of abs(image - image window). This", 430 " useful for comparing two very similar images.", 431 "", 432 "Multiply", 433 " The result of image * image window. This", 434 " useful for the creation of drop-shadows.", 435 "", 436 "Bumpmap The result of surface normals from image * image", 437 " window.", 438 "", 439 "Copy The resulting image is image window replaced with", 440 " image. Here the matte information is ignored.", 441 "", 442 "CopyRed The red layer of the image window is replace with", 443 " the red layer of the image. The other layers are", 444 " untouched.", 445 "", 446 "CopyGreen", 447 " The green layer of the image window is replace with", 448 " the green layer of the image. The other layers are", 449 " untouched.", 450 "", 451 "CopyBlue The blue layer of the image window is replace with", 452 " the blue layer of the image. The other layers are", 453 " untouched.", 454 "", 455 "CopyOpacity", 456 " The matte layer of the image window is replace with", 457 " the matte layer of the image. The other layers are", 458 " untouched.", 459 "", 460 "The image compositor requires a matte, or alpha channel in", 461 "the image for some operations. This extra channel usually", 462 "defines a mask which represents a sort of a cookie-cutter", 463 "for the image. This the case when matte is opaque (full", 464 "coverage) for pixels inside the shape, zero outside, and", 465 "between 0 and QuantumRange on the boundary. If image does not", 466 "have a matte channel, it is initialized with 0 for any pixel", 467 "matching in color to pixel location (0,0), otherwise QuantumRange.", 468 "", 469 "If you choose Dissolve, the composite operator becomes Over. The", 470 "image matte channel percent transparency is initialized to factor.", 471 "The image window is initialized to (100-factor). Where factor is the", 472 "value you specify in the Dialog widget.", 473 "", 474 "Displace shifts the image pixels as defined by a displacement", 475 "map. With this option, image is used as a displacement map.", 476 "Black, within the displacement map, is a maximum positive", 477 "displacement. White is a maximum negative displacement and", 478 "middle gray is neutral. The displacement is scaled to determine", 479 "the pixel shift. By default, the displacement applies in both the", 480 "horizontal and vertical directions. However, if you specify a mask,", 481 "image is the horizontal X displacement and mask the vertical Y", 482 "displacement.", 483 "", 484 "Note that matte information for image window is not retained", 485 "for colormapped X server visuals (e.g. StaticColor,", 486 "StaticColor, GrayScale, PseudoColor). Correct compositing", 487 "behavior may require a TrueColor or DirectColor visual or a", 488 "Standard Colormap.", 489 "", 490 "Choosing a composite operator is optional. The default", 491 "operator is replace. However, you must choose a location to", 492 "composite your image and press button 1. Press and hold the", 493 "button before releasing and an outline of the image will", 494 "appear to help you identify your location.", 495 "", 496 "The actual colors of the composite image is saved. However,", 497 "the color that appears in image window may be different.", 498 "For example, on a monochrome screen image window will appear", 499 "black or white even though your composited image may have", 500 "many colors. If the image is saved to a file it is written", 501 "with the correct colors. To assure the correct colors are", 502 "saved in the final image, any PseudoClass image is promoted", 503 "to DirectClass (see miff(5)). To force a PseudoClass image", 504 "to remain PseudoClass, use -colors.", 505 (char *) NULL, 506 }, 507 *ImageCutHelp[] = 508 { 509 "In cut mode, the Command widget has these options:", 510 "", 511 " Help", 512 " Dismiss", 513 "", 514 "To define a cut region, press button 1 and drag. The", 515 "cut region is defined by a highlighted rectangle that", 516 "expands or contracts as it follows the pointer. Once you", 517 "are satisfied with the cut region, release the button.", 518 "You are now in rectify mode. In rectify mode, the Command", 519 "widget has these options:", 520 "", 521 " Cut", 522 " Help", 523 " Dismiss", 524 "", 525 "You can make adjustments by moving the pointer to one of the", 526 "cut rectangle corners, pressing a button, and dragging.", 527 "Finally, press Cut to commit your copy region. To", 528 "exit without cutting the image, press Dismiss.", 529 (char *) NULL, 530 }, 531 *ImageCopyHelp[] = 532 { 533 "In copy mode, the Command widget has these options:", 534 "", 535 " Help", 536 " Dismiss", 537 "", 538 "To define a copy region, press button 1 and drag. The", 539 "copy region is defined by a highlighted rectangle that", 540 "expands or contracts as it follows the pointer. Once you", 541 "are satisfied with the copy region, release the button.", 542 "You are now in rectify mode. In rectify mode, the Command", 543 "widget has these options:", 544 "", 545 " Copy", 546 " Help", 547 " Dismiss", 548 "", 549 "You can make adjustments by moving the pointer to one of the", 550 "copy rectangle corners, pressing a button, and dragging.", 551 "Finally, press Copy to commit your copy region. To", 552 "exit without copying the image, press Dismiss.", 553 (char *) NULL, 554 }, 555 *ImageCropHelp[] = 556 { 557 "In crop mode, the Command widget has these options:", 558 "", 559 " Help", 560 " Dismiss", 561 "", 562 "To define a cropping region, press button 1 and drag. The", 563 "cropping region is defined by a highlighted rectangle that", 564 "expands or contracts as it follows the pointer. Once you", 565 "are satisfied with the cropping region, release the button.", 566 "You are now in rectify mode. In rectify mode, the Command", 567 "widget has these options:", 568 "", 569 " Crop", 570 " Help", 571 " Dismiss", 572 "", 573 "You can make adjustments by moving the pointer to one of the", 574 "cropping rectangle corners, pressing a button, and dragging.", 575 "Finally, press Crop to commit your cropping region. To", 576 "exit without cropping the image, press Dismiss.", 577 (char *) NULL, 578 }, 579 *ImageDrawHelp[] = 580 { 581 "The cursor changes to a crosshair to indicate you are in", 582 "draw mode. To exit immediately, press Dismiss. In draw mode,", 583 "the Command widget has these options:", 584 "", 585 " Element", 586 " point", 587 " line", 588 " rectangle", 589 " fill rectangle", 590 " circle", 591 " fill circle", 592 " ellipse", 593 " fill ellipse", 594 " polygon", 595 " fill polygon", 596 " Color", 597 " black", 598 " blue", 599 " cyan", 600 " green", 601 " gray", 602 " red", 603 " magenta", 604 " yellow", 605 " white", 606 " transparent", 607 " Browser...", 608 " Stipple", 609 " Brick", 610 " Diagonal", 611 " Scales", 612 " Vertical", 613 " Wavy", 614 " Translucent", 615 " Opaque", 616 " Open...", 617 " Width", 618 " 1", 619 " 2", 620 " 4", 621 " 8", 622 " 16", 623 " Dialog...", 624 " Undo", 625 " Help", 626 " Dismiss", 627 "", 628 "Choose a drawing primitive from the Element sub-menu.", 629 "", 630 "Choose a color from the Color sub-menu. Additional", 631 "colors can be specified with the color browser.", 632 "", 633 "If you choose the color browser and press Grab, you can", 634 "select the color by moving the pointer to the desired", 635 "color on the screen and press any button. The transparent", 636 "color updates the image matte channel and is useful for", 637 "image compositing.", 638 "", 639 "Choose a stipple, if appropriate, from the Stipple sub-menu.", 640 "Additional stipples can be specified with the file browser.", 641 "Stipples obtained from the file browser must be on disk in the", 642 "X11 bitmap format.", 643 "", 644 "Choose a width, if appropriate, from the Width sub-menu. To", 645 "choose a specific width select the Dialog widget.", 646 "", 647 "Choose a point in the Image window and press button 1 and", 648 "hold. Next, move the pointer to another location in the", 649 "image. As you move, a line connects the initial location and", 650 "the pointer. When you release the button, the image is", 651 "updated with the primitive you just drew. For polygons, the", 652 "image is updated when you press and release the button without", 653 "moving the pointer.", 654 "", 655 "To cancel image drawing, move the pointer back to the", 656 "starting point of the line and release the button.", 657 (char *) NULL, 658 }, 659 *DisplayHelp[] = 660 { 661 "BUTTONS", 662 " The effects of each button press is described below. Three", 663 " buttons are required. If you have a two button mouse,", 664 " button 1 and 3 are returned. Press ALT and button 3 to", 665 " simulate button 2.", 666 "", 667 " 1 Press this button to map or unmap the Command widget.", 668 "", 669 " 2 Press and drag to define a region of the image to", 670 " magnify.", 671 "", 672 " 3 Press and drag to choose from a select set of commands.", 673 " This button behaves differently if the image being", 674 " displayed is a visual image directory. Here, choose a", 675 " particular tile of the directory and press this button and", 676 " drag to select a command from a pop-up menu. Choose from", 677 " these menu items:", 678 "", 679 " Open", 680 " Next", 681 " Former", 682 " Delete", 683 " Update", 684 "", 685 " If you choose Open, the image represented by the tile is", 686 " displayed. To return to the visual image directory, choose", 687 " Next from the Command widget. Next and Former moves to the", 688 " next or former image respectively. Choose Delete to delete", 689 " a particular image tile. Finally, choose Update to", 690 " synchronize all the image tiles with their respective", 691 " images.", 692 "", 693 "COMMAND WIDGET", 694 " The Command widget lists a number of sub-menus and commands.", 695 " They are", 696 "", 697 " File", 698 " Open...", 699 " Next", 700 " Former", 701 " Select...", 702 " Save...", 703 " Print...", 704 " Delete...", 705 " New...", 706 " Visual Directory...", 707 " Quit", 708 " Edit", 709 " Undo", 710 " Redo", 711 " Cut", 712 " Copy", 713 " Paste", 714 " View", 715 " Half Size", 716 " Original Size", 717 " Double Size", 718 " Resize...", 719 " Apply", 720 " Refresh", 721 " Restore", 722 " Transform", 723 " Crop", 724 " Chop", 725 " Flop", 726 " Flip", 727 " Rotate Right", 728 " Rotate Left", 729 " Rotate...", 730 " Shear...", 731 " Roll...", 732 " Trim Edges", 733 " Enhance", 734 " Brightness...", 735 " Saturation...", 736 " Hue...", 737 " Gamma...", 738 " Sharpen...", 739 " Dull", 740 " Contrast Stretch...", 741 " Sigmoidal Contrast...", 742 " Normalize", 743 " Equalize", 744 " Negate", 745 " Grayscale", 746 " Map...", 747 " Quantize...", 748 " Effects", 749 " Despeckle", 750 " Emboss", 751 " Reduce Noise", 752 " Add Noise", 753 " Sharpen...", 754 " Blur...", 755 " Threshold...", 756 " Edge Detect...", 757 " Spread...", 758 " Shade...", 759 " Painting...", 760 " Segment...", 761 " F/X", 762 " Solarize...", 763 " Sepia Tone...", 764 " Swirl...", 765 " Implode...", 766 " Vignette...", 767 " Wave...", 768 " Oil Painting...", 769 " Charcoal Drawing...", 770 " Image Edit", 771 " Annotate...", 772 " Draw...", 773 " Color...", 774 " Matte...", 775 " Composite...", 776 " Add Border...", 777 " Add Frame...", 778 " Comment...", 779 " Launch...", 780 " Region of Interest...", 781 " Miscellany", 782 " Image Info", 783 " Zoom Image", 784 " Show Preview...", 785 " Show Histogram", 786 " Show Matte", 787 " Background...", 788 " Slide Show", 789 " Preferences...", 790 " Help", 791 " Overview", 792 " Browse Documentation", 793 " About Display", 794 "", 795 " Menu items with a indented triangle have a sub-menu. They", 796 " are represented above as the indented items. To access a", 797 " sub-menu item, move the pointer to the appropriate menu and", 798 " press a button and drag. When you find the desired sub-menu", 799 " item, release the button and the command is executed. Move", 800 " the pointer away from the sub-menu if you decide not to", 801 " execute a particular command.", 802 "", 803 "KEYBOARD ACCELERATORS", 804 " Accelerators are one or two key presses that effect a", 805 " particular command. The keyboard accelerators that", 806 " display(1) understands is:", 807 "", 808 " Ctl+O Press to open an image from a file.", 809 "", 810 " space Press to display the next image.", 811 "", 812 " If the image is a multi-paged document such as a Postscript", 813 " document, you can skip ahead several pages by preceding", 814 " this command with a number. For example to display the", 815 " third page beyond the current page, press 3<space>.", 816 "", 817 " backspace Press to display the former image.", 818 "", 819 " If the image is a multi-paged document such as a Postscript", 820 " document, you can skip behind several pages by preceding", 821 " this command with a number. For example to display the", 822 " third page preceding the current page, press 3<backspace>.", 823 "", 824 " Ctl+S Press to write the image to a file.", 825 "", 826 " Ctl+P Press to print the image to a Postscript printer.", 827 "", 828 " Ctl+D Press to delete an image file.", 829 "", 830 " Ctl+N Press to create a blank canvas.", 831 "", 832 " Ctl+Q Press to discard all images and exit program.", 833 "", 834 " Ctl+Z Press to undo last image transformation.", 835 "", 836 " Ctl+R Press to redo last image transformation.", 837 "", 838 " Ctl+X Press to cut a region of the image.", 839 "", 840 " Ctl+C Press to copy a region of the image.", 841 "", 842 " Ctl+V Press to paste a region to the image.", 843 "", 844 " < Press to half the image size.", 845 "", 846 " - Press to return to the original image size.", 847 "", 848 " > Press to double the image size.", 849 "", 850 " % Press to resize the image to a width and height you", 851 " specify.", 852 "", 853 "Cmd-A Press to make any image transformations permanent." 854 "", 855 " By default, any image size transformations are applied", 856 " to the original image to create the image displayed on", 857 " the X server. However, the transformations are not", 858 " permanent (i.e. the original image does not change", 859 " size only the X image does). For example, if you", 860 " press > the X image will appear to double in size,", 861 " but the original image will in fact remain the same size.", 862 " To force the original image to double in size, press >", 863 " followed by Cmd-A.", 864 "", 865 " @ Press to refresh the image window.", 866 "", 867 " C Press to cut out a rectangular region of the image.", 868 "", 869 " [ Press to chop the image.", 870 "", 871 " H Press to flop image in the horizontal direction.", 872 "", 873 " V Press to flip image in the vertical direction.", 874 "", 875 " / Press to rotate the image 90 degrees clockwise.", 876 "", 877 " \\ Press to rotate the image 90 degrees counter-clockwise.", 878 "", 879 " * Press to rotate the image the number of degrees you", 880 " specify.", 881 "", 882 " S Press to shear the image the number of degrees you", 883 " specify.", 884 "", 885 " R Press to roll the image.", 886 "", 887 " T Press to trim the image edges.", 888 "", 889 " Shft-H Press to vary the image hue.", 890 "", 891 " Shft-S Press to vary the color saturation.", 892 "", 893 " Shft-L Press to vary the color brightness.", 894 "", 895 " Shft-G Press to gamma correct the image.", 896 "", 897 " Shft-C Press to sharpen the image contrast.", 898 "", 899 " Shft-Z Press to dull the image contrast.", 900 "", 901 " = Press to perform histogram equalization on the image.", 902 "", 903 " Shft-N Press to perform histogram normalization on the image.", 904 "", 905 " Shft-~ Press to negate the colors of the image.", 906 "", 907 " . Press to convert the image colors to gray.", 908 "", 909 " Shft-# Press to set the maximum number of unique colors in the", 910 " image.", 911 "", 912 " F2 Press to reduce the speckles in an image.", 913 "", 914 " F3 Press to eliminate peak noise from an image.", 915 "", 916 " F4 Press to add noise to an image.", 917 "", 918 " F5 Press to sharpen an image.", 919 "", 920 " F6 Press to delete an image file.", 921 "", 922 " F7 Press to threshold the image.", 923 "", 924 " F8 Press to detect edges within an image.", 925 "", 926 " F9 Press to emboss an image.", 927 "", 928 " F10 Press to displace pixels by a random amount.", 929 "", 930 " F11 Press to negate all pixels above the threshold level.", 931 "", 932 " F12 Press to shade the image using a distant light source.", 933 "", 934 " F13 Press to lighten or darken image edges to create a 3-D effect.", 935 "", 936 " F14 Press to segment the image by color.", 937 "", 938 " Meta-S Press to swirl image pixels about the center.", 939 "", 940 " Meta-I Press to implode image pixels about the center.", 941 "", 942 " Meta-W Press to alter an image along a sine wave.", 943 "", 944 " Meta-P Press to simulate an oil painting.", 945 "", 946 " Meta-C Press to simulate a charcoal drawing.", 947 "", 948 " Alt-A Press to annotate the image with text.", 949 "", 950 " Alt-D Press to draw on an image.", 951 "", 952 " Alt-P Press to edit an image pixel color.", 953 "", 954 " Alt-M Press to edit the image matte information.", 955 "", 956 " Alt-V Press to composite the image with another.", 957 "", 958 " Alt-B Press to add a border to the image.", 959 "", 960 " Alt-F Press to add an ornamental border to the image.", 961 "", 962 " Alt-Shft-!", 963 " Press to add an image comment.", 964 "", 965 " Ctl-A Press to apply image processing techniques to a region", 966 " of interest.", 967 "", 968 " Shft-? Press to display information about the image.", 969 "", 970 " Shft-+ Press to map the zoom image window.", 971 "", 972 " Shft-P Press to preview an image enhancement, effect, or f/x.", 973 "", 974 " F1 Press to display helpful information about display(1).", 975 "", 976 " Find Press to browse documentation about ImageMagick.", 977 "", 978 " 1-9 Press to change the level of magnification.", 979 "", 980 " Use the arrow keys to move the image one pixel up, down,", 981 " left, or right within the magnify window. Be sure to first", 982 " map the magnify window by pressing button 2.", 983 "", 984 " Press ALT and one of the arrow keys to trim off one pixel", 985 " from any side of the image.", 986 (char *) NULL, 987 }, 988 *ImageMatteEditHelp[] = 989 { 990 "Matte information within an image is useful for some", 991 "operations such as image compositing (See IMAGE", 992 "COMPOSITING). This extra channel usually defines a mask", 993 "which represents a sort of a cookie-cutter for the image.", 994 "This the case when matte is opaque (full coverage) for", 995 "pixels inside the shape, zero outside, and between 0 and", 996 "QuantumRange on the boundary.", 997 "", 998 "A small window appears showing the location of the cursor in", 999 "the image window. You are now in matte edit mode. To exit", 1000 "immediately, press Dismiss. In matte edit mode, the Command", 1001 "widget has these options:", 1002 "", 1003 " Method", 1004 " point", 1005 " replace", 1006 " floodfill", 1007 " filltoborder", 1008 " reset", 1009 " Border Color", 1010 " black", 1011 " blue", 1012 " cyan", 1013 " green", 1014 " gray", 1015 " red", 1016 " magenta", 1017 " yellow", 1018 " white", 1019 " Browser...", 1020 " Fuzz", 1021 " 0%", 1022 " 2%", 1023 " 5%", 1024 " 10%", 1025 " 15%", 1026 " Dialog...", 1027 " Matte", 1028 " Opaque", 1029 " Transparent", 1030 " Dialog...", 1031 " Undo", 1032 " Help", 1033 " Dismiss", 1034 "", 1035 "Choose a matte editing method from the Method sub-menu of", 1036 "the Command widget. The point method changes the matte value", 1037 "of any pixel selected with the pointer until the button is", 1038 "is released. The replace method changes the matte value of", 1039 "any pixel that matches the color of the pixel you select with", 1040 "a button press. Floodfill changes the matte value of any pixel", 1041 "that matches the color of the pixel you select with a button", 1042 "press and is a neighbor. Whereas filltoborder changes the matte", 1043 "value any neighbor pixel that is not the border color. Finally", 1044 "reset changes the entire image to the designated matte value.", 1045 "", 1046 "Choose Matte Value and pick Opaque or Transarent. For other values", 1047 "select the Dialog entry. Here a dialog appears requesting a matte", 1048 "value. The value you select is assigned as the opacity value of the", 1049 "selected pixel or pixels.", 1050 "", 1051 "Now, press any button to select a pixel within the image", 1052 "window to change its matte value.", 1053 "", 1054 "If the Magnify widget is mapped, it can be helpful in positioning", 1055 "your pointer within the image (refer to button 2).", 1056 "", 1057 "Matte information is only valid in a DirectClass image.", 1058 "Therefore, any PseudoClass image is promoted to DirectClass", 1059 "(see miff(5)). Note that matte information for PseudoClass", 1060 "is not retained for colormapped X server visuals (e.g.", 1061 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you", 1062 "immediately save your image to a file (refer to Write).", 1063 "Correct matte editing behavior may require a TrueColor or", 1064 "DirectColor visual or a Standard Colormap.", 1065 (char *) NULL, 1066 }, 1067 *ImagePanHelp[] = 1068 { 1069 "When an image exceeds the width or height of the X server", 1070 "screen, display maps a small panning icon. The rectangle", 1071 "within the panning icon shows the area that is currently", 1072 "displayed in the image window. To pan about the image,", 1073 "press any button and drag the pointer within the panning", 1074 "icon. The pan rectangle moves with the pointer and the", 1075 "image window is updated to reflect the location of the", 1076 "rectangle within the panning icon. When you have selected", 1077 "the area of the image you wish to view, release the button.", 1078 "", 1079 "Use the arrow keys to pan the image one pixel up, down,", 1080 "left, or right within the image window.", 1081 "", 1082 "The panning icon is withdrawn if the image becomes smaller", 1083 "than the dimensions of the X server screen.", 1084 (char *) NULL, 1085 }, 1086 *ImagePasteHelp[] = 1087 { 1088 "A small window appears showing the location of the cursor in", 1089 "the image window. You are now in paste mode. To exit", 1090 "immediately, press Dismiss. In paste mode, the Command", 1091 "widget has these options:", 1092 "", 1093 " Operators", 1094 " over", 1095 " in", 1096 " out", 1097 " atop", 1098 " xor", 1099 " plus", 1100 " minus", 1101 " add", 1102 " subtract", 1103 " difference", 1104 " replace", 1105 " Help", 1106 " Dismiss", 1107 "", 1108 "Choose a composite operation from the Operators sub-menu of", 1109 "the Command widget. How each operator behaves is described", 1110 "below. Image window is the image currently displayed on", 1111 "your X server and image is the image obtained with the File", 1112 "Browser widget.", 1113 "", 1114 "Over The result is the union of the two image shapes,", 1115 " with image obscuring image window in the region of", 1116 " overlap.", 1117 "", 1118 "In The result is simply image cut by the shape of", 1119 " image window. None of the image data of image", 1120 " window is in the result.", 1121 "", 1122 "Out The resulting image is image with the shape of", 1123 " image window cut out.", 1124 "", 1125 "Atop The result is the same shape as image image window,", 1126 " with image obscuring image window where the image", 1127 " shapes overlap. Note this differs from over", 1128 " because the portion of image outside image window's", 1129 " shape does not appear in the result.", 1130 "", 1131 "Xor The result is the image data from both image and", 1132 " image window that is outside the overlap region.", 1133 " The overlap region is blank.", 1134 "", 1135 "Plus The result is just the sum of the image data.", 1136 " Output values are cropped to QuantumRange (no overflow).", 1137 " This operation is independent of the matte", 1138 " channels.", 1139 "", 1140 "Minus The result of image - image window, with underflow", 1141 " cropped to zero.", 1142 "", 1143 "Add The result of image + image window, with overflow", 1144 " wrapping around (mod 256).", 1145 "", 1146 "Subtract The result of image - image window, with underflow", 1147 " wrapping around (mod 256). The add and subtract", 1148 " operators can be used to perform reversible", 1149 " transformations.", 1150 "", 1151 "Difference", 1152 " The result of abs(image - image window). This", 1153 " useful for comparing two very similar images.", 1154 "", 1155 "Copy The resulting image is image window replaced with", 1156 " image. Here the matte information is ignored.", 1157 "", 1158 "CopyRed The red layer of the image window is replace with", 1159 " the red layer of the image. The other layers are", 1160 " untouched.", 1161 "", 1162 "CopyGreen", 1163 " The green layer of the image window is replace with", 1164 " the green layer of the image. The other layers are", 1165 " untouched.", 1166 "", 1167 "CopyBlue The blue layer of the image window is replace with", 1168 " the blue layer of the image. The other layers are", 1169 " untouched.", 1170 "", 1171 "CopyOpacity", 1172 " The matte layer of the image window is replace with", 1173 " the matte layer of the image. The other layers are", 1174 " untouched.", 1175 "", 1176 "The image compositor requires a matte, or alpha channel in", 1177 "the image for some operations. This extra channel usually", 1178 "defines a mask which represents a sort of a cookie-cutter", 1179 "for the image. This the case when matte is opaque (full", 1180 "coverage) for pixels inside the shape, zero outside, and", 1181 "between 0 and QuantumRange on the boundary. If image does not", 1182 "have a matte channel, it is initialized with 0 for any pixel", 1183 "matching in color to pixel location (0,0), otherwise QuantumRange.", 1184 "", 1185 "Note that matte information for image window is not retained", 1186 "for colormapped X server visuals (e.g. StaticColor,", 1187 "StaticColor, GrayScale, PseudoColor). Correct compositing", 1188 "behavior may require a TrueColor or DirectColor visual or a", 1189 "Standard Colormap.", 1190 "", 1191 "Choosing a composite operator is optional. The default", 1192 "operator is replace. However, you must choose a location to", 1193 "paste your image and press button 1. Press and hold the", 1194 "button before releasing and an outline of the image will", 1195 "appear to help you identify your location.", 1196 "", 1197 "The actual colors of the pasted image is saved. However,", 1198 "the color that appears in image window may be different.", 1199 "For example, on a monochrome screen image window will appear", 1200 "black or white even though your pasted image may have", 1201 "many colors. If the image is saved to a file it is written", 1202 "with the correct colors. To assure the correct colors are", 1203 "saved in the final image, any PseudoClass image is promoted", 1204 "to DirectClass (see miff(5)). To force a PseudoClass image", 1205 "to remain PseudoClass, use -colors.", 1206 (char *) NULL, 1207 }, 1208 *ImageROIHelp[] = 1209 { 1210 "In region of interest mode, the Command widget has these", 1211 "options:", 1212 "", 1213 " Help", 1214 " Dismiss", 1215 "", 1216 "To define a region of interest, press button 1 and drag.", 1217 "The region of interest is defined by a highlighted rectangle", 1218 "that expands or contracts as it follows the pointer. Once", 1219 "you are satisfied with the region of interest, release the", 1220 "button. You are now in apply mode. In apply mode the", 1221 "Command widget has these options:", 1222 "", 1223 " File", 1224 " Save...", 1225 " Print...", 1226 " Edit", 1227 " Undo", 1228 " Redo", 1229 " Transform", 1230 " Flop", 1231 " Flip", 1232 " Rotate Right", 1233 " Rotate Left", 1234 " Enhance", 1235 " Hue...", 1236 " Saturation...", 1237 " Brightness...", 1238 " Gamma...", 1239 " Spiff", 1240 " Dull", 1241 " Contrast Stretch", 1242 " Sigmoidal Contrast...", 1243 " Normalize", 1244 " Equalize", 1245 " Negate", 1246 " Grayscale", 1247 " Map...", 1248 " Quantize...", 1249 " Effects", 1250 " Despeckle", 1251 " Emboss", 1252 " Reduce Noise", 1253 " Sharpen...", 1254 " Blur...", 1255 " Threshold...", 1256 " Edge Detect...", 1257 " Spread...", 1258 " Shade...", 1259 " Raise...", 1260 " Segment...", 1261 " F/X", 1262 " Solarize...", 1263 " Sepia Tone...", 1264 " Swirl...", 1265 " Implode...", 1266 " Vignette...", 1267 " Wave...", 1268 " Oil Painting...", 1269 " Charcoal Drawing...", 1270 " Miscellany", 1271 " Image Info", 1272 " Zoom Image", 1273 " Show Preview...", 1274 " Show Histogram", 1275 " Show Matte", 1276 " Help", 1277 " Dismiss", 1278 "", 1279 "You can make adjustments to the region of interest by moving", 1280 "the pointer to one of the rectangle corners, pressing a", 1281 "button, and dragging. Finally, choose an image processing", 1282 "technique from the Command widget. You can choose more than", 1283 "one image processing technique to apply to an area.", 1284 "Alternatively, you can move the region of interest before", 1285 "applying another image processing technique. To exit, press", 1286 "Dismiss.", 1287 (char *) NULL, 1288 }, 1289 *ImageRotateHelp[] = 1290 { 1291 "In rotate mode, the Command widget has these options:", 1292 "", 1293 " Pixel Color", 1294 " black", 1295 " blue", 1296 " cyan", 1297 " green", 1298 " gray", 1299 " red", 1300 " magenta", 1301 " yellow", 1302 " white", 1303 " Browser...", 1304 " Direction", 1305 " horizontal", 1306 " vertical", 1307 " Help", 1308 " Dismiss", 1309 "", 1310 "Choose a background color from the Pixel Color sub-menu.", 1311 "Additional background colors can be specified with the color", 1312 "browser. You can change the menu colors by setting the X", 1313 "resources pen1 through pen9.", 1314 "", 1315 "If you choose the color browser and press Grab, you can", 1316 "select the background color by moving the pointer to the", 1317 "desired color on the screen and press any button.", 1318 "", 1319 "Choose a point in the image window and press this button and", 1320 "hold. Next, move the pointer to another location in the", 1321 "image. As you move a line connects the initial location and", 1322 "the pointer. When you release the button, the degree of", 1323 "image rotation is determined by the slope of the line you", 1324 "just drew. The slope is relative to the direction you", 1325 "choose from the Direction sub-menu of the Command widget.", 1326 "", 1327 "To cancel the image rotation, move the pointer back to the", 1328 "starting point of the line and release the button.", 1329 (char *) NULL, 1330 }; 1331 1332/* 1333 Enumeration declarations. 1334*/ 1335typedef enum 1336{ 1337 CopyMode, 1338 CropMode, 1339 CutMode 1340} ClipboardMode; 1341 1342typedef enum 1343{ 1344 OpenCommand, 1345 NextCommand, 1346 FormerCommand, 1347 SelectCommand, 1348 SaveCommand, 1349 PrintCommand, 1350 DeleteCommand, 1351 NewCommand, 1352 VisualDirectoryCommand, 1353 QuitCommand, 1354 UndoCommand, 1355 RedoCommand, 1356 CutCommand, 1357 CopyCommand, 1358 PasteCommand, 1359 HalfSizeCommand, 1360 OriginalSizeCommand, 1361 DoubleSizeCommand, 1362 ResizeCommand, 1363 ApplyCommand, 1364 RefreshCommand, 1365 RestoreCommand, 1366 CropCommand, 1367 ChopCommand, 1368 FlopCommand, 1369 FlipCommand, 1370 RotateRightCommand, 1371 RotateLeftCommand, 1372 RotateCommand, 1373 ShearCommand, 1374 RollCommand, 1375 TrimCommand, 1376 HueCommand, 1377 SaturationCommand, 1378 BrightnessCommand, 1379 GammaCommand, 1380 SpiffCommand, 1381 DullCommand, 1382 ContrastStretchCommand, 1383 SigmoidalContrastCommand, 1384 NormalizeCommand, 1385 EqualizeCommand, 1386 NegateCommand, 1387 GrayscaleCommand, 1388 MapCommand, 1389 QuantizeCommand, 1390 DespeckleCommand, 1391 EmbossCommand, 1392 ReduceNoiseCommand, 1393 AddNoiseCommand, 1394 SharpenCommand, 1395 BlurCommand, 1396 ThresholdCommand, 1397 EdgeDetectCommand, 1398 SpreadCommand, 1399 ShadeCommand, 1400 RaiseCommand, 1401 SegmentCommand, 1402 SolarizeCommand, 1403 SepiaToneCommand, 1404 SwirlCommand, 1405 ImplodeCommand, 1406 VignetteCommand, 1407 WaveCommand, 1408 OilPaintCommand, 1409 CharcoalDrawCommand, 1410 AnnotateCommand, 1411 DrawCommand, 1412 ColorCommand, 1413 MatteCommand, 1414 CompositeCommand, 1415 AddBorderCommand, 1416 AddFrameCommand, 1417 CommentCommand, 1418 LaunchCommand, 1419 RegionofInterestCommand, 1420 ROIHelpCommand, 1421 ROIDismissCommand, 1422 InfoCommand, 1423 ZoomCommand, 1424 ShowPreviewCommand, 1425 ShowHistogramCommand, 1426 ShowMatteCommand, 1427 BackgroundCommand, 1428 SlideShowCommand, 1429 PreferencesCommand, 1430 HelpCommand, 1431 BrowseDocumentationCommand, 1432 VersionCommand, 1433 SaveToUndoBufferCommand, 1434 FreeBuffersCommand, 1435 NullCommand 1436} CommandType; 1437 1438typedef enum 1439{ 1440 AnnotateNameCommand, 1441 AnnotateFontColorCommand, 1442 AnnotateBackgroundColorCommand, 1443 AnnotateRotateCommand, 1444 AnnotateHelpCommand, 1445 AnnotateDismissCommand, 1446 TextHelpCommand, 1447 TextApplyCommand, 1448 ChopDirectionCommand, 1449 ChopHelpCommand, 1450 ChopDismissCommand, 1451 HorizontalChopCommand, 1452 VerticalChopCommand, 1453 ColorEditMethodCommand, 1454 ColorEditColorCommand, 1455 ColorEditBorderCommand, 1456 ColorEditFuzzCommand, 1457 ColorEditUndoCommand, 1458 ColorEditHelpCommand, 1459 ColorEditDismissCommand, 1460 CompositeOperatorsCommand, 1461 CompositeDissolveCommand, 1462 CompositeDisplaceCommand, 1463 CompositeHelpCommand, 1464 CompositeDismissCommand, 1465 CropHelpCommand, 1466 CropDismissCommand, 1467 RectifyCopyCommand, 1468 RectifyHelpCommand, 1469 RectifyDismissCommand, 1470 DrawElementCommand, 1471 DrawColorCommand, 1472 DrawStippleCommand, 1473 DrawWidthCommand, 1474 DrawUndoCommand, 1475 DrawHelpCommand, 1476 DrawDismissCommand, 1477 MatteEditMethod, 1478 MatteEditBorderCommand, 1479 MatteEditFuzzCommand, 1480 MatteEditValueCommand, 1481 MatteEditUndoCommand, 1482 MatteEditHelpCommand, 1483 MatteEditDismissCommand, 1484 PasteOperatorsCommand, 1485 PasteHelpCommand, 1486 PasteDismissCommand, 1487 RotateColorCommand, 1488 RotateDirectionCommand, 1489 RotateCropCommand, 1490 RotateSharpenCommand, 1491 RotateHelpCommand, 1492 RotateDismissCommand, 1493 HorizontalRotateCommand, 1494 VerticalRotateCommand, 1495 TileLoadCommand, 1496 TileNextCommand, 1497 TileFormerCommand, 1498 TileDeleteCommand, 1499 TileUpdateCommand 1500} ModeType; 1501 1502/* 1503 Stipples. 1504*/ 1505#define BricksWidth 20 1506#define BricksHeight 20 1507#define DiagonalWidth 16 1508#define DiagonalHeight 16 1509#define HighlightWidth 8 1510#define HighlightHeight 8 1511#define OpaqueWidth 8 1512#define OpaqueHeight 8 1513#define ScalesWidth 16 1514#define ScalesHeight 16 1515#define ShadowWidth 8 1516#define ShadowHeight 8 1517#define VerticalWidth 16 1518#define VerticalHeight 16 1519#define WavyWidth 16 1520#define WavyHeight 16 1521 1522/* 1523 Constant declaration. 1524*/ 1525static const int 1526 RoiDelta = 8; 1527 1528static const unsigned char 1529 BricksBitmap[] = 1530 { 1531 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 1532 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 1533 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 1534 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 1535 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01 1536 }, 1537 DiagonalBitmap[] = 1538 { 1539 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 1540 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 1541 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22 1542 }, 1543 ScalesBitmap[] = 1544 { 1545 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80, 1546 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 1547 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e 1548 }, 1549 VerticalBitmap[] = 1550 { 1551 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1552 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1553 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 1554 }, 1555 WavyBitmap[] = 1556 { 1557 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff, 1558 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf, 1559 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f 1560 }; 1561 1562/* 1563 Function prototypes. 1564*/ 1565static CommandType 1566 XImageWindowCommand(Display *,XResourceInfo *,XWindows *, 1567 const MagickStatusType,KeySym,Image **,ExceptionInfo *); 1568 1569static Image 1570 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType, 1571 Image **,ExceptionInfo *), 1572 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType), 1573 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *, 1574 ExceptionInfo *), 1575 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *, 1576 ExceptionInfo *); 1577 1578static MagickBooleanType 1579 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *, 1580 ExceptionInfo *), 1581 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **, 1582 ExceptionInfo *), 1583 XChopImage(Display *,XResourceInfo *,XWindows *,Image **, 1584 ExceptionInfo *), 1585 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode, 1586 ExceptionInfo *), 1587 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1588 ExceptionInfo *), 1589 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *, 1590 ExceptionInfo *), 1591 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1592 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1593 ExceptionInfo *), 1594 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1595 ExceptionInfo *), 1596 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1597 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1598 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **, 1599 ExceptionInfo *), 1600 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *), 1601 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1602 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *); 1603 1604static void 1605 XDrawPanRectangle(Display *,XWindows *), 1606 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **, 1607 ExceptionInfo *), 1608 XMagnifyImage(Display *,XWindows *,XEvent *), 1609 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1610 XPanImage(Display *,XWindows *,XEvent *), 1611 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType, 1612 const KeySym), 1613 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *), 1614 XScreenEvent(Display *,XWindows *,XEvent *), 1615 XTranslateImage(Display *,XWindows *,Image *,const KeySym); 1616 1617/* 1618%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1619% % 1620% % 1621% % 1622% D i s p l a y I m a g e s % 1623% % 1624% % 1625% % 1626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1627% 1628% DisplayImages() displays an image sequence to any X window screen. It 1629% returns a value other than 0 if successful. Check the exception member 1630% of image to determine the reason for any failure. 1631% 1632% The format of the DisplayImages method is: 1633% 1634% MagickBooleanType DisplayImages(const ImageInfo *image_info, 1635% Image *images,ExceptionInfo *exception) 1636% 1637% A description of each parameter follows: 1638% 1639% o image_info: the image info. 1640% 1641% o image: the image. 1642% 1643% o exception: return any errors or warnings in this structure. 1644% 1645*/ 1646MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 1647 Image *images,ExceptionInfo *exception) 1648{ 1649 char 1650 *argv[1]; 1651 1652 Display 1653 *display; 1654 1655 Image 1656 *image; 1657 1658 register ssize_t 1659 i; 1660 1661 size_t 1662 state; 1663 1664 XrmDatabase 1665 resource_database; 1666 1667 XResourceInfo 1668 resource_info; 1669 1670 assert(image_info != (const ImageInfo *) NULL); 1671 assert(image_info->signature == MagickSignature); 1672 assert(images != (Image *) NULL); 1673 assert(images->signature == MagickSignature); 1674 if (images->debug != MagickFalse) 1675 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 1676 display=XOpenDisplay(image_info->server_name); 1677 if (display == (Display *) NULL) 1678 { 1679 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1680 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1681 return(MagickFalse); 1682 } 1683 if (exception->severity != UndefinedException) 1684 CatchException(exception); 1685 (void) XSetErrorHandler(XError); 1686 resource_database=XGetResourceDatabase(display,GetClientName()); 1687 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info)); 1688 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info); 1689 if (image_info->page != (char *) NULL) 1690 resource_info.image_geometry=AcquireString(image_info->page); 1691 resource_info.immutable=MagickTrue; 1692 argv[0]=AcquireString(GetClientName()); 1693 state=DefaultState; 1694 for (i=0; (state & ExitState) == 0; i++) 1695 { 1696 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations)) 1697 break; 1698 image=GetImageFromList(images,i % GetImageListLength(images)); 1699 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception); 1700 } 1701 SetErrorHandler((ErrorHandler) NULL); 1702 SetWarningHandler((WarningHandler) NULL); 1703 argv[0]=DestroyString(argv[0]); 1704 (void) XCloseDisplay(display); 1705 XDestroyResourceInfo(&resource_info); 1706 if (exception->severity != UndefinedException) 1707 return(MagickFalse); 1708 return(MagickTrue); 1709} 1710 1711/* 1712%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1713% % 1714% % 1715% % 1716% R e m o t e D i s p l a y C o m m a n d % 1717% % 1718% % 1719% % 1720%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1721% 1722% RemoteDisplayCommand() encourages a remote display program to display the 1723% specified image filename. 1724% 1725% The format of the RemoteDisplayCommand method is: 1726% 1727% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1728% const char *window,const char *filename,ExceptionInfo *exception) 1729% 1730% A description of each parameter follows: 1731% 1732% o image_info: the image info. 1733% 1734% o window: Specifies the name or id of an X window. 1735% 1736% o filename: the name of the image filename to display. 1737% 1738% o exception: return any errors or warnings in this structure. 1739% 1740*/ 1741MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1742 const char *window,const char *filename,ExceptionInfo *exception) 1743{ 1744 Display 1745 *display; 1746 1747 MagickStatusType 1748 status; 1749 1750 assert(image_info != (const ImageInfo *) NULL); 1751 assert(image_info->signature == MagickSignature); 1752 assert(filename != (char *) NULL); 1753 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 1754 display=XOpenDisplay(image_info->server_name); 1755 if (display == (Display *) NULL) 1756 { 1757 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1758 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1759 return(MagickFalse); 1760 } 1761 (void) XSetErrorHandler(XError); 1762 status=XRemoteCommand(display,window,filename); 1763 (void) XCloseDisplay(display); 1764 return(status != 0 ? MagickTrue : MagickFalse); 1765} 1766 1767/* 1768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1769% % 1770% % 1771% % 1772+ X A n n o t a t e E d i t I m a g e % 1773% % 1774% % 1775% % 1776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1777% 1778% XAnnotateEditImage() annotates the image with text. 1779% 1780% The format of the XAnnotateEditImage method is: 1781% 1782% MagickBooleanType XAnnotateEditImage(Display *display, 1783% XResourceInfo *resource_info,XWindows *windows,Image *image, 1784% ExceptionInfo *exception) 1785% 1786% A description of each parameter follows: 1787% 1788% o display: Specifies a connection to an X server; returned from 1789% XOpenDisplay. 1790% 1791% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 1792% 1793% o windows: Specifies a pointer to a XWindows structure. 1794% 1795% o image: the image; returned from ReadImage. 1796% 1797*/ 1798 1799static inline ssize_t MagickMax(const ssize_t x,const ssize_t y) 1800{ 1801 if (x > y) 1802 return(x); 1803 return(y); 1804} 1805 1806static inline ssize_t MagickMin(const ssize_t x,const ssize_t y) 1807{ 1808 if (x < y) 1809 return(x); 1810 return(y); 1811} 1812 1813static MagickBooleanType XAnnotateEditImage(Display *display, 1814 XResourceInfo *resource_info,XWindows *windows,Image *image, 1815 ExceptionInfo *exception) 1816{ 1817 static const char 1818 *AnnotateMenu[] = 1819 { 1820 "Font Name", 1821 "Font Color", 1822 "Box Color", 1823 "Rotate Text", 1824 "Help", 1825 "Dismiss", 1826 (char *) NULL 1827 }, 1828 *TextMenu[] = 1829 { 1830 "Help", 1831 "Apply", 1832 (char *) NULL 1833 }; 1834 1835 static const ModeType 1836 AnnotateCommands[] = 1837 { 1838 AnnotateNameCommand, 1839 AnnotateFontColorCommand, 1840 AnnotateBackgroundColorCommand, 1841 AnnotateRotateCommand, 1842 AnnotateHelpCommand, 1843 AnnotateDismissCommand 1844 }, 1845 TextCommands[] = 1846 { 1847 TextHelpCommand, 1848 TextApplyCommand 1849 }; 1850 1851 static MagickBooleanType 1852 transparent_box = MagickTrue, 1853 transparent_pen = MagickFalse; 1854 1855 static MagickRealType 1856 degrees = 0.0; 1857 1858 static unsigned int 1859 box_id = MaxNumberPens-2, 1860 font_id = 0, 1861 pen_id = 0; 1862 1863 char 1864 command[MaxTextExtent], 1865 text[MaxTextExtent]; 1866 1867 const char 1868 *ColorMenu[MaxNumberPens+1]; 1869 1870 Cursor 1871 cursor; 1872 1873 GC 1874 annotate_context; 1875 1876 int 1877 id, 1878 pen_number, 1879 status, 1880 x, 1881 y; 1882 1883 KeySym 1884 key_symbol; 1885 1886 register char 1887 *p; 1888 1889 register ssize_t 1890 i; 1891 1892 unsigned int 1893 height, 1894 width; 1895 1896 size_t 1897 state; 1898 1899 XAnnotateInfo 1900 *annotate_info, 1901 *previous_info; 1902 1903 XColor 1904 color; 1905 1906 XFontStruct 1907 *font_info; 1908 1909 XEvent 1910 event, 1911 text_event; 1912 1913 /* 1914 Map Command widget. 1915 */ 1916 (void) CloneString(&windows->command.name,"Annotate"); 1917 windows->command.data=4; 1918 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL); 1919 (void) XMapRaised(display,windows->command.id); 1920 XClientMessage(display,windows->image.id,windows->im_protocols, 1921 windows->im_update_widget,CurrentTime); 1922 /* 1923 Track pointer until button 1 is pressed. 1924 */ 1925 XQueryPosition(display,windows->image.id,&x,&y); 1926 (void) XSelectInput(display,windows->image.id, 1927 windows->image.attributes.event_mask | PointerMotionMask); 1928 cursor=XCreateFontCursor(display,XC_left_side); 1929 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1930 state=DefaultState; 1931 do 1932 { 1933 if (windows->info.mapped != MagickFalse) 1934 { 1935 /* 1936 Display pointer position. 1937 */ 1938 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 1939 x+windows->image.x,y+windows->image.y); 1940 XInfoWidget(display,windows,text); 1941 } 1942 /* 1943 Wait for next event. 1944 */ 1945 XScreenEvent(display,windows,&event); 1946 if (event.xany.window == windows->command.id) 1947 { 1948 /* 1949 Select a command from the Command widget. 1950 */ 1951 id=XCommandWidget(display,windows,AnnotateMenu,&event); 1952 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1953 if (id < 0) 1954 continue; 1955 switch (AnnotateCommands[id]) 1956 { 1957 case AnnotateNameCommand: 1958 { 1959 const char 1960 *FontMenu[MaxNumberFonts]; 1961 1962 int 1963 font_number; 1964 1965 /* 1966 Initialize menu selections. 1967 */ 1968 for (i=0; i < MaxNumberFonts; i++) 1969 FontMenu[i]=resource_info->font_name[i]; 1970 FontMenu[MaxNumberFonts-2]="Browser..."; 1971 FontMenu[MaxNumberFonts-1]=(const char *) NULL; 1972 /* 1973 Select a font name from the pop-up menu. 1974 */ 1975 font_number=XMenuWidget(display,windows,AnnotateMenu[id], 1976 (const char **) FontMenu,command); 1977 if (font_number < 0) 1978 break; 1979 if (font_number == (MaxNumberFonts-2)) 1980 { 1981 static char 1982 font_name[MaxTextExtent] = "fixed"; 1983 1984 /* 1985 Select a font name from a browser. 1986 */ 1987 resource_info->font_name[font_number]=font_name; 1988 XFontBrowserWidget(display,windows,"Select",font_name); 1989 if (*font_name == '\0') 1990 break; 1991 } 1992 /* 1993 Initialize font info. 1994 */ 1995 font_info=XLoadQueryFont(display,resource_info->font_name[ 1996 font_number]); 1997 if (font_info == (XFontStruct *) NULL) 1998 { 1999 XNoticeWidget(display,windows,"Unable to load font:", 2000 resource_info->font_name[font_number]); 2001 break; 2002 } 2003 font_id=(unsigned int) font_number; 2004 (void) XFreeFont(display,font_info); 2005 break; 2006 } 2007 case AnnotateFontColorCommand: 2008 { 2009 /* 2010 Initialize menu selections. 2011 */ 2012 for (i=0; i < (int) (MaxNumberPens-2); i++) 2013 ColorMenu[i]=resource_info->pen_colors[i]; 2014 ColorMenu[MaxNumberPens-2]="transparent"; 2015 ColorMenu[MaxNumberPens-1]="Browser..."; 2016 ColorMenu[MaxNumberPens]=(const char *) NULL; 2017 /* 2018 Select a pen color from the pop-up menu. 2019 */ 2020 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2021 (const char **) ColorMenu,command); 2022 if (pen_number < 0) 2023 break; 2024 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue : 2025 MagickFalse; 2026 if (transparent_pen != MagickFalse) 2027 break; 2028 if (pen_number == (MaxNumberPens-1)) 2029 { 2030 static char 2031 color_name[MaxTextExtent] = "gray"; 2032 2033 /* 2034 Select a pen color from a dialog. 2035 */ 2036 resource_info->pen_colors[pen_number]=color_name; 2037 XColorBrowserWidget(display,windows,"Select",color_name); 2038 if (*color_name == '\0') 2039 break; 2040 } 2041 /* 2042 Set pen color. 2043 */ 2044 (void) XParseColor(display,windows->map_info->colormap, 2045 resource_info->pen_colors[pen_number],&color); 2046 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2047 (unsigned int) MaxColors,&color); 2048 windows->pixel_info->pen_colors[pen_number]=color; 2049 pen_id=(unsigned int) pen_number; 2050 break; 2051 } 2052 case AnnotateBackgroundColorCommand: 2053 { 2054 /* 2055 Initialize menu selections. 2056 */ 2057 for (i=0; i < (int) (MaxNumberPens-2); i++) 2058 ColorMenu[i]=resource_info->pen_colors[i]; 2059 ColorMenu[MaxNumberPens-2]="transparent"; 2060 ColorMenu[MaxNumberPens-1]="Browser..."; 2061 ColorMenu[MaxNumberPens]=(const char *) NULL; 2062 /* 2063 Select a pen color from the pop-up menu. 2064 */ 2065 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2066 (const char **) ColorMenu,command); 2067 if (pen_number < 0) 2068 break; 2069 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue : 2070 MagickFalse; 2071 if (transparent_box != MagickFalse) 2072 break; 2073 if (pen_number == (MaxNumberPens-1)) 2074 { 2075 static char 2076 color_name[MaxTextExtent] = "gray"; 2077 2078 /* 2079 Select a pen color from a dialog. 2080 */ 2081 resource_info->pen_colors[pen_number]=color_name; 2082 XColorBrowserWidget(display,windows,"Select",color_name); 2083 if (*color_name == '\0') 2084 break; 2085 } 2086 /* 2087 Set pen color. 2088 */ 2089 (void) XParseColor(display,windows->map_info->colormap, 2090 resource_info->pen_colors[pen_number],&color); 2091 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2092 (unsigned int) MaxColors,&color); 2093 windows->pixel_info->pen_colors[pen_number]=color; 2094 box_id=(unsigned int) pen_number; 2095 break; 2096 } 2097 case AnnotateRotateCommand: 2098 { 2099 int 2100 entry; 2101 2102 static char 2103 angle[MaxTextExtent] = "30.0"; 2104 2105 static const char 2106 *RotateMenu[] = 2107 { 2108 "-90", 2109 "-45", 2110 "-30", 2111 "0", 2112 "30", 2113 "45", 2114 "90", 2115 "180", 2116 "Dialog...", 2117 (char *) NULL, 2118 }; 2119 2120 /* 2121 Select a command from the pop-up menu. 2122 */ 2123 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu, 2124 command); 2125 if (entry < 0) 2126 break; 2127 if (entry != 8) 2128 { 2129 degrees=InterpretLocaleValue(RotateMenu[entry],(char **) NULL); 2130 break; 2131 } 2132 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:", 2133 angle); 2134 if (*angle == '\0') 2135 break; 2136 degrees=InterpretLocaleValue(angle,(char **) NULL); 2137 break; 2138 } 2139 case AnnotateHelpCommand: 2140 { 2141 XTextViewWidget(display,resource_info,windows,MagickFalse, 2142 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2143 break; 2144 } 2145 case AnnotateDismissCommand: 2146 { 2147 /* 2148 Prematurely exit. 2149 */ 2150 state|=EscapeState; 2151 state|=ExitState; 2152 break; 2153 } 2154 default: 2155 break; 2156 } 2157 continue; 2158 } 2159 switch (event.type) 2160 { 2161 case ButtonPress: 2162 { 2163 if (event.xbutton.button != Button1) 2164 break; 2165 if (event.xbutton.window != windows->image.id) 2166 break; 2167 /* 2168 Change to text entering mode. 2169 */ 2170 x=event.xbutton.x; 2171 y=event.xbutton.y; 2172 state|=ExitState; 2173 break; 2174 } 2175 case ButtonRelease: 2176 break; 2177 case Expose: 2178 break; 2179 case KeyPress: 2180 { 2181 if (event.xkey.window != windows->image.id) 2182 break; 2183 /* 2184 Respond to a user key press. 2185 */ 2186 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2187 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2188 switch ((int) key_symbol) 2189 { 2190 case XK_Escape: 2191 case XK_F20: 2192 { 2193 /* 2194 Prematurely exit. 2195 */ 2196 state|=EscapeState; 2197 state|=ExitState; 2198 break; 2199 } 2200 case XK_F1: 2201 case XK_Help: 2202 { 2203 XTextViewWidget(display,resource_info,windows,MagickFalse, 2204 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2205 break; 2206 } 2207 default: 2208 { 2209 (void) XBell(display,0); 2210 break; 2211 } 2212 } 2213 break; 2214 } 2215 case MotionNotify: 2216 { 2217 /* 2218 Map and unmap Info widget as cursor crosses its boundaries. 2219 */ 2220 x=event.xmotion.x; 2221 y=event.xmotion.y; 2222 if (windows->info.mapped != MagickFalse) 2223 { 2224 if ((x < (int) (windows->info.x+windows->info.width)) && 2225 (y < (int) (windows->info.y+windows->info.height))) 2226 (void) XWithdrawWindow(display,windows->info.id, 2227 windows->info.screen); 2228 } 2229 else 2230 if ((x > (int) (windows->info.x+windows->info.width)) || 2231 (y > (int) (windows->info.y+windows->info.height))) 2232 (void) XMapWindow(display,windows->info.id); 2233 break; 2234 } 2235 default: 2236 break; 2237 } 2238 } while ((state & ExitState) == 0); 2239 (void) XSelectInput(display,windows->image.id, 2240 windows->image.attributes.event_mask); 2241 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 2242 if ((state & EscapeState) != 0) 2243 return(MagickTrue); 2244 /* 2245 Set font info and check boundary conditions. 2246 */ 2247 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]); 2248 if (font_info == (XFontStruct *) NULL) 2249 { 2250 XNoticeWidget(display,windows,"Unable to load font:", 2251 resource_info->font_name[font_id]); 2252 font_info=windows->font_info; 2253 } 2254 if ((x+font_info->max_bounds.width) >= (int) windows->image.width) 2255 x=(int) windows->image.width-font_info->max_bounds.width; 2256 if (y < (int) (font_info->ascent+font_info->descent)) 2257 y=(int) font_info->ascent+font_info->descent; 2258 if (((int) font_info->max_bounds.width > (int) windows->image.width) || 2259 ((font_info->ascent+font_info->descent) >= (int) windows->image.height)) 2260 return(MagickFalse); 2261 /* 2262 Initialize annotate structure. 2263 */ 2264 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info)); 2265 if (annotate_info == (XAnnotateInfo *) NULL) 2266 return(MagickFalse); 2267 XGetAnnotateInfo(annotate_info); 2268 annotate_info->x=x; 2269 annotate_info->y=y; 2270 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse)) 2271 annotate_info->stencil=OpaqueStencil; 2272 else 2273 if (transparent_box == MagickFalse) 2274 annotate_info->stencil=BackgroundStencil; 2275 else 2276 annotate_info->stencil=ForegroundStencil; 2277 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent; 2278 annotate_info->degrees=degrees; 2279 annotate_info->font_info=font_info; 2280 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2281 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL, 2282 sizeof(*annotate_info->text)); 2283 if (annotate_info->text == (char *) NULL) 2284 return(MagickFalse); 2285 /* 2286 Create cursor and set graphic context. 2287 */ 2288 cursor=XCreateFontCursor(display,XC_pencil); 2289 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2290 annotate_context=windows->image.annotate_context; 2291 (void) XSetFont(display,annotate_context,font_info->fid); 2292 (void) XSetBackground(display,annotate_context, 2293 windows->pixel_info->pen_colors[box_id].pixel); 2294 (void) XSetForeground(display,annotate_context, 2295 windows->pixel_info->pen_colors[pen_id].pixel); 2296 /* 2297 Begin annotating the image with text. 2298 */ 2299 (void) CloneString(&windows->command.name,"Text"); 2300 windows->command.data=0; 2301 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL); 2302 state=DefaultState; 2303 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2304 text_event.xexpose.width=(int) font_info->max_bounds.width; 2305 text_event.xexpose.height=font_info->max_bounds.ascent+ 2306 font_info->max_bounds.descent; 2307 p=annotate_info->text; 2308 do 2309 { 2310 /* 2311 Display text cursor. 2312 */ 2313 *p='\0'; 2314 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2315 /* 2316 Wait for next event. 2317 */ 2318 XScreenEvent(display,windows,&event); 2319 if (event.xany.window == windows->command.id) 2320 { 2321 /* 2322 Select a command from the Command widget. 2323 */ 2324 (void) XSetBackground(display,annotate_context, 2325 windows->pixel_info->background_color.pixel); 2326 (void) XSetForeground(display,annotate_context, 2327 windows->pixel_info->foreground_color.pixel); 2328 id=XCommandWidget(display,windows,AnnotateMenu,&event); 2329 (void) XSetBackground(display,annotate_context, 2330 windows->pixel_info->pen_colors[box_id].pixel); 2331 (void) XSetForeground(display,annotate_context, 2332 windows->pixel_info->pen_colors[pen_id].pixel); 2333 if (id < 0) 2334 continue; 2335 switch (TextCommands[id]) 2336 { 2337 case TextHelpCommand: 2338 { 2339 XTextViewWidget(display,resource_info,windows,MagickFalse, 2340 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2341 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2342 break; 2343 } 2344 case TextApplyCommand: 2345 { 2346 /* 2347 Finished annotating. 2348 */ 2349 annotate_info->width=(unsigned int) XTextWidth(font_info, 2350 annotate_info->text,(int) strlen(annotate_info->text)); 2351 XRefreshWindow(display,&windows->image,&text_event); 2352 state|=ExitState; 2353 break; 2354 } 2355 default: 2356 break; 2357 } 2358 continue; 2359 } 2360 /* 2361 Erase text cursor. 2362 */ 2363 text_event.xexpose.x=x; 2364 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2365 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y, 2366 (unsigned int) text_event.xexpose.width,(unsigned int) 2367 text_event.xexpose.height,MagickFalse); 2368 XRefreshWindow(display,&windows->image,&text_event); 2369 switch (event.type) 2370 { 2371 case ButtonPress: 2372 { 2373 if (event.xbutton.window != windows->image.id) 2374 break; 2375 if (event.xbutton.button == Button2) 2376 { 2377 /* 2378 Request primary selection. 2379 */ 2380 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, 2381 windows->image.id,CurrentTime); 2382 break; 2383 } 2384 break; 2385 } 2386 case Expose: 2387 { 2388 if (event.xexpose.count == 0) 2389 { 2390 XAnnotateInfo 2391 *text_info; 2392 2393 /* 2394 Refresh Image window. 2395 */ 2396 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 2397 text_info=annotate_info; 2398 while (text_info != (XAnnotateInfo *) NULL) 2399 { 2400 if (annotate_info->stencil == ForegroundStencil) 2401 (void) XDrawString(display,windows->image.id,annotate_context, 2402 text_info->x,text_info->y,text_info->text, 2403 (int) strlen(text_info->text)); 2404 else 2405 (void) XDrawImageString(display,windows->image.id, 2406 annotate_context,text_info->x,text_info->y,text_info->text, 2407 (int) strlen(text_info->text)); 2408 text_info=text_info->previous; 2409 } 2410 (void) XDrawString(display,windows->image.id,annotate_context, 2411 x,y,"_",1); 2412 } 2413 break; 2414 } 2415 case KeyPress: 2416 { 2417 int 2418 length; 2419 2420 if (event.xkey.window != windows->image.id) 2421 break; 2422 /* 2423 Respond to a user key press. 2424 */ 2425 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 2426 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2427 *(command+length)='\0'; 2428 if (((event.xkey.state & ControlMask) != 0) || 2429 ((event.xkey.state & Mod1Mask) != 0)) 2430 state|=ModifierState; 2431 if ((state & ModifierState) != 0) 2432 switch ((int) key_symbol) 2433 { 2434 case XK_u: 2435 case XK_U: 2436 { 2437 key_symbol=DeleteCommand; 2438 break; 2439 } 2440 default: 2441 break; 2442 } 2443 switch ((int) key_symbol) 2444 { 2445 case XK_BackSpace: 2446 { 2447 /* 2448 Erase one character. 2449 */ 2450 if (p == annotate_info->text) 2451 { 2452 if (annotate_info->previous == (XAnnotateInfo *) NULL) 2453 break; 2454 else 2455 { 2456 /* 2457 Go to end of the previous line of text. 2458 */ 2459 annotate_info=annotate_info->previous; 2460 p=annotate_info->text; 2461 x=annotate_info->x+annotate_info->width; 2462 y=annotate_info->y; 2463 if (annotate_info->width != 0) 2464 p+=strlen(annotate_info->text); 2465 break; 2466 } 2467 } 2468 p--; 2469 x-=XTextWidth(font_info,p,1); 2470 text_event.xexpose.x=x; 2471 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2472 XRefreshWindow(display,&windows->image,&text_event); 2473 break; 2474 } 2475 case XK_bracketleft: 2476 { 2477 key_symbol=XK_Escape; 2478 break; 2479 } 2480 case DeleteCommand: 2481 { 2482 /* 2483 Erase the entire line of text. 2484 */ 2485 while (p != annotate_info->text) 2486 { 2487 p--; 2488 x-=XTextWidth(font_info,p,1); 2489 text_event.xexpose.x=x; 2490 XRefreshWindow(display,&windows->image,&text_event); 2491 } 2492 break; 2493 } 2494 case XK_Escape: 2495 case XK_F20: 2496 { 2497 /* 2498 Finished annotating. 2499 */ 2500 annotate_info->width=(unsigned int) XTextWidth(font_info, 2501 annotate_info->text,(int) strlen(annotate_info->text)); 2502 XRefreshWindow(display,&windows->image,&text_event); 2503 state|=ExitState; 2504 break; 2505 } 2506 default: 2507 { 2508 /* 2509 Draw a single character on the Image window. 2510 */ 2511 if ((state & ModifierState) != 0) 2512 break; 2513 if (*command == '\0') 2514 break; 2515 *p=(*command); 2516 if (annotate_info->stencil == ForegroundStencil) 2517 (void) XDrawString(display,windows->image.id,annotate_context, 2518 x,y,p,1); 2519 else 2520 (void) XDrawImageString(display,windows->image.id, 2521 annotate_context,x,y,p,1); 2522 x+=XTextWidth(font_info,p,1); 2523 p++; 2524 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2525 break; 2526 } 2527 case XK_Return: 2528 case XK_KP_Enter: 2529 { 2530 /* 2531 Advance to the next line of text. 2532 */ 2533 *p='\0'; 2534 annotate_info->width=(unsigned int) XTextWidth(font_info, 2535 annotate_info->text,(int) strlen(annotate_info->text)); 2536 if (annotate_info->next != (XAnnotateInfo *) NULL) 2537 { 2538 /* 2539 Line of text already exists. 2540 */ 2541 annotate_info=annotate_info->next; 2542 x=annotate_info->x; 2543 y=annotate_info->y; 2544 p=annotate_info->text; 2545 break; 2546 } 2547 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2548 sizeof(*annotate_info->next)); 2549 if (annotate_info->next == (XAnnotateInfo *) NULL) 2550 return(MagickFalse); 2551 *annotate_info->next=(*annotate_info); 2552 annotate_info->next->previous=annotate_info; 2553 annotate_info=annotate_info->next; 2554 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2555 windows->image.width/MagickMax((ssize_t) 2556 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2557 if (annotate_info->text == (char *) NULL) 2558 return(MagickFalse); 2559 annotate_info->y+=annotate_info->height; 2560 if (annotate_info->y > (int) windows->image.height) 2561 annotate_info->y=(int) annotate_info->height; 2562 annotate_info->next=(XAnnotateInfo *) NULL; 2563 x=annotate_info->x; 2564 y=annotate_info->y; 2565 p=annotate_info->text; 2566 break; 2567 } 2568 } 2569 break; 2570 } 2571 case KeyRelease: 2572 { 2573 /* 2574 Respond to a user key release. 2575 */ 2576 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2577 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2578 state&=(~ModifierState); 2579 break; 2580 } 2581 case SelectionNotify: 2582 { 2583 Atom 2584 type; 2585 2586 int 2587 format; 2588 2589 unsigned char 2590 *data; 2591 2592 unsigned long 2593 after, 2594 length; 2595 2596 /* 2597 Obtain response from primary selection. 2598 */ 2599 if (event.xselection.property == (Atom) None) 2600 break; 2601 status=XGetWindowProperty(display,event.xselection.requestor, 2602 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING, 2603 &type,&format,&length,&after,&data); 2604 if ((status != Success) || (type != XA_STRING) || (format == 32) || 2605 (length == 0)) 2606 break; 2607 /* 2608 Annotate Image window with primary selection. 2609 */ 2610 for (i=0; i < (ssize_t) length; i++) 2611 { 2612 if ((char) data[i] != '\n') 2613 { 2614 /* 2615 Draw a single character on the Image window. 2616 */ 2617 *p=(char) data[i]; 2618 (void) XDrawString(display,windows->image.id,annotate_context, 2619 x,y,p,1); 2620 x+=XTextWidth(font_info,p,1); 2621 p++; 2622 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2623 continue; 2624 } 2625 /* 2626 Advance to the next line of text. 2627 */ 2628 *p='\0'; 2629 annotate_info->width=(unsigned int) XTextWidth(font_info, 2630 annotate_info->text,(int) strlen(annotate_info->text)); 2631 if (annotate_info->next != (XAnnotateInfo *) NULL) 2632 { 2633 /* 2634 Line of text already exists. 2635 */ 2636 annotate_info=annotate_info->next; 2637 x=annotate_info->x; 2638 y=annotate_info->y; 2639 p=annotate_info->text; 2640 continue; 2641 } 2642 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2643 sizeof(*annotate_info->next)); 2644 if (annotate_info->next == (XAnnotateInfo *) NULL) 2645 return(MagickFalse); 2646 *annotate_info->next=(*annotate_info); 2647 annotate_info->next->previous=annotate_info; 2648 annotate_info=annotate_info->next; 2649 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2650 windows->image.width/MagickMax((ssize_t) 2651 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2652 if (annotate_info->text == (char *) NULL) 2653 return(MagickFalse); 2654 annotate_info->y+=annotate_info->height; 2655 if (annotate_info->y > (int) windows->image.height) 2656 annotate_info->y=(int) annotate_info->height; 2657 annotate_info->next=(XAnnotateInfo *) NULL; 2658 x=annotate_info->x; 2659 y=annotate_info->y; 2660 p=annotate_info->text; 2661 } 2662 (void) XFree((void *) data); 2663 break; 2664 } 2665 default: 2666 break; 2667 } 2668 } while ((state & ExitState) == 0); 2669 (void) XFreeCursor(display,cursor); 2670 /* 2671 Annotation is relative to image configuration. 2672 */ 2673 width=(unsigned int) image->columns; 2674 height=(unsigned int) image->rows; 2675 x=0; 2676 y=0; 2677 if (windows->image.crop_geometry != (char *) NULL) 2678 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 2679 /* 2680 Initialize annotated image. 2681 */ 2682 XSetCursorState(display,windows,MagickTrue); 2683 XCheckRefreshWindows(display,windows); 2684 while (annotate_info != (XAnnotateInfo *) NULL) 2685 { 2686 if (annotate_info->width == 0) 2687 { 2688 /* 2689 No text on this line-- go to the next line of text. 2690 */ 2691 previous_info=annotate_info->previous; 2692 annotate_info->text=(char *) 2693 RelinquishMagickMemory(annotate_info->text); 2694 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2695 annotate_info=previous_info; 2696 continue; 2697 } 2698 /* 2699 Determine pixel index for box and pen color. 2700 */ 2701 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id]; 2702 if (windows->pixel_info->colors != 0) 2703 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2704 if (windows->pixel_info->pixels[i] == 2705 windows->pixel_info->pen_colors[box_id].pixel) 2706 { 2707 windows->pixel_info->box_index=(unsigned short) i; 2708 break; 2709 } 2710 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 2711 if (windows->pixel_info->colors != 0) 2712 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2713 if (windows->pixel_info->pixels[i] == 2714 windows->pixel_info->pen_colors[pen_id].pixel) 2715 { 2716 windows->pixel_info->pen_index=(unsigned short) i; 2717 break; 2718 } 2719 /* 2720 Define the annotate geometry string. 2721 */ 2722 annotate_info->x=(int) 2723 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width; 2724 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+ 2725 windows->image.y)/windows->image.ximage->height; 2726 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent, 2727 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width, 2728 height*annotate_info->height/windows->image.ximage->height, 2729 annotate_info->x+x,annotate_info->y+y); 2730 /* 2731 Annotate image with text. 2732 */ 2733 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image); 2734 if (status == 0) 2735 return(MagickFalse); 2736 /* 2737 Free up memory. 2738 */ 2739 previous_info=annotate_info->previous; 2740 annotate_info->text=DestroyString(annotate_info->text); 2741 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2742 annotate_info=previous_info; 2743 } 2744 (void) XSetForeground(display,annotate_context, 2745 windows->pixel_info->foreground_color.pixel); 2746 (void) XSetBackground(display,annotate_context, 2747 windows->pixel_info->background_color.pixel); 2748 (void) XSetFont(display,annotate_context,windows->font_info->fid); 2749 XSetCursorState(display,windows,MagickFalse); 2750 (void) XFreeFont(display,font_info); 2751 /* 2752 Update image configuration. 2753 */ 2754 XConfigureImageColormap(display,resource_info,windows,image); 2755 (void) XConfigureImage(display,resource_info,windows,image,exception); 2756 return(MagickTrue); 2757} 2758 2759/* 2760%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2761% % 2762% % 2763% % 2764+ X B a c k g r o u n d I m a g e % 2765% % 2766% % 2767% % 2768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2769% 2770% XBackgroundImage() displays the image in the background of a window. 2771% 2772% The format of the XBackgroundImage method is: 2773% 2774% MagickBooleanType XBackgroundImage(Display *display, 2775% XResourceInfo *resource_info,XWindows *windows,Image **image, 2776% ExceptionInfo *exception) 2777% 2778% A description of each parameter follows: 2779% 2780% o display: Specifies a connection to an X server; returned from 2781% XOpenDisplay. 2782% 2783% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2784% 2785% o windows: Specifies a pointer to a XWindows structure. 2786% 2787% o image: the image. 2788% 2789% o exception: return any errors or warnings in this structure. 2790% 2791*/ 2792static MagickBooleanType XBackgroundImage(Display *display, 2793 XResourceInfo *resource_info,XWindows *windows,Image **image, 2794 ExceptionInfo *exception) 2795{ 2796#define BackgroundImageTag "Background/Image" 2797 2798 int 2799 status; 2800 2801 static char 2802 window_id[MaxTextExtent] = "root"; 2803 2804 XResourceInfo 2805 background_resources; 2806 2807 /* 2808 Put image in background. 2809 */ 2810 status=XDialogWidget(display,windows,"Background", 2811 "Enter window id (id 0x00 selects window with pointer):",window_id); 2812 if (*window_id == '\0') 2813 return(MagickFalse); 2814 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 2815 exception); 2816 XInfoWidget(display,windows,BackgroundImageTag); 2817 XSetCursorState(display,windows,MagickTrue); 2818 XCheckRefreshWindows(display,windows); 2819 background_resources=(*resource_info); 2820 background_resources.window_id=window_id; 2821 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse; 2822 status=XDisplayBackgroundImage(display,&background_resources,*image, 2823 exception); 2824 if (status != MagickFalse) 2825 XClientMessage(display,windows->image.id,windows->im_protocols, 2826 windows->im_retain_colors,CurrentTime); 2827 XSetCursorState(display,windows,MagickFalse); 2828 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image, 2829 exception); 2830 return(MagickTrue); 2831} 2832 2833/* 2834%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2835% % 2836% % 2837% % 2838+ X C h o p I m a g e % 2839% % 2840% % 2841% % 2842%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2843% 2844% XChopImage() chops the X image. 2845% 2846% The format of the XChopImage method is: 2847% 2848% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info, 2849% XWindows *windows,Image **image,ExceptionInfo *exception) 2850% 2851% A description of each parameter follows: 2852% 2853% o display: Specifies a connection to an X server; returned from 2854% XOpenDisplay. 2855% 2856% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2857% 2858% o windows: Specifies a pointer to a XWindows structure. 2859% 2860% o image: the image. 2861% 2862% o exception: return any errors or warnings in this structure. 2863% 2864*/ 2865static MagickBooleanType XChopImage(Display *display, 2866 XResourceInfo *resource_info,XWindows *windows,Image **image, 2867 ExceptionInfo *exception) 2868{ 2869 static const char 2870 *ChopMenu[] = 2871 { 2872 "Direction", 2873 "Help", 2874 "Dismiss", 2875 (char *) NULL 2876 }; 2877 2878 static ModeType 2879 direction = HorizontalChopCommand; 2880 2881 static const ModeType 2882 ChopCommands[] = 2883 { 2884 ChopDirectionCommand, 2885 ChopHelpCommand, 2886 ChopDismissCommand 2887 }, 2888 DirectionCommands[] = 2889 { 2890 HorizontalChopCommand, 2891 VerticalChopCommand 2892 }; 2893 2894 char 2895 text[MaxTextExtent]; 2896 2897 Image 2898 *chop_image; 2899 2900 int 2901 id, 2902 x, 2903 y; 2904 2905 MagickRealType 2906 scale_factor; 2907 2908 RectangleInfo 2909 chop_info; 2910 2911 unsigned int 2912 distance, 2913 height, 2914 width; 2915 2916 size_t 2917 state; 2918 2919 XEvent 2920 event; 2921 2922 XSegment 2923 segment_info; 2924 2925 /* 2926 Map Command widget. 2927 */ 2928 (void) CloneString(&windows->command.name,"Chop"); 2929 windows->command.data=1; 2930 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL); 2931 (void) XMapRaised(display,windows->command.id); 2932 XClientMessage(display,windows->image.id,windows->im_protocols, 2933 windows->im_update_widget,CurrentTime); 2934 /* 2935 Track pointer until button 1 is pressed. 2936 */ 2937 XQueryPosition(display,windows->image.id,&x,&y); 2938 (void) XSelectInput(display,windows->image.id, 2939 windows->image.attributes.event_mask | PointerMotionMask); 2940 state=DefaultState; 2941 do 2942 { 2943 if (windows->info.mapped != MagickFalse) 2944 { 2945 /* 2946 Display pointer position. 2947 */ 2948 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 2949 x+windows->image.x,y+windows->image.y); 2950 XInfoWidget(display,windows,text); 2951 } 2952 /* 2953 Wait for next event. 2954 */ 2955 XScreenEvent(display,windows,&event); 2956 if (event.xany.window == windows->command.id) 2957 { 2958 /* 2959 Select a command from the Command widget. 2960 */ 2961 id=XCommandWidget(display,windows,ChopMenu,&event); 2962 if (id < 0) 2963 continue; 2964 switch (ChopCommands[id]) 2965 { 2966 case ChopDirectionCommand: 2967 { 2968 char 2969 command[MaxTextExtent]; 2970 2971 static const char 2972 *Directions[] = 2973 { 2974 "horizontal", 2975 "vertical", 2976 (char *) NULL, 2977 }; 2978 2979 /* 2980 Select a command from the pop-up menu. 2981 */ 2982 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 2983 if (id >= 0) 2984 direction=DirectionCommands[id]; 2985 break; 2986 } 2987 case ChopHelpCommand: 2988 { 2989 XTextViewWidget(display,resource_info,windows,MagickFalse, 2990 "Help Viewer - Image Chop",ImageChopHelp); 2991 break; 2992 } 2993 case ChopDismissCommand: 2994 { 2995 /* 2996 Prematurely exit. 2997 */ 2998 state|=EscapeState; 2999 state|=ExitState; 3000 break; 3001 } 3002 default: 3003 break; 3004 } 3005 continue; 3006 } 3007 switch (event.type) 3008 { 3009 case ButtonPress: 3010 { 3011 if (event.xbutton.button != Button1) 3012 break; 3013 if (event.xbutton.window != windows->image.id) 3014 break; 3015 /* 3016 User has committed to start point of chopping line. 3017 */ 3018 segment_info.x1=(short int) event.xbutton.x; 3019 segment_info.x2=(short int) event.xbutton.x; 3020 segment_info.y1=(short int) event.xbutton.y; 3021 segment_info.y2=(short int) event.xbutton.y; 3022 state|=ExitState; 3023 break; 3024 } 3025 case ButtonRelease: 3026 break; 3027 case Expose: 3028 break; 3029 case KeyPress: 3030 { 3031 char 3032 command[MaxTextExtent]; 3033 3034 KeySym 3035 key_symbol; 3036 3037 if (event.xkey.window != windows->image.id) 3038 break; 3039 /* 3040 Respond to a user key press. 3041 */ 3042 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3043 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3044 switch ((int) key_symbol) 3045 { 3046 case XK_Escape: 3047 case XK_F20: 3048 { 3049 /* 3050 Prematurely exit. 3051 */ 3052 state|=EscapeState; 3053 state|=ExitState; 3054 break; 3055 } 3056 case XK_F1: 3057 case XK_Help: 3058 { 3059 (void) XSetFunction(display,windows->image.highlight_context, 3060 GXcopy); 3061 XTextViewWidget(display,resource_info,windows,MagickFalse, 3062 "Help Viewer - Image Chop",ImageChopHelp); 3063 (void) XSetFunction(display,windows->image.highlight_context, 3064 GXinvert); 3065 break; 3066 } 3067 default: 3068 { 3069 (void) XBell(display,0); 3070 break; 3071 } 3072 } 3073 break; 3074 } 3075 case MotionNotify: 3076 { 3077 /* 3078 Map and unmap Info widget as text cursor crosses its boundaries. 3079 */ 3080 x=event.xmotion.x; 3081 y=event.xmotion.y; 3082 if (windows->info.mapped != MagickFalse) 3083 { 3084 if ((x < (int) (windows->info.x+windows->info.width)) && 3085 (y < (int) (windows->info.y+windows->info.height))) 3086 (void) XWithdrawWindow(display,windows->info.id, 3087 windows->info.screen); 3088 } 3089 else 3090 if ((x > (int) (windows->info.x+windows->info.width)) || 3091 (y > (int) (windows->info.y+windows->info.height))) 3092 (void) XMapWindow(display,windows->info.id); 3093 } 3094 } 3095 } while ((state & ExitState) == 0); 3096 (void) XSelectInput(display,windows->image.id, 3097 windows->image.attributes.event_mask); 3098 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3099 if ((state & EscapeState) != 0) 3100 return(MagickTrue); 3101 /* 3102 Draw line as pointer moves until the mouse button is released. 3103 */ 3104 chop_info.width=0; 3105 chop_info.height=0; 3106 chop_info.x=0; 3107 chop_info.y=0; 3108 distance=0; 3109 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3110 state=DefaultState; 3111 do 3112 { 3113 if (distance > 9) 3114 { 3115 /* 3116 Display info and draw chopping line. 3117 */ 3118 if (windows->info.mapped == MagickFalse) 3119 (void) XMapWindow(display,windows->info.id); 3120 (void) FormatLocaleString(text,MaxTextExtent, 3121 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 3122 chop_info.height,(double) chop_info.x,(double) chop_info.y); 3123 XInfoWidget(display,windows,text); 3124 XHighlightLine(display,windows->image.id, 3125 windows->image.highlight_context,&segment_info); 3126 } 3127 else 3128 if (windows->info.mapped != MagickFalse) 3129 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3130 /* 3131 Wait for next event. 3132 */ 3133 XScreenEvent(display,windows,&event); 3134 if (distance > 9) 3135 XHighlightLine(display,windows->image.id, 3136 windows->image.highlight_context,&segment_info); 3137 switch (event.type) 3138 { 3139 case ButtonPress: 3140 { 3141 segment_info.x2=(short int) event.xmotion.x; 3142 segment_info.y2=(short int) event.xmotion.y; 3143 break; 3144 } 3145 case ButtonRelease: 3146 { 3147 /* 3148 User has committed to chopping line. 3149 */ 3150 segment_info.x2=(short int) event.xbutton.x; 3151 segment_info.y2=(short int) event.xbutton.y; 3152 state|=ExitState; 3153 break; 3154 } 3155 case Expose: 3156 break; 3157 case MotionNotify: 3158 { 3159 segment_info.x2=(short int) event.xmotion.x; 3160 segment_info.y2=(short int) event.xmotion.y; 3161 } 3162 default: 3163 break; 3164 } 3165 /* 3166 Check boundary conditions. 3167 */ 3168 if (segment_info.x2 < 0) 3169 segment_info.x2=0; 3170 else 3171 if (segment_info.x2 > windows->image.ximage->width) 3172 segment_info.x2=windows->image.ximage->width; 3173 if (segment_info.y2 < 0) 3174 segment_info.y2=0; 3175 else 3176 if (segment_info.y2 > windows->image.ximage->height) 3177 segment_info.y2=windows->image.ximage->height; 3178 distance=(unsigned int) 3179 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 3180 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 3181 /* 3182 Compute chopping geometry. 3183 */ 3184 if (direction == HorizontalChopCommand) 3185 { 3186 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 3187 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 3188 chop_info.height=0; 3189 chop_info.y=0; 3190 if (segment_info.x1 > (int) segment_info.x2) 3191 { 3192 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 3193 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 3194 } 3195 } 3196 else 3197 { 3198 chop_info.width=0; 3199 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 3200 chop_info.x=0; 3201 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 3202 if (segment_info.y1 > segment_info.y2) 3203 { 3204 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 3205 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 3206 } 3207 } 3208 } while ((state & ExitState) == 0); 3209 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 3210 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3211 if (distance <= 9) 3212 return(MagickTrue); 3213 /* 3214 Image chopping is relative to image configuration. 3215 */ 3216 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 3217 exception); 3218 XSetCursorState(display,windows,MagickTrue); 3219 XCheckRefreshWindows(display,windows); 3220 windows->image.window_changes.width=windows->image.ximage->width- 3221 (unsigned int) chop_info.width; 3222 windows->image.window_changes.height=windows->image.ximage->height- 3223 (unsigned int) chop_info.height; 3224 width=(unsigned int) (*image)->columns; 3225 height=(unsigned int) (*image)->rows; 3226 x=0; 3227 y=0; 3228 if (windows->image.crop_geometry != (char *) NULL) 3229 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 3230 scale_factor=(MagickRealType) width/windows->image.ximage->width; 3231 chop_info.x+=x; 3232 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 3233 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 3234 scale_factor=(MagickRealType) height/windows->image.ximage->height; 3235 chop_info.y+=y; 3236 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 3237 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 3238 /* 3239 Chop image. 3240 */ 3241 chop_image=ChopImage(*image,&chop_info,exception); 3242 XSetCursorState(display,windows,MagickFalse); 3243 if (chop_image == (Image *) NULL) 3244 return(MagickFalse); 3245 *image=DestroyImage(*image); 3246 *image=chop_image; 3247 /* 3248 Update image configuration. 3249 */ 3250 XConfigureImageColormap(display,resource_info,windows,*image); 3251 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3252 return(MagickTrue); 3253} 3254 3255/* 3256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3257% % 3258% % 3259% % 3260+ X C o l o r E d i t I m a g e % 3261% % 3262% % 3263% % 3264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3265% 3266% XColorEditImage() allows the user to interactively change the color of one 3267% pixel for a DirectColor image or one colormap entry for a PseudoClass image. 3268% 3269% The format of the XColorEditImage method is: 3270% 3271% MagickBooleanType XColorEditImage(Display *display, 3272% XResourceInfo *resource_info,XWindows *windows,Image **image, 3273% ExceptionInfo *exception) 3274% 3275% A description of each parameter follows: 3276% 3277% o display: Specifies a connection to an X server; returned from 3278% XOpenDisplay. 3279% 3280% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3281% 3282% o windows: Specifies a pointer to a XWindows structure. 3283% 3284% o image: the image; returned from ReadImage. 3285% 3286% o exception: return any errors or warnings in this structure. 3287% 3288*/ 3289static MagickBooleanType XColorEditImage(Display *display, 3290 XResourceInfo *resource_info,XWindows *windows,Image **image, 3291 ExceptionInfo *exception) 3292{ 3293 static const char 3294 *ColorEditMenu[] = 3295 { 3296 "Method", 3297 "Pixel Color", 3298 "Border Color", 3299 "Fuzz", 3300 "Undo", 3301 "Help", 3302 "Dismiss", 3303 (char *) NULL 3304 }; 3305 3306 static const ModeType 3307 ColorEditCommands[] = 3308 { 3309 ColorEditMethodCommand, 3310 ColorEditColorCommand, 3311 ColorEditBorderCommand, 3312 ColorEditFuzzCommand, 3313 ColorEditUndoCommand, 3314 ColorEditHelpCommand, 3315 ColorEditDismissCommand 3316 }; 3317 3318 static PaintMethod 3319 method = PointMethod; 3320 3321 static unsigned int 3322 pen_id = 0; 3323 3324 static XColor 3325 border_color = { 0, 0, 0, 0, 0, 0 }; 3326 3327 char 3328 command[MaxTextExtent], 3329 text[MaxTextExtent]; 3330 3331 Cursor 3332 cursor; 3333 3334 int 3335 entry, 3336 id, 3337 x, 3338 x_offset, 3339 y, 3340 y_offset; 3341 3342 register Quantum 3343 *q; 3344 3345 register ssize_t 3346 i; 3347 3348 unsigned int 3349 height, 3350 width; 3351 3352 size_t 3353 state; 3354 3355 XColor 3356 color; 3357 3358 XEvent 3359 event; 3360 3361 /* 3362 Map Command widget. 3363 */ 3364 (void) CloneString(&windows->command.name,"Color Edit"); 3365 windows->command.data=4; 3366 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 3367 (void) XMapRaised(display,windows->command.id); 3368 XClientMessage(display,windows->image.id,windows->im_protocols, 3369 windows->im_update_widget,CurrentTime); 3370 /* 3371 Make cursor. 3372 */ 3373 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 3374 resource_info->background_color,resource_info->foreground_color); 3375 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3376 /* 3377 Track pointer until button 1 is pressed. 3378 */ 3379 XQueryPosition(display,windows->image.id,&x,&y); 3380 (void) XSelectInput(display,windows->image.id, 3381 windows->image.attributes.event_mask | PointerMotionMask); 3382 state=DefaultState; 3383 do 3384 { 3385 if (windows->info.mapped != MagickFalse) 3386 { 3387 /* 3388 Display pointer position. 3389 */ 3390 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 3391 x+windows->image.x,y+windows->image.y); 3392 XInfoWidget(display,windows,text); 3393 } 3394 /* 3395 Wait for next event. 3396 */ 3397 XScreenEvent(display,windows,&event); 3398 if (event.xany.window == windows->command.id) 3399 { 3400 /* 3401 Select a command from the Command widget. 3402 */ 3403 id=XCommandWidget(display,windows,ColorEditMenu,&event); 3404 if (id < 0) 3405 { 3406 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3407 continue; 3408 } 3409 switch (ColorEditCommands[id]) 3410 { 3411 case ColorEditMethodCommand: 3412 { 3413 char 3414 **methods; 3415 3416 /* 3417 Select a method from the pop-up menu. 3418 */ 3419 methods=(char **) GetCommandOptions(MagickMethodOptions); 3420 if (methods == (char **) NULL) 3421 break; 3422 entry=XMenuWidget(display,windows,ColorEditMenu[id], 3423 (const char **) methods,command); 3424 if (entry >= 0) 3425 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 3426 MagickFalse,methods[entry]); 3427 methods=DestroyStringList(methods); 3428 break; 3429 } 3430 case ColorEditColorCommand: 3431 { 3432 const char 3433 *ColorMenu[MaxNumberPens]; 3434 3435 int 3436 pen_number; 3437 3438 /* 3439 Initialize menu selections. 3440 */ 3441 for (i=0; i < (int) (MaxNumberPens-2); i++) 3442 ColorMenu[i]=resource_info->pen_colors[i]; 3443 ColorMenu[MaxNumberPens-2]="Browser..."; 3444 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3445 /* 3446 Select a pen color from the pop-up menu. 3447 */ 3448 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3449 (const char **) ColorMenu,command); 3450 if (pen_number < 0) 3451 break; 3452 if (pen_number == (MaxNumberPens-2)) 3453 { 3454 static char 3455 color_name[MaxTextExtent] = "gray"; 3456 3457 /* 3458 Select a pen color from a dialog. 3459 */ 3460 resource_info->pen_colors[pen_number]=color_name; 3461 XColorBrowserWidget(display,windows,"Select",color_name); 3462 if (*color_name == '\0') 3463 break; 3464 } 3465 /* 3466 Set pen color. 3467 */ 3468 (void) XParseColor(display,windows->map_info->colormap, 3469 resource_info->pen_colors[pen_number],&color); 3470 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 3471 (unsigned int) MaxColors,&color); 3472 windows->pixel_info->pen_colors[pen_number]=color; 3473 pen_id=(unsigned int) pen_number; 3474 break; 3475 } 3476 case ColorEditBorderCommand: 3477 { 3478 const char 3479 *ColorMenu[MaxNumberPens]; 3480 3481 int 3482 pen_number; 3483 3484 /* 3485 Initialize menu selections. 3486 */ 3487 for (i=0; i < (int) (MaxNumberPens-2); i++) 3488 ColorMenu[i]=resource_info->pen_colors[i]; 3489 ColorMenu[MaxNumberPens-2]="Browser..."; 3490 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3491 /* 3492 Select a pen color from the pop-up menu. 3493 */ 3494 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3495 (const char **) ColorMenu,command); 3496 if (pen_number < 0) 3497 break; 3498 if (pen_number == (MaxNumberPens-2)) 3499 { 3500 static char 3501 color_name[MaxTextExtent] = "gray"; 3502 3503 /* 3504 Select a pen color from a dialog. 3505 */ 3506 resource_info->pen_colors[pen_number]=color_name; 3507 XColorBrowserWidget(display,windows,"Select",color_name); 3508 if (*color_name == '\0') 3509 break; 3510 } 3511 /* 3512 Set border color. 3513 */ 3514 (void) XParseColor(display,windows->map_info->colormap, 3515 resource_info->pen_colors[pen_number],&border_color); 3516 break; 3517 } 3518 case ColorEditFuzzCommand: 3519 { 3520 static char 3521 fuzz[MaxTextExtent]; 3522 3523 static const char 3524 *FuzzMenu[] = 3525 { 3526 "0%", 3527 "2%", 3528 "5%", 3529 "10%", 3530 "15%", 3531 "Dialog...", 3532 (char *) NULL, 3533 }; 3534 3535 /* 3536 Select a command from the pop-up menu. 3537 */ 3538 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 3539 command); 3540 if (entry < 0) 3541 break; 3542 if (entry != 5) 3543 { 3544 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],(double) 3545 QuantumRange+1.0); 3546 break; 3547 } 3548 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 3549 (void) XDialogWidget(display,windows,"Ok", 3550 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 3551 if (*fuzz == '\0') 3552 break; 3553 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 3554 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0); 3555 break; 3556 } 3557 case ColorEditUndoCommand: 3558 { 3559 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 3560 image,exception); 3561 break; 3562 } 3563 case ColorEditHelpCommand: 3564 default: 3565 { 3566 XTextViewWidget(display,resource_info,windows,MagickFalse, 3567 "Help Viewer - Image Annotation",ImageColorEditHelp); 3568 break; 3569 } 3570 case ColorEditDismissCommand: 3571 { 3572 /* 3573 Prematurely exit. 3574 */ 3575 state|=EscapeState; 3576 state|=ExitState; 3577 break; 3578 } 3579 } 3580 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3581 continue; 3582 } 3583 switch (event.type) 3584 { 3585 case ButtonPress: 3586 { 3587 if (event.xbutton.button != Button1) 3588 break; 3589 if ((event.xbutton.window != windows->image.id) && 3590 (event.xbutton.window != windows->magnify.id)) 3591 break; 3592 /* 3593 exit loop. 3594 */ 3595 x=event.xbutton.x; 3596 y=event.xbutton.y; 3597 (void) XMagickCommand(display,resource_info,windows, 3598 SaveToUndoBufferCommand,image,exception); 3599 state|=UpdateConfigurationState; 3600 break; 3601 } 3602 case ButtonRelease: 3603 { 3604 if (event.xbutton.button != Button1) 3605 break; 3606 if ((event.xbutton.window != windows->image.id) && 3607 (event.xbutton.window != windows->magnify.id)) 3608 break; 3609 /* 3610 Update colormap information. 3611 */ 3612 x=event.xbutton.x; 3613 y=event.xbutton.y; 3614 XConfigureImageColormap(display,resource_info,windows,*image); 3615 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3616 XInfoWidget(display,windows,text); 3617 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3618 state&=(~UpdateConfigurationState); 3619 break; 3620 } 3621 case Expose: 3622 break; 3623 case KeyPress: 3624 { 3625 KeySym 3626 key_symbol; 3627 3628 if (event.xkey.window == windows->magnify.id) 3629 { 3630 Window 3631 window; 3632 3633 window=windows->magnify.id; 3634 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 3635 } 3636 if (event.xkey.window != windows->image.id) 3637 break; 3638 /* 3639 Respond to a user key press. 3640 */ 3641 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3642 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3643 switch ((int) key_symbol) 3644 { 3645 case XK_Escape: 3646 case XK_F20: 3647 { 3648 /* 3649 Prematurely exit. 3650 */ 3651 state|=ExitState; 3652 break; 3653 } 3654 case XK_F1: 3655 case XK_Help: 3656 { 3657 XTextViewWidget(display,resource_info,windows,MagickFalse, 3658 "Help Viewer - Image Annotation",ImageColorEditHelp); 3659 break; 3660 } 3661 default: 3662 { 3663 (void) XBell(display,0); 3664 break; 3665 } 3666 } 3667 break; 3668 } 3669 case MotionNotify: 3670 { 3671 /* 3672 Map and unmap Info widget as cursor crosses its boundaries. 3673 */ 3674 x=event.xmotion.x; 3675 y=event.xmotion.y; 3676 if (windows->info.mapped != MagickFalse) 3677 { 3678 if ((x < (int) (windows->info.x+windows->info.width)) && 3679 (y < (int) (windows->info.y+windows->info.height))) 3680 (void) XWithdrawWindow(display,windows->info.id, 3681 windows->info.screen); 3682 } 3683 else 3684 if ((x > (int) (windows->info.x+windows->info.width)) || 3685 (y > (int) (windows->info.y+windows->info.height))) 3686 (void) XMapWindow(display,windows->info.id); 3687 break; 3688 } 3689 default: 3690 break; 3691 } 3692 if (event.xany.window == windows->magnify.id) 3693 { 3694 x=windows->magnify.x-windows->image.x; 3695 y=windows->magnify.y-windows->image.y; 3696 } 3697 x_offset=x; 3698 y_offset=y; 3699 if ((state & UpdateConfigurationState) != 0) 3700 { 3701 CacheView 3702 *image_view; 3703 3704 int 3705 x, 3706 y; 3707 3708 /* 3709 Pixel edit is relative to image configuration. 3710 */ 3711 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 3712 MagickTrue); 3713 color=windows->pixel_info->pen_colors[pen_id]; 3714 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 3715 width=(unsigned int) (*image)->columns; 3716 height=(unsigned int) (*image)->rows; 3717 x=0; 3718 y=0; 3719 if (windows->image.crop_geometry != (char *) NULL) 3720 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 3721 &width,&height); 3722 x_offset=(int) 3723 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 3724 y_offset=(int) 3725 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 3726 if ((x_offset < 0) || (y_offset < 0)) 3727 continue; 3728 if ((x_offset >= (int) (*image)->columns) || 3729 (y_offset >= (int) (*image)->rows)) 3730 continue; 3731 image_view=AcquireCacheView(*image); 3732 switch (method) 3733 { 3734 case PointMethod: 3735 default: 3736 { 3737 /* 3738 Update color information using point algorithm. 3739 */ 3740 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3741 return(MagickFalse); 3742 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 3743 (ssize_t) y_offset,1,1,exception); 3744 if (q == (Quantum *) NULL) 3745 break; 3746 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3747 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3748 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3749 (void) SyncCacheViewAuthenticPixels(image_view,exception); 3750 break; 3751 } 3752 case ReplaceMethod: 3753 { 3754 PixelInfo 3755 pixel, 3756 target; 3757 3758 Quantum 3759 virtual_pixel[MaxPixelChannels]; 3760 3761 /* 3762 Update color information using replace algorithm. 3763 */ 3764 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 3765 (ssize_t) y_offset,virtual_pixel,exception); 3766 target.red=virtual_pixel[RedPixelChannel]; 3767 target.green=virtual_pixel[GreenPixelChannel]; 3768 target.blue=virtual_pixel[BluePixelChannel]; 3769 target.alpha=virtual_pixel[AlphaPixelChannel]; 3770 if ((*image)->storage_class == DirectClass) 3771 { 3772 for (y=0; y < (int) (*image)->rows; y++) 3773 { 3774 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3775 (*image)->columns,1,exception); 3776 if (q == (Quantum *) NULL) 3777 break; 3778 for (x=0; x < (int) (*image)->columns; x++) 3779 { 3780 GetPixelInfoPixel(*image,q,&pixel); 3781 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 3782 { 3783 SetPixelRed(*image,ScaleShortToQuantum( 3784 color.red),q); 3785 SetPixelGreen(*image,ScaleShortToQuantum( 3786 color.green),q); 3787 SetPixelBlue(*image,ScaleShortToQuantum( 3788 color.blue),q); 3789 } 3790 q+=GetPixelChannels(*image); 3791 } 3792 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3793 break; 3794 } 3795 } 3796 else 3797 { 3798 for (i=0; i < (ssize_t) (*image)->colors; i++) 3799 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target)) 3800 { 3801 (*image)->colormap[i].red=ScaleShortToQuantum( 3802 color.red); 3803 (*image)->colormap[i].green=ScaleShortToQuantum( 3804 color.green); 3805 (*image)->colormap[i].blue=ScaleShortToQuantum( 3806 color.blue); 3807 } 3808 (void) SyncImage(*image,exception); 3809 } 3810 break; 3811 } 3812 case FloodfillMethod: 3813 case FillToBorderMethod: 3814 { 3815 DrawInfo 3816 *draw_info; 3817 3818 PixelInfo 3819 target; 3820 3821 /* 3822 Update color information using floodfill algorithm. 3823 */ 3824 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset, 3825 (ssize_t) y_offset,&target,exception); 3826 if (method == FillToBorderMethod) 3827 { 3828 target.red=(MagickRealType) 3829 ScaleShortToQuantum(border_color.red); 3830 target.green=(MagickRealType) 3831 ScaleShortToQuantum(border_color.green); 3832 target.blue=(MagickRealType) 3833 ScaleShortToQuantum(border_color.blue); 3834 } 3835 draw_info=CloneDrawInfo(resource_info->image_info, 3836 (DrawInfo *) NULL); 3837 (void) QueryColorCompliance(resource_info->pen_colors[pen_id], 3838 AllCompliance,&draw_info->fill,exception); 3839 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 3840 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 3841 MagickFalse : MagickTrue,exception); 3842 draw_info=DestroyDrawInfo(draw_info); 3843 break; 3844 } 3845 case ResetMethod: 3846 { 3847 /* 3848 Update color information using reset algorithm. 3849 */ 3850 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3851 return(MagickFalse); 3852 for (y=0; y < (int) (*image)->rows; y++) 3853 { 3854 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3855 (*image)->columns,1,exception); 3856 if (q == (Quantum *) NULL) 3857 break; 3858 for (x=0; x < (int) (*image)->columns; x++) 3859 { 3860 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3861 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3862 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3863 q+=GetPixelChannels(*image); 3864 } 3865 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3866 break; 3867 } 3868 break; 3869 } 3870 } 3871 image_view=DestroyCacheView(image_view); 3872 state&=(~UpdateConfigurationState); 3873 } 3874 } while ((state & ExitState) == 0); 3875 (void) XSelectInput(display,windows->image.id, 3876 windows->image.attributes.event_mask); 3877 XSetCursorState(display,windows,MagickFalse); 3878 (void) XFreeCursor(display,cursor); 3879 return(MagickTrue); 3880} 3881 3882/* 3883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3884% % 3885% % 3886% % 3887+ X C o m p o s i t e I m a g e % 3888% % 3889% % 3890% % 3891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3892% 3893% XCompositeImage() requests an image name from the user, reads the image and 3894% composites it with the X window image at a location the user chooses with 3895% the pointer. 3896% 3897% The format of the XCompositeImage method is: 3898% 3899% MagickBooleanType XCompositeImage(Display *display, 3900% XResourceInfo *resource_info,XWindows *windows,Image *image, 3901% ExceptionInfo *exception) 3902% 3903% A description of each parameter follows: 3904% 3905% o display: Specifies a connection to an X server; returned from 3906% XOpenDisplay. 3907% 3908% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3909% 3910% o windows: Specifies a pointer to a XWindows structure. 3911% 3912% o image: the image; returned from ReadImage. 3913% 3914% o exception: return any errors or warnings in this structure. 3915% 3916*/ 3917static MagickBooleanType XCompositeImage(Display *display, 3918 XResourceInfo *resource_info,XWindows *windows,Image *image, 3919 ExceptionInfo *exception) 3920{ 3921 static char 3922 displacement_geometry[MaxTextExtent] = "30x30", 3923 filename[MaxTextExtent] = "\0"; 3924 3925 static const char 3926 *CompositeMenu[] = 3927 { 3928 "Operators", 3929 "Dissolve", 3930 "Displace", 3931 "Help", 3932 "Dismiss", 3933 (char *) NULL 3934 }; 3935 3936 static CompositeOperator 3937 compose = CopyCompositeOp; 3938 3939 static const ModeType 3940 CompositeCommands[] = 3941 { 3942 CompositeOperatorsCommand, 3943 CompositeDissolveCommand, 3944 CompositeDisplaceCommand, 3945 CompositeHelpCommand, 3946 CompositeDismissCommand 3947 }; 3948 3949 char 3950 text[MaxTextExtent]; 3951 3952 Cursor 3953 cursor; 3954 3955 Image 3956 *composite_image; 3957 3958 int 3959 entry, 3960 id, 3961 x, 3962 y; 3963 3964 MagickRealType 3965 blend, 3966 scale_factor; 3967 3968 RectangleInfo 3969 highlight_info, 3970 composite_info; 3971 3972 unsigned int 3973 height, 3974 width; 3975 3976 size_t 3977 state; 3978 3979 XEvent 3980 event; 3981 3982 /* 3983 Request image file name from user. 3984 */ 3985 XFileBrowserWidget(display,windows,"Composite",filename); 3986 if (*filename == '\0') 3987 return(MagickTrue); 3988 /* 3989 Read image. 3990 */ 3991 XSetCursorState(display,windows,MagickTrue); 3992 XCheckRefreshWindows(display,windows); 3993 (void) CopyMagickString(resource_info->image_info->filename,filename, 3994 MaxTextExtent); 3995 composite_image=ReadImage(resource_info->image_info,exception); 3996 CatchException(exception); 3997 XSetCursorState(display,windows,MagickFalse); 3998 if (composite_image == (Image *) NULL) 3999 return(MagickFalse); 4000 /* 4001 Map Command widget. 4002 */ 4003 (void) CloneString(&windows->command.name,"Composite"); 4004 windows->command.data=1; 4005 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 4006 (void) XMapRaised(display,windows->command.id); 4007 XClientMessage(display,windows->image.id,windows->im_protocols, 4008 windows->im_update_widget,CurrentTime); 4009 /* 4010 Track pointer until button 1 is pressed. 4011 */ 4012 XQueryPosition(display,windows->image.id,&x,&y); 4013 (void) XSelectInput(display,windows->image.id, 4014 windows->image.attributes.event_mask | PointerMotionMask); 4015 composite_info.x=(ssize_t) windows->image.x+x; 4016 composite_info.y=(ssize_t) windows->image.y+y; 4017 composite_info.width=0; 4018 composite_info.height=0; 4019 cursor=XCreateFontCursor(display,XC_ul_angle); 4020 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4021 blend=0.0; 4022 state=DefaultState; 4023 do 4024 { 4025 if (windows->info.mapped != MagickFalse) 4026 { 4027 /* 4028 Display pointer position. 4029 */ 4030 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4031 (long) composite_info.x,(long) composite_info.y); 4032 XInfoWidget(display,windows,text); 4033 } 4034 highlight_info=composite_info; 4035 highlight_info.x=composite_info.x-windows->image.x; 4036 highlight_info.y=composite_info.y-windows->image.y; 4037 XHighlightRectangle(display,windows->image.id, 4038 windows->image.highlight_context,&highlight_info); 4039 /* 4040 Wait for next event. 4041 */ 4042 XScreenEvent(display,windows,&event); 4043 XHighlightRectangle(display,windows->image.id, 4044 windows->image.highlight_context,&highlight_info); 4045 if (event.xany.window == windows->command.id) 4046 { 4047 /* 4048 Select a command from the Command widget. 4049 */ 4050 id=XCommandWidget(display,windows,CompositeMenu,&event); 4051 if (id < 0) 4052 continue; 4053 switch (CompositeCommands[id]) 4054 { 4055 case CompositeOperatorsCommand: 4056 { 4057 char 4058 command[MaxTextExtent], 4059 **operators; 4060 4061 /* 4062 Select a command from the pop-up menu. 4063 */ 4064 operators=GetCommandOptions(MagickComposeOptions); 4065 if (operators == (char **) NULL) 4066 break; 4067 entry=XMenuWidget(display,windows,CompositeMenu[id], 4068 (const char **) operators,command); 4069 if (entry >= 0) 4070 compose=(CompositeOperator) ParseCommandOption( 4071 MagickComposeOptions,MagickFalse,operators[entry]); 4072 operators=DestroyStringList(operators); 4073 break; 4074 } 4075 case CompositeDissolveCommand: 4076 { 4077 static char 4078 factor[MaxTextExtent] = "20.0"; 4079 4080 /* 4081 Dissolve the two images a given percent. 4082 */ 4083 (void) XSetFunction(display,windows->image.highlight_context, 4084 GXcopy); 4085 (void) XDialogWidget(display,windows,"Dissolve", 4086 "Enter the blend factor (0.0 - 99.9%):",factor); 4087 (void) XSetFunction(display,windows->image.highlight_context, 4088 GXinvert); 4089 if (*factor == '\0') 4090 break; 4091 blend=InterpretLocaleValue(factor,(char **) NULL); 4092 compose=DissolveCompositeOp; 4093 break; 4094 } 4095 case CompositeDisplaceCommand: 4096 { 4097 /* 4098 Get horizontal and vertical scale displacement geometry. 4099 */ 4100 (void) XSetFunction(display,windows->image.highlight_context, 4101 GXcopy); 4102 (void) XDialogWidget(display,windows,"Displace", 4103 "Enter the horizontal and vertical scale:",displacement_geometry); 4104 (void) XSetFunction(display,windows->image.highlight_context, 4105 GXinvert); 4106 if (*displacement_geometry == '\0') 4107 break; 4108 compose=DisplaceCompositeOp; 4109 break; 4110 } 4111 case CompositeHelpCommand: 4112 { 4113 (void) XSetFunction(display,windows->image.highlight_context, 4114 GXcopy); 4115 XTextViewWidget(display,resource_info,windows,MagickFalse, 4116 "Help Viewer - Image Composite",ImageCompositeHelp); 4117 (void) XSetFunction(display,windows->image.highlight_context, 4118 GXinvert); 4119 break; 4120 } 4121 case CompositeDismissCommand: 4122 { 4123 /* 4124 Prematurely exit. 4125 */ 4126 state|=EscapeState; 4127 state|=ExitState; 4128 break; 4129 } 4130 default: 4131 break; 4132 } 4133 continue; 4134 } 4135 switch (event.type) 4136 { 4137 case ButtonPress: 4138 { 4139 if (image->debug != MagickFalse) 4140 (void) LogMagickEvent(X11Event,GetMagickModule(), 4141 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 4142 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4143 if (event.xbutton.button != Button1) 4144 break; 4145 if (event.xbutton.window != windows->image.id) 4146 break; 4147 /* 4148 Change cursor. 4149 */ 4150 composite_info.width=composite_image->columns; 4151 composite_info.height=composite_image->rows; 4152 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4153 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4154 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4155 break; 4156 } 4157 case ButtonRelease: 4158 { 4159 if (image->debug != MagickFalse) 4160 (void) LogMagickEvent(X11Event,GetMagickModule(), 4161 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 4162 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4163 if (event.xbutton.button != Button1) 4164 break; 4165 if (event.xbutton.window != windows->image.id) 4166 break; 4167 if ((composite_info.width != 0) && (composite_info.height != 0)) 4168 { 4169 /* 4170 User has selected the location of the composite image. 4171 */ 4172 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4173 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4174 state|=ExitState; 4175 } 4176 break; 4177 } 4178 case Expose: 4179 break; 4180 case KeyPress: 4181 { 4182 char 4183 command[MaxTextExtent]; 4184 4185 KeySym 4186 key_symbol; 4187 4188 int 4189 length; 4190 4191 if (event.xkey.window != windows->image.id) 4192 break; 4193 /* 4194 Respond to a user key press. 4195 */ 4196 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 4197 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4198 *(command+length)='\0'; 4199 if (image->debug != MagickFalse) 4200 (void) LogMagickEvent(X11Event,GetMagickModule(), 4201 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 4202 switch ((int) key_symbol) 4203 { 4204 case XK_Escape: 4205 case XK_F20: 4206 { 4207 /* 4208 Prematurely exit. 4209 */ 4210 composite_image=DestroyImage(composite_image); 4211 state|=EscapeState; 4212 state|=ExitState; 4213 break; 4214 } 4215 case XK_F1: 4216 case XK_Help: 4217 { 4218 (void) XSetFunction(display,windows->image.highlight_context, 4219 GXcopy); 4220 XTextViewWidget(display,resource_info,windows,MagickFalse, 4221 "Help Viewer - Image Composite",ImageCompositeHelp); 4222 (void) XSetFunction(display,windows->image.highlight_context, 4223 GXinvert); 4224 break; 4225 } 4226 default: 4227 { 4228 (void) XBell(display,0); 4229 break; 4230 } 4231 } 4232 break; 4233 } 4234 case MotionNotify: 4235 { 4236 /* 4237 Map and unmap Info widget as text cursor crosses its boundaries. 4238 */ 4239 x=event.xmotion.x; 4240 y=event.xmotion.y; 4241 if (windows->info.mapped != MagickFalse) 4242 { 4243 if ((x < (int) (windows->info.x+windows->info.width)) && 4244 (y < (int) (windows->info.y+windows->info.height))) 4245 (void) XWithdrawWindow(display,windows->info.id, 4246 windows->info.screen); 4247 } 4248 else 4249 if ((x > (int) (windows->info.x+windows->info.width)) || 4250 (y > (int) (windows->info.y+windows->info.height))) 4251 (void) XMapWindow(display,windows->info.id); 4252 composite_info.x=(ssize_t) windows->image.x+x; 4253 composite_info.y=(ssize_t) windows->image.y+y; 4254 break; 4255 } 4256 default: 4257 { 4258 if (image->debug != MagickFalse) 4259 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 4260 event.type); 4261 break; 4262 } 4263 } 4264 } while ((state & ExitState) == 0); 4265 (void) XSelectInput(display,windows->image.id, 4266 windows->image.attributes.event_mask); 4267 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4268 XSetCursorState(display,windows,MagickFalse); 4269 (void) XFreeCursor(display,cursor); 4270 if ((state & EscapeState) != 0) 4271 return(MagickTrue); 4272 /* 4273 Image compositing is relative to image configuration. 4274 */ 4275 XSetCursorState(display,windows,MagickTrue); 4276 XCheckRefreshWindows(display,windows); 4277 width=(unsigned int) image->columns; 4278 height=(unsigned int) image->rows; 4279 x=0; 4280 y=0; 4281 if (windows->image.crop_geometry != (char *) NULL) 4282 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 4283 scale_factor=(MagickRealType) width/windows->image.ximage->width; 4284 composite_info.x+=x; 4285 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 4286 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 4287 scale_factor=(MagickRealType) height/windows->image.ximage->height; 4288 composite_info.y+=y; 4289 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 4290 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 4291 if ((composite_info.width != composite_image->columns) || 4292 (composite_info.height != composite_image->rows)) 4293 { 4294 Image 4295 *resize_image; 4296 4297 /* 4298 Scale composite image. 4299 */ 4300 resize_image=ResizeImage(composite_image,composite_info.width, 4301 composite_info.height,composite_image->filter,composite_image->blur, 4302 exception); 4303 composite_image=DestroyImage(composite_image); 4304 if (resize_image == (Image *) NULL) 4305 { 4306 XSetCursorState(display,windows,MagickFalse); 4307 return(MagickFalse); 4308 } 4309 composite_image=resize_image; 4310 } 4311 if (compose == DisplaceCompositeOp) 4312 (void) SetImageArtifact(composite_image,"compose:args", 4313 displacement_geometry); 4314 if (blend != 0.0) 4315 { 4316 CacheView 4317 *image_view; 4318 4319 int 4320 y; 4321 4322 Quantum 4323 opacity; 4324 4325 register int 4326 x; 4327 4328 register Quantum 4329 *q; 4330 4331 /* 4332 Create mattes for blending. 4333 */ 4334 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception); 4335 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)- 4336 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100); 4337 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 4338 return(MagickFalse); 4339 image->matte=MagickTrue; 4340 image_view=AcquireCacheView(image); 4341 for (y=0; y < (int) image->rows; y++) 4342 { 4343 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 4344 exception); 4345 if (q == (Quantum *) NULL) 4346 break; 4347 for (x=0; x < (int) image->columns; x++) 4348 { 4349 SetPixelAlpha(image,opacity,q); 4350 q+=GetPixelChannels(image); 4351 } 4352 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 4353 break; 4354 } 4355 image_view=DestroyCacheView(image_view); 4356 } 4357 /* 4358 Composite image with X Image window. 4359 */ 4360 (void) CompositeImage(image,compose,composite_image,composite_info.x, 4361 composite_info.y,exception); 4362 composite_image=DestroyImage(composite_image); 4363 XSetCursorState(display,windows,MagickFalse); 4364 /* 4365 Update image configuration. 4366 */ 4367 XConfigureImageColormap(display,resource_info,windows,image); 4368 (void) XConfigureImage(display,resource_info,windows,image,exception); 4369 return(MagickTrue); 4370} 4371 4372/* 4373%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4374% % 4375% % 4376% % 4377+ X C o n f i g u r e I m a g e % 4378% % 4379% % 4380% % 4381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4382% 4383% XConfigureImage() creates a new X image. It also notifies the window 4384% manager of the new image size and configures the transient widows. 4385% 4386% The format of the XConfigureImage method is: 4387% 4388% MagickBooleanType XConfigureImage(Display *display, 4389% XResourceInfo *resource_info,XWindows *windows,Image *image, 4390% ExceptionInfo *exception) 4391% 4392% A description of each parameter follows: 4393% 4394% o display: Specifies a connection to an X server; returned from 4395% XOpenDisplay. 4396% 4397% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4398% 4399% o windows: Specifies a pointer to a XWindows structure. 4400% 4401% o image: the image. 4402% 4403% o exception: return any errors or warnings in this structure. 4404% 4405% o exception: return any errors or warnings in this structure. 4406% 4407*/ 4408static MagickBooleanType XConfigureImage(Display *display, 4409 XResourceInfo *resource_info,XWindows *windows,Image *image, 4410 ExceptionInfo *exception) 4411{ 4412 char 4413 geometry[MaxTextExtent]; 4414 4415 MagickStatusType 4416 status; 4417 4418 size_t 4419 mask, 4420 height, 4421 width; 4422 4423 ssize_t 4424 x, 4425 y; 4426 4427 XSizeHints 4428 *size_hints; 4429 4430 XWindowChanges 4431 window_changes; 4432 4433 /* 4434 Dismiss if window dimensions are zero. 4435 */ 4436 width=(unsigned int) windows->image.window_changes.width; 4437 height=(unsigned int) windows->image.window_changes.height; 4438 if (image->debug != MagickFalse) 4439 (void) LogMagickEvent(X11Event,GetMagickModule(), 4440 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 4441 windows->image.ximage->height,(double) width,(double) height); 4442 if ((width*height) == 0) 4443 return(MagickTrue); 4444 x=0; 4445 y=0; 4446 /* 4447 Resize image to fit Image window dimensions. 4448 */ 4449 XSetCursorState(display,windows,MagickTrue); 4450 (void) XFlush(display); 4451 if (((int) width != windows->image.ximage->width) || 4452 ((int) height != windows->image.ximage->height)) 4453 image->taint=MagickTrue; 4454 windows->magnify.x=(int) 4455 width*windows->magnify.x/windows->image.ximage->width; 4456 windows->magnify.y=(int) 4457 height*windows->magnify.y/windows->image.ximage->height; 4458 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 4459 windows->image.y=(int) 4460 (height*windows->image.y/windows->image.ximage->height); 4461 status=XMakeImage(display,resource_info,&windows->image,image, 4462 (unsigned int) width,(unsigned int) height,exception); 4463 if (status == MagickFalse) 4464 XNoticeWidget(display,windows,"Unable to configure X image:", 4465 windows->image.name); 4466 /* 4467 Notify window manager of the new configuration. 4468 */ 4469 if (resource_info->image_geometry != (char *) NULL) 4470 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!", 4471 resource_info->image_geometry); 4472 else 4473 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 4474 XDisplayWidth(display,windows->image.screen), 4475 XDisplayHeight(display,windows->image.screen)); 4476 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 4477 window_changes.width=(int) width; 4478 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 4479 window_changes.width=XDisplayWidth(display,windows->image.screen); 4480 window_changes.height=(int) height; 4481 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 4482 window_changes.height=XDisplayHeight(display,windows->image.screen); 4483 mask=(size_t) (CWWidth | CWHeight); 4484 if (resource_info->backdrop) 4485 { 4486 mask|=CWX | CWY; 4487 window_changes.x=(int) 4488 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 4489 window_changes.y=(int) 4490 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 4491 } 4492 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 4493 (unsigned int) mask,&window_changes); 4494 (void) XClearWindow(display,windows->image.id); 4495 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 4496 /* 4497 Update Magnify window configuration. 4498 */ 4499 if (windows->magnify.mapped != MagickFalse) 4500 XMakeMagnifyImage(display,windows); 4501 windows->pan.crop_geometry=windows->image.crop_geometry; 4502 XBestIconSize(display,&windows->pan,image); 4503 while (((windows->pan.width << 1) < MaxIconSize) && 4504 ((windows->pan.height << 1) < MaxIconSize)) 4505 { 4506 windows->pan.width<<=1; 4507 windows->pan.height<<=1; 4508 } 4509 if (windows->pan.geometry != (char *) NULL) 4510 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 4511 &windows->pan.width,&windows->pan.height); 4512 window_changes.width=(int) windows->pan.width; 4513 window_changes.height=(int) windows->pan.height; 4514 size_hints=XAllocSizeHints(); 4515 if (size_hints != (XSizeHints *) NULL) 4516 { 4517 /* 4518 Set new size hints. 4519 */ 4520 size_hints->flags=PSize | PMinSize | PMaxSize; 4521 size_hints->width=window_changes.width; 4522 size_hints->height=window_changes.height; 4523 size_hints->min_width=size_hints->width; 4524 size_hints->min_height=size_hints->height; 4525 size_hints->max_width=size_hints->width; 4526 size_hints->max_height=size_hints->height; 4527 (void) XSetNormalHints(display,windows->pan.id,size_hints); 4528 (void) XFree((void *) size_hints); 4529 } 4530 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 4531 (unsigned int) (CWWidth | CWHeight),&window_changes); 4532 /* 4533 Update icon window configuration. 4534 */ 4535 windows->icon.crop_geometry=windows->image.crop_geometry; 4536 XBestIconSize(display,&windows->icon,image); 4537 window_changes.width=(int) windows->icon.width; 4538 window_changes.height=(int) windows->icon.height; 4539 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 4540 (unsigned int) (CWWidth | CWHeight),&window_changes); 4541 XSetCursorState(display,windows,MagickFalse); 4542 return(status != 0 ? MagickTrue : MagickFalse); 4543} 4544 4545/* 4546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4547% % 4548% % 4549% % 4550+ X C r o p I m a g e % 4551% % 4552% % 4553% % 4554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4555% 4556% XCropImage() allows the user to select a region of the image and crop, copy, 4557% or cut it. For copy or cut, the image can subsequently be composited onto 4558% the image with XPasteImage. 4559% 4560% The format of the XCropImage method is: 4561% 4562% MagickBooleanType XCropImage(Display *display, 4563% XResourceInfo *resource_info,XWindows *windows,Image *image, 4564% const ClipboardMode mode,ExceptionInfo *exception) 4565% 4566% A description of each parameter follows: 4567% 4568% o display: Specifies a connection to an X server; returned from 4569% XOpenDisplay. 4570% 4571% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4572% 4573% o windows: Specifies a pointer to a XWindows structure. 4574% 4575% o image: the image; returned from ReadImage. 4576% 4577% o mode: This unsigned value specified whether the image should be 4578% cropped, copied, or cut. 4579% 4580% o exception: return any errors or warnings in this structure. 4581% 4582*/ 4583static MagickBooleanType XCropImage(Display *display, 4584 XResourceInfo *resource_info,XWindows *windows,Image *image, 4585 const ClipboardMode mode,ExceptionInfo *exception) 4586{ 4587 static const char 4588 *CropModeMenu[] = 4589 { 4590 "Help", 4591 "Dismiss", 4592 (char *) NULL 4593 }, 4594 *RectifyModeMenu[] = 4595 { 4596 "Crop", 4597 "Help", 4598 "Dismiss", 4599 (char *) NULL 4600 }; 4601 4602 static const ModeType 4603 CropCommands[] = 4604 { 4605 CropHelpCommand, 4606 CropDismissCommand 4607 }, 4608 RectifyCommands[] = 4609 { 4610 RectifyCopyCommand, 4611 RectifyHelpCommand, 4612 RectifyDismissCommand 4613 }; 4614 4615 CacheView 4616 *image_view; 4617 4618 char 4619 command[MaxTextExtent], 4620 text[MaxTextExtent]; 4621 4622 Cursor 4623 cursor; 4624 4625 int 4626 id, 4627 x, 4628 y; 4629 4630 KeySym 4631 key_symbol; 4632 4633 Image 4634 *crop_image; 4635 4636 MagickRealType 4637 scale_factor; 4638 4639 RectangleInfo 4640 crop_info, 4641 highlight_info; 4642 4643 register Quantum 4644 *q; 4645 4646 unsigned int 4647 height, 4648 width; 4649 4650 size_t 4651 state; 4652 4653 XEvent 4654 event; 4655 4656 /* 4657 Map Command widget. 4658 */ 4659 switch (mode) 4660 { 4661 case CopyMode: 4662 { 4663 (void) CloneString(&windows->command.name,"Copy"); 4664 break; 4665 } 4666 case CropMode: 4667 { 4668 (void) CloneString(&windows->command.name,"Crop"); 4669 break; 4670 } 4671 case CutMode: 4672 { 4673 (void) CloneString(&windows->command.name,"Cut"); 4674 break; 4675 } 4676 } 4677 RectifyModeMenu[0]=windows->command.name; 4678 windows->command.data=0; 4679 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 4680 (void) XMapRaised(display,windows->command.id); 4681 XClientMessage(display,windows->image.id,windows->im_protocols, 4682 windows->im_update_widget,CurrentTime); 4683 /* 4684 Track pointer until button 1 is pressed. 4685 */ 4686 XQueryPosition(display,windows->image.id,&x,&y); 4687 (void) XSelectInput(display,windows->image.id, 4688 windows->image.attributes.event_mask | PointerMotionMask); 4689 crop_info.x=(ssize_t) windows->image.x+x; 4690 crop_info.y=(ssize_t) windows->image.y+y; 4691 crop_info.width=0; 4692 crop_info.height=0; 4693 cursor=XCreateFontCursor(display,XC_fleur); 4694 state=DefaultState; 4695 do 4696 { 4697 if (windows->info.mapped != MagickFalse) 4698 { 4699 /* 4700 Display pointer position. 4701 */ 4702 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4703 (long) crop_info.x,(long) crop_info.y); 4704 XInfoWidget(display,windows,text); 4705 } 4706 /* 4707 Wait for next event. 4708 */ 4709 XScreenEvent(display,windows,&event); 4710 if (event.xany.window == windows->command.id) 4711 { 4712 /* 4713 Select a command from the Command widget. 4714 */ 4715 id=XCommandWidget(display,windows,CropModeMenu,&event); 4716 if (id < 0) 4717 continue; 4718 switch (CropCommands[id]) 4719 { 4720 case CropHelpCommand: 4721 { 4722 switch (mode) 4723 { 4724 case CopyMode: 4725 { 4726 XTextViewWidget(display,resource_info,windows,MagickFalse, 4727 "Help Viewer - Image Copy",ImageCopyHelp); 4728 break; 4729 } 4730 case CropMode: 4731 { 4732 XTextViewWidget(display,resource_info,windows,MagickFalse, 4733 "Help Viewer - Image Crop",ImageCropHelp); 4734 break; 4735 } 4736 case CutMode: 4737 { 4738 XTextViewWidget(display,resource_info,windows,MagickFalse, 4739 "Help Viewer - Image Cut",ImageCutHelp); 4740 break; 4741 } 4742 } 4743 break; 4744 } 4745 case CropDismissCommand: 4746 { 4747 /* 4748 Prematurely exit. 4749 */ 4750 state|=EscapeState; 4751 state|=ExitState; 4752 break; 4753 } 4754 default: 4755 break; 4756 } 4757 continue; 4758 } 4759 switch (event.type) 4760 { 4761 case ButtonPress: 4762 { 4763 if (event.xbutton.button != Button1) 4764 break; 4765 if (event.xbutton.window != windows->image.id) 4766 break; 4767 /* 4768 Note first corner of cropping rectangle-- exit loop. 4769 */ 4770 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4771 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4772 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4773 state|=ExitState; 4774 break; 4775 } 4776 case ButtonRelease: 4777 break; 4778 case Expose: 4779 break; 4780 case KeyPress: 4781 { 4782 if (event.xkey.window != windows->image.id) 4783 break; 4784 /* 4785 Respond to a user key press. 4786 */ 4787 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 4788 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4789 switch ((int) key_symbol) 4790 { 4791 case XK_Escape: 4792 case XK_F20: 4793 { 4794 /* 4795 Prematurely exit. 4796 */ 4797 state|=EscapeState; 4798 state|=ExitState; 4799 break; 4800 } 4801 case XK_F1: 4802 case XK_Help: 4803 { 4804 switch (mode) 4805 { 4806 case CopyMode: 4807 { 4808 XTextViewWidget(display,resource_info,windows,MagickFalse, 4809 "Help Viewer - Image Copy",ImageCopyHelp); 4810 break; 4811 } 4812 case CropMode: 4813 { 4814 XTextViewWidget(display,resource_info,windows,MagickFalse, 4815 "Help Viewer - Image Crop",ImageCropHelp); 4816 break; 4817 } 4818 case CutMode: 4819 { 4820 XTextViewWidget(display,resource_info,windows,MagickFalse, 4821 "Help Viewer - Image Cut",ImageCutHelp); 4822 break; 4823 } 4824 } 4825 break; 4826 } 4827 default: 4828 { 4829 (void) XBell(display,0); 4830 break; 4831 } 4832 } 4833 break; 4834 } 4835 case MotionNotify: 4836 { 4837 if (event.xmotion.window != windows->image.id) 4838 break; 4839 /* 4840 Map and unmap Info widget as text cursor crosses its boundaries. 4841 */ 4842 x=event.xmotion.x; 4843 y=event.xmotion.y; 4844 if (windows->info.mapped != MagickFalse) 4845 { 4846 if ((x < (int) (windows->info.x+windows->info.width)) && 4847 (y < (int) (windows->info.y+windows->info.height))) 4848 (void) XWithdrawWindow(display,windows->info.id, 4849 windows->info.screen); 4850 } 4851 else 4852 if ((x > (int) (windows->info.x+windows->info.width)) || 4853 (y > (int) (windows->info.y+windows->info.height))) 4854 (void) XMapWindow(display,windows->info.id); 4855 crop_info.x=(ssize_t) windows->image.x+x; 4856 crop_info.y=(ssize_t) windows->image.y+y; 4857 break; 4858 } 4859 default: 4860 break; 4861 } 4862 } while ((state & ExitState) == 0); 4863 (void) XSelectInput(display,windows->image.id, 4864 windows->image.attributes.event_mask); 4865 if ((state & EscapeState) != 0) 4866 { 4867 /* 4868 User want to exit without cropping. 4869 */ 4870 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4871 (void) XFreeCursor(display,cursor); 4872 return(MagickTrue); 4873 } 4874 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4875 do 4876 { 4877 /* 4878 Size rectangle as pointer moves until the mouse button is released. 4879 */ 4880 x=(int) crop_info.x; 4881 y=(int) crop_info.y; 4882 crop_info.width=0; 4883 crop_info.height=0; 4884 state=DefaultState; 4885 do 4886 { 4887 highlight_info=crop_info; 4888 highlight_info.x=crop_info.x-windows->image.x; 4889 highlight_info.y=crop_info.y-windows->image.y; 4890 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4891 { 4892 /* 4893 Display info and draw cropping rectangle. 4894 */ 4895 if (windows->info.mapped == MagickFalse) 4896 (void) XMapWindow(display,windows->info.id); 4897 (void) FormatLocaleString(text,MaxTextExtent, 4898 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4899 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4900 XInfoWidget(display,windows,text); 4901 XHighlightRectangle(display,windows->image.id, 4902 windows->image.highlight_context,&highlight_info); 4903 } 4904 else 4905 if (windows->info.mapped != MagickFalse) 4906 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4907 /* 4908 Wait for next event. 4909 */ 4910 XScreenEvent(display,windows,&event); 4911 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4912 XHighlightRectangle(display,windows->image.id, 4913 windows->image.highlight_context,&highlight_info); 4914 switch (event.type) 4915 { 4916 case ButtonPress: 4917 { 4918 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4919 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4920 break; 4921 } 4922 case ButtonRelease: 4923 { 4924 /* 4925 User has committed to cropping rectangle. 4926 */ 4927 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4928 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4929 XSetCursorState(display,windows,MagickFalse); 4930 state|=ExitState; 4931 windows->command.data=0; 4932 (void) XCommandWidget(display,windows,RectifyModeMenu, 4933 (XEvent *) NULL); 4934 break; 4935 } 4936 case Expose: 4937 break; 4938 case MotionNotify: 4939 { 4940 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 4941 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 4942 } 4943 default: 4944 break; 4945 } 4946 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 4947 ((state & ExitState) != 0)) 4948 { 4949 /* 4950 Check boundary conditions. 4951 */ 4952 if (crop_info.x < 0) 4953 crop_info.x=0; 4954 else 4955 if (crop_info.x > (ssize_t) windows->image.ximage->width) 4956 crop_info.x=(ssize_t) windows->image.ximage->width; 4957 if ((int) crop_info.x < x) 4958 crop_info.width=(unsigned int) (x-crop_info.x); 4959 else 4960 { 4961 crop_info.width=(unsigned int) (crop_info.x-x); 4962 crop_info.x=(ssize_t) x; 4963 } 4964 if (crop_info.y < 0) 4965 crop_info.y=0; 4966 else 4967 if (crop_info.y > (ssize_t) windows->image.ximage->height) 4968 crop_info.y=(ssize_t) windows->image.ximage->height; 4969 if ((int) crop_info.y < y) 4970 crop_info.height=(unsigned int) (y-crop_info.y); 4971 else 4972 { 4973 crop_info.height=(unsigned int) (crop_info.y-y); 4974 crop_info.y=(ssize_t) y; 4975 } 4976 } 4977 } while ((state & ExitState) == 0); 4978 /* 4979 Wait for user to grab a corner of the rectangle or press return. 4980 */ 4981 state=DefaultState; 4982 (void) XMapWindow(display,windows->info.id); 4983 do 4984 { 4985 if (windows->info.mapped != MagickFalse) 4986 { 4987 /* 4988 Display pointer position. 4989 */ 4990 (void) FormatLocaleString(text,MaxTextExtent, 4991 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4992 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4993 XInfoWidget(display,windows,text); 4994 } 4995 highlight_info=crop_info; 4996 highlight_info.x=crop_info.x-windows->image.x; 4997 highlight_info.y=crop_info.y-windows->image.y; 4998 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 4999 { 5000 state|=EscapeState; 5001 state|=ExitState; 5002 break; 5003 } 5004 XHighlightRectangle(display,windows->image.id, 5005 windows->image.highlight_context,&highlight_info); 5006 XScreenEvent(display,windows,&event); 5007 if (event.xany.window == windows->command.id) 5008 { 5009 /* 5010 Select a command from the Command widget. 5011 */ 5012 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5013 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 5014 (void) XSetFunction(display,windows->image.highlight_context, 5015 GXinvert); 5016 XHighlightRectangle(display,windows->image.id, 5017 windows->image.highlight_context,&highlight_info); 5018 if (id >= 0) 5019 switch (RectifyCommands[id]) 5020 { 5021 case RectifyCopyCommand: 5022 { 5023 state|=ExitState; 5024 break; 5025 } 5026 case RectifyHelpCommand: 5027 { 5028 (void) XSetFunction(display,windows->image.highlight_context, 5029 GXcopy); 5030 switch (mode) 5031 { 5032 case CopyMode: 5033 { 5034 XTextViewWidget(display,resource_info,windows,MagickFalse, 5035 "Help Viewer - Image Copy",ImageCopyHelp); 5036 break; 5037 } 5038 case CropMode: 5039 { 5040 XTextViewWidget(display,resource_info,windows,MagickFalse, 5041 "Help Viewer - Image Crop",ImageCropHelp); 5042 break; 5043 } 5044 case CutMode: 5045 { 5046 XTextViewWidget(display,resource_info,windows,MagickFalse, 5047 "Help Viewer - Image Cut",ImageCutHelp); 5048 break; 5049 } 5050 } 5051 (void) XSetFunction(display,windows->image.highlight_context, 5052 GXinvert); 5053 break; 5054 } 5055 case RectifyDismissCommand: 5056 { 5057 /* 5058 Prematurely exit. 5059 */ 5060 state|=EscapeState; 5061 state|=ExitState; 5062 break; 5063 } 5064 default: 5065 break; 5066 } 5067 continue; 5068 } 5069 XHighlightRectangle(display,windows->image.id, 5070 windows->image.highlight_context,&highlight_info); 5071 switch (event.type) 5072 { 5073 case ButtonPress: 5074 { 5075 if (event.xbutton.button != Button1) 5076 break; 5077 if (event.xbutton.window != windows->image.id) 5078 break; 5079 x=windows->image.x+event.xbutton.x; 5080 y=windows->image.y+event.xbutton.y; 5081 if ((x < (int) (crop_info.x+RoiDelta)) && 5082 (x > (int) (crop_info.x-RoiDelta)) && 5083 (y < (int) (crop_info.y+RoiDelta)) && 5084 (y > (int) (crop_info.y-RoiDelta))) 5085 { 5086 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5087 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5088 state|=UpdateConfigurationState; 5089 break; 5090 } 5091 if ((x < (int) (crop_info.x+RoiDelta)) && 5092 (x > (int) (crop_info.x-RoiDelta)) && 5093 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5094 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5095 { 5096 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5097 state|=UpdateConfigurationState; 5098 break; 5099 } 5100 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5101 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5102 (y < (int) (crop_info.y+RoiDelta)) && 5103 (y > (int) (crop_info.y-RoiDelta))) 5104 { 5105 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5106 state|=UpdateConfigurationState; 5107 break; 5108 } 5109 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5110 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5111 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5112 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5113 { 5114 state|=UpdateConfigurationState; 5115 break; 5116 } 5117 } 5118 case ButtonRelease: 5119 { 5120 if (event.xbutton.window == windows->pan.id) 5121 if ((highlight_info.x != crop_info.x-windows->image.x) || 5122 (highlight_info.y != crop_info.y-windows->image.y)) 5123 XHighlightRectangle(display,windows->image.id, 5124 windows->image.highlight_context,&highlight_info); 5125 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5126 event.xbutton.time); 5127 break; 5128 } 5129 case Expose: 5130 { 5131 if (event.xexpose.window == windows->image.id) 5132 if (event.xexpose.count == 0) 5133 { 5134 event.xexpose.x=(int) highlight_info.x; 5135 event.xexpose.y=(int) highlight_info.y; 5136 event.xexpose.width=(int) highlight_info.width; 5137 event.xexpose.height=(int) highlight_info.height; 5138 XRefreshWindow(display,&windows->image,&event); 5139 } 5140 if (event.xexpose.window == windows->info.id) 5141 if (event.xexpose.count == 0) 5142 XInfoWidget(display,windows,text); 5143 break; 5144 } 5145 case KeyPress: 5146 { 5147 if (event.xkey.window != windows->image.id) 5148 break; 5149 /* 5150 Respond to a user key press. 5151 */ 5152 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5153 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5154 switch ((int) key_symbol) 5155 { 5156 case XK_Escape: 5157 case XK_F20: 5158 state|=EscapeState; 5159 case XK_Return: 5160 { 5161 state|=ExitState; 5162 break; 5163 } 5164 case XK_Home: 5165 case XK_KP_Home: 5166 { 5167 crop_info.x=(ssize_t) (windows->image.width/2L- 5168 crop_info.width/2L); 5169 crop_info.y=(ssize_t) (windows->image.height/2L- 5170 crop_info.height/2L); 5171 break; 5172 } 5173 case XK_Left: 5174 case XK_KP_Left: 5175 { 5176 crop_info.x--; 5177 break; 5178 } 5179 case XK_Up: 5180 case XK_KP_Up: 5181 case XK_Next: 5182 { 5183 crop_info.y--; 5184 break; 5185 } 5186 case XK_Right: 5187 case XK_KP_Right: 5188 { 5189 crop_info.x++; 5190 break; 5191 } 5192 case XK_Prior: 5193 case XK_Down: 5194 case XK_KP_Down: 5195 { 5196 crop_info.y++; 5197 break; 5198 } 5199 case XK_F1: 5200 case XK_Help: 5201 { 5202 (void) XSetFunction(display,windows->image.highlight_context, 5203 GXcopy); 5204 switch (mode) 5205 { 5206 case CopyMode: 5207 { 5208 XTextViewWidget(display,resource_info,windows,MagickFalse, 5209 "Help Viewer - Image Copy",ImageCopyHelp); 5210 break; 5211 } 5212 case CropMode: 5213 { 5214 XTextViewWidget(display,resource_info,windows,MagickFalse, 5215 "Help Viewer - Image Cropg",ImageCropHelp); 5216 break; 5217 } 5218 case CutMode: 5219 { 5220 XTextViewWidget(display,resource_info,windows,MagickFalse, 5221 "Help Viewer - Image Cutg",ImageCutHelp); 5222 break; 5223 } 5224 } 5225 (void) XSetFunction(display,windows->image.highlight_context, 5226 GXinvert); 5227 break; 5228 } 5229 default: 5230 { 5231 (void) XBell(display,0); 5232 break; 5233 } 5234 } 5235 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5236 event.xkey.time); 5237 break; 5238 } 5239 case KeyRelease: 5240 break; 5241 case MotionNotify: 5242 { 5243 if (event.xmotion.window != windows->image.id) 5244 break; 5245 /* 5246 Map and unmap Info widget as text cursor crosses its boundaries. 5247 */ 5248 x=event.xmotion.x; 5249 y=event.xmotion.y; 5250 if (windows->info.mapped != MagickFalse) 5251 { 5252 if ((x < (int) (windows->info.x+windows->info.width)) && 5253 (y < (int) (windows->info.y+windows->info.height))) 5254 (void) XWithdrawWindow(display,windows->info.id, 5255 windows->info.screen); 5256 } 5257 else 5258 if ((x > (int) (windows->info.x+windows->info.width)) || 5259 (y > (int) (windows->info.y+windows->info.height))) 5260 (void) XMapWindow(display,windows->info.id); 5261 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 5262 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 5263 break; 5264 } 5265 case SelectionRequest: 5266 { 5267 XSelectionEvent 5268 notify; 5269 5270 XSelectionRequestEvent 5271 *request; 5272 5273 /* 5274 Set primary selection. 5275 */ 5276 (void) FormatLocaleString(text,MaxTextExtent, 5277 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 5278 crop_info.height,(double) crop_info.x,(double) crop_info.y); 5279 request=(&(event.xselectionrequest)); 5280 (void) XChangeProperty(request->display,request->requestor, 5281 request->property,request->target,8,PropModeReplace, 5282 (unsigned char *) text,(int) strlen(text)); 5283 notify.type=SelectionNotify; 5284 notify.display=request->display; 5285 notify.requestor=request->requestor; 5286 notify.selection=request->selection; 5287 notify.target=request->target; 5288 notify.time=request->time; 5289 if (request->property == None) 5290 notify.property=request->target; 5291 else 5292 notify.property=request->property; 5293 (void) XSendEvent(request->display,request->requestor,False,0, 5294 (XEvent *) ¬ify); 5295 } 5296 default: 5297 break; 5298 } 5299 if ((state & UpdateConfigurationState) != 0) 5300 { 5301 (void) XPutBackEvent(display,&event); 5302 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5303 break; 5304 } 5305 } while ((state & ExitState) == 0); 5306 } while ((state & ExitState) == 0); 5307 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5308 XSetCursorState(display,windows,MagickFalse); 5309 if ((state & EscapeState) != 0) 5310 return(MagickTrue); 5311 if (mode == CropMode) 5312 if (((int) crop_info.width != windows->image.ximage->width) || 5313 ((int) crop_info.height != windows->image.ximage->height)) 5314 { 5315 /* 5316 Reconfigure Image window as defined by cropping rectangle. 5317 */ 5318 XSetCropGeometry(display,windows,&crop_info,image); 5319 windows->image.window_changes.width=(int) crop_info.width; 5320 windows->image.window_changes.height=(int) crop_info.height; 5321 (void) XConfigureImage(display,resource_info,windows,image,exception); 5322 return(MagickTrue); 5323 } 5324 /* 5325 Copy image before applying image transforms. 5326 */ 5327 XSetCursorState(display,windows,MagickTrue); 5328 XCheckRefreshWindows(display,windows); 5329 width=(unsigned int) image->columns; 5330 height=(unsigned int) image->rows; 5331 x=0; 5332 y=0; 5333 if (windows->image.crop_geometry != (char *) NULL) 5334 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 5335 scale_factor=(MagickRealType) width/windows->image.ximage->width; 5336 crop_info.x+=x; 5337 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 5338 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 5339 scale_factor=(MagickRealType) height/windows->image.ximage->height; 5340 crop_info.y+=y; 5341 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 5342 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5); 5343 crop_image=CropImage(image,&crop_info,exception); 5344 XSetCursorState(display,windows,MagickFalse); 5345 if (crop_image == (Image *) NULL) 5346 return(MagickFalse); 5347 if (resource_info->copy_image != (Image *) NULL) 5348 resource_info->copy_image=DestroyImage(resource_info->copy_image); 5349 resource_info->copy_image=crop_image; 5350 if (mode == CopyMode) 5351 { 5352 (void) XConfigureImage(display,resource_info,windows,image,exception); 5353 return(MagickTrue); 5354 } 5355 /* 5356 Cut image. 5357 */ 5358 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 5359 return(MagickFalse); 5360 image->matte=MagickTrue; 5361 image_view=AcquireCacheView(image); 5362 for (y=0; y < (int) crop_info.height; y++) 5363 { 5364 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y, 5365 crop_info.width,1,exception); 5366 if (q == (Quantum *) NULL) 5367 break; 5368 for (x=0; x < (int) crop_info.width; x++) 5369 { 5370 SetPixelAlpha(image,TransparentAlpha,q); 5371 q+=GetPixelChannels(image); 5372 } 5373 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 5374 break; 5375 } 5376 image_view=DestroyCacheView(image_view); 5377 /* 5378 Update image configuration. 5379 */ 5380 XConfigureImageColormap(display,resource_info,windows,image); 5381 (void) XConfigureImage(display,resource_info,windows,image,exception); 5382 return(MagickTrue); 5383} 5384 5385/* 5386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5387% % 5388% % 5389% % 5390+ X D r a w I m a g e % 5391% % 5392% % 5393% % 5394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5395% 5396% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on 5397% the image. 5398% 5399% The format of the XDrawEditImage method is: 5400% 5401% MagickBooleanType XDrawEditImage(Display *display, 5402% XResourceInfo *resource_info,XWindows *windows,Image **image, 5403% ExceptionInfo *exception) 5404% 5405% A description of each parameter follows: 5406% 5407% o display: Specifies a connection to an X server; returned from 5408% XOpenDisplay. 5409% 5410% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 5411% 5412% o windows: Specifies a pointer to a XWindows structure. 5413% 5414% o image: the image. 5415% 5416% o exception: return any errors or warnings in this structure. 5417% 5418*/ 5419static MagickBooleanType XDrawEditImage(Display *display, 5420 XResourceInfo *resource_info,XWindows *windows,Image **image, 5421 ExceptionInfo *exception) 5422{ 5423 static const char 5424 *DrawMenu[] = 5425 { 5426 "Element", 5427 "Color", 5428 "Stipple", 5429 "Width", 5430 "Undo", 5431 "Help", 5432 "Dismiss", 5433 (char *) NULL 5434 }; 5435 5436 static ElementType 5437 element = PointElement; 5438 5439 static const ModeType 5440 DrawCommands[] = 5441 { 5442 DrawElementCommand, 5443 DrawColorCommand, 5444 DrawStippleCommand, 5445 DrawWidthCommand, 5446 DrawUndoCommand, 5447 DrawHelpCommand, 5448 DrawDismissCommand 5449 }; 5450 5451 static Pixmap 5452 stipple = (Pixmap) NULL; 5453 5454 static unsigned int 5455 pen_id = 0, 5456 line_width = 1; 5457 5458 char 5459 command[MaxTextExtent], 5460 text[MaxTextExtent]; 5461 5462 Cursor 5463 cursor; 5464 5465 int 5466 entry, 5467 id, 5468 number_coordinates, 5469 x, 5470 y; 5471 5472 MagickRealType 5473 degrees; 5474 5475 MagickStatusType 5476 status; 5477 5478 RectangleInfo 5479 rectangle_info; 5480 5481 register int 5482 i; 5483 5484 unsigned int 5485 distance, 5486 height, 5487 max_coordinates, 5488 width; 5489 5490 size_t 5491 state; 5492 5493 Window 5494 root_window; 5495 5496 XDrawInfo 5497 draw_info; 5498 5499 XEvent 5500 event; 5501 5502 XPoint 5503 *coordinate_info; 5504 5505 XSegment 5506 line_info; 5507 5508 /* 5509 Allocate polygon info. 5510 */ 5511 max_coordinates=2048; 5512 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates, 5513 sizeof(*coordinate_info)); 5514 if (coordinate_info == (XPoint *) NULL) 5515 { 5516 (void) ThrowMagickException(exception,GetMagickModule(), 5517 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 5518 return(MagickFalse); 5519 } 5520 /* 5521 Map Command widget. 5522 */ 5523 (void) CloneString(&windows->command.name,"Draw"); 5524 windows->command.data=4; 5525 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL); 5526 (void) XMapRaised(display,windows->command.id); 5527 XClientMessage(display,windows->image.id,windows->im_protocols, 5528 windows->im_update_widget,CurrentTime); 5529 /* 5530 Wait for first button press. 5531 */ 5532 root_window=XRootWindow(display,XDefaultScreen(display)); 5533 draw_info.stencil=OpaqueStencil; 5534 status=MagickTrue; 5535 cursor=XCreateFontCursor(display,XC_tcross); 5536 for ( ; ; ) 5537 { 5538 XQueryPosition(display,windows->image.id,&x,&y); 5539 (void) XSelectInput(display,windows->image.id, 5540 windows->image.attributes.event_mask | PointerMotionMask); 5541 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5542 state=DefaultState; 5543 do 5544 { 5545 if (windows->info.mapped != MagickFalse) 5546 { 5547 /* 5548 Display pointer position. 5549 */ 5550 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 5551 x+windows->image.x,y+windows->image.y); 5552 XInfoWidget(display,windows,text); 5553 } 5554 /* 5555 Wait for next event. 5556 */ 5557 XScreenEvent(display,windows,&event); 5558 if (event.xany.window == windows->command.id) 5559 { 5560 /* 5561 Select a command from the Command widget. 5562 */ 5563 id=XCommandWidget(display,windows,DrawMenu,&event); 5564 if (id < 0) 5565 continue; 5566 switch (DrawCommands[id]) 5567 { 5568 case DrawElementCommand: 5569 { 5570 static const char 5571 *Elements[] = 5572 { 5573 "point", 5574 "line", 5575 "rectangle", 5576 "fill rectangle", 5577 "circle", 5578 "fill circle", 5579 "ellipse", 5580 "fill ellipse", 5581 "polygon", 5582 "fill polygon", 5583 (char *) NULL, 5584 }; 5585 5586 /* 5587 Select a command from the pop-up menu. 5588 */ 5589 element=(ElementType) (XMenuWidget(display,windows, 5590 DrawMenu[id],Elements,command)+1); 5591 break; 5592 } 5593 case DrawColorCommand: 5594 { 5595 const char 5596 *ColorMenu[MaxNumberPens+1]; 5597 5598 int 5599 pen_number; 5600 5601 MagickBooleanType 5602 transparent; 5603 5604 XColor 5605 color; 5606 5607 /* 5608 Initialize menu selections. 5609 */ 5610 for (i=0; i < (int) (MaxNumberPens-2); i++) 5611 ColorMenu[i]=resource_info->pen_colors[i]; 5612 ColorMenu[MaxNumberPens-2]="transparent"; 5613 ColorMenu[MaxNumberPens-1]="Browser..."; 5614 ColorMenu[MaxNumberPens]=(char *) NULL; 5615 /* 5616 Select a pen color from the pop-up menu. 5617 */ 5618 pen_number=XMenuWidget(display,windows,DrawMenu[id], 5619 (const char **) ColorMenu,command); 5620 if (pen_number < 0) 5621 break; 5622 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue : 5623 MagickFalse; 5624 if (transparent != MagickFalse) 5625 { 5626 draw_info.stencil=TransparentStencil; 5627 break; 5628 } 5629 if (pen_number == (MaxNumberPens-1)) 5630 { 5631 static char 5632 color_name[MaxTextExtent] = "gray"; 5633 5634 /* 5635 Select a pen color from a dialog. 5636 */ 5637 resource_info->pen_colors[pen_number]=color_name; 5638 XColorBrowserWidget(display,windows,"Select",color_name); 5639 if (*color_name == '\0') 5640 break; 5641 } 5642 /* 5643 Set pen color. 5644 */ 5645 (void) XParseColor(display,windows->map_info->colormap, 5646 resource_info->pen_colors[pen_number],&color); 5647 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 5648 (unsigned int) MaxColors,&color); 5649 windows->pixel_info->pen_colors[pen_number]=color; 5650 pen_id=(unsigned int) pen_number; 5651 draw_info.stencil=OpaqueStencil; 5652 break; 5653 } 5654 case DrawStippleCommand: 5655 { 5656 Image 5657 *stipple_image; 5658 5659 ImageInfo 5660 *image_info; 5661 5662 int 5663 status; 5664 5665 static char 5666 filename[MaxTextExtent] = "\0"; 5667 5668 static const char 5669 *StipplesMenu[] = 5670 { 5671 "Brick", 5672 "Diagonal", 5673 "Scales", 5674 "Vertical", 5675 "Wavy", 5676 "Translucent", 5677 "Opaque", 5678 (char *) NULL, 5679 (char *) NULL, 5680 }; 5681 5682 /* 5683 Select a command from the pop-up menu. 5684 */ 5685 StipplesMenu[7]="Open..."; 5686 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu, 5687 command); 5688 if (entry < 0) 5689 break; 5690 if (stipple != (Pixmap) NULL) 5691 (void) XFreePixmap(display,stipple); 5692 stipple=(Pixmap) NULL; 5693 if (entry != 7) 5694 { 5695 switch (entry) 5696 { 5697 case 0: 5698 { 5699 stipple=XCreateBitmapFromData(display,root_window, 5700 (char *) BricksBitmap,BricksWidth,BricksHeight); 5701 break; 5702 } 5703 case 1: 5704 { 5705 stipple=XCreateBitmapFromData(display,root_window, 5706 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight); 5707 break; 5708 } 5709 case 2: 5710 { 5711 stipple=XCreateBitmapFromData(display,root_window, 5712 (char *) ScalesBitmap,ScalesWidth,ScalesHeight); 5713 break; 5714 } 5715 case 3: 5716 { 5717 stipple=XCreateBitmapFromData(display,root_window, 5718 (char *) VerticalBitmap,VerticalWidth,VerticalHeight); 5719 break; 5720 } 5721 case 4: 5722 { 5723 stipple=XCreateBitmapFromData(display,root_window, 5724 (char *) WavyBitmap,WavyWidth,WavyHeight); 5725 break; 5726 } 5727 case 5: 5728 { 5729 stipple=XCreateBitmapFromData(display,root_window, 5730 (char *) HighlightBitmap,HighlightWidth, 5731 HighlightHeight); 5732 break; 5733 } 5734 case 6: 5735 default: 5736 { 5737 stipple=XCreateBitmapFromData(display,root_window, 5738 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight); 5739 break; 5740 } 5741 } 5742 break; 5743 } 5744 XFileBrowserWidget(display,windows,"Stipple",filename); 5745 if (*filename == '\0') 5746 break; 5747 /* 5748 Read image. 5749 */ 5750 XSetCursorState(display,windows,MagickTrue); 5751 XCheckRefreshWindows(display,windows); 5752 image_info=AcquireImageInfo(); 5753 (void) CopyMagickString(image_info->filename,filename, 5754 MaxTextExtent); 5755 stipple_image=ReadImage(image_info,exception); 5756 CatchException(exception); 5757 XSetCursorState(display,windows,MagickFalse); 5758 if (stipple_image == (Image *) NULL) 5759 break; 5760 (void) AcquireUniqueFileResource(filename); 5761 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent, 5762 "xbm:%s",filename); 5763 (void) WriteImage(image_info,stipple_image,exception); 5764 stipple_image=DestroyImage(stipple_image); 5765 image_info=DestroyImageInfo(image_info); 5766 status=XReadBitmapFile(display,root_window,filename,&width, 5767 &height,&stipple,&x,&y); 5768 (void) RelinquishUniqueFileResource(filename); 5769 if ((status != BitmapSuccess) != 0) 5770 XNoticeWidget(display,windows,"Unable to read X bitmap image:", 5771 filename); 5772 break; 5773 } 5774 case DrawWidthCommand: 5775 { 5776 static char 5777 width[MaxTextExtent] = "0"; 5778 5779 static const char 5780 *WidthsMenu[] = 5781 { 5782 "1", 5783 "2", 5784 "4", 5785 "8", 5786 "16", 5787 "Dialog...", 5788 (char *) NULL, 5789 }; 5790 5791 /* 5792 Select a command from the pop-up menu. 5793 */ 5794 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu, 5795 command); 5796 if (entry < 0) 5797 break; 5798 if (entry != 5) 5799 { 5800 line_width=(unsigned int) StringToUnsignedLong( 5801 WidthsMenu[entry]); 5802 break; 5803 } 5804 (void) XDialogWidget(display,windows,"Ok","Enter line width:", 5805 width); 5806 if (*width == '\0') 5807 break; 5808 line_width=(unsigned int) StringToUnsignedLong(width); 5809 break; 5810 } 5811 case DrawUndoCommand: 5812 { 5813 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 5814 image,exception); 5815 break; 5816 } 5817 case DrawHelpCommand: 5818 { 5819 XTextViewWidget(display,resource_info,windows,MagickFalse, 5820 "Help Viewer - Image Rotation",ImageDrawHelp); 5821 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5822 break; 5823 } 5824 case DrawDismissCommand: 5825 { 5826 /* 5827 Prematurely exit. 5828 */ 5829 state|=EscapeState; 5830 state|=ExitState; 5831 break; 5832 } 5833 default: 5834 break; 5835 } 5836 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5837 continue; 5838 } 5839 switch (event.type) 5840 { 5841 case ButtonPress: 5842 { 5843 if (event.xbutton.button != Button1) 5844 break; 5845 if (event.xbutton.window != windows->image.id) 5846 break; 5847 /* 5848 exit loop. 5849 */ 5850 x=event.xbutton.x; 5851 y=event.xbutton.y; 5852 state|=ExitState; 5853 break; 5854 } 5855 case ButtonRelease: 5856 break; 5857 case Expose: 5858 break; 5859 case KeyPress: 5860 { 5861 KeySym 5862 key_symbol; 5863 5864 if (event.xkey.window != windows->image.id) 5865 break; 5866 /* 5867 Respond to a user key press. 5868 */ 5869 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5870 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5871 switch ((int) key_symbol) 5872 { 5873 case XK_Escape: 5874 case XK_F20: 5875 { 5876 /* 5877 Prematurely exit. 5878 */ 5879 state|=EscapeState; 5880 state|=ExitState; 5881 break; 5882 } 5883 case XK_F1: 5884 case XK_Help: 5885 { 5886 XTextViewWidget(display,resource_info,windows,MagickFalse, 5887 "Help Viewer - Image Rotation",ImageDrawHelp); 5888 break; 5889 } 5890 default: 5891 { 5892 (void) XBell(display,0); 5893 break; 5894 } 5895 } 5896 break; 5897 } 5898 case MotionNotify: 5899 { 5900 /* 5901 Map and unmap Info widget as text cursor crosses its boundaries. 5902 */ 5903 x=event.xmotion.x; 5904 y=event.xmotion.y; 5905 if (windows->info.mapped != MagickFalse) 5906 { 5907 if ((x < (int) (windows->info.x+windows->info.width)) && 5908 (y < (int) (windows->info.y+windows->info.height))) 5909 (void) XWithdrawWindow(display,windows->info.id, 5910 windows->info.screen); 5911 } 5912 else 5913 if ((x > (int) (windows->info.x+windows->info.width)) || 5914 (y > (int) (windows->info.y+windows->info.height))) 5915 (void) XMapWindow(display,windows->info.id); 5916 break; 5917 } 5918 } 5919 } while ((state & ExitState) == 0); 5920 (void) XSelectInput(display,windows->image.id, 5921 windows->image.attributes.event_mask); 5922 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 5923 if ((state & EscapeState) != 0) 5924 break; 5925 /* 5926 Draw element as pointer moves until the button is released. 5927 */ 5928 distance=0; 5929 degrees=0.0; 5930 line_info.x1=x; 5931 line_info.y1=y; 5932 line_info.x2=x; 5933 line_info.y2=y; 5934 rectangle_info.x=(ssize_t) x; 5935 rectangle_info.y=(ssize_t) y; 5936 rectangle_info.width=0; 5937 rectangle_info.height=0; 5938 number_coordinates=1; 5939 coordinate_info->x=x; 5940 coordinate_info->y=y; 5941 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 5942 state=DefaultState; 5943 do 5944 { 5945 switch (element) 5946 { 5947 case PointElement: 5948 default: 5949 { 5950 if (number_coordinates > 1) 5951 { 5952 (void) XDrawLines(display,windows->image.id, 5953 windows->image.highlight_context,coordinate_info, 5954 number_coordinates,CoordModeOrigin); 5955 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d", 5956 coordinate_info[number_coordinates-1].x, 5957 coordinate_info[number_coordinates-1].y); 5958 XInfoWidget(display,windows,text); 5959 } 5960 break; 5961 } 5962 case LineElement: 5963 { 5964 if (distance > 9) 5965 { 5966 /* 5967 Display angle of the line. 5968 */ 5969 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 5970 line_info.y1),(double) (line_info.x2-line_info.x1))); 5971 (void) FormatLocaleString(text,MaxTextExtent," %g", 5972 (double) degrees); 5973 XInfoWidget(display,windows,text); 5974 XHighlightLine(display,windows->image.id, 5975 windows->image.highlight_context,&line_info); 5976 } 5977 else 5978 if (windows->info.mapped != MagickFalse) 5979 (void) XWithdrawWindow(display,windows->info.id, 5980 windows->info.screen); 5981 break; 5982 } 5983 case RectangleElement: 5984 case FillRectangleElement: 5985 { 5986 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5987 { 5988 /* 5989 Display info and draw drawing rectangle. 5990 */ 5991 (void) FormatLocaleString(text,MaxTextExtent, 5992 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5993 (double) rectangle_info.height,(double) rectangle_info.x, 5994 (double) rectangle_info.y); 5995 XInfoWidget(display,windows,text); 5996 XHighlightRectangle(display,windows->image.id, 5997 windows->image.highlight_context,&rectangle_info); 5998 } 5999 else 6000 if (windows->info.mapped != MagickFalse) 6001 (void) XWithdrawWindow(display,windows->info.id, 6002 windows->info.screen); 6003 break; 6004 } 6005 case CircleElement: 6006 case FillCircleElement: 6007 case EllipseElement: 6008 case FillEllipseElement: 6009 { 6010 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6011 { 6012 /* 6013 Display info and draw drawing rectangle. 6014 */ 6015 (void) FormatLocaleString(text,MaxTextExtent, 6016 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 6017 (double) rectangle_info.height,(double) rectangle_info.x, 6018 (double) rectangle_info.y); 6019 XInfoWidget(display,windows,text); 6020 XHighlightEllipse(display,windows->image.id, 6021 windows->image.highlight_context,&rectangle_info); 6022 } 6023 else 6024 if (windows->info.mapped != MagickFalse) 6025 (void) XWithdrawWindow(display,windows->info.id, 6026 windows->info.screen); 6027 break; 6028 } 6029 case PolygonElement: 6030 case FillPolygonElement: 6031 { 6032 if (number_coordinates > 1) 6033 (void) XDrawLines(display,windows->image.id, 6034 windows->image.highlight_context,coordinate_info, 6035 number_coordinates,CoordModeOrigin); 6036 if (distance > 9) 6037 { 6038 /* 6039 Display angle of the line. 6040 */ 6041 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 6042 line_info.y1),(double) (line_info.x2-line_info.x1))); 6043 (void) FormatLocaleString(text,MaxTextExtent," %g", 6044 (double) degrees); 6045 XInfoWidget(display,windows,text); 6046 XHighlightLine(display,windows->image.id, 6047 windows->image.highlight_context,&line_info); 6048 } 6049 else 6050 if (windows->info.mapped != MagickFalse) 6051 (void) XWithdrawWindow(display,windows->info.id, 6052 windows->info.screen); 6053 break; 6054 } 6055 } 6056 /* 6057 Wait for next event. 6058 */ 6059 XScreenEvent(display,windows,&event); 6060 switch (element) 6061 { 6062 case PointElement: 6063 default: 6064 { 6065 if (number_coordinates > 1) 6066 (void) XDrawLines(display,windows->image.id, 6067 windows->image.highlight_context,coordinate_info, 6068 number_coordinates,CoordModeOrigin); 6069 break; 6070 } 6071 case LineElement: 6072 { 6073 if (distance > 9) 6074 XHighlightLine(display,windows->image.id, 6075 windows->image.highlight_context,&line_info); 6076 break; 6077 } 6078 case RectangleElement: 6079 case FillRectangleElement: 6080 { 6081 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6082 XHighlightRectangle(display,windows->image.id, 6083 windows->image.highlight_context,&rectangle_info); 6084 break; 6085 } 6086 case CircleElement: 6087 case FillCircleElement: 6088 case EllipseElement: 6089 case FillEllipseElement: 6090 { 6091 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6092 XHighlightEllipse(display,windows->image.id, 6093 windows->image.highlight_context,&rectangle_info); 6094 break; 6095 } 6096 case PolygonElement: 6097 case FillPolygonElement: 6098 { 6099 if (number_coordinates > 1) 6100 (void) XDrawLines(display,windows->image.id, 6101 windows->image.highlight_context,coordinate_info, 6102 number_coordinates,CoordModeOrigin); 6103 if (distance > 9) 6104 XHighlightLine(display,windows->image.id, 6105 windows->image.highlight_context,&line_info); 6106 break; 6107 } 6108 } 6109 switch (event.type) 6110 { 6111 case ButtonPress: 6112 break; 6113 case ButtonRelease: 6114 { 6115 /* 6116 User has committed to element. 6117 */ 6118 line_info.x2=event.xbutton.x; 6119 line_info.y2=event.xbutton.y; 6120 rectangle_info.x=(ssize_t) event.xbutton.x; 6121 rectangle_info.y=(ssize_t) event.xbutton.y; 6122 coordinate_info[number_coordinates].x=event.xbutton.x; 6123 coordinate_info[number_coordinates].y=event.xbutton.y; 6124 if (((element != PolygonElement) && 6125 (element != FillPolygonElement)) || (distance <= 9)) 6126 { 6127 state|=ExitState; 6128 break; 6129 } 6130 number_coordinates++; 6131 if (number_coordinates < (int) max_coordinates) 6132 { 6133 line_info.x1=event.xbutton.x; 6134 line_info.y1=event.xbutton.y; 6135 break; 6136 } 6137 max_coordinates<<=1; 6138 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6139 max_coordinates,sizeof(*coordinate_info)); 6140 if (coordinate_info == (XPoint *) NULL) 6141 (void) ThrowMagickException(exception,GetMagickModule(), 6142 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6143 break; 6144 } 6145 case Expose: 6146 break; 6147 case MotionNotify: 6148 { 6149 if (event.xmotion.window != windows->image.id) 6150 break; 6151 if (element != PointElement) 6152 { 6153 line_info.x2=event.xmotion.x; 6154 line_info.y2=event.xmotion.y; 6155 rectangle_info.x=(ssize_t) event.xmotion.x; 6156 rectangle_info.y=(ssize_t) event.xmotion.y; 6157 break; 6158 } 6159 coordinate_info[number_coordinates].x=event.xbutton.x; 6160 coordinate_info[number_coordinates].y=event.xbutton.y; 6161 number_coordinates++; 6162 if (number_coordinates < (int) max_coordinates) 6163 break; 6164 max_coordinates<<=1; 6165 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6166 max_coordinates,sizeof(*coordinate_info)); 6167 if (coordinate_info == (XPoint *) NULL) 6168 (void) ThrowMagickException(exception,GetMagickModule(), 6169 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6170 break; 6171 } 6172 default: 6173 break; 6174 } 6175 /* 6176 Check boundary conditions. 6177 */ 6178 if (line_info.x2 < 0) 6179 line_info.x2=0; 6180 else 6181 if (line_info.x2 > (int) windows->image.width) 6182 line_info.x2=(short) windows->image.width; 6183 if (line_info.y2 < 0) 6184 line_info.y2=0; 6185 else 6186 if (line_info.y2 > (int) windows->image.height) 6187 line_info.y2=(short) windows->image.height; 6188 distance=(unsigned int) 6189 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+ 6190 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1))); 6191 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) || 6192 ((state & ExitState) != 0)) 6193 { 6194 if (rectangle_info.x < 0) 6195 rectangle_info.x=0; 6196 else 6197 if (rectangle_info.x > (ssize_t) windows->image.width) 6198 rectangle_info.x=(ssize_t) windows->image.width; 6199 if ((int) rectangle_info.x < x) 6200 rectangle_info.width=(unsigned int) (x-rectangle_info.x); 6201 else 6202 { 6203 rectangle_info.width=(unsigned int) (rectangle_info.x-x); 6204 rectangle_info.x=(ssize_t) x; 6205 } 6206 if (rectangle_info.y < 0) 6207 rectangle_info.y=0; 6208 else 6209 if (rectangle_info.y > (ssize_t) windows->image.height) 6210 rectangle_info.y=(ssize_t) windows->image.height; 6211 if ((int) rectangle_info.y < y) 6212 rectangle_info.height=(unsigned int) (y-rectangle_info.y); 6213 else 6214 { 6215 rectangle_info.height=(unsigned int) (rectangle_info.y-y); 6216 rectangle_info.y=(ssize_t) y; 6217 } 6218 } 6219 } while ((state & ExitState) == 0); 6220 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 6221 if ((element == PointElement) || (element == PolygonElement) || 6222 (element == FillPolygonElement)) 6223 { 6224 /* 6225 Determine polygon bounding box. 6226 */ 6227 rectangle_info.x=(ssize_t) coordinate_info->x; 6228 rectangle_info.y=(ssize_t) coordinate_info->y; 6229 x=coordinate_info->x; 6230 y=coordinate_info->y; 6231 for (i=1; i < number_coordinates; i++) 6232 { 6233 if (coordinate_info[i].x > x) 6234 x=coordinate_info[i].x; 6235 if (coordinate_info[i].y > y) 6236 y=coordinate_info[i].y; 6237 if ((ssize_t) coordinate_info[i].x < rectangle_info.x) 6238 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0); 6239 if ((ssize_t) coordinate_info[i].y < rectangle_info.y) 6240 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0); 6241 } 6242 rectangle_info.width=(size_t) (x-rectangle_info.x); 6243 rectangle_info.height=(size_t) (y-rectangle_info.y); 6244 for (i=0; i < number_coordinates; i++) 6245 { 6246 coordinate_info[i].x-=rectangle_info.x; 6247 coordinate_info[i].y-=rectangle_info.y; 6248 } 6249 } 6250 else 6251 if (distance <= 9) 6252 continue; 6253 else 6254 if ((element == RectangleElement) || 6255 (element == CircleElement) || (element == EllipseElement)) 6256 { 6257 rectangle_info.width--; 6258 rectangle_info.height--; 6259 } 6260 /* 6261 Drawing is relative to image configuration. 6262 */ 6263 draw_info.x=(int) rectangle_info.x; 6264 draw_info.y=(int) rectangle_info.y; 6265 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand, 6266 image,exception); 6267 width=(unsigned int) (*image)->columns; 6268 height=(unsigned int) (*image)->rows; 6269 x=0; 6270 y=0; 6271 if (windows->image.crop_geometry != (char *) NULL) 6272 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 6273 draw_info.x+=windows->image.x-(line_width/2); 6274 if (draw_info.x < 0) 6275 draw_info.x=0; 6276 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width); 6277 draw_info.y+=windows->image.y-(line_width/2); 6278 if (draw_info.y < 0) 6279 draw_info.y=0; 6280 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height; 6281 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1); 6282 if (draw_info.width > (unsigned int) (*image)->columns) 6283 draw_info.width=(unsigned int) (*image)->columns; 6284 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1); 6285 if (draw_info.height > (unsigned int) (*image)->rows) 6286 draw_info.height=(unsigned int) (*image)->rows; 6287 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d", 6288 width*draw_info.width/windows->image.ximage->width, 6289 height*draw_info.height/windows->image.ximage->height, 6290 draw_info.x+x,draw_info.y+y); 6291 /* 6292 Initialize drawing attributes. 6293 */ 6294 draw_info.degrees=0.0; 6295 draw_info.element=element; 6296 draw_info.stipple=stipple; 6297 draw_info.line_width=line_width; 6298 draw_info.line_info=line_info; 6299 if (line_info.x1 > (int) (line_width/2)) 6300 draw_info.line_info.x1=(short) line_width/2; 6301 if (line_info.y1 > (int) (line_width/2)) 6302 draw_info.line_info.y1=(short) line_width/2; 6303 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2)); 6304 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2)); 6305 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0)) 6306 { 6307 draw_info.line_info.x2=(-draw_info.line_info.x2); 6308 draw_info.line_info.y2=(-draw_info.line_info.y2); 6309 } 6310 if (draw_info.line_info.x2 < 0) 6311 { 6312 draw_info.line_info.x2=(-draw_info.line_info.x2); 6313 Swap(draw_info.line_info.x1,draw_info.line_info.x2); 6314 } 6315 if (draw_info.line_info.y2 < 0) 6316 { 6317 draw_info.line_info.y2=(-draw_info.line_info.y2); 6318 Swap(draw_info.line_info.y1,draw_info.line_info.y2); 6319 } 6320 draw_info.rectangle_info=rectangle_info; 6321 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2)) 6322 draw_info.rectangle_info.x=(ssize_t) line_width/2; 6323 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2)) 6324 draw_info.rectangle_info.y=(ssize_t) line_width/2; 6325 draw_info.number_coordinates=(unsigned int) number_coordinates; 6326 draw_info.coordinate_info=coordinate_info; 6327 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 6328 /* 6329 Draw element on image. 6330 */ 6331 XSetCursorState(display,windows,MagickTrue); 6332 XCheckRefreshWindows(display,windows); 6333 status=XDrawImage(display,windows->pixel_info,&draw_info,*image); 6334 XSetCursorState(display,windows,MagickFalse); 6335 /* 6336 Update image colormap and return to image drawing. 6337 */ 6338 XConfigureImageColormap(display,resource_info,windows,*image); 6339 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6340 } 6341 XSetCursorState(display,windows,MagickFalse); 6342 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info); 6343 return(status != 0 ? MagickTrue : MagickFalse); 6344} 6345 6346/* 6347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6348% % 6349% % 6350% % 6351+ X D r a w P a n R e c t a n g l e % 6352% % 6353% % 6354% % 6355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6356% 6357% XDrawPanRectangle() draws a rectangle in the pan window. The pan window 6358% displays a zoom image and the rectangle shows which portion of the image is 6359% displayed in the Image window. 6360% 6361% The format of the XDrawPanRectangle method is: 6362% 6363% XDrawPanRectangle(Display *display,XWindows *windows) 6364% 6365% A description of each parameter follows: 6366% 6367% o display: Specifies a connection to an X server; returned from 6368% XOpenDisplay. 6369% 6370% o windows: Specifies a pointer to a XWindows structure. 6371% 6372*/ 6373static void XDrawPanRectangle(Display *display,XWindows *windows) 6374{ 6375 MagickRealType 6376 scale_factor; 6377 6378 RectangleInfo 6379 highlight_info; 6380 6381 /* 6382 Determine dimensions of the panning rectangle. 6383 */ 6384 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width; 6385 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5); 6386 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5); 6387 scale_factor=(MagickRealType) 6388 windows->pan.height/windows->image.ximage->height; 6389 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5); 6390 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5); 6391 /* 6392 Display the panning rectangle. 6393 */ 6394 (void) XClearWindow(display,windows->pan.id); 6395 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context, 6396 &highlight_info); 6397} 6398 6399/* 6400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6401% % 6402% % 6403% % 6404+ X I m a g e C a c h e % 6405% % 6406% % 6407% % 6408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6409% 6410% XImageCache() handles the creation, manipulation, and destruction of the 6411% image cache (undo and redo buffers). 6412% 6413% The format of the XImageCache method is: 6414% 6415% void XImageCache(Display *display,XResourceInfo *resource_info, 6416% XWindows *windows,const CommandType command,Image **image, 6417% ExceptionInfo *exception) 6418% 6419% A description of each parameter follows: 6420% 6421% o display: Specifies a connection to an X server; returned from 6422% XOpenDisplay. 6423% 6424% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6425% 6426% o windows: Specifies a pointer to a XWindows structure. 6427% 6428% o command: Specifies a command to perform. 6429% 6430% o image: the image; XImageCache may transform the image and return a new 6431% image pointer. 6432% 6433% o exception: return any errors or warnings in this structure. 6434% 6435*/ 6436static void XImageCache(Display *display,XResourceInfo *resource_info, 6437 XWindows *windows,const CommandType command,Image **image, 6438 ExceptionInfo *exception) 6439{ 6440 Image 6441 *cache_image; 6442 6443 static Image 6444 *redo_image = (Image *) NULL, 6445 *undo_image = (Image *) NULL; 6446 6447 switch (command) 6448 { 6449 case FreeBuffersCommand: 6450 { 6451 /* 6452 Free memory from the undo and redo cache. 6453 */ 6454 while (undo_image != (Image *) NULL) 6455 { 6456 cache_image=undo_image; 6457 undo_image=GetPreviousImageInList(undo_image); 6458 cache_image->list=DestroyImage(cache_image->list); 6459 cache_image=DestroyImage(cache_image); 6460 } 6461 undo_image=NewImageList(); 6462 if (redo_image != (Image *) NULL) 6463 redo_image=DestroyImage(redo_image); 6464 redo_image=NewImageList(); 6465 return; 6466 } 6467 case UndoCommand: 6468 { 6469 char 6470 image_geometry[MaxTextExtent]; 6471 6472 /* 6473 Undo the last image transformation. 6474 */ 6475 if (undo_image == (Image *) NULL) 6476 { 6477 (void) XBell(display,0); 6478 return; 6479 } 6480 cache_image=undo_image; 6481 undo_image=GetPreviousImageInList(undo_image); 6482 windows->image.window_changes.width=(int) cache_image->columns; 6483 windows->image.window_changes.height=(int) cache_image->rows; 6484 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 6485 windows->image.ximage->width,windows->image.ximage->height); 6486 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 6487 exception); 6488 if (windows->image.crop_geometry != (char *) NULL) 6489 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 6490 windows->image.crop_geometry); 6491 windows->image.crop_geometry=cache_image->geometry; 6492 if (redo_image != (Image *) NULL) 6493 redo_image=DestroyImage(redo_image); 6494 redo_image=(*image); 6495 *image=cache_image->list; 6496 cache_image=DestroyImage(cache_image); 6497 if (windows->image.orphan != MagickFalse) 6498 return; 6499 XConfigureImageColormap(display,resource_info,windows,*image); 6500 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6501 return; 6502 } 6503 case CutCommand: 6504 case PasteCommand: 6505 case ApplyCommand: 6506 case HalfSizeCommand: 6507 case OriginalSizeCommand: 6508 case DoubleSizeCommand: 6509 case ResizeCommand: 6510 case TrimCommand: 6511 case CropCommand: 6512 case ChopCommand: 6513 case FlipCommand: 6514 case FlopCommand: 6515 case RotateRightCommand: 6516 case RotateLeftCommand: 6517 case RotateCommand: 6518 case ShearCommand: 6519 case RollCommand: 6520 case NegateCommand: 6521 case ContrastStretchCommand: 6522 case SigmoidalContrastCommand: 6523 case NormalizeCommand: 6524 case EqualizeCommand: 6525 case HueCommand: 6526 case SaturationCommand: 6527 case BrightnessCommand: 6528 case GammaCommand: 6529 case SpiffCommand: 6530 case DullCommand: 6531 case GrayscaleCommand: 6532 case MapCommand: 6533 case QuantizeCommand: 6534 case DespeckleCommand: 6535 case EmbossCommand: 6536 case ReduceNoiseCommand: 6537 case AddNoiseCommand: 6538 case SharpenCommand: 6539 case BlurCommand: 6540 case ThresholdCommand: 6541 case EdgeDetectCommand: 6542 case SpreadCommand: 6543 case ShadeCommand: 6544 case RaiseCommand: 6545 case SegmentCommand: 6546 case SolarizeCommand: 6547 case SepiaToneCommand: 6548 case SwirlCommand: 6549 case ImplodeCommand: 6550 case VignetteCommand: 6551 case WaveCommand: 6552 case OilPaintCommand: 6553 case CharcoalDrawCommand: 6554 case AnnotateCommand: 6555 case AddBorderCommand: 6556 case AddFrameCommand: 6557 case CompositeCommand: 6558 case CommentCommand: 6559 case LaunchCommand: 6560 case RegionofInterestCommand: 6561 case SaveToUndoBufferCommand: 6562 case RedoCommand: 6563 { 6564 Image 6565 *previous_image; 6566 6567 ssize_t 6568 bytes; 6569 6570 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo)); 6571 if (undo_image != (Image *) NULL) 6572 { 6573 /* 6574 Ensure the undo cache has enough memory available. 6575 */ 6576 previous_image=undo_image; 6577 while (previous_image != (Image *) NULL) 6578 { 6579 bytes+=previous_image->list->columns*previous_image->list->rows* 6580 sizeof(PixelInfo); 6581 if (bytes <= (ssize_t) (resource_info->undo_cache << 20)) 6582 { 6583 previous_image=GetPreviousImageInList(previous_image); 6584 continue; 6585 } 6586 bytes-=previous_image->list->columns*previous_image->list->rows* 6587 sizeof(PixelInfo); 6588 if (previous_image == undo_image) 6589 undo_image=NewImageList(); 6590 else 6591 previous_image->next->previous=NewImageList(); 6592 break; 6593 } 6594 while (previous_image != (Image *) NULL) 6595 { 6596 /* 6597 Delete any excess memory from undo cache. 6598 */ 6599 cache_image=previous_image; 6600 previous_image=GetPreviousImageInList(previous_image); 6601 cache_image->list=DestroyImage(cache_image->list); 6602 cache_image=DestroyImage(cache_image); 6603 } 6604 } 6605 if (bytes > (ssize_t) (resource_info->undo_cache << 20)) 6606 break; 6607 /* 6608 Save image before transformations are applied. 6609 */ 6610 cache_image=AcquireImage((ImageInfo *) NULL,exception); 6611 if (cache_image == (Image *) NULL) 6612 break; 6613 XSetCursorState(display,windows,MagickTrue); 6614 XCheckRefreshWindows(display,windows); 6615 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception); 6616 XSetCursorState(display,windows,MagickFalse); 6617 if (cache_image->list == (Image *) NULL) 6618 { 6619 cache_image=DestroyImage(cache_image); 6620 break; 6621 } 6622 cache_image->columns=(size_t) windows->image.ximage->width; 6623 cache_image->rows=(size_t) windows->image.ximage->height; 6624 cache_image->geometry=windows->image.crop_geometry; 6625 if (windows->image.crop_geometry != (char *) NULL) 6626 { 6627 cache_image->geometry=AcquireString((char *) NULL); 6628 (void) CopyMagickString(cache_image->geometry, 6629 windows->image.crop_geometry,MaxTextExtent); 6630 } 6631 if (undo_image == (Image *) NULL) 6632 { 6633 undo_image=cache_image; 6634 break; 6635 } 6636 undo_image->next=cache_image; 6637 undo_image->next->previous=undo_image; 6638 undo_image=undo_image->next; 6639 break; 6640 } 6641 default: 6642 break; 6643 } 6644 if (command == RedoCommand) 6645 { 6646 /* 6647 Redo the last image transformation. 6648 */ 6649 if (redo_image == (Image *) NULL) 6650 { 6651 (void) XBell(display,0); 6652 return; 6653 } 6654 windows->image.window_changes.width=(int) redo_image->columns; 6655 windows->image.window_changes.height=(int) redo_image->rows; 6656 if (windows->image.crop_geometry != (char *) NULL) 6657 windows->image.crop_geometry=(char *) 6658 RelinquishMagickMemory(windows->image.crop_geometry); 6659 windows->image.crop_geometry=redo_image->geometry; 6660 *image=DestroyImage(*image); 6661 *image=redo_image; 6662 redo_image=NewImageList(); 6663 if (windows->image.orphan != MagickFalse) 6664 return; 6665 XConfigureImageColormap(display,resource_info,windows,*image); 6666 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6667 return; 6668 } 6669 if (command != InfoCommand) 6670 return; 6671 /* 6672 Display image info. 6673 */ 6674 XSetCursorState(display,windows,MagickTrue); 6675 XCheckRefreshWindows(display,windows); 6676 XDisplayImageInfo(display,resource_info,windows,undo_image,*image); 6677 XSetCursorState(display,windows,MagickFalse); 6678} 6679 6680/* 6681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6682% % 6683% % 6684% % 6685+ X I m a g e W i n d o w C o m m a n d % 6686% % 6687% % 6688% % 6689%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6690% 6691% XImageWindowCommand() makes a transform to the image or Image window as 6692% specified by a user menu button or keyboard command. 6693% 6694% The format of the XImageWindowCommand method is: 6695% 6696% CommandType XImageWindowCommand(Display *display, 6697% XResourceInfo *resource_info,XWindows *windows, 6698% const MagickStatusType state,KeySym key_symbol,Image **image, 6699% ExceptionInfo *exception) 6700% 6701% A description of each parameter follows: 6702% 6703% o nexus: Method XImageWindowCommand returns an image when the 6704% user chooses 'Open Image' from the command menu. Otherwise a null 6705% image is returned. 6706% 6707% o display: Specifies a connection to an X server; returned from 6708% XOpenDisplay. 6709% 6710% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6711% 6712% o windows: Specifies a pointer to a XWindows structure. 6713% 6714% o state: key mask. 6715% 6716% o key_symbol: Specifies a command to perform. 6717% 6718% o image: the image; XImageWIndowCommand may transform the image and 6719% return a new image pointer. 6720% 6721% o exception: return any errors or warnings in this structure. 6722% 6723*/ 6724static CommandType XImageWindowCommand(Display *display, 6725 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state, 6726 KeySym key_symbol,Image **image,ExceptionInfo *exception) 6727{ 6728 static char 6729 delta[MaxTextExtent] = ""; 6730 6731 static const char 6732 Digits[] = "01234567890"; 6733 6734 static KeySym 6735 last_symbol = XK_0; 6736 6737 if ((key_symbol >= XK_0) && (key_symbol <= XK_9)) 6738 { 6739 if (((last_symbol < XK_0) || (last_symbol > XK_9))) 6740 { 6741 *delta='\0'; 6742 resource_info->quantum=1; 6743 } 6744 last_symbol=key_symbol; 6745 delta[strlen(delta)+1]='\0'; 6746 delta[strlen(delta)]=Digits[key_symbol-XK_0]; 6747 resource_info->quantum=StringToLong(delta); 6748 return(NullCommand); 6749 } 6750 last_symbol=key_symbol; 6751 if (resource_info->immutable) 6752 { 6753 /* 6754 Virtual image window has a restricted command set. 6755 */ 6756 switch (key_symbol) 6757 { 6758 case XK_question: 6759 return(InfoCommand); 6760 case XK_p: 6761 case XK_Print: 6762 return(PrintCommand); 6763 case XK_space: 6764 return(NextCommand); 6765 case XK_q: 6766 case XK_Escape: 6767 return(QuitCommand); 6768 default: 6769 break; 6770 } 6771 return(NullCommand); 6772 } 6773 switch ((int) key_symbol) 6774 { 6775 case XK_o: 6776 { 6777 if ((state & ControlMask) == 0) 6778 break; 6779 return(OpenCommand); 6780 } 6781 case XK_space: 6782 return(NextCommand); 6783 case XK_BackSpace: 6784 return(FormerCommand); 6785 case XK_s: 6786 { 6787 if ((state & Mod1Mask) != 0) 6788 return(SwirlCommand); 6789 if ((state & ControlMask) == 0) 6790 return(ShearCommand); 6791 return(SaveCommand); 6792 } 6793 case XK_p: 6794 case XK_Print: 6795 { 6796 if ((state & Mod1Mask) != 0) 6797 return(OilPaintCommand); 6798 if ((state & Mod4Mask) != 0) 6799 return(ColorCommand); 6800 if ((state & ControlMask) == 0) 6801 return(NullCommand); 6802 return(PrintCommand); 6803 } 6804 case XK_d: 6805 { 6806 if ((state & Mod4Mask) != 0) 6807 return(DrawCommand); 6808 if ((state & ControlMask) == 0) 6809 return(NullCommand); 6810 return(DeleteCommand); 6811 } 6812 case XK_Select: 6813 { 6814 if ((state & ControlMask) == 0) 6815 return(NullCommand); 6816 return(SelectCommand); 6817 } 6818 case XK_n: 6819 { 6820 if ((state & ControlMask) == 0) 6821 return(NullCommand); 6822 return(NewCommand); 6823 } 6824 case XK_q: 6825 case XK_Escape: 6826 return(QuitCommand); 6827 case XK_z: 6828 case XK_Undo: 6829 { 6830 if ((state & ControlMask) == 0) 6831 return(NullCommand); 6832 return(UndoCommand); 6833 } 6834 case XK_r: 6835 case XK_Redo: 6836 { 6837 if ((state & ControlMask) == 0) 6838 return(RollCommand); 6839 return(RedoCommand); 6840 } 6841 case XK_x: 6842 { 6843 if ((state & ControlMask) == 0) 6844 return(NullCommand); 6845 return(CutCommand); 6846 } 6847 case XK_c: 6848 { 6849 if ((state & Mod1Mask) != 0) 6850 return(CharcoalDrawCommand); 6851 if ((state & ControlMask) == 0) 6852 return(CropCommand); 6853 return(CopyCommand); 6854 } 6855 case XK_v: 6856 case XK_Insert: 6857 { 6858 if ((state & Mod4Mask) != 0) 6859 return(CompositeCommand); 6860 if ((state & ControlMask) == 0) 6861 return(FlipCommand); 6862 return(PasteCommand); 6863 } 6864 case XK_less: 6865 return(HalfSizeCommand); 6866 case XK_minus: 6867 return(OriginalSizeCommand); 6868 case XK_greater: 6869 return(DoubleSizeCommand); 6870 case XK_percent: 6871 return(ResizeCommand); 6872 case XK_at: 6873 return(RefreshCommand); 6874 case XK_bracketleft: 6875 return(ChopCommand); 6876 case XK_h: 6877 return(FlopCommand); 6878 case XK_slash: 6879 return(RotateRightCommand); 6880 case XK_backslash: 6881 return(RotateLeftCommand); 6882 case XK_asterisk: 6883 return(RotateCommand); 6884 case XK_t: 6885 return(TrimCommand); 6886 case XK_H: 6887 return(HueCommand); 6888 case XK_S: 6889 return(SaturationCommand); 6890 case XK_L: 6891 return(BrightnessCommand); 6892 case XK_G: 6893 return(GammaCommand); 6894 case XK_C: 6895 return(SpiffCommand); 6896 case XK_Z: 6897 return(DullCommand); 6898 case XK_N: 6899 return(NormalizeCommand); 6900 case XK_equal: 6901 return(EqualizeCommand); 6902 case XK_asciitilde: 6903 return(NegateCommand); 6904 case XK_period: 6905 return(GrayscaleCommand); 6906 case XK_numbersign: 6907 return(QuantizeCommand); 6908 case XK_F2: 6909 return(DespeckleCommand); 6910 case XK_F3: 6911 return(EmbossCommand); 6912 case XK_F4: 6913 return(ReduceNoiseCommand); 6914 case XK_F5: 6915 return(AddNoiseCommand); 6916 case XK_F6: 6917 return(SharpenCommand); 6918 case XK_F7: 6919 return(BlurCommand); 6920 case XK_F8: 6921 return(ThresholdCommand); 6922 case XK_F9: 6923 return(EdgeDetectCommand); 6924 case XK_F10: 6925 return(SpreadCommand); 6926 case XK_F11: 6927 return(ShadeCommand); 6928 case XK_F12: 6929 return(RaiseCommand); 6930 case XK_F13: 6931 return(SegmentCommand); 6932 case XK_i: 6933 { 6934 if ((state & Mod1Mask) == 0) 6935 return(NullCommand); 6936 return(ImplodeCommand); 6937 } 6938 case XK_w: 6939 { 6940 if ((state & Mod1Mask) == 0) 6941 return(NullCommand); 6942 return(WaveCommand); 6943 } 6944 case XK_m: 6945 { 6946 if ((state & Mod4Mask) == 0) 6947 return(NullCommand); 6948 return(MatteCommand); 6949 } 6950 case XK_b: 6951 { 6952 if ((state & Mod4Mask) == 0) 6953 return(NullCommand); 6954 return(AddBorderCommand); 6955 } 6956 case XK_f: 6957 { 6958 if ((state & Mod4Mask) == 0) 6959 return(NullCommand); 6960 return(AddFrameCommand); 6961 } 6962 case XK_exclam: 6963 { 6964 if ((state & Mod4Mask) == 0) 6965 return(NullCommand); 6966 return(CommentCommand); 6967 } 6968 case XK_a: 6969 { 6970 if ((state & Mod1Mask) != 0) 6971 return(ApplyCommand); 6972 if ((state & Mod4Mask) != 0) 6973 return(AnnotateCommand); 6974 if ((state & ControlMask) == 0) 6975 return(NullCommand); 6976 return(RegionofInterestCommand); 6977 } 6978 case XK_question: 6979 return(InfoCommand); 6980 case XK_plus: 6981 return(ZoomCommand); 6982 case XK_P: 6983 { 6984 if ((state & ShiftMask) == 0) 6985 return(NullCommand); 6986 return(ShowPreviewCommand); 6987 } 6988 case XK_Execute: 6989 return(LaunchCommand); 6990 case XK_F1: 6991 return(HelpCommand); 6992 case XK_Find: 6993 return(BrowseDocumentationCommand); 6994 case XK_Menu: 6995 { 6996 (void) XMapRaised(display,windows->command.id); 6997 return(NullCommand); 6998 } 6999 case XK_Next: 7000 case XK_Prior: 7001 case XK_Home: 7002 case XK_KP_Home: 7003 { 7004 XTranslateImage(display,windows,*image,key_symbol); 7005 return(NullCommand); 7006 } 7007 case XK_Up: 7008 case XK_KP_Up: 7009 case XK_Down: 7010 case XK_KP_Down: 7011 case XK_Left: 7012 case XK_KP_Left: 7013 case XK_Right: 7014 case XK_KP_Right: 7015 { 7016 if ((state & Mod1Mask) != 0) 7017 { 7018 RectangleInfo 7019 crop_info; 7020 7021 /* 7022 Trim one pixel from edge of image. 7023 */ 7024 crop_info.x=0; 7025 crop_info.y=0; 7026 crop_info.width=(size_t) windows->image.ximage->width; 7027 crop_info.height=(size_t) windows->image.ximage->height; 7028 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up)) 7029 { 7030 if (resource_info->quantum >= (int) crop_info.height) 7031 resource_info->quantum=(int) crop_info.height-1; 7032 crop_info.height-=resource_info->quantum; 7033 } 7034 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down)) 7035 { 7036 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y)) 7037 resource_info->quantum=(int) (crop_info.height-crop_info.y-1); 7038 crop_info.y+=resource_info->quantum; 7039 crop_info.height-=resource_info->quantum; 7040 } 7041 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left)) 7042 { 7043 if (resource_info->quantum >= (int) crop_info.width) 7044 resource_info->quantum=(int) crop_info.width-1; 7045 crop_info.width-=resource_info->quantum; 7046 } 7047 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right)) 7048 { 7049 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x)) 7050 resource_info->quantum=(int) (crop_info.width-crop_info.x-1); 7051 crop_info.x+=resource_info->quantum; 7052 crop_info.width-=resource_info->quantum; 7053 } 7054 if ((int) (windows->image.x+windows->image.width) > 7055 (int) crop_info.width) 7056 windows->image.x=(int) (crop_info.width-windows->image.width); 7057 if ((int) (windows->image.y+windows->image.height) > 7058 (int) crop_info.height) 7059 windows->image.y=(int) (crop_info.height-windows->image.height); 7060 XSetCropGeometry(display,windows,&crop_info,*image); 7061 windows->image.window_changes.width=(int) crop_info.width; 7062 windows->image.window_changes.height=(int) crop_info.height; 7063 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None); 7064 (void) XConfigureImage(display,resource_info,windows,*image, 7065 exception); 7066 return(NullCommand); 7067 } 7068 XTranslateImage(display,windows,*image,key_symbol); 7069 return(NullCommand); 7070 } 7071 default: 7072 return(NullCommand); 7073 } 7074 return(NullCommand); 7075} 7076 7077/* 7078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7079% % 7080% % 7081% % 7082+ X M a g i c k C o m m a n d % 7083% % 7084% % 7085% % 7086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7087% 7088% XMagickCommand() makes a transform to the image or Image window as 7089% specified by a user menu button or keyboard command. 7090% 7091% The format of the XMagickCommand method is: 7092% 7093% Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7094% XWindows *windows,const CommandType command,Image **image, 7095% ExceptionInfo *exception) 7096% 7097% A description of each parameter follows: 7098% 7099% o display: Specifies a connection to an X server; returned from 7100% XOpenDisplay. 7101% 7102% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 7103% 7104% o windows: Specifies a pointer to a XWindows structure. 7105% 7106% o command: Specifies a command to perform. 7107% 7108% o image: the image; XMagickCommand may transform the image and return a 7109% new image pointer. 7110% 7111% o exception: return any errors or warnings in this structure. 7112% 7113*/ 7114static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7115 XWindows *windows,const CommandType command,Image **image, 7116 ExceptionInfo *exception) 7117{ 7118 char 7119 filename[MaxTextExtent], 7120 geometry[MaxTextExtent], 7121 modulate_factors[MaxTextExtent]; 7122 7123 GeometryInfo 7124 geometry_info; 7125 7126 Image 7127 *nexus; 7128 7129 ImageInfo 7130 *image_info; 7131 7132 int 7133 x, 7134 y; 7135 7136 MagickStatusType 7137 flags, 7138 status; 7139 7140 QuantizeInfo 7141 quantize_info; 7142 7143 RectangleInfo 7144 page_geometry; 7145 7146 register int 7147 i; 7148 7149 static char 7150 color[MaxTextExtent] = "gray"; 7151 7152 unsigned int 7153 height, 7154 width; 7155 7156 /* 7157 Process user command. 7158 */ 7159 XCheckRefreshWindows(display,windows); 7160 XImageCache(display,resource_info,windows,command,image,exception); 7161 nexus=NewImageList(); 7162 windows->image.window_changes.width=windows->image.ximage->width; 7163 windows->image.window_changes.height=windows->image.ximage->height; 7164 image_info=CloneImageInfo(resource_info->image_info); 7165 SetGeometryInfo(&geometry_info); 7166 GetQuantizeInfo(&quantize_info); 7167 switch (command) 7168 { 7169 case OpenCommand: 7170 { 7171 /* 7172 Load image. 7173 */ 7174 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 7175 break; 7176 } 7177 case NextCommand: 7178 { 7179 /* 7180 Display next image. 7181 */ 7182 for (i=0; i < resource_info->quantum; i++) 7183 XClientMessage(display,windows->image.id,windows->im_protocols, 7184 windows->im_next_image,CurrentTime); 7185 break; 7186 } 7187 case FormerCommand: 7188 { 7189 /* 7190 Display former image. 7191 */ 7192 for (i=0; i < resource_info->quantum; i++) 7193 XClientMessage(display,windows->image.id,windows->im_protocols, 7194 windows->im_former_image,CurrentTime); 7195 break; 7196 } 7197 case SelectCommand: 7198 { 7199 int 7200 status; 7201 7202 /* 7203 Select image. 7204 */ 7205 status=chdir(resource_info->home_directory); 7206 if (status == -1) 7207 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 7208 "UnableToOpenFile","%s",resource_info->home_directory); 7209 nexus=XOpenImage(display,resource_info,windows,MagickTrue); 7210 break; 7211 } 7212 case SaveCommand: 7213 { 7214 /* 7215 Save image. 7216 */ 7217 status=XSaveImage(display,resource_info,windows,*image,exception); 7218 if (status == MagickFalse) 7219 { 7220 char 7221 message[MaxTextExtent]; 7222 7223 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7224 exception->reason != (char *) NULL ? exception->reason : "", 7225 exception->description != (char *) NULL ? exception->description : 7226 ""); 7227 XNoticeWidget(display,windows,"Unable to save file:",message); 7228 break; 7229 } 7230 break; 7231 } 7232 case PrintCommand: 7233 { 7234 /* 7235 Print image. 7236 */ 7237 status=XPrintImage(display,resource_info,windows,*image,exception); 7238 if (status == MagickFalse) 7239 { 7240 char 7241 message[MaxTextExtent]; 7242 7243 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7244 exception->reason != (char *) NULL ? exception->reason : "", 7245 exception->description != (char *) NULL ? exception->description : 7246 ""); 7247 XNoticeWidget(display,windows,"Unable to print file:",message); 7248 break; 7249 } 7250 break; 7251 } 7252 case DeleteCommand: 7253 { 7254 static char 7255 filename[MaxTextExtent] = "\0"; 7256 7257 /* 7258 Delete image file. 7259 */ 7260 XFileBrowserWidget(display,windows,"Delete",filename); 7261 if (*filename == '\0') 7262 break; 7263 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse; 7264 if (status != MagickFalse) 7265 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7266 break; 7267 } 7268 case NewCommand: 7269 { 7270 int 7271 status; 7272 7273 static char 7274 color[MaxTextExtent] = "gray", 7275 geometry[MaxTextExtent] = "640x480"; 7276 7277 static const char 7278 *format = "gradient"; 7279 7280 /* 7281 Query user for canvas geometry. 7282 */ 7283 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7284 geometry); 7285 if (*geometry == '\0') 7286 break; 7287 if (status == 0) 7288 format="xc"; 7289 XColorBrowserWidget(display,windows,"Select",color); 7290 if (*color == '\0') 7291 break; 7292 /* 7293 Create canvas. 7294 */ 7295 (void) FormatLocaleString(image_info->filename,MaxTextExtent, 7296 "%s:%s",format,color); 7297 (void) CloneString(&image_info->size,geometry); 7298 nexus=ReadImage(image_info,exception); 7299 CatchException(exception); 7300 XClientMessage(display,windows->image.id,windows->im_protocols, 7301 windows->im_next_image,CurrentTime); 7302 break; 7303 } 7304 case VisualDirectoryCommand: 7305 { 7306 /* 7307 Visual Image directory. 7308 */ 7309 nexus=XVisualDirectoryImage(display,resource_info,windows,exception); 7310 break; 7311 } 7312 case QuitCommand: 7313 { 7314 /* 7315 exit program. 7316 */ 7317 if (resource_info->confirm_exit == MagickFalse) 7318 XClientMessage(display,windows->image.id,windows->im_protocols, 7319 windows->im_exit,CurrentTime); 7320 else 7321 { 7322 int 7323 status; 7324 7325 /* 7326 Confirm program exit. 7327 */ 7328 status=XConfirmWidget(display,windows,"Do you really want to exit", 7329 resource_info->client_name); 7330 if (status > 0) 7331 XClientMessage(display,windows->image.id,windows->im_protocols, 7332 windows->im_exit,CurrentTime); 7333 } 7334 break; 7335 } 7336 case CutCommand: 7337 { 7338 /* 7339 Cut image. 7340 */ 7341 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception); 7342 break; 7343 } 7344 case CopyCommand: 7345 { 7346 /* 7347 Copy image. 7348 */ 7349 (void) XCropImage(display,resource_info,windows,*image,CopyMode, 7350 exception); 7351 break; 7352 } 7353 case PasteCommand: 7354 { 7355 /* 7356 Paste image. 7357 */ 7358 status=XPasteImage(display,resource_info,windows,*image,exception); 7359 if (status == MagickFalse) 7360 { 7361 XNoticeWidget(display,windows,"Unable to paste X image", 7362 (*image)->filename); 7363 break; 7364 } 7365 break; 7366 } 7367 case HalfSizeCommand: 7368 { 7369 /* 7370 Half image size. 7371 */ 7372 windows->image.window_changes.width=windows->image.ximage->width/2; 7373 windows->image.window_changes.height=windows->image.ximage->height/2; 7374 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7375 break; 7376 } 7377 case OriginalSizeCommand: 7378 { 7379 /* 7380 Original image size. 7381 */ 7382 windows->image.window_changes.width=(int) (*image)->columns; 7383 windows->image.window_changes.height=(int) (*image)->rows; 7384 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7385 break; 7386 } 7387 case DoubleSizeCommand: 7388 { 7389 /* 7390 Double the image size. 7391 */ 7392 windows->image.window_changes.width=windows->image.ximage->width << 1; 7393 windows->image.window_changes.height=windows->image.ximage->height << 1; 7394 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7395 break; 7396 } 7397 case ResizeCommand: 7398 { 7399 int 7400 status; 7401 7402 size_t 7403 height, 7404 width; 7405 7406 ssize_t 7407 x, 7408 y; 7409 7410 /* 7411 Resize image. 7412 */ 7413 width=(size_t) windows->image.ximage->width; 7414 height=(size_t) windows->image.ximage->height; 7415 x=0; 7416 y=0; 7417 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0", 7418 (double) width,(double) height); 7419 status=XDialogWidget(display,windows,"Resize", 7420 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7421 if (*geometry == '\0') 7422 break; 7423 if (status == 0) 7424 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent); 7425 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7426 windows->image.window_changes.width=(int) width; 7427 windows->image.window_changes.height=(int) height; 7428 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7429 break; 7430 } 7431 case ApplyCommand: 7432 { 7433 char 7434 image_geometry[MaxTextExtent]; 7435 7436 if ((windows->image.crop_geometry == (char *) NULL) && 7437 ((int) (*image)->columns == windows->image.ximage->width) && 7438 ((int) (*image)->rows == windows->image.ximage->height)) 7439 break; 7440 /* 7441 Apply size transforms to image. 7442 */ 7443 XSetCursorState(display,windows,MagickTrue); 7444 XCheckRefreshWindows(display,windows); 7445 /* 7446 Crop and/or scale displayed image. 7447 */ 7448 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 7449 windows->image.ximage->width,windows->image.ximage->height); 7450 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 7451 exception); 7452 if (windows->image.crop_geometry != (char *) NULL) 7453 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 7454 windows->image.crop_geometry); 7455 windows->image.x=0; 7456 windows->image.y=0; 7457 XConfigureImageColormap(display,resource_info,windows,*image); 7458 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7459 break; 7460 } 7461 case RefreshCommand: 7462 { 7463 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7464 break; 7465 } 7466 case RestoreCommand: 7467 { 7468 /* 7469 Restore Image window to its original size. 7470 */ 7471 if ((windows->image.width == (unsigned int) (*image)->columns) && 7472 (windows->image.height == (unsigned int) (*image)->rows) && 7473 (windows->image.crop_geometry == (char *) NULL)) 7474 { 7475 (void) XBell(display,0); 7476 break; 7477 } 7478 windows->image.window_changes.width=(int) (*image)->columns; 7479 windows->image.window_changes.height=(int) (*image)->rows; 7480 if (windows->image.crop_geometry != (char *) NULL) 7481 { 7482 windows->image.crop_geometry=(char *) 7483 RelinquishMagickMemory(windows->image.crop_geometry); 7484 windows->image.crop_geometry=(char *) NULL; 7485 windows->image.x=0; 7486 windows->image.y=0; 7487 } 7488 XConfigureImageColormap(display,resource_info,windows,*image); 7489 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7490 break; 7491 } 7492 case CropCommand: 7493 { 7494 /* 7495 Crop image. 7496 */ 7497 (void) XCropImage(display,resource_info,windows,*image,CropMode, 7498 exception); 7499 break; 7500 } 7501 case ChopCommand: 7502 { 7503 /* 7504 Chop image. 7505 */ 7506 status=XChopImage(display,resource_info,windows,image,exception); 7507 if (status == MagickFalse) 7508 { 7509 XNoticeWidget(display,windows,"Unable to cut X image", 7510 (*image)->filename); 7511 break; 7512 } 7513 break; 7514 } 7515 case FlopCommand: 7516 { 7517 Image 7518 *flop_image; 7519 7520 /* 7521 Flop image scanlines. 7522 */ 7523 XSetCursorState(display,windows,MagickTrue); 7524 XCheckRefreshWindows(display,windows); 7525 flop_image=FlopImage(*image,exception); 7526 if (flop_image != (Image *) NULL) 7527 { 7528 *image=DestroyImage(*image); 7529 *image=flop_image; 7530 } 7531 CatchException(exception); 7532 XSetCursorState(display,windows,MagickFalse); 7533 if (windows->image.crop_geometry != (char *) NULL) 7534 { 7535 /* 7536 Flop crop geometry. 7537 */ 7538 width=(unsigned int) (*image)->columns; 7539 height=(unsigned int) (*image)->rows; 7540 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7541 &width,&height); 7542 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7543 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7544 } 7545 if (windows->image.orphan != MagickFalse) 7546 break; 7547 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7548 break; 7549 } 7550 case FlipCommand: 7551 { 7552 Image 7553 *flip_image; 7554 7555 /* 7556 Flip image scanlines. 7557 */ 7558 XSetCursorState(display,windows,MagickTrue); 7559 XCheckRefreshWindows(display,windows); 7560 flip_image=FlipImage(*image,exception); 7561 if (flip_image != (Image *) NULL) 7562 { 7563 *image=DestroyImage(*image); 7564 *image=flip_image; 7565 } 7566 CatchException(exception); 7567 XSetCursorState(display,windows,MagickFalse); 7568 if (windows->image.crop_geometry != (char *) NULL) 7569 { 7570 /* 7571 Flip crop geometry. 7572 */ 7573 width=(unsigned int) (*image)->columns; 7574 height=(unsigned int) (*image)->rows; 7575 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7576 &width,&height); 7577 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7578 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7579 } 7580 if (windows->image.orphan != MagickFalse) 7581 break; 7582 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7583 break; 7584 } 7585 case RotateRightCommand: 7586 { 7587 /* 7588 Rotate image 90 degrees clockwise. 7589 */ 7590 status=XRotateImage(display,resource_info,windows,90.0,image,exception); 7591 if (status == MagickFalse) 7592 { 7593 XNoticeWidget(display,windows,"Unable to rotate X image", 7594 (*image)->filename); 7595 break; 7596 } 7597 break; 7598 } 7599 case RotateLeftCommand: 7600 { 7601 /* 7602 Rotate image 90 degrees counter-clockwise. 7603 */ 7604 status=XRotateImage(display,resource_info,windows,-90.0,image,exception); 7605 if (status == MagickFalse) 7606 { 7607 XNoticeWidget(display,windows,"Unable to rotate X image", 7608 (*image)->filename); 7609 break; 7610 } 7611 break; 7612 } 7613 case RotateCommand: 7614 { 7615 /* 7616 Rotate image. 7617 */ 7618 status=XRotateImage(display,resource_info,windows,0.0,image,exception); 7619 if (status == MagickFalse) 7620 { 7621 XNoticeWidget(display,windows,"Unable to rotate X image", 7622 (*image)->filename); 7623 break; 7624 } 7625 break; 7626 } 7627 case ShearCommand: 7628 { 7629 Image 7630 *shear_image; 7631 7632 static char 7633 geometry[MaxTextExtent] = "45.0x45.0"; 7634 7635 /* 7636 Query user for shear color and geometry. 7637 */ 7638 XColorBrowserWidget(display,windows,"Select",color); 7639 if (*color == '\0') 7640 break; 7641 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7642 geometry); 7643 if (*geometry == '\0') 7644 break; 7645 /* 7646 Shear image. 7647 */ 7648 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7649 exception); 7650 XSetCursorState(display,windows,MagickTrue); 7651 XCheckRefreshWindows(display,windows); 7652 (void) QueryColorCompliance(color,AllCompliance, 7653 &(*image)->background_color,exception); 7654 flags=ParseGeometry(geometry,&geometry_info); 7655 if ((flags & SigmaValue) == 0) 7656 geometry_info.sigma=geometry_info.rho; 7657 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7658 exception); 7659 if (shear_image != (Image *) NULL) 7660 { 7661 *image=DestroyImage(*image); 7662 *image=shear_image; 7663 } 7664 CatchException(exception); 7665 XSetCursorState(display,windows,MagickFalse); 7666 if (windows->image.orphan != MagickFalse) 7667 break; 7668 windows->image.window_changes.width=(int) (*image)->columns; 7669 windows->image.window_changes.height=(int) (*image)->rows; 7670 XConfigureImageColormap(display,resource_info,windows,*image); 7671 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7672 break; 7673 } 7674 case RollCommand: 7675 { 7676 Image 7677 *roll_image; 7678 7679 static char 7680 geometry[MaxTextExtent] = "+2+2"; 7681 7682 /* 7683 Query user for the roll geometry. 7684 */ 7685 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7686 geometry); 7687 if (*geometry == '\0') 7688 break; 7689 /* 7690 Roll image. 7691 */ 7692 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7693 exception); 7694 XSetCursorState(display,windows,MagickTrue); 7695 XCheckRefreshWindows(display,windows); 7696 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7697 exception); 7698 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7699 exception); 7700 if (roll_image != (Image *) NULL) 7701 { 7702 *image=DestroyImage(*image); 7703 *image=roll_image; 7704 } 7705 CatchException(exception); 7706 XSetCursorState(display,windows,MagickFalse); 7707 if (windows->image.orphan != MagickFalse) 7708 break; 7709 windows->image.window_changes.width=(int) (*image)->columns; 7710 windows->image.window_changes.height=(int) (*image)->rows; 7711 XConfigureImageColormap(display,resource_info,windows,*image); 7712 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7713 break; 7714 } 7715 case TrimCommand: 7716 { 7717 static char 7718 fuzz[MaxTextExtent]; 7719 7720 /* 7721 Query user for the fuzz factor. 7722 */ 7723 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0* 7724 (*image)->fuzz/(QuantumRange+1.0)); 7725 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7726 if (*fuzz == '\0') 7727 break; 7728 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0); 7729 /* 7730 Trim image. 7731 */ 7732 status=XTrimImage(display,resource_info,windows,*image,exception); 7733 if (status == MagickFalse) 7734 { 7735 XNoticeWidget(display,windows,"Unable to trim X image", 7736 (*image)->filename); 7737 break; 7738 } 7739 break; 7740 } 7741 case HueCommand: 7742 { 7743 static char 7744 hue_percent[MaxTextExtent] = "110"; 7745 7746 /* 7747 Query user for percent hue change. 7748 */ 7749 (void) XDialogWidget(display,windows,"Apply", 7750 "Enter percent change in image hue (0-200):",hue_percent); 7751 if (*hue_percent == '\0') 7752 break; 7753 /* 7754 Vary the image hue. 7755 */ 7756 XSetCursorState(display,windows,MagickTrue); 7757 XCheckRefreshWindows(display,windows); 7758 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent); 7759 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7760 MaxTextExtent); 7761 (void) ModulateImage(*image,modulate_factors,exception); 7762 XSetCursorState(display,windows,MagickFalse); 7763 if (windows->image.orphan != MagickFalse) 7764 break; 7765 XConfigureImageColormap(display,resource_info,windows,*image); 7766 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7767 break; 7768 } 7769 case SaturationCommand: 7770 { 7771 static char 7772 saturation_percent[MaxTextExtent] = "110"; 7773 7774 /* 7775 Query user for percent saturation change. 7776 */ 7777 (void) XDialogWidget(display,windows,"Apply", 7778 "Enter percent change in color saturation (0-200):",saturation_percent); 7779 if (*saturation_percent == '\0') 7780 break; 7781 /* 7782 Vary color saturation. 7783 */ 7784 XSetCursorState(display,windows,MagickTrue); 7785 XCheckRefreshWindows(display,windows); 7786 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent); 7787 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7788 MaxTextExtent); 7789 (void) ModulateImage(*image,modulate_factors,exception); 7790 XSetCursorState(display,windows,MagickFalse); 7791 if (windows->image.orphan != MagickFalse) 7792 break; 7793 XConfigureImageColormap(display,resource_info,windows,*image); 7794 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7795 break; 7796 } 7797 case BrightnessCommand: 7798 { 7799 static char 7800 brightness_percent[MaxTextExtent] = "110"; 7801 7802 /* 7803 Query user for percent brightness change. 7804 */ 7805 (void) XDialogWidget(display,windows,"Apply", 7806 "Enter percent change in color brightness (0-200):",brightness_percent); 7807 if (*brightness_percent == '\0') 7808 break; 7809 /* 7810 Vary the color brightness. 7811 */ 7812 XSetCursorState(display,windows,MagickTrue); 7813 XCheckRefreshWindows(display,windows); 7814 (void) CopyMagickString(modulate_factors,brightness_percent, 7815 MaxTextExtent); 7816 (void) ModulateImage(*image,modulate_factors,exception); 7817 XSetCursorState(display,windows,MagickFalse); 7818 if (windows->image.orphan != MagickFalse) 7819 break; 7820 XConfigureImageColormap(display,resource_info,windows,*image); 7821 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7822 break; 7823 } 7824 case GammaCommand: 7825 { 7826 static char 7827 factor[MaxTextExtent] = "1.6"; 7828 7829 /* 7830 Query user for gamma value. 7831 */ 7832 (void) XDialogWidget(display,windows,"Gamma", 7833 "Enter gamma value (e.g. 1.2):",factor); 7834 if (*factor == '\0') 7835 break; 7836 /* 7837 Gamma correct image. 7838 */ 7839 XSetCursorState(display,windows,MagickTrue); 7840 XCheckRefreshWindows(display,windows); 7841 (void) GammaImage(*image,atof(factor),exception); 7842 XSetCursorState(display,windows,MagickFalse); 7843 if (windows->image.orphan != MagickFalse) 7844 break; 7845 XConfigureImageColormap(display,resource_info,windows,*image); 7846 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7847 break; 7848 } 7849 case SpiffCommand: 7850 { 7851 /* 7852 Sharpen the image contrast. 7853 */ 7854 XSetCursorState(display,windows,MagickTrue); 7855 XCheckRefreshWindows(display,windows); 7856 (void) ContrastImage(*image,MagickTrue,exception); 7857 XSetCursorState(display,windows,MagickFalse); 7858 if (windows->image.orphan != MagickFalse) 7859 break; 7860 XConfigureImageColormap(display,resource_info,windows,*image); 7861 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7862 break; 7863 } 7864 case DullCommand: 7865 { 7866 /* 7867 Dull the image contrast. 7868 */ 7869 XSetCursorState(display,windows,MagickTrue); 7870 XCheckRefreshWindows(display,windows); 7871 (void) ContrastImage(*image,MagickFalse,exception); 7872 XSetCursorState(display,windows,MagickFalse); 7873 if (windows->image.orphan != MagickFalse) 7874 break; 7875 XConfigureImageColormap(display,resource_info,windows,*image); 7876 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7877 break; 7878 } 7879 case ContrastStretchCommand: 7880 { 7881 double 7882 black_point, 7883 white_point; 7884 7885 static char 7886 levels[MaxTextExtent] = "1%"; 7887 7888 /* 7889 Query user for gamma value. 7890 */ 7891 (void) XDialogWidget(display,windows,"Contrast Stretch", 7892 "Enter black and white points:",levels); 7893 if (*levels == '\0') 7894 break; 7895 /* 7896 Contrast stretch image. 7897 */ 7898 XSetCursorState(display,windows,MagickTrue); 7899 XCheckRefreshWindows(display,windows); 7900 flags=ParseGeometry(levels,&geometry_info); 7901 black_point=geometry_info.rho; 7902 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7903 if ((flags & PercentValue) != 0) 7904 { 7905 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7906 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7907 } 7908 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point; 7909 (void) ContrastStretchImage(*image,black_point,white_point, 7910 exception); 7911 XSetCursorState(display,windows,MagickFalse); 7912 if (windows->image.orphan != MagickFalse) 7913 break; 7914 XConfigureImageColormap(display,resource_info,windows,*image); 7915 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7916 break; 7917 } 7918 case SigmoidalContrastCommand: 7919 { 7920 GeometryInfo 7921 geometry_info; 7922 7923 MagickStatusType 7924 flags; 7925 7926 static char 7927 levels[MaxTextExtent] = "3x50%"; 7928 7929 /* 7930 Query user for gamma value. 7931 */ 7932 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7933 "Enter contrast and midpoint:",levels); 7934 if (*levels == '\0') 7935 break; 7936 /* 7937 Contrast stretch image. 7938 */ 7939 XSetCursorState(display,windows,MagickTrue); 7940 XCheckRefreshWindows(display,windows); 7941 flags=ParseGeometry(levels,&geometry_info); 7942 if ((flags & SigmaValue) == 0) 7943 geometry_info.sigma=1.0*QuantumRange/2.0; 7944 if ((flags & PercentValue) != 0) 7945 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0; 7946 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho, 7947 geometry_info.sigma,exception); 7948 XSetCursorState(display,windows,MagickFalse); 7949 if (windows->image.orphan != MagickFalse) 7950 break; 7951 XConfigureImageColormap(display,resource_info,windows,*image); 7952 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7953 break; 7954 } 7955 case NormalizeCommand: 7956 { 7957 /* 7958 Perform histogram normalization on the image. 7959 */ 7960 XSetCursorState(display,windows,MagickTrue); 7961 XCheckRefreshWindows(display,windows); 7962 (void) NormalizeImage(*image,exception); 7963 XSetCursorState(display,windows,MagickFalse); 7964 if (windows->image.orphan != MagickFalse) 7965 break; 7966 XConfigureImageColormap(display,resource_info,windows,*image); 7967 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7968 break; 7969 } 7970 case EqualizeCommand: 7971 { 7972 /* 7973 Perform histogram equalization on the image. 7974 */ 7975 XSetCursorState(display,windows,MagickTrue); 7976 XCheckRefreshWindows(display,windows); 7977 (void) EqualizeImage(*image,exception); 7978 XSetCursorState(display,windows,MagickFalse); 7979 if (windows->image.orphan != MagickFalse) 7980 break; 7981 XConfigureImageColormap(display,resource_info,windows,*image); 7982 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7983 break; 7984 } 7985 case NegateCommand: 7986 { 7987 /* 7988 Negate colors in image. 7989 */ 7990 XSetCursorState(display,windows,MagickTrue); 7991 XCheckRefreshWindows(display,windows); 7992 (void) NegateImage(*image,MagickFalse,exception); 7993 XSetCursorState(display,windows,MagickFalse); 7994 if (windows->image.orphan != MagickFalse) 7995 break; 7996 XConfigureImageColormap(display,resource_info,windows,*image); 7997 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7998 break; 7999 } 8000 case GrayscaleCommand: 8001 { 8002 /* 8003 Convert image to grayscale. 8004 */ 8005 XSetCursorState(display,windows,MagickTrue); 8006 XCheckRefreshWindows(display,windows); 8007 (void) SetImageType(*image,(*image)->matte == MagickFalse ? 8008 GrayscaleType : GrayscaleMatteType,exception); 8009 XSetCursorState(display,windows,MagickFalse); 8010 if (windows->image.orphan != MagickFalse) 8011 break; 8012 XConfigureImageColormap(display,resource_info,windows,*image); 8013 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8014 break; 8015 } 8016 case MapCommand: 8017 { 8018 Image 8019 *affinity_image; 8020 8021 static char 8022 filename[MaxTextExtent] = "\0"; 8023 8024 /* 8025 Request image file name from user. 8026 */ 8027 XFileBrowserWidget(display,windows,"Map",filename); 8028 if (*filename == '\0') 8029 break; 8030 /* 8031 Map image. 8032 */ 8033 XSetCursorState(display,windows,MagickTrue); 8034 XCheckRefreshWindows(display,windows); 8035 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 8036 affinity_image=ReadImage(image_info,exception); 8037 if (affinity_image != (Image *) NULL) 8038 { 8039 (void) RemapImage(&quantize_info,*image,affinity_image,exception); 8040 affinity_image=DestroyImage(affinity_image); 8041 } 8042 CatchException(exception); 8043 XSetCursorState(display,windows,MagickFalse); 8044 if (windows->image.orphan != MagickFalse) 8045 break; 8046 XConfigureImageColormap(display,resource_info,windows,*image); 8047 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8048 break; 8049 } 8050 case QuantizeCommand: 8051 { 8052 int 8053 status; 8054 8055 static char 8056 colors[MaxTextExtent] = "256"; 8057 8058 /* 8059 Query user for maximum number of colors. 8060 */ 8061 status=XDialogWidget(display,windows,"Quantize", 8062 "Maximum number of colors:",colors); 8063 if (*colors == '\0') 8064 break; 8065 /* 8066 Color reduce the image. 8067 */ 8068 XSetCursorState(display,windows,MagickTrue); 8069 XCheckRefreshWindows(display,windows); 8070 quantize_info.number_colors=StringToUnsignedLong(colors); 8071 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse; 8072 (void) QuantizeImage(&quantize_info,*image,exception); 8073 XSetCursorState(display,windows,MagickFalse); 8074 if (windows->image.orphan != MagickFalse) 8075 break; 8076 XConfigureImageColormap(display,resource_info,windows,*image); 8077 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8078 break; 8079 } 8080 case DespeckleCommand: 8081 { 8082 Image 8083 *despeckle_image; 8084 8085 /* 8086 Despeckle image. 8087 */ 8088 XSetCursorState(display,windows,MagickTrue); 8089 XCheckRefreshWindows(display,windows); 8090 despeckle_image=DespeckleImage(*image,exception); 8091 if (despeckle_image != (Image *) NULL) 8092 { 8093 *image=DestroyImage(*image); 8094 *image=despeckle_image; 8095 } 8096 CatchException(exception); 8097 XSetCursorState(display,windows,MagickFalse); 8098 if (windows->image.orphan != MagickFalse) 8099 break; 8100 XConfigureImageColormap(display,resource_info,windows,*image); 8101 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8102 break; 8103 } 8104 case EmbossCommand: 8105 { 8106 Image 8107 *emboss_image; 8108 8109 static char 8110 radius[MaxTextExtent] = "0.0x1.0"; 8111 8112 /* 8113 Query user for emboss radius. 8114 */ 8115 (void) XDialogWidget(display,windows,"Emboss", 8116 "Enter the emboss radius and standard deviation:",radius); 8117 if (*radius == '\0') 8118 break; 8119 /* 8120 Reduce noise in the image. 8121 */ 8122 XSetCursorState(display,windows,MagickTrue); 8123 XCheckRefreshWindows(display,windows); 8124 flags=ParseGeometry(radius,&geometry_info); 8125 if ((flags & SigmaValue) == 0) 8126 geometry_info.sigma=1.0; 8127 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma, 8128 exception); 8129 if (emboss_image != (Image *) NULL) 8130 { 8131 *image=DestroyImage(*image); 8132 *image=emboss_image; 8133 } 8134 CatchException(exception); 8135 XSetCursorState(display,windows,MagickFalse); 8136 if (windows->image.orphan != MagickFalse) 8137 break; 8138 XConfigureImageColormap(display,resource_info,windows,*image); 8139 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8140 break; 8141 } 8142 case ReduceNoiseCommand: 8143 { 8144 Image 8145 *noise_image; 8146 8147 static char 8148 radius[MaxTextExtent] = "0"; 8149 8150 /* 8151 Query user for noise radius. 8152 */ 8153 (void) XDialogWidget(display,windows,"Reduce Noise", 8154 "Enter the noise radius:",radius); 8155 if (*radius == '\0') 8156 break; 8157 /* 8158 Reduce noise in the image. 8159 */ 8160 XSetCursorState(display,windows,MagickTrue); 8161 XCheckRefreshWindows(display,windows); 8162 flags=ParseGeometry(radius,&geometry_info); 8163 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t) 8164 geometry_info.rho,(size_t) geometry_info.rho,exception); 8165 if (noise_image != (Image *) NULL) 8166 { 8167 *image=DestroyImage(*image); 8168 *image=noise_image; 8169 } 8170 CatchException(exception); 8171 XSetCursorState(display,windows,MagickFalse); 8172 if (windows->image.orphan != MagickFalse) 8173 break; 8174 XConfigureImageColormap(display,resource_info,windows,*image); 8175 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8176 break; 8177 } 8178 case AddNoiseCommand: 8179 { 8180 char 8181 **noises; 8182 8183 Image 8184 *noise_image; 8185 8186 static char 8187 noise_type[MaxTextExtent] = "Gaussian"; 8188 8189 /* 8190 Add noise to the image. 8191 */ 8192 noises=GetCommandOptions(MagickNoiseOptions); 8193 if (noises == (char **) NULL) 8194 break; 8195 XListBrowserWidget(display,windows,&windows->widget, 8196 (const char **) noises,"Add Noise", 8197 "Select a type of noise to add to your image:",noise_type); 8198 noises=DestroyStringList(noises); 8199 if (*noise_type == '\0') 8200 break; 8201 XSetCursorState(display,windows,MagickTrue); 8202 XCheckRefreshWindows(display,windows); 8203 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption( 8204 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception); 8205 if (noise_image != (Image *) NULL) 8206 { 8207 *image=DestroyImage(*image); 8208 *image=noise_image; 8209 } 8210 CatchException(exception); 8211 XSetCursorState(display,windows,MagickFalse); 8212 if (windows->image.orphan != MagickFalse) 8213 break; 8214 XConfigureImageColormap(display,resource_info,windows,*image); 8215 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8216 break; 8217 } 8218 case SharpenCommand: 8219 { 8220 Image 8221 *sharp_image; 8222 8223 static char 8224 radius[MaxTextExtent] = "0.0x1.0"; 8225 8226 /* 8227 Query user for sharpen radius. 8228 */ 8229 (void) XDialogWidget(display,windows,"Sharpen", 8230 "Enter the sharpen radius and standard deviation:",radius); 8231 if (*radius == '\0') 8232 break; 8233 /* 8234 Sharpen image scanlines. 8235 */ 8236 XSetCursorState(display,windows,MagickTrue); 8237 XCheckRefreshWindows(display,windows); 8238 flags=ParseGeometry(radius,&geometry_info); 8239 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma, 8240 geometry_info.xi,exception); 8241 if (sharp_image != (Image *) NULL) 8242 { 8243 *image=DestroyImage(*image); 8244 *image=sharp_image; 8245 } 8246 CatchException(exception); 8247 XSetCursorState(display,windows,MagickFalse); 8248 if (windows->image.orphan != MagickFalse) 8249 break; 8250 XConfigureImageColormap(display,resource_info,windows,*image); 8251 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8252 break; 8253 } 8254 case BlurCommand: 8255 { 8256 Image 8257 *blur_image; 8258 8259 static char 8260 radius[MaxTextExtent] = "0.0x1.0"; 8261 8262 /* 8263 Query user for blur radius. 8264 */ 8265 (void) XDialogWidget(display,windows,"Blur", 8266 "Enter the blur radius and standard deviation:",radius); 8267 if (*radius == '\0') 8268 break; 8269 /* 8270 Blur an image. 8271 */ 8272 XSetCursorState(display,windows,MagickTrue); 8273 XCheckRefreshWindows(display,windows); 8274 flags=ParseGeometry(radius,&geometry_info); 8275 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma, 8276 geometry_info.xi,exception); 8277 if (blur_image != (Image *) NULL) 8278 { 8279 *image=DestroyImage(*image); 8280 *image=blur_image; 8281 } 8282 CatchException(exception); 8283 XSetCursorState(display,windows,MagickFalse); 8284 if (windows->image.orphan != MagickFalse) 8285 break; 8286 XConfigureImageColormap(display,resource_info,windows,*image); 8287 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8288 break; 8289 } 8290 case ThresholdCommand: 8291 { 8292 double 8293 threshold; 8294 8295 static char 8296 factor[MaxTextExtent] = "128"; 8297 8298 /* 8299 Query user for threshold value. 8300 */ 8301 (void) XDialogWidget(display,windows,"Threshold", 8302 "Enter threshold value:",factor); 8303 if (*factor == '\0') 8304 break; 8305 /* 8306 Gamma correct image. 8307 */ 8308 XSetCursorState(display,windows,MagickTrue); 8309 XCheckRefreshWindows(display,windows); 8310 threshold=SiPrefixToDouble(factor,QuantumRange); 8311 (void) BilevelImage(*image,threshold,exception); 8312 XSetCursorState(display,windows,MagickFalse); 8313 if (windows->image.orphan != MagickFalse) 8314 break; 8315 XConfigureImageColormap(display,resource_info,windows,*image); 8316 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8317 break; 8318 } 8319 case EdgeDetectCommand: 8320 { 8321 Image 8322 *edge_image; 8323 8324 static char 8325 radius[MaxTextExtent] = "0"; 8326 8327 /* 8328 Query user for edge factor. 8329 */ 8330 (void) XDialogWidget(display,windows,"Detect Edges", 8331 "Enter the edge detect radius:",radius); 8332 if (*radius == '\0') 8333 break; 8334 /* 8335 Detect edge in image. 8336 */ 8337 XSetCursorState(display,windows,MagickTrue); 8338 XCheckRefreshWindows(display,windows); 8339 flags=ParseGeometry(radius,&geometry_info); 8340 edge_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8341 exception); 8342 if (edge_image != (Image *) NULL) 8343 { 8344 *image=DestroyImage(*image); 8345 *image=edge_image; 8346 } 8347 CatchException(exception); 8348 XSetCursorState(display,windows,MagickFalse); 8349 if (windows->image.orphan != MagickFalse) 8350 break; 8351 XConfigureImageColormap(display,resource_info,windows,*image); 8352 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8353 break; 8354 } 8355 case SpreadCommand: 8356 { 8357 Image 8358 *spread_image; 8359 8360 static char 8361 amount[MaxTextExtent] = "2"; 8362 8363 /* 8364 Query user for spread amount. 8365 */ 8366 (void) XDialogWidget(display,windows,"Spread", 8367 "Enter the displacement amount:",amount); 8368 if (*amount == '\0') 8369 break; 8370 /* 8371 Displace image pixels by a random amount. 8372 */ 8373 XSetCursorState(display,windows,MagickTrue); 8374 XCheckRefreshWindows(display,windows); 8375 flags=ParseGeometry(amount,&geometry_info); 8376 spread_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8377 exception); 8378 if (spread_image != (Image *) NULL) 8379 { 8380 *image=DestroyImage(*image); 8381 *image=spread_image; 8382 } 8383 CatchException(exception); 8384 XSetCursorState(display,windows,MagickFalse); 8385 if (windows->image.orphan != MagickFalse) 8386 break; 8387 XConfigureImageColormap(display,resource_info,windows,*image); 8388 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8389 break; 8390 } 8391 case ShadeCommand: 8392 { 8393 Image 8394 *shade_image; 8395 8396 int 8397 status; 8398 8399 static char 8400 geometry[MaxTextExtent] = "30x30"; 8401 8402 /* 8403 Query user for the shade geometry. 8404 */ 8405 status=XDialogWidget(display,windows,"Shade", 8406 "Enter the azimuth and elevation of the light source:",geometry); 8407 if (*geometry == '\0') 8408 break; 8409 /* 8410 Shade image pixels. 8411 */ 8412 XSetCursorState(display,windows,MagickTrue); 8413 XCheckRefreshWindows(display,windows); 8414 flags=ParseGeometry(geometry,&geometry_info); 8415 if ((flags & SigmaValue) == 0) 8416 geometry_info.sigma=1.0; 8417 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue, 8418 geometry_info.rho,geometry_info.sigma,exception); 8419 if (shade_image != (Image *) NULL) 8420 { 8421 *image=DestroyImage(*image); 8422 *image=shade_image; 8423 } 8424 CatchException(exception); 8425 XSetCursorState(display,windows,MagickFalse); 8426 if (windows->image.orphan != MagickFalse) 8427 break; 8428 XConfigureImageColormap(display,resource_info,windows,*image); 8429 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8430 break; 8431 } 8432 case RaiseCommand: 8433 { 8434 static char 8435 bevel_width[MaxTextExtent] = "10"; 8436 8437 /* 8438 Query user for bevel width. 8439 */ 8440 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8441 if (*bevel_width == '\0') 8442 break; 8443 /* 8444 Raise an image. 8445 */ 8446 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8447 exception); 8448 XSetCursorState(display,windows,MagickTrue); 8449 XCheckRefreshWindows(display,windows); 8450 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8451 exception); 8452 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception); 8453 XSetCursorState(display,windows,MagickFalse); 8454 if (windows->image.orphan != MagickFalse) 8455 break; 8456 XConfigureImageColormap(display,resource_info,windows,*image); 8457 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8458 break; 8459 } 8460 case SegmentCommand: 8461 { 8462 static char 8463 threshold[MaxTextExtent] = "1.0x1.5"; 8464 8465 /* 8466 Query user for smoothing threshold. 8467 */ 8468 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8469 threshold); 8470 if (*threshold == '\0') 8471 break; 8472 /* 8473 Segment an image. 8474 */ 8475 XSetCursorState(display,windows,MagickTrue); 8476 XCheckRefreshWindows(display,windows); 8477 flags=ParseGeometry(threshold,&geometry_info); 8478 if ((flags & SigmaValue) == 0) 8479 geometry_info.sigma=1.0; 8480 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho, 8481 geometry_info.sigma,exception); 8482 XSetCursorState(display,windows,MagickFalse); 8483 if (windows->image.orphan != MagickFalse) 8484 break; 8485 XConfigureImageColormap(display,resource_info,windows,*image); 8486 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8487 break; 8488 } 8489 case SepiaToneCommand: 8490 { 8491 double 8492 threshold; 8493 8494 Image 8495 *sepia_image; 8496 8497 static char 8498 factor[MaxTextExtent] = "80%"; 8499 8500 /* 8501 Query user for sepia-tone factor. 8502 */ 8503 (void) XDialogWidget(display,windows,"Sepia Tone", 8504 "Enter the sepia tone factor (0 - 99.9%):",factor); 8505 if (*factor == '\0') 8506 break; 8507 /* 8508 Sepia tone image pixels. 8509 */ 8510 XSetCursorState(display,windows,MagickTrue); 8511 XCheckRefreshWindows(display,windows); 8512 threshold=SiPrefixToDouble(factor,QuantumRange); 8513 sepia_image=SepiaToneImage(*image,threshold,exception); 8514 if (sepia_image != (Image *) NULL) 8515 { 8516 *image=DestroyImage(*image); 8517 *image=sepia_image; 8518 } 8519 CatchException(exception); 8520 XSetCursorState(display,windows,MagickFalse); 8521 if (windows->image.orphan != MagickFalse) 8522 break; 8523 XConfigureImageColormap(display,resource_info,windows,*image); 8524 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8525 break; 8526 } 8527 case SolarizeCommand: 8528 { 8529 double 8530 threshold; 8531 8532 static char 8533 factor[MaxTextExtent] = "60%"; 8534 8535 /* 8536 Query user for solarize factor. 8537 */ 8538 (void) XDialogWidget(display,windows,"Solarize", 8539 "Enter the solarize factor (0 - 99.9%):",factor); 8540 if (*factor == '\0') 8541 break; 8542 /* 8543 Solarize image pixels. 8544 */ 8545 XSetCursorState(display,windows,MagickTrue); 8546 XCheckRefreshWindows(display,windows); 8547 threshold=SiPrefixToDouble(factor,QuantumRange); 8548 (void) SolarizeImage(*image,threshold,exception); 8549 XSetCursorState(display,windows,MagickFalse); 8550 if (windows->image.orphan != MagickFalse) 8551 break; 8552 XConfigureImageColormap(display,resource_info,windows,*image); 8553 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8554 break; 8555 } 8556 case SwirlCommand: 8557 { 8558 Image 8559 *swirl_image; 8560 8561 static char 8562 degrees[MaxTextExtent] = "60"; 8563 8564 /* 8565 Query user for swirl angle. 8566 */ 8567 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8568 degrees); 8569 if (*degrees == '\0') 8570 break; 8571 /* 8572 Swirl image pixels about the center. 8573 */ 8574 XSetCursorState(display,windows,MagickTrue); 8575 XCheckRefreshWindows(display,windows); 8576 flags=ParseGeometry(degrees,&geometry_info); 8577 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate, 8578 exception); 8579 if (swirl_image != (Image *) NULL) 8580 { 8581 *image=DestroyImage(*image); 8582 *image=swirl_image; 8583 } 8584 CatchException(exception); 8585 XSetCursorState(display,windows,MagickFalse); 8586 if (windows->image.orphan != MagickFalse) 8587 break; 8588 XConfigureImageColormap(display,resource_info,windows,*image); 8589 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8590 break; 8591 } 8592 case ImplodeCommand: 8593 { 8594 Image 8595 *implode_image; 8596 8597 static char 8598 factor[MaxTextExtent] = "0.3"; 8599 8600 /* 8601 Query user for implode factor. 8602 */ 8603 (void) XDialogWidget(display,windows,"Implode", 8604 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8605 if (*factor == '\0') 8606 break; 8607 /* 8608 Implode image pixels about the center. 8609 */ 8610 XSetCursorState(display,windows,MagickTrue); 8611 XCheckRefreshWindows(display,windows); 8612 flags=ParseGeometry(factor,&geometry_info); 8613 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate, 8614 exception); 8615 if (implode_image != (Image *) NULL) 8616 { 8617 *image=DestroyImage(*image); 8618 *image=implode_image; 8619 } 8620 CatchException(exception); 8621 XSetCursorState(display,windows,MagickFalse); 8622 if (windows->image.orphan != MagickFalse) 8623 break; 8624 XConfigureImageColormap(display,resource_info,windows,*image); 8625 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8626 break; 8627 } 8628 case VignetteCommand: 8629 { 8630 Image 8631 *vignette_image; 8632 8633 static char 8634 geometry[MaxTextExtent] = "0x20"; 8635 8636 /* 8637 Query user for the vignette geometry. 8638 */ 8639 (void) XDialogWidget(display,windows,"Vignette", 8640 "Enter the radius, sigma, and x and y offsets:",geometry); 8641 if (*geometry == '\0') 8642 break; 8643 /* 8644 Soften the edges of the image in vignette style 8645 */ 8646 XSetCursorState(display,windows,MagickTrue); 8647 XCheckRefreshWindows(display,windows); 8648 flags=ParseGeometry(geometry,&geometry_info); 8649 if ((flags & SigmaValue) == 0) 8650 geometry_info.sigma=1.0; 8651 if ((flags & XiValue) == 0) 8652 geometry_info.xi=0.1*(*image)->columns; 8653 if ((flags & PsiValue) == 0) 8654 geometry_info.psi=0.1*(*image)->rows; 8655 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma, 8656 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi- 8657 0.5),exception); 8658 if (vignette_image != (Image *) NULL) 8659 { 8660 *image=DestroyImage(*image); 8661 *image=vignette_image; 8662 } 8663 CatchException(exception); 8664 XSetCursorState(display,windows,MagickFalse); 8665 if (windows->image.orphan != MagickFalse) 8666 break; 8667 XConfigureImageColormap(display,resource_info,windows,*image); 8668 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8669 break; 8670 } 8671 case WaveCommand: 8672 { 8673 Image 8674 *wave_image; 8675 8676 static char 8677 geometry[MaxTextExtent] = "25x150"; 8678 8679 /* 8680 Query user for the wave geometry. 8681 */ 8682 (void) XDialogWidget(display,windows,"Wave", 8683 "Enter the amplitude and length of the wave:",geometry); 8684 if (*geometry == '\0') 8685 break; 8686 /* 8687 Alter an image along a sine wave. 8688 */ 8689 XSetCursorState(display,windows,MagickTrue); 8690 XCheckRefreshWindows(display,windows); 8691 flags=ParseGeometry(geometry,&geometry_info); 8692 if ((flags & SigmaValue) == 0) 8693 geometry_info.sigma=1.0; 8694 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8695 (*image)->interpolate,exception); 8696 if (wave_image != (Image *) NULL) 8697 { 8698 *image=DestroyImage(*image); 8699 *image=wave_image; 8700 } 8701 CatchException(exception); 8702 XSetCursorState(display,windows,MagickFalse); 8703 if (windows->image.orphan != MagickFalse) 8704 break; 8705 XConfigureImageColormap(display,resource_info,windows,*image); 8706 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8707 break; 8708 } 8709 case OilPaintCommand: 8710 { 8711 Image 8712 *paint_image; 8713 8714 static char 8715 radius[MaxTextExtent] = "0"; 8716 8717 /* 8718 Query user for circular neighborhood radius. 8719 */ 8720 (void) XDialogWidget(display,windows,"Oil Paint", 8721 "Enter the mask radius:",radius); 8722 if (*radius == '\0') 8723 break; 8724 /* 8725 OilPaint image scanlines. 8726 */ 8727 XSetCursorState(display,windows,MagickTrue); 8728 XCheckRefreshWindows(display,windows); 8729 flags=ParseGeometry(radius,&geometry_info); 8730 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma, 8731 exception); 8732 if (paint_image != (Image *) NULL) 8733 { 8734 *image=DestroyImage(*image); 8735 *image=paint_image; 8736 } 8737 CatchException(exception); 8738 XSetCursorState(display,windows,MagickFalse); 8739 if (windows->image.orphan != MagickFalse) 8740 break; 8741 XConfigureImageColormap(display,resource_info,windows,*image); 8742 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8743 break; 8744 } 8745 case CharcoalDrawCommand: 8746 { 8747 Image 8748 *charcoal_image; 8749 8750 static char 8751 radius[MaxTextExtent] = "0x1"; 8752 8753 /* 8754 Query user for charcoal radius. 8755 */ 8756 (void) XDialogWidget(display,windows,"Charcoal Draw", 8757 "Enter the charcoal radius and sigma:",radius); 8758 if (*radius == '\0') 8759 break; 8760 /* 8761 Charcoal the image. 8762 */ 8763 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8764 exception); 8765 XSetCursorState(display,windows,MagickTrue); 8766 XCheckRefreshWindows(display,windows); 8767 flags=ParseGeometry(radius,&geometry_info); 8768 if ((flags & SigmaValue) == 0) 8769 geometry_info.sigma=geometry_info.rho; 8770 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8771 geometry_info.xi,exception); 8772 if (charcoal_image != (Image *) NULL) 8773 { 8774 *image=DestroyImage(*image); 8775 *image=charcoal_image; 8776 } 8777 CatchException(exception); 8778 XSetCursorState(display,windows,MagickFalse); 8779 if (windows->image.orphan != MagickFalse) 8780 break; 8781 XConfigureImageColormap(display,resource_info,windows,*image); 8782 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8783 break; 8784 } 8785 case AnnotateCommand: 8786 { 8787 /* 8788 Annotate the image with text. 8789 */ 8790 status=XAnnotateEditImage(display,resource_info,windows,*image,exception); 8791 if (status == MagickFalse) 8792 { 8793 XNoticeWidget(display,windows,"Unable to annotate X image", 8794 (*image)->filename); 8795 break; 8796 } 8797 break; 8798 } 8799 case DrawCommand: 8800 { 8801 /* 8802 Draw image. 8803 */ 8804 status=XDrawEditImage(display,resource_info,windows,image,exception); 8805 if (status == MagickFalse) 8806 { 8807 XNoticeWidget(display,windows,"Unable to draw on the X image", 8808 (*image)->filename); 8809 break; 8810 } 8811 break; 8812 } 8813 case ColorCommand: 8814 { 8815 /* 8816 Color edit. 8817 */ 8818 status=XColorEditImage(display,resource_info,windows,image,exception); 8819 if (status == MagickFalse) 8820 { 8821 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8822 (*image)->filename); 8823 break; 8824 } 8825 break; 8826 } 8827 case MatteCommand: 8828 { 8829 /* 8830 Matte edit. 8831 */ 8832 status=XMatteEditImage(display,resource_info,windows,image,exception); 8833 if (status == MagickFalse) 8834 { 8835 XNoticeWidget(display,windows,"Unable to matte edit X image", 8836 (*image)->filename); 8837 break; 8838 } 8839 break; 8840 } 8841 case CompositeCommand: 8842 { 8843 /* 8844 Composite image. 8845 */ 8846 status=XCompositeImage(display,resource_info,windows,*image, 8847 exception); 8848 if (status == MagickFalse) 8849 { 8850 XNoticeWidget(display,windows,"Unable to composite X image", 8851 (*image)->filename); 8852 break; 8853 } 8854 break; 8855 } 8856 case AddBorderCommand: 8857 { 8858 Image 8859 *border_image; 8860 8861 static char 8862 geometry[MaxTextExtent] = "6x6"; 8863 8864 /* 8865 Query user for border color and geometry. 8866 */ 8867 XColorBrowserWidget(display,windows,"Select",color); 8868 if (*color == '\0') 8869 break; 8870 (void) XDialogWidget(display,windows,"Add Border", 8871 "Enter border geometry:",geometry); 8872 if (*geometry == '\0') 8873 break; 8874 /* 8875 Add a border to the image. 8876 */ 8877 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8878 exception); 8879 XSetCursorState(display,windows,MagickTrue); 8880 XCheckRefreshWindows(display,windows); 8881 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color, 8882 exception); 8883 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8884 exception); 8885 border_image=BorderImage(*image,&page_geometry,(*image)->compose, 8886 exception); 8887 if (border_image != (Image *) NULL) 8888 { 8889 *image=DestroyImage(*image); 8890 *image=border_image; 8891 } 8892 CatchException(exception); 8893 XSetCursorState(display,windows,MagickFalse); 8894 if (windows->image.orphan != MagickFalse) 8895 break; 8896 windows->image.window_changes.width=(int) (*image)->columns; 8897 windows->image.window_changes.height=(int) (*image)->rows; 8898 XConfigureImageColormap(display,resource_info,windows,*image); 8899 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8900 break; 8901 } 8902 case AddFrameCommand: 8903 { 8904 FrameInfo 8905 frame_info; 8906 8907 Image 8908 *frame_image; 8909 8910 static char 8911 geometry[MaxTextExtent] = "6x6"; 8912 8913 /* 8914 Query user for frame color and geometry. 8915 */ 8916 XColorBrowserWidget(display,windows,"Select",color); 8917 if (*color == '\0') 8918 break; 8919 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8920 geometry); 8921 if (*geometry == '\0') 8922 break; 8923 /* 8924 Surround image with an ornamental border. 8925 */ 8926 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8927 exception); 8928 XSetCursorState(display,windows,MagickTrue); 8929 XCheckRefreshWindows(display,windows); 8930 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color, 8931 exception); 8932 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8933 exception); 8934 frame_info.width=page_geometry.width; 8935 frame_info.height=page_geometry.height; 8936 frame_info.outer_bevel=page_geometry.x; 8937 frame_info.inner_bevel=page_geometry.y; 8938 frame_info.x=(ssize_t) frame_info.width; 8939 frame_info.y=(ssize_t) frame_info.height; 8940 frame_info.width=(*image)->columns+2*frame_info.width; 8941 frame_info.height=(*image)->rows+2*frame_info.height; 8942 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception); 8943 if (frame_image != (Image *) NULL) 8944 { 8945 *image=DestroyImage(*image); 8946 *image=frame_image; 8947 } 8948 CatchException(exception); 8949 XSetCursorState(display,windows,MagickFalse); 8950 if (windows->image.orphan != MagickFalse) 8951 break; 8952 windows->image.window_changes.width=(int) (*image)->columns; 8953 windows->image.window_changes.height=(int) (*image)->rows; 8954 XConfigureImageColormap(display,resource_info,windows,*image); 8955 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8956 break; 8957 } 8958 case CommentCommand: 8959 { 8960 const char 8961 *value; 8962 8963 FILE 8964 *file; 8965 8966 int 8967 unique_file; 8968 8969 /* 8970 Edit image comment. 8971 */ 8972 unique_file=AcquireUniqueFileResource(image_info->filename); 8973 if (unique_file == -1) 8974 XNoticeWidget(display,windows,"Unable to edit image comment", 8975 image_info->filename); 8976 value=GetImageProperty(*image,"comment",exception); 8977 if (value == (char *) NULL) 8978 unique_file=close(unique_file)-1; 8979 else 8980 { 8981 register const char 8982 *p; 8983 8984 file=fdopen(unique_file,"w"); 8985 if (file == (FILE *) NULL) 8986 { 8987 XNoticeWidget(display,windows,"Unable to edit image comment", 8988 image_info->filename); 8989 break; 8990 } 8991 for (p=value; *p != '\0'; p++) 8992 (void) fputc((int) *p,file); 8993 (void) fputc('\n',file); 8994 (void) fclose(file); 8995 } 8996 XSetCursorState(display,windows,MagickTrue); 8997 XCheckRefreshWindows(display,windows); 8998 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 8999 exception); 9000 if (status == MagickFalse) 9001 XNoticeWidget(display,windows,"Unable to edit image comment", 9002 (char *) NULL); 9003 else 9004 { 9005 char 9006 *comment; 9007 9008 comment=FileToString(image_info->filename,~0UL,exception); 9009 if (comment != (char *) NULL) 9010 { 9011 (void) SetImageProperty(*image,"comment",comment,exception); 9012 (*image)->taint=MagickTrue; 9013 } 9014 } 9015 (void) RelinquishUniqueFileResource(image_info->filename); 9016 XSetCursorState(display,windows,MagickFalse); 9017 break; 9018 } 9019 case LaunchCommand: 9020 { 9021 /* 9022 Launch program. 9023 */ 9024 XSetCursorState(display,windows,MagickTrue); 9025 XCheckRefreshWindows(display,windows); 9026 (void) AcquireUniqueFilename(filename); 9027 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s", 9028 filename); 9029 status=WriteImage(image_info,*image,exception); 9030 if (status == MagickFalse) 9031 XNoticeWidget(display,windows,"Unable to launch image editor", 9032 (char *) NULL); 9033 else 9034 { 9035 nexus=ReadImage(resource_info->image_info,exception); 9036 CatchException(exception); 9037 XClientMessage(display,windows->image.id,windows->im_protocols, 9038 windows->im_next_image,CurrentTime); 9039 } 9040 (void) RelinquishUniqueFileResource(filename); 9041 XSetCursorState(display,windows,MagickFalse); 9042 break; 9043 } 9044 case RegionofInterestCommand: 9045 { 9046 /* 9047 Apply an image processing technique to a region of interest. 9048 */ 9049 (void) XROIImage(display,resource_info,windows,image,exception); 9050 break; 9051 } 9052 case InfoCommand: 9053 break; 9054 case ZoomCommand: 9055 { 9056 /* 9057 Zoom image. 9058 */ 9059 if (windows->magnify.mapped != MagickFalse) 9060 (void) XRaiseWindow(display,windows->magnify.id); 9061 else 9062 { 9063 /* 9064 Make magnify image. 9065 */ 9066 XSetCursorState(display,windows,MagickTrue); 9067 (void) XMapRaised(display,windows->magnify.id); 9068 XSetCursorState(display,windows,MagickFalse); 9069 } 9070 break; 9071 } 9072 case ShowPreviewCommand: 9073 { 9074 char 9075 **previews; 9076 9077 Image 9078 *preview_image; 9079 9080 static char 9081 preview_type[MaxTextExtent] = "Gamma"; 9082 9083 /* 9084 Select preview type from menu. 9085 */ 9086 previews=GetCommandOptions(MagickPreviewOptions); 9087 if (previews == (char **) NULL) 9088 break; 9089 XListBrowserWidget(display,windows,&windows->widget, 9090 (const char **) previews,"Preview", 9091 "Select an enhancement, effect, or F/X:",preview_type); 9092 previews=DestroyStringList(previews); 9093 if (*preview_type == '\0') 9094 break; 9095 /* 9096 Show image preview. 9097 */ 9098 XSetCursorState(display,windows,MagickTrue); 9099 XCheckRefreshWindows(display,windows); 9100 image_info->preview_type=(PreviewType) 9101 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type); 9102 image_info->group=(ssize_t) windows->image.id; 9103 (void) DeleteImageProperty(*image,"label"); 9104 (void) SetImageProperty(*image,"label","Preview",exception); 9105 (void) AcquireUniqueFilename(filename); 9106 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s", 9107 filename); 9108 status=WriteImage(image_info,*image,exception); 9109 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9110 preview_image=ReadImage(image_info,exception); 9111 (void) RelinquishUniqueFileResource(filename); 9112 if (preview_image == (Image *) NULL) 9113 break; 9114 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s", 9115 filename); 9116 status=WriteImage(image_info,preview_image,exception); 9117 preview_image=DestroyImage(preview_image); 9118 if (status == MagickFalse) 9119 XNoticeWidget(display,windows,"Unable to show image preview", 9120 (*image)->filename); 9121 XDelay(display,1500); 9122 XSetCursorState(display,windows,MagickFalse); 9123 break; 9124 } 9125 case ShowHistogramCommand: 9126 { 9127 Image 9128 *histogram_image; 9129 9130 /* 9131 Show image histogram. 9132 */ 9133 XSetCursorState(display,windows,MagickTrue); 9134 XCheckRefreshWindows(display,windows); 9135 image_info->group=(ssize_t) windows->image.id; 9136 (void) DeleteImageProperty(*image,"label"); 9137 (void) SetImageProperty(*image,"label","Histogram",exception); 9138 (void) AcquireUniqueFilename(filename); 9139 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s", 9140 filename); 9141 status=WriteImage(image_info,*image,exception); 9142 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9143 histogram_image=ReadImage(image_info,exception); 9144 (void) RelinquishUniqueFileResource(filename); 9145 if (histogram_image == (Image *) NULL) 9146 break; 9147 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent, 9148 "show:%s",filename); 9149 status=WriteImage(image_info,histogram_image,exception); 9150 histogram_image=DestroyImage(histogram_image); 9151 if (status == MagickFalse) 9152 XNoticeWidget(display,windows,"Unable to show histogram", 9153 (*image)->filename); 9154 XDelay(display,1500); 9155 XSetCursorState(display,windows,MagickFalse); 9156 break; 9157 } 9158 case ShowMatteCommand: 9159 { 9160 Image 9161 *matte_image; 9162 9163 if ((*image)->matte == MagickFalse) 9164 { 9165 XNoticeWidget(display,windows, 9166 "Image does not have any matte information",(*image)->filename); 9167 break; 9168 } 9169 /* 9170 Show image matte. 9171 */ 9172 XSetCursorState(display,windows,MagickTrue); 9173 XCheckRefreshWindows(display,windows); 9174 image_info->group=(ssize_t) windows->image.id; 9175 (void) DeleteImageProperty(*image,"label"); 9176 (void) SetImageProperty(*image,"label","Matte",exception); 9177 (void) AcquireUniqueFilename(filename); 9178 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s", 9179 filename); 9180 status=WriteImage(image_info,*image,exception); 9181 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9182 matte_image=ReadImage(image_info,exception); 9183 (void) RelinquishUniqueFileResource(filename); 9184 if (matte_image == (Image *) NULL) 9185 break; 9186 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s", 9187 filename); 9188 status=WriteImage(image_info,matte_image,exception); 9189 matte_image=DestroyImage(matte_image); 9190 if (status == MagickFalse) 9191 XNoticeWidget(display,windows,"Unable to show matte", 9192 (*image)->filename); 9193 XDelay(display,1500); 9194 XSetCursorState(display,windows,MagickFalse); 9195 break; 9196 } 9197 case BackgroundCommand: 9198 { 9199 /* 9200 Background image. 9201 */ 9202 status=XBackgroundImage(display,resource_info,windows,image,exception); 9203 if (status == MagickFalse) 9204 break; 9205 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9206 if (nexus != (Image *) NULL) 9207 XClientMessage(display,windows->image.id,windows->im_protocols, 9208 windows->im_next_image,CurrentTime); 9209 break; 9210 } 9211 case SlideShowCommand: 9212 { 9213 static char 9214 delay[MaxTextExtent] = "5"; 9215 9216 /* 9217 Display next image after pausing. 9218 */ 9219 (void) XDialogWidget(display,windows,"Slide Show", 9220 "Pause how many 1/100ths of a second between images:",delay); 9221 if (*delay == '\0') 9222 break; 9223 resource_info->delay=StringToUnsignedLong(delay); 9224 XClientMessage(display,windows->image.id,windows->im_protocols, 9225 windows->im_next_image,CurrentTime); 9226 break; 9227 } 9228 case PreferencesCommand: 9229 { 9230 /* 9231 Set user preferences. 9232 */ 9233 status=XPreferencesWidget(display,resource_info,windows); 9234 if (status == MagickFalse) 9235 break; 9236 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9237 if (nexus != (Image *) NULL) 9238 XClientMessage(display,windows->image.id,windows->im_protocols, 9239 windows->im_next_image,CurrentTime); 9240 break; 9241 } 9242 case HelpCommand: 9243 { 9244 /* 9245 User requested help. 9246 */ 9247 XTextViewWidget(display,resource_info,windows,MagickFalse, 9248 "Help Viewer - Display",DisplayHelp); 9249 break; 9250 } 9251 case BrowseDocumentationCommand: 9252 { 9253 Atom 9254 mozilla_atom; 9255 9256 Window 9257 mozilla_window, 9258 root_window; 9259 9260 /* 9261 Browse the ImageMagick documentation. 9262 */ 9263 root_window=XRootWindow(display,XDefaultScreen(display)); 9264 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); 9265 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); 9266 if (mozilla_window != (Window) NULL) 9267 { 9268 char 9269 command[MaxTextExtent], 9270 *url; 9271 9272 /* 9273 Display documentation using Netscape remote control. 9274 */ 9275 url=GetMagickHomeURL(); 9276 (void) FormatLocaleString(command,MaxTextExtent, 9277 "openurl(%s,new-tab)",url); 9278 url=DestroyString(url); 9279 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); 9280 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING, 9281 8,PropModeReplace,(unsigned char *) command,(int) strlen(command)); 9282 XSetCursorState(display,windows,MagickFalse); 9283 break; 9284 } 9285 XSetCursorState(display,windows,MagickTrue); 9286 XCheckRefreshWindows(display,windows); 9287 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL, 9288 exception); 9289 if (status == MagickFalse) 9290 XNoticeWidget(display,windows,"Unable to browse documentation", 9291 (char *) NULL); 9292 XDelay(display,1500); 9293 XSetCursorState(display,windows,MagickFalse); 9294 break; 9295 } 9296 case VersionCommand: 9297 { 9298 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), 9299 GetMagickCopyright()); 9300 break; 9301 } 9302 case SaveToUndoBufferCommand: 9303 break; 9304 default: 9305 { 9306 (void) XBell(display,0); 9307 break; 9308 } 9309 } 9310 image_info=DestroyImageInfo(image_info); 9311 return(nexus); 9312} 9313 9314/* 9315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9316% % 9317% % 9318% % 9319+ X M a g n i f y I m a g e % 9320% % 9321% % 9322% % 9323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9324% 9325% XMagnifyImage() magnifies portions of the image as indicated by the pointer. 9326% The magnified portion is displayed in a separate window. 9327% 9328% The format of the XMagnifyImage method is: 9329% 9330% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event) 9331% 9332% A description of each parameter follows: 9333% 9334% o display: Specifies a connection to an X server; returned from 9335% XOpenDisplay. 9336% 9337% o windows: Specifies a pointer to a XWindows structure. 9338% 9339% o event: Specifies a pointer to a XEvent structure. If it is NULL, 9340% the entire image is refreshed. 9341% 9342*/ 9343static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event) 9344{ 9345 char 9346 text[MaxTextExtent]; 9347 9348 register int 9349 x, 9350 y; 9351 9352 size_t 9353 state; 9354 9355 /* 9356 Update magnified image until the mouse button is released. 9357 */ 9358 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor); 9359 state=DefaultState; 9360 x=event->xbutton.x; 9361 y=event->xbutton.y; 9362 windows->magnify.x=(int) windows->image.x+x; 9363 windows->magnify.y=(int) windows->image.y+y; 9364 do 9365 { 9366 /* 9367 Map and unmap Info widget as text cursor crosses its boundaries. 9368 */ 9369 if (windows->info.mapped != MagickFalse) 9370 { 9371 if ((x < (int) (windows->info.x+windows->info.width)) && 9372 (y < (int) (windows->info.y+windows->info.height))) 9373 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 9374 } 9375 else 9376 if ((x > (int) (windows->info.x+windows->info.width)) || 9377 (y > (int) (windows->info.y+windows->info.height))) 9378 (void) XMapWindow(display,windows->info.id); 9379 if (windows->info.mapped != MagickFalse) 9380 { 9381 /* 9382 Display pointer position. 9383 */ 9384 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9385 windows->magnify.x,windows->magnify.y); 9386 XInfoWidget(display,windows,text); 9387 } 9388 /* 9389 Wait for next event. 9390 */ 9391 XScreenEvent(display,windows,event); 9392 switch (event->type) 9393 { 9394 case ButtonPress: 9395 break; 9396 case ButtonRelease: 9397 { 9398 /* 9399 User has finished magnifying image. 9400 */ 9401 x=event->xbutton.x; 9402 y=event->xbutton.y; 9403 state|=ExitState; 9404 break; 9405 } 9406 case Expose: 9407 break; 9408 case MotionNotify: 9409 { 9410 x=event->xmotion.x; 9411 y=event->xmotion.y; 9412 break; 9413 } 9414 default: 9415 break; 9416 } 9417 /* 9418 Check boundary conditions. 9419 */ 9420 if (x < 0) 9421 x=0; 9422 else 9423 if (x >= (int) windows->image.width) 9424 x=(int) windows->image.width-1; 9425 if (y < 0) 9426 y=0; 9427 else 9428 if (y >= (int) windows->image.height) 9429 y=(int) windows->image.height-1; 9430 } while ((state & ExitState) == 0); 9431 /* 9432 Display magnified image. 9433 */ 9434 XSetCursorState(display,windows,MagickFalse); 9435} 9436 9437/* 9438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9439% % 9440% % 9441% % 9442+ X M a g n i f y W i n d o w C o m m a n d % 9443% % 9444% % 9445% % 9446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9447% 9448% XMagnifyWindowCommand() moves the image within an Magnify window by one 9449% pixel as specified by the key symbol. 9450% 9451% The format of the XMagnifyWindowCommand method is: 9452% 9453% void XMagnifyWindowCommand(Display *display,XWindows *windows, 9454% const MagickStatusType state,const KeySym key_symbol) 9455% 9456% A description of each parameter follows: 9457% 9458% o display: Specifies a connection to an X server; returned from 9459% XOpenDisplay. 9460% 9461% o windows: Specifies a pointer to a XWindows structure. 9462% 9463% o state: key mask. 9464% 9465% o key_symbol: Specifies a KeySym which indicates which side of the image 9466% to trim. 9467% 9468*/ 9469static void XMagnifyWindowCommand(Display *display,XWindows *windows, 9470 const MagickStatusType state,const KeySym key_symbol) 9471{ 9472 unsigned int 9473 quantum; 9474 9475 /* 9476 User specified a magnify factor or position. 9477 */ 9478 quantum=1; 9479 if ((state & Mod1Mask) != 0) 9480 quantum=10; 9481 switch ((int) key_symbol) 9482 { 9483 case QuitCommand: 9484 { 9485 (void) XWithdrawWindow(display,windows->magnify.id, 9486 windows->magnify.screen); 9487 break; 9488 } 9489 case XK_Home: 9490 case XK_KP_Home: 9491 { 9492 windows->magnify.x=(int) windows->image.width/2; 9493 windows->magnify.y=(int) windows->image.height/2; 9494 break; 9495 } 9496 case XK_Left: 9497 case XK_KP_Left: 9498 { 9499 if (windows->magnify.x > 0) 9500 windows->magnify.x-=quantum; 9501 break; 9502 } 9503 case XK_Up: 9504 case XK_KP_Up: 9505 { 9506 if (windows->magnify.y > 0) 9507 windows->magnify.y-=quantum; 9508 break; 9509 } 9510 case XK_Right: 9511 case XK_KP_Right: 9512 { 9513 if (windows->magnify.x < (int) (windows->image.ximage->width-1)) 9514 windows->magnify.x+=quantum; 9515 break; 9516 } 9517 case XK_Down: 9518 case XK_KP_Down: 9519 { 9520 if (windows->magnify.y < (int) (windows->image.ximage->height-1)) 9521 windows->magnify.y+=quantum; 9522 break; 9523 } 9524 case XK_0: 9525 case XK_1: 9526 case XK_2: 9527 case XK_3: 9528 case XK_4: 9529 case XK_5: 9530 case XK_6: 9531 case XK_7: 9532 case XK_8: 9533 case XK_9: 9534 { 9535 windows->magnify.data=(key_symbol-XK_0); 9536 break; 9537 } 9538 case XK_KP_0: 9539 case XK_KP_1: 9540 case XK_KP_2: 9541 case XK_KP_3: 9542 case XK_KP_4: 9543 case XK_KP_5: 9544 case XK_KP_6: 9545 case XK_KP_7: 9546 case XK_KP_8: 9547 case XK_KP_9: 9548 { 9549 windows->magnify.data=(key_symbol-XK_KP_0); 9550 break; 9551 } 9552 default: 9553 break; 9554 } 9555 XMakeMagnifyImage(display,windows); 9556} 9557 9558/* 9559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9560% % 9561% % 9562% % 9563+ X M a k e P a n I m a g e % 9564% % 9565% % 9566% % 9567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9568% 9569% XMakePanImage() creates a thumbnail of the image and displays it in the Pan 9570% icon window. 9571% 9572% The format of the XMakePanImage method is: 9573% 9574% void XMakePanImage(Display *display,XResourceInfo *resource_info, 9575% XWindows *windows,Image *image,ExceptionInfo *exception) 9576% 9577% A description of each parameter follows: 9578% 9579% o display: Specifies a connection to an X server; returned from 9580% XOpenDisplay. 9581% 9582% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9583% 9584% o windows: Specifies a pointer to a XWindows structure. 9585% 9586% o image: the image. 9587% 9588% o exception: return any errors or warnings in this structure. 9589% 9590*/ 9591static void XMakePanImage(Display *display,XResourceInfo *resource_info, 9592 XWindows *windows,Image *image,ExceptionInfo *exception) 9593{ 9594 MagickStatusType 9595 status; 9596 9597 /* 9598 Create and display image for panning icon. 9599 */ 9600 XSetCursorState(display,windows,MagickTrue); 9601 XCheckRefreshWindows(display,windows); 9602 windows->pan.x=(int) windows->image.x; 9603 windows->pan.y=(int) windows->image.y; 9604 status=XMakeImage(display,resource_info,&windows->pan,image, 9605 windows->pan.width,windows->pan.height,exception); 9606 if (status == MagickFalse) 9607 ThrowXWindowFatalException(ResourceLimitError, 9608 "MemoryAllocationFailed",image->filename); 9609 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 9610 windows->pan.pixmap); 9611 (void) XClearWindow(display,windows->pan.id); 9612 XDrawPanRectangle(display,windows); 9613 XSetCursorState(display,windows,MagickFalse); 9614} 9615 9616/* 9617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9618% % 9619% % 9620% % 9621+ X M a t t a E d i t I m a g e % 9622% % 9623% % 9624% % 9625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9626% 9627% XMatteEditImage() allows the user to interactively change the Matte channel 9628% of an image. If the image is PseudoClass it is promoted to DirectClass 9629% before the matte information is stored. 9630% 9631% The format of the XMatteEditImage method is: 9632% 9633% MagickBooleanType XMatteEditImage(Display *display, 9634% XResourceInfo *resource_info,XWindows *windows,Image **image, 9635% ExceptionInfo *exception) 9636% 9637% A description of each parameter follows: 9638% 9639% o display: Specifies a connection to an X server; returned from 9640% XOpenDisplay. 9641% 9642% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9643% 9644% o windows: Specifies a pointer to a XWindows structure. 9645% 9646% o image: the image; returned from ReadImage. 9647% 9648% o exception: return any errors or warnings in this structure. 9649% 9650*/ 9651static MagickBooleanType XMatteEditImage(Display *display, 9652 XResourceInfo *resource_info,XWindows *windows,Image **image, 9653 ExceptionInfo *exception) 9654{ 9655 static char 9656 matte[MaxTextExtent] = "0"; 9657 9658 static const char 9659 *MatteEditMenu[] = 9660 { 9661 "Method", 9662 "Border Color", 9663 "Fuzz", 9664 "Matte Value", 9665 "Undo", 9666 "Help", 9667 "Dismiss", 9668 (char *) NULL 9669 }; 9670 9671 static const ModeType 9672 MatteEditCommands[] = 9673 { 9674 MatteEditMethod, 9675 MatteEditBorderCommand, 9676 MatteEditFuzzCommand, 9677 MatteEditValueCommand, 9678 MatteEditUndoCommand, 9679 MatteEditHelpCommand, 9680 MatteEditDismissCommand 9681 }; 9682 9683 static PaintMethod 9684 method = PointMethod; 9685 9686 static XColor 9687 border_color = { 0, 0, 0, 0, 0, 0 }; 9688 9689 char 9690 command[MaxTextExtent], 9691 text[MaxTextExtent]; 9692 9693 Cursor 9694 cursor; 9695 9696 int 9697 entry, 9698 id, 9699 x, 9700 x_offset, 9701 y, 9702 y_offset; 9703 9704 register int 9705 i; 9706 9707 register Quantum 9708 *q; 9709 9710 unsigned int 9711 height, 9712 width; 9713 9714 size_t 9715 state; 9716 9717 XEvent 9718 event; 9719 9720 /* 9721 Map Command widget. 9722 */ 9723 (void) CloneString(&windows->command.name,"Matte Edit"); 9724 windows->command.data=4; 9725 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL); 9726 (void) XMapRaised(display,windows->command.id); 9727 XClientMessage(display,windows->image.id,windows->im_protocols, 9728 windows->im_update_widget,CurrentTime); 9729 /* 9730 Make cursor. 9731 */ 9732 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 9733 resource_info->background_color,resource_info->foreground_color); 9734 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9735 /* 9736 Track pointer until button 1 is pressed. 9737 */ 9738 XQueryPosition(display,windows->image.id,&x,&y); 9739 (void) XSelectInput(display,windows->image.id, 9740 windows->image.attributes.event_mask | PointerMotionMask); 9741 state=DefaultState; 9742 do 9743 { 9744 if (windows->info.mapped != MagickFalse) 9745 { 9746 /* 9747 Display pointer position. 9748 */ 9749 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9750 x+windows->image.x,y+windows->image.y); 9751 XInfoWidget(display,windows,text); 9752 } 9753 /* 9754 Wait for next event. 9755 */ 9756 XScreenEvent(display,windows,&event); 9757 if (event.xany.window == windows->command.id) 9758 { 9759 /* 9760 Select a command from the Command widget. 9761 */ 9762 id=XCommandWidget(display,windows,MatteEditMenu,&event); 9763 if (id < 0) 9764 { 9765 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9766 continue; 9767 } 9768 switch (MatteEditCommands[id]) 9769 { 9770 case MatteEditMethod: 9771 { 9772 char 9773 **methods; 9774 9775 /* 9776 Select a method from the pop-up menu. 9777 */ 9778 methods=GetCommandOptions(MagickMethodOptions); 9779 if (methods == (char **) NULL) 9780 break; 9781 entry=XMenuWidget(display,windows,MatteEditMenu[id], 9782 (const char **) methods,command); 9783 if (entry >= 0) 9784 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 9785 MagickFalse,methods[entry]); 9786 methods=DestroyStringList(methods); 9787 break; 9788 } 9789 case MatteEditBorderCommand: 9790 { 9791 const char 9792 *ColorMenu[MaxNumberPens]; 9793 9794 int 9795 pen_number; 9796 9797 /* 9798 Initialize menu selections. 9799 */ 9800 for (i=0; i < (int) (MaxNumberPens-2); i++) 9801 ColorMenu[i]=resource_info->pen_colors[i]; 9802 ColorMenu[MaxNumberPens-2]="Browser..."; 9803 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 9804 /* 9805 Select a pen color from the pop-up menu. 9806 */ 9807 pen_number=XMenuWidget(display,windows,MatteEditMenu[id], 9808 (const char **) ColorMenu,command); 9809 if (pen_number < 0) 9810 break; 9811 if (pen_number == (MaxNumberPens-2)) 9812 { 9813 static char 9814 color_name[MaxTextExtent] = "gray"; 9815 9816 /* 9817 Select a pen color from a dialog. 9818 */ 9819 resource_info->pen_colors[pen_number]=color_name; 9820 XColorBrowserWidget(display,windows,"Select",color_name); 9821 if (*color_name == '\0') 9822 break; 9823 } 9824 /* 9825 Set border color. 9826 */ 9827 (void) XParseColor(display,windows->map_info->colormap, 9828 resource_info->pen_colors[pen_number],&border_color); 9829 break; 9830 } 9831 case MatteEditFuzzCommand: 9832 { 9833 static char 9834 fuzz[MaxTextExtent]; 9835 9836 static const char 9837 *FuzzMenu[] = 9838 { 9839 "0%", 9840 "2%", 9841 "5%", 9842 "10%", 9843 "15%", 9844 "Dialog...", 9845 (char *) NULL, 9846 }; 9847 9848 /* 9849 Select a command from the pop-up menu. 9850 */ 9851 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu, 9852 command); 9853 if (entry < 0) 9854 break; 9855 if (entry != 5) 9856 { 9857 (*image)->fuzz=SiPrefixToDouble(FuzzMenu[entry],(double) 9858 QuantumRange+1.0); 9859 break; 9860 } 9861 (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 9862 (void) XDialogWidget(display,windows,"Ok", 9863 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 9864 if (*fuzz == '\0') 9865 break; 9866 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 9867 (*image)->fuzz=SiPrefixToDouble(fuzz,(double) QuantumRange+1.0); 9868 break; 9869 } 9870 case MatteEditValueCommand: 9871 { 9872 static char 9873 message[MaxTextExtent]; 9874 9875 static const char 9876 *MatteMenu[] = 9877 { 9878 "Opaque", 9879 "Transparent", 9880 "Dialog...", 9881 (char *) NULL, 9882 }; 9883 9884 /* 9885 Select a command from the pop-up menu. 9886 */ 9887 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu, 9888 command); 9889 if (entry < 0) 9890 break; 9891 if (entry != 2) 9892 { 9893 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9894 OpaqueAlpha); 9895 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9896 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9897 (Quantum) TransparentAlpha); 9898 break; 9899 } 9900 (void) FormatLocaleString(message,MaxTextExtent, 9901 "Enter matte value (0 - " QuantumFormat "):",(Quantum) 9902 QuantumRange); 9903 (void) XDialogWidget(display,windows,"Matte",message,matte); 9904 if (*matte == '\0') 9905 break; 9906 break; 9907 } 9908 case MatteEditUndoCommand: 9909 { 9910 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 9911 image,exception); 9912 break; 9913 } 9914 case MatteEditHelpCommand: 9915 { 9916 XTextViewWidget(display,resource_info,windows,MagickFalse, 9917 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9918 break; 9919 } 9920 case MatteEditDismissCommand: 9921 { 9922 /* 9923 Prematurely exit. 9924 */ 9925 state|=EscapeState; 9926 state|=ExitState; 9927 break; 9928 } 9929 default: 9930 break; 9931 } 9932 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9933 continue; 9934 } 9935 switch (event.type) 9936 { 9937 case ButtonPress: 9938 { 9939 if (event.xbutton.button != Button1) 9940 break; 9941 if ((event.xbutton.window != windows->image.id) && 9942 (event.xbutton.window != windows->magnify.id)) 9943 break; 9944 /* 9945 Update matte data. 9946 */ 9947 x=event.xbutton.x; 9948 y=event.xbutton.y; 9949 (void) XMagickCommand(display,resource_info,windows, 9950 SaveToUndoBufferCommand,image,exception); 9951 state|=UpdateConfigurationState; 9952 break; 9953 } 9954 case ButtonRelease: 9955 { 9956 if (event.xbutton.button != Button1) 9957 break; 9958 if ((event.xbutton.window != windows->image.id) && 9959 (event.xbutton.window != windows->magnify.id)) 9960 break; 9961 /* 9962 Update colormap information. 9963 */ 9964 x=event.xbutton.x; 9965 y=event.xbutton.y; 9966 XConfigureImageColormap(display,resource_info,windows,*image); 9967 (void) XConfigureImage(display,resource_info,windows,*image,exception); 9968 XInfoWidget(display,windows,text); 9969 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9970 state&=(~UpdateConfigurationState); 9971 break; 9972 } 9973 case Expose: 9974 break; 9975 case KeyPress: 9976 { 9977 char 9978 command[MaxTextExtent]; 9979 9980 KeySym 9981 key_symbol; 9982 9983 if (event.xkey.window == windows->magnify.id) 9984 { 9985 Window 9986 window; 9987 9988 window=windows->magnify.id; 9989 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 9990 } 9991 if (event.xkey.window != windows->image.id) 9992 break; 9993 /* 9994 Respond to a user key press. 9995 */ 9996 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 9997 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 9998 switch ((int) key_symbol) 9999 { 10000 case XK_Escape: 10001 case XK_F20: 10002 { 10003 /* 10004 Prematurely exit. 10005 */ 10006 state|=ExitState; 10007 break; 10008 } 10009 case XK_F1: 10010 case XK_Help: 10011 { 10012 XTextViewWidget(display,resource_info,windows,MagickFalse, 10013 "Help Viewer - Matte Edit",ImageMatteEditHelp); 10014 break; 10015 } 10016 default: 10017 { 10018 (void) XBell(display,0); 10019 break; 10020 } 10021 } 10022 break; 10023 } 10024 case MotionNotify: 10025 { 10026 /* 10027 Map and unmap Info widget as cursor crosses its boundaries. 10028 */ 10029 x=event.xmotion.x; 10030 y=event.xmotion.y; 10031 if (windows->info.mapped != MagickFalse) 10032 { 10033 if ((x < (int) (windows->info.x+windows->info.width)) && 10034 (y < (int) (windows->info.y+windows->info.height))) 10035 (void) XWithdrawWindow(display,windows->info.id, 10036 windows->info.screen); 10037 } 10038 else 10039 if ((x > (int) (windows->info.x+windows->info.width)) || 10040 (y > (int) (windows->info.y+windows->info.height))) 10041 (void) XMapWindow(display,windows->info.id); 10042 break; 10043 } 10044 default: 10045 break; 10046 } 10047 if (event.xany.window == windows->magnify.id) 10048 { 10049 x=windows->magnify.x-windows->image.x; 10050 y=windows->magnify.y-windows->image.y; 10051 } 10052 x_offset=x; 10053 y_offset=y; 10054 if ((state & UpdateConfigurationState) != 0) 10055 { 10056 CacheView 10057 *image_view; 10058 10059 int 10060 x, 10061 y; 10062 10063 /* 10064 Matte edit is relative to image configuration. 10065 */ 10066 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 10067 MagickTrue); 10068 XPutPixel(windows->image.ximage,x_offset,y_offset, 10069 windows->pixel_info->background_color.pixel); 10070 width=(unsigned int) (*image)->columns; 10071 height=(unsigned int) (*image)->rows; 10072 x=0; 10073 y=0; 10074 if (windows->image.crop_geometry != (char *) NULL) 10075 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width, 10076 &height); 10077 x_offset=(int) (width*(windows->image.x+x_offset)/ 10078 windows->image.ximage->width+x); 10079 y_offset=(int) (height*(windows->image.y+y_offset)/ 10080 windows->image.ximage->height+y); 10081 if ((x_offset < 0) || (y_offset < 0)) 10082 continue; 10083 if ((x_offset >= (int) (*image)->columns) || 10084 (y_offset >= (int) (*image)->rows)) 10085 continue; 10086 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10087 return(MagickFalse); 10088 (*image)->matte=MagickTrue; 10089 image_view=AcquireCacheView(*image); 10090 switch (method) 10091 { 10092 case PointMethod: 10093 default: 10094 { 10095 /* 10096 Update matte information using point algorithm. 10097 */ 10098 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset, 10099 (ssize_t) y_offset,1,1,exception); 10100 if (q == (Quantum *) NULL) 10101 break; 10102 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10103 (void) SyncCacheViewAuthenticPixels(image_view,exception); 10104 break; 10105 } 10106 case ReplaceMethod: 10107 { 10108 PixelInfo 10109 pixel, 10110 target; 10111 10112 Quantum 10113 virtual_pixel[MaxPixelChannels]; 10114 10115 /* 10116 Update matte information using replace algorithm. 10117 */ 10118 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 10119 (ssize_t) y_offset,virtual_pixel,exception); 10120 target.red=virtual_pixel[RedPixelChannel]; 10121 target.green=virtual_pixel[GreenPixelChannel]; 10122 target.blue=virtual_pixel[BluePixelChannel]; 10123 target.alpha=virtual_pixel[AlphaPixelChannel]; 10124 for (y=0; y < (int) (*image)->rows; y++) 10125 { 10126 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10127 (*image)->columns,1,exception); 10128 if (q == (Quantum *) NULL) 10129 break; 10130 for (x=0; x < (int) (*image)->columns; x++) 10131 { 10132 GetPixelInfoPixel(*image,q,&pixel); 10133 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 10134 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10135 q+=GetPixelChannels(*image); 10136 } 10137 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10138 break; 10139 } 10140 break; 10141 } 10142 case FloodfillMethod: 10143 case FillToBorderMethod: 10144 { 10145 ChannelType 10146 channel_mask; 10147 10148 DrawInfo 10149 *draw_info; 10150 10151 PixelInfo 10152 target; 10153 10154 /* 10155 Update matte information using floodfill algorithm. 10156 */ 10157 (void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset, 10158 (ssize_t) y_offset,&target,exception); 10159 if (method == FillToBorderMethod) 10160 { 10161 target.red=(MagickRealType) ScaleShortToQuantum( 10162 border_color.red); 10163 target.green=(MagickRealType) ScaleShortToQuantum( 10164 border_color.green); 10165 target.blue=(MagickRealType) ScaleShortToQuantum( 10166 border_color.blue); 10167 } 10168 draw_info=CloneDrawInfo(resource_info->image_info, 10169 (DrawInfo *) NULL); 10170 draw_info->fill.alpha=ClampToQuantum(InterpretLocaleValue(matte, 10171 (char **) NULL)); 10172 channel_mask=SetPixelChannelMask(*image,AlphaChannel); 10173 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 10174 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 10175 MagickFalse : MagickTrue,exception); 10176 (void) SetPixelChannelMap(*image,channel_mask); 10177 draw_info=DestroyDrawInfo(draw_info); 10178 break; 10179 } 10180 case ResetMethod: 10181 { 10182 /* 10183 Update matte information using reset algorithm. 10184 */ 10185 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10186 return(MagickFalse); 10187 for (y=0; y < (int) (*image)->rows; y++) 10188 { 10189 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10190 (*image)->columns,1,exception); 10191 if (q == (Quantum *) NULL) 10192 break; 10193 for (x=0; x < (int) (*image)->columns; x++) 10194 { 10195 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10196 q+=GetPixelChannels(*image); 10197 } 10198 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10199 break; 10200 } 10201 if (StringToLong(matte) == (long) OpaqueAlpha) 10202 (*image)->matte=MagickFalse; 10203 break; 10204 } 10205 } 10206 image_view=DestroyCacheView(image_view); 10207 state&=(~UpdateConfigurationState); 10208 } 10209 } while ((state & ExitState) == 0); 10210 (void) XSelectInput(display,windows->image.id, 10211 windows->image.attributes.event_mask); 10212 XSetCursorState(display,windows,MagickFalse); 10213 (void) XFreeCursor(display,cursor); 10214 return(MagickTrue); 10215} 10216 10217/* 10218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10219% % 10220% % 10221% % 10222+ X O p e n I m a g e % 10223% % 10224% % 10225% % 10226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10227% 10228% XOpenImage() loads an image from a file. 10229% 10230% The format of the XOpenImage method is: 10231% 10232% Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10233% XWindows *windows,const unsigned int command) 10234% 10235% A description of each parameter follows: 10236% 10237% o display: Specifies a connection to an X server; returned from 10238% XOpenDisplay. 10239% 10240% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10241% 10242% o windows: Specifies a pointer to a XWindows structure. 10243% 10244% o command: A value other than zero indicates that the file is selected 10245% from the command line argument list. 10246% 10247*/ 10248static Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10249 XWindows *windows,const MagickBooleanType command) 10250{ 10251 const MagickInfo 10252 *magick_info; 10253 10254 ExceptionInfo 10255 *exception; 10256 10257 Image 10258 *nexus; 10259 10260 ImageInfo 10261 *image_info; 10262 10263 static char 10264 filename[MaxTextExtent] = "\0"; 10265 10266 /* 10267 Request file name from user. 10268 */ 10269 if (command == MagickFalse) 10270 XFileBrowserWidget(display,windows,"Open",filename); 10271 else 10272 { 10273 char 10274 **filelist, 10275 **files; 10276 10277 int 10278 count, 10279 status; 10280 10281 register int 10282 i, 10283 j; 10284 10285 /* 10286 Select next image from the command line. 10287 */ 10288 status=XGetCommand(display,windows->image.id,&files,&count); 10289 if (status == 0) 10290 { 10291 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","..."); 10292 return((Image *) NULL); 10293 } 10294 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10295 if (filelist == (char **) NULL) 10296 { 10297 ThrowXWindowFatalException(ResourceLimitError, 10298 "MemoryAllocationFailed","..."); 10299 (void) XFreeStringList(files); 10300 return((Image *) NULL); 10301 } 10302 j=0; 10303 for (i=1; i < count; i++) 10304 if (*files[i] != '-') 10305 filelist[j++]=files[i]; 10306 filelist[j]=(char *) NULL; 10307 XListBrowserWidget(display,windows,&windows->widget, 10308 (const char **) filelist,"Load","Select Image to Load:",filename); 10309 filelist=(char **) RelinquishMagickMemory(filelist); 10310 (void) XFreeStringList(files); 10311 } 10312 if (*filename == '\0') 10313 return((Image *) NULL); 10314 image_info=CloneImageInfo(resource_info->image_info); 10315 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL, 10316 (void *) NULL); 10317 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10318 exception=AcquireExceptionInfo(); 10319 (void) SetImageInfo(image_info,0,exception); 10320 if (LocaleCompare(image_info->magick,"X") == 0) 10321 { 10322 char 10323 seconds[MaxTextExtent]; 10324 10325 /* 10326 User may want to delay the X server screen grab. 10327 */ 10328 (void) CopyMagickString(seconds,"0",MaxTextExtent); 10329 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:", 10330 seconds); 10331 if (*seconds == '\0') 10332 return((Image *) NULL); 10333 XDelay(display,(size_t) (1000*StringToLong(seconds))); 10334 } 10335 magick_info=GetMagickInfo(image_info->magick,exception); 10336 if ((magick_info != (const MagickInfo *) NULL) && 10337 (magick_info->raw != MagickFalse)) 10338 { 10339 char 10340 geometry[MaxTextExtent]; 10341 10342 /* 10343 Request image size from the user. 10344 */ 10345 (void) CopyMagickString(geometry,"512x512",MaxTextExtent); 10346 if (image_info->size != (char *) NULL) 10347 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent); 10348 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:", 10349 geometry); 10350 (void) CloneString(&image_info->size,geometry); 10351 } 10352 /* 10353 Load the image. 10354 */ 10355 XSetCursorState(display,windows,MagickTrue); 10356 XCheckRefreshWindows(display,windows); 10357 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10358 nexus=ReadImage(image_info,exception); 10359 CatchException(exception); 10360 XSetCursorState(display,windows,MagickFalse); 10361 if (nexus != (Image *) NULL) 10362 XClientMessage(display,windows->image.id,windows->im_protocols, 10363 windows->im_next_image,CurrentTime); 10364 else 10365 { 10366 char 10367 *text, 10368 **textlist; 10369 10370 /* 10371 Unknown image format. 10372 */ 10373 text=FileToString(filename,~0,exception); 10374 if (text == (char *) NULL) 10375 return((Image *) NULL); 10376 textlist=StringToList(text); 10377 if (textlist != (char **) NULL) 10378 { 10379 char 10380 title[MaxTextExtent]; 10381 10382 register int 10383 i; 10384 10385 (void) FormatLocaleString(title,MaxTextExtent, 10386 "Unknown format: %s",filename); 10387 XTextViewWidget(display,resource_info,windows,MagickTrue,title, 10388 (const char **) textlist); 10389 for (i=0; textlist[i] != (char *) NULL; i++) 10390 textlist[i]=DestroyString(textlist[i]); 10391 textlist=(char **) RelinquishMagickMemory(textlist); 10392 } 10393 text=DestroyString(text); 10394 } 10395 exception=DestroyExceptionInfo(exception); 10396 image_info=DestroyImageInfo(image_info); 10397 return(nexus); 10398} 10399 10400/* 10401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10402% % 10403% % 10404% % 10405+ X P a n I m a g e % 10406% % 10407% % 10408% % 10409%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10410% 10411% XPanImage() pans the image until the mouse button is released. 10412% 10413% The format of the XPanImage method is: 10414% 10415% void XPanImage(Display *display,XWindows *windows,XEvent *event) 10416% 10417% A description of each parameter follows: 10418% 10419% o display: Specifies a connection to an X server; returned from 10420% XOpenDisplay. 10421% 10422% o windows: Specifies a pointer to a XWindows structure. 10423% 10424% o event: Specifies a pointer to a XEvent structure. If it is NULL, 10425% the entire image is refreshed. 10426% 10427*/ 10428static void XPanImage(Display *display,XWindows *windows,XEvent *event) 10429{ 10430 char 10431 text[MaxTextExtent]; 10432 10433 Cursor 10434 cursor; 10435 10436 MagickRealType 10437 x_factor, 10438 y_factor; 10439 10440 RectangleInfo 10441 pan_info; 10442 10443 size_t 10444 state; 10445 10446 /* 10447 Define cursor. 10448 */ 10449 if ((windows->image.ximage->width > (int) windows->image.width) && 10450 (windows->image.ximage->height > (int) windows->image.height)) 10451 cursor=XCreateFontCursor(display,XC_fleur); 10452 else 10453 if (windows->image.ximage->width > (int) windows->image.width) 10454 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow); 10455 else 10456 if (windows->image.ximage->height > (int) windows->image.height) 10457 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow); 10458 else 10459 cursor=XCreateFontCursor(display,XC_arrow); 10460 (void) XCheckDefineCursor(display,windows->pan.id,cursor); 10461 /* 10462 Pan image as pointer moves until the mouse button is released. 10463 */ 10464 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width; 10465 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height; 10466 pan_info.width=windows->pan.width*windows->image.width/ 10467 windows->image.ximage->width; 10468 pan_info.height=windows->pan.height*windows->image.height/ 10469 windows->image.ximage->height; 10470 pan_info.x=0; 10471 pan_info.y=0; 10472 state=UpdateConfigurationState; 10473 do 10474 { 10475 switch (event->type) 10476 { 10477 case ButtonPress: 10478 { 10479 /* 10480 User choose an initial pan location. 10481 */ 10482 pan_info.x=(ssize_t) event->xbutton.x; 10483 pan_info.y=(ssize_t) event->xbutton.y; 10484 state|=UpdateConfigurationState; 10485 break; 10486 } 10487 case ButtonRelease: 10488 { 10489 /* 10490 User has finished panning the image. 10491 */ 10492 pan_info.x=(ssize_t) event->xbutton.x; 10493 pan_info.y=(ssize_t) event->xbutton.y; 10494 state|=UpdateConfigurationState | ExitState; 10495 break; 10496 } 10497 case MotionNotify: 10498 { 10499 pan_info.x=(ssize_t) event->xmotion.x; 10500 pan_info.y=(ssize_t) event->xmotion.y; 10501 state|=UpdateConfigurationState; 10502 } 10503 default: 10504 break; 10505 } 10506 if ((state & UpdateConfigurationState) != 0) 10507 { 10508 /* 10509 Check boundary conditions. 10510 */ 10511 if (pan_info.x < (ssize_t) (pan_info.width/2)) 10512 pan_info.x=0; 10513 else 10514 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2))); 10515 if (pan_info.x < 0) 10516 pan_info.x=0; 10517 else 10518 if ((int) (pan_info.x+windows->image.width) > 10519 windows->image.ximage->width) 10520 pan_info.x=(ssize_t) 10521 (windows->image.ximage->width-windows->image.width); 10522 if (pan_info.y < (ssize_t) (pan_info.height/2)) 10523 pan_info.y=0; 10524 else 10525 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2))); 10526 if (pan_info.y < 0) 10527 pan_info.y=0; 10528 else 10529 if ((int) (pan_info.y+windows->image.height) > 10530 windows->image.ximage->height) 10531 pan_info.y=(ssize_t) 10532 (windows->image.ximage->height-windows->image.height); 10533 if ((windows->image.x != (int) pan_info.x) || 10534 (windows->image.y != (int) pan_info.y)) 10535 { 10536 /* 10537 Display image pan offset. 10538 */ 10539 windows->image.x=(int) pan_info.x; 10540 windows->image.y=(int) pan_info.y; 10541 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 10542 windows->image.width,windows->image.height,windows->image.x, 10543 windows->image.y); 10544 XInfoWidget(display,windows,text); 10545 /* 10546 Refresh Image window. 10547 */ 10548 XDrawPanRectangle(display,windows); 10549 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 10550 } 10551 state&=(~UpdateConfigurationState); 10552 } 10553 /* 10554 Wait for next event. 10555 */ 10556 if ((state & ExitState) == 0) 10557 XScreenEvent(display,windows,event); 10558 } while ((state & ExitState) == 0); 10559 /* 10560 Restore cursor. 10561 */ 10562 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor); 10563 (void) XFreeCursor(display,cursor); 10564 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 10565} 10566 10567/* 10568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10569% % 10570% % 10571% % 10572+ X P a s t e I m a g e % 10573% % 10574% % 10575% % 10576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10577% 10578% XPasteImage() pastes an image previously saved with XCropImage in the X 10579% window image at a location the user chooses with the pointer. 10580% 10581% The format of the XPasteImage method is: 10582% 10583% MagickBooleanType XPasteImage(Display *display, 10584% XResourceInfo *resource_info,XWindows *windows,Image *image, 10585% ExceptionInfo *exception) 10586% 10587% A description of each parameter follows: 10588% 10589% o display: Specifies a connection to an X server; returned from 10590% XOpenDisplay. 10591% 10592% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10593% 10594% o windows: Specifies a pointer to a XWindows structure. 10595% 10596% o image: the image; returned from ReadImage. 10597% 10598% o exception: return any errors or warnings in this structure. 10599% 10600*/ 10601static MagickBooleanType XPasteImage(Display *display, 10602 XResourceInfo *resource_info,XWindows *windows,Image *image, 10603 ExceptionInfo *exception) 10604{ 10605 static const char 10606 *PasteMenu[] = 10607 { 10608 "Operator", 10609 "Help", 10610 "Dismiss", 10611 (char *) NULL 10612 }; 10613 10614 static const ModeType 10615 PasteCommands[] = 10616 { 10617 PasteOperatorsCommand, 10618 PasteHelpCommand, 10619 PasteDismissCommand 10620 }; 10621 10622 static CompositeOperator 10623 compose = CopyCompositeOp; 10624 10625 char 10626 text[MaxTextExtent]; 10627 10628 Cursor 10629 cursor; 10630 10631 Image 10632 *paste_image; 10633 10634 int 10635 entry, 10636 id, 10637 x, 10638 y; 10639 10640 MagickRealType 10641 scale_factor; 10642 10643 RectangleInfo 10644 highlight_info, 10645 paste_info; 10646 10647 unsigned int 10648 height, 10649 width; 10650 10651 size_t 10652 state; 10653 10654 XEvent 10655 event; 10656 10657 /* 10658 Copy image. 10659 */ 10660 if (resource_info->copy_image == (Image *) NULL) 10661 return(MagickFalse); 10662 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception); 10663 /* 10664 Map Command widget. 10665 */ 10666 (void) CloneString(&windows->command.name,"Paste"); 10667 windows->command.data=1; 10668 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL); 10669 (void) XMapRaised(display,windows->command.id); 10670 XClientMessage(display,windows->image.id,windows->im_protocols, 10671 windows->im_update_widget,CurrentTime); 10672 /* 10673 Track pointer until button 1 is pressed. 10674 */ 10675 XSetCursorState(display,windows,MagickFalse); 10676 XQueryPosition(display,windows->image.id,&x,&y); 10677 (void) XSelectInput(display,windows->image.id, 10678 windows->image.attributes.event_mask | PointerMotionMask); 10679 paste_info.x=(ssize_t) windows->image.x+x; 10680 paste_info.y=(ssize_t) windows->image.y+y; 10681 paste_info.width=0; 10682 paste_info.height=0; 10683 cursor=XCreateFontCursor(display,XC_ul_angle); 10684 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 10685 state=DefaultState; 10686 do 10687 { 10688 if (windows->info.mapped != MagickFalse) 10689 { 10690 /* 10691 Display pointer position. 10692 */ 10693 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 10694 (long) paste_info.x,(long) paste_info.y); 10695 XInfoWidget(display,windows,text); 10696 } 10697 highlight_info=paste_info; 10698 highlight_info.x=paste_info.x-windows->image.x; 10699 highlight_info.y=paste_info.y-windows->image.y; 10700 XHighlightRectangle(display,windows->image.id, 10701 windows->image.highlight_context,&highlight_info); 10702 /* 10703 Wait for next event. 10704 */ 10705 XScreenEvent(display,windows,&event); 10706 XHighlightRectangle(display,windows->image.id, 10707 windows->image.highlight_context,&highlight_info); 10708 if (event.xany.window == windows->command.id) 10709 { 10710 /* 10711 Select a command from the Command widget. 10712 */ 10713 id=XCommandWidget(display,windows,PasteMenu,&event); 10714 if (id < 0) 10715 continue; 10716 switch (PasteCommands[id]) 10717 { 10718 case PasteOperatorsCommand: 10719 { 10720 char 10721 command[MaxTextExtent], 10722 **operators; 10723 10724 /* 10725 Select a command from the pop-up menu. 10726 */ 10727 operators=GetCommandOptions(MagickComposeOptions); 10728 if (operators == (char **) NULL) 10729 break; 10730 entry=XMenuWidget(display,windows,PasteMenu[id], 10731 (const char **) operators,command); 10732 if (entry >= 0) 10733 compose=(CompositeOperator) ParseCommandOption( 10734 MagickComposeOptions,MagickFalse,operators[entry]); 10735 operators=DestroyStringList(operators); 10736 break; 10737 } 10738 case PasteHelpCommand: 10739 { 10740 XTextViewWidget(display,resource_info,windows,MagickFalse, 10741 "Help Viewer - Image Composite",ImagePasteHelp); 10742 break; 10743 } 10744 case PasteDismissCommand: 10745 { 10746 /* 10747 Prematurely exit. 10748 */ 10749 state|=EscapeState; 10750 state|=ExitState; 10751 break; 10752 } 10753 default: 10754 break; 10755 } 10756 continue; 10757 } 10758 switch (event.type) 10759 { 10760 case ButtonPress: 10761 { 10762 if (image->debug != MagickFalse) 10763 (void) LogMagickEvent(X11Event,GetMagickModule(), 10764 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 10765 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10766 if (event.xbutton.button != Button1) 10767 break; 10768 if (event.xbutton.window != windows->image.id) 10769 break; 10770 /* 10771 Paste rectangle is relative to image configuration. 10772 */ 10773 width=(unsigned int) image->columns; 10774 height=(unsigned int) image->rows; 10775 x=0; 10776 y=0; 10777 if (windows->image.crop_geometry != (char *) NULL) 10778 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 10779 &width,&height); 10780 scale_factor=(MagickRealType) windows->image.ximage->width/width; 10781 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5); 10782 scale_factor=(MagickRealType) windows->image.ximage->height/height; 10783 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5); 10784 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10785 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10786 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10787 break; 10788 } 10789 case ButtonRelease: 10790 { 10791 if (image->debug != MagickFalse) 10792 (void) LogMagickEvent(X11Event,GetMagickModule(), 10793 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 10794 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10795 if (event.xbutton.button != Button1) 10796 break; 10797 if (event.xbutton.window != windows->image.id) 10798 break; 10799 if ((paste_info.width != 0) && (paste_info.height != 0)) 10800 { 10801 /* 10802 User has selected the location of the paste image. 10803 */ 10804 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10805 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10806 state|=ExitState; 10807 } 10808 break; 10809 } 10810 case Expose: 10811 break; 10812 case KeyPress: 10813 { 10814 char 10815 command[MaxTextExtent]; 10816 10817 KeySym 10818 key_symbol; 10819 10820 int 10821 length; 10822 10823 if (event.xkey.window != windows->image.id) 10824 break; 10825 /* 10826 Respond to a user key press. 10827 */ 10828 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 10829 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10830 *(command+length)='\0'; 10831 if (image->debug != MagickFalse) 10832 (void) LogMagickEvent(X11Event,GetMagickModule(), 10833 "Key press: 0x%lx (%s)",(long) key_symbol,command); 10834 switch ((int) key_symbol) 10835 { 10836 case XK_Escape: 10837 case XK_F20: 10838 { 10839 /* 10840 Prematurely exit. 10841 */ 10842 paste_image=DestroyImage(paste_image); 10843 state|=EscapeState; 10844 state|=ExitState; 10845 break; 10846 } 10847 case XK_F1: 10848 case XK_Help: 10849 { 10850 (void) XSetFunction(display,windows->image.highlight_context, 10851 GXcopy); 10852 XTextViewWidget(display,resource_info,windows,MagickFalse, 10853 "Help Viewer - Image Composite",ImagePasteHelp); 10854 (void) XSetFunction(display,windows->image.highlight_context, 10855 GXinvert); 10856 break; 10857 } 10858 default: 10859 { 10860 (void) XBell(display,0); 10861 break; 10862 } 10863 } 10864 break; 10865 } 10866 case MotionNotify: 10867 { 10868 /* 10869 Map and unmap Info widget as text cursor crosses its boundaries. 10870 */ 10871 x=event.xmotion.x; 10872 y=event.xmotion.y; 10873 if (windows->info.mapped != MagickFalse) 10874 { 10875 if ((x < (int) (windows->info.x+windows->info.width)) && 10876 (y < (int) (windows->info.y+windows->info.height))) 10877 (void) XWithdrawWindow(display,windows->info.id, 10878 windows->info.screen); 10879 } 10880 else 10881 if ((x > (int) (windows->info.x+windows->info.width)) || 10882 (y > (int) (windows->info.y+windows->info.height))) 10883 (void) XMapWindow(display,windows->info.id); 10884 paste_info.x=(ssize_t) windows->image.x+x; 10885 paste_info.y=(ssize_t) windows->image.y+y; 10886 break; 10887 } 10888 default: 10889 { 10890 if (image->debug != MagickFalse) 10891 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 10892 event.type); 10893 break; 10894 } 10895 } 10896 } while ((state & ExitState) == 0); 10897 (void) XSelectInput(display,windows->image.id, 10898 windows->image.attributes.event_mask); 10899 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 10900 XSetCursorState(display,windows,MagickFalse); 10901 (void) XFreeCursor(display,cursor); 10902 if ((state & EscapeState) != 0) 10903 return(MagickTrue); 10904 /* 10905 Image pasting is relative to image configuration. 10906 */ 10907 XSetCursorState(display,windows,MagickTrue); 10908 XCheckRefreshWindows(display,windows); 10909 width=(unsigned int) image->columns; 10910 height=(unsigned int) image->rows; 10911 x=0; 10912 y=0; 10913 if (windows->image.crop_geometry != (char *) NULL) 10914 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 10915 scale_factor=(MagickRealType) width/windows->image.ximage->width; 10916 paste_info.x+=x; 10917 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5); 10918 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5); 10919 scale_factor=(MagickRealType) height/windows->image.ximage->height; 10920 paste_info.y+=y; 10921 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5); 10922 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5); 10923 /* 10924 Paste image with X Image window. 10925 */ 10926 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y, 10927 exception); 10928 paste_image=DestroyImage(paste_image); 10929 XSetCursorState(display,windows,MagickFalse); 10930 /* 10931 Update image colormap. 10932 */ 10933 XConfigureImageColormap(display,resource_info,windows,image); 10934 (void) XConfigureImage(display,resource_info,windows,image,exception); 10935 return(MagickTrue); 10936} 10937 10938/* 10939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10940% % 10941% % 10942% % 10943+ X P r i n t I m a g e % 10944% % 10945% % 10946% % 10947%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10948% 10949% XPrintImage() prints an image to a Postscript printer. 10950% 10951% The format of the XPrintImage method is: 10952% 10953% MagickBooleanType XPrintImage(Display *display, 10954% XResourceInfo *resource_info,XWindows *windows,Image *image, 10955% ExceptionInfo *exception) 10956% 10957% A description of each parameter follows: 10958% 10959% o display: Specifies a connection to an X server; returned from 10960% XOpenDisplay. 10961% 10962% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10963% 10964% o windows: Specifies a pointer to a XWindows structure. 10965% 10966% o image: the image. 10967% 10968% o exception: return any errors or warnings in this structure. 10969% 10970*/ 10971static MagickBooleanType XPrintImage(Display *display, 10972 XResourceInfo *resource_info,XWindows *windows,Image *image, 10973 ExceptionInfo *exception) 10974{ 10975 char 10976 filename[MaxTextExtent], 10977 geometry[MaxTextExtent]; 10978 10979 Image 10980 *print_image; 10981 10982 ImageInfo 10983 *image_info; 10984 10985 MagickStatusType 10986 status; 10987 10988 /* 10989 Request Postscript page geometry from user. 10990 */ 10991 image_info=CloneImageInfo(resource_info->image_info); 10992 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter"); 10993 if (image_info->page != (char *) NULL) 10994 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 10995 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 10996 "Select Postscript Page Geometry:",geometry); 10997 if (*geometry == '\0') 10998 return(MagickTrue); 10999 image_info->page=GetPageGeometry(geometry); 11000 /* 11001 Apply image transforms. 11002 */ 11003 XSetCursorState(display,windows,MagickTrue); 11004 XCheckRefreshWindows(display,windows); 11005 print_image=CloneImage(image,0,0,MagickTrue,exception); 11006 if (print_image == (Image *) NULL) 11007 return(MagickFalse); 11008 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 11009 windows->image.ximage->width,windows->image.ximage->height); 11010 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry, 11011 exception); 11012 /* 11013 Print image. 11014 */ 11015 (void) AcquireUniqueFilename(filename); 11016 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s", 11017 filename); 11018 status=WriteImage(image_info,print_image,exception); 11019 (void) RelinquishUniqueFileResource(filename); 11020 print_image=DestroyImage(print_image); 11021 image_info=DestroyImageInfo(image_info); 11022 XSetCursorState(display,windows,MagickFalse); 11023 return(status != 0 ? MagickTrue : MagickFalse); 11024} 11025 11026/* 11027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11028% % 11029% % 11030% % 11031+ X R O I I m a g e % 11032% % 11033% % 11034% % 11035%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11036% 11037% XROIImage() applies an image processing technique to a region of interest. 11038% 11039% The format of the XROIImage method is: 11040% 11041% MagickBooleanType XROIImage(Display *display, 11042% XResourceInfo *resource_info,XWindows *windows,Image **image, 11043% ExceptionInfo *exception) 11044% 11045% A description of each parameter follows: 11046% 11047% o display: Specifies a connection to an X server; returned from 11048% XOpenDisplay. 11049% 11050% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11051% 11052% o windows: Specifies a pointer to a XWindows structure. 11053% 11054% o image: the image; returned from ReadImage. 11055% 11056% o exception: return any errors or warnings in this structure. 11057% 11058*/ 11059static MagickBooleanType XROIImage(Display *display, 11060 XResourceInfo *resource_info,XWindows *windows,Image **image, 11061 ExceptionInfo *exception) 11062{ 11063#define ApplyMenus 7 11064 11065 static const char 11066 *ROIMenu[] = 11067 { 11068 "Help", 11069 "Dismiss", 11070 (char *) NULL 11071 }, 11072 *ApplyMenu[] = 11073 { 11074 "File", 11075 "Edit", 11076 "Transform", 11077 "Enhance", 11078 "Effects", 11079 "F/X", 11080 "Miscellany", 11081 "Help", 11082 "Dismiss", 11083 (char *) NULL 11084 }, 11085 *FileMenu[] = 11086 { 11087 "Save...", 11088 "Print...", 11089 (char *) NULL 11090 }, 11091 *EditMenu[] = 11092 { 11093 "Undo", 11094 "Redo", 11095 (char *) NULL 11096 }, 11097 *TransformMenu[] = 11098 { 11099 "Flop", 11100 "Flip", 11101 "Rotate Right", 11102 "Rotate Left", 11103 (char *) NULL 11104 }, 11105 *EnhanceMenu[] = 11106 { 11107 "Hue...", 11108 "Saturation...", 11109 "Brightness...", 11110 "Gamma...", 11111 "Spiff", 11112 "Dull", 11113 "Contrast Stretch...", 11114 "Sigmoidal Contrast...", 11115 "Normalize", 11116 "Equalize", 11117 "Negate", 11118 "Grayscale", 11119 "Map...", 11120 "Quantize...", 11121 (char *) NULL 11122 }, 11123 *EffectsMenu[] = 11124 { 11125 "Despeckle", 11126 "Emboss", 11127 "Reduce Noise", 11128 "Add Noise", 11129 "Sharpen...", 11130 "Blur...", 11131 "Threshold...", 11132 "Edge Detect...", 11133 "Spread...", 11134 "Shade...", 11135 "Raise...", 11136 "Segment...", 11137 (char *) NULL 11138 }, 11139 *FXMenu[] = 11140 { 11141 "Solarize...", 11142 "Sepia Tone...", 11143 "Swirl...", 11144 "Implode...", 11145 "Vignette...", 11146 "Wave...", 11147 "Oil Paint...", 11148 "Charcoal Draw...", 11149 (char *) NULL 11150 }, 11151 *MiscellanyMenu[] = 11152 { 11153 "Image Info", 11154 "Zoom Image", 11155 "Show Preview...", 11156 "Show Histogram", 11157 "Show Matte", 11158 (char *) NULL 11159 }; 11160 11161 static const char 11162 **Menus[ApplyMenus] = 11163 { 11164 FileMenu, 11165 EditMenu, 11166 TransformMenu, 11167 EnhanceMenu, 11168 EffectsMenu, 11169 FXMenu, 11170 MiscellanyMenu 11171 }; 11172 11173 static const CommandType 11174 ApplyCommands[] = 11175 { 11176 NullCommand, 11177 NullCommand, 11178 NullCommand, 11179 NullCommand, 11180 NullCommand, 11181 NullCommand, 11182 NullCommand, 11183 HelpCommand, 11184 QuitCommand 11185 }, 11186 FileCommands[] = 11187 { 11188 SaveCommand, 11189 PrintCommand 11190 }, 11191 EditCommands[] = 11192 { 11193 UndoCommand, 11194 RedoCommand 11195 }, 11196 TransformCommands[] = 11197 { 11198 FlopCommand, 11199 FlipCommand, 11200 RotateRightCommand, 11201 RotateLeftCommand 11202 }, 11203 EnhanceCommands[] = 11204 { 11205 HueCommand, 11206 SaturationCommand, 11207 BrightnessCommand, 11208 GammaCommand, 11209 SpiffCommand, 11210 DullCommand, 11211 ContrastStretchCommand, 11212 SigmoidalContrastCommand, 11213 NormalizeCommand, 11214 EqualizeCommand, 11215 NegateCommand, 11216 GrayscaleCommand, 11217 MapCommand, 11218 QuantizeCommand 11219 }, 11220 EffectsCommands[] = 11221 { 11222 DespeckleCommand, 11223 EmbossCommand, 11224 ReduceNoiseCommand, 11225 AddNoiseCommand, 11226 SharpenCommand, 11227 BlurCommand, 11228 EdgeDetectCommand, 11229 SpreadCommand, 11230 ShadeCommand, 11231 RaiseCommand, 11232 SegmentCommand 11233 }, 11234 FXCommands[] = 11235 { 11236 SolarizeCommand, 11237 SepiaToneCommand, 11238 SwirlCommand, 11239 ImplodeCommand, 11240 VignetteCommand, 11241 WaveCommand, 11242 OilPaintCommand, 11243 CharcoalDrawCommand 11244 }, 11245 MiscellanyCommands[] = 11246 { 11247 InfoCommand, 11248 ZoomCommand, 11249 ShowPreviewCommand, 11250 ShowHistogramCommand, 11251 ShowMatteCommand 11252 }, 11253 ROICommands[] = 11254 { 11255 ROIHelpCommand, 11256 ROIDismissCommand 11257 }; 11258 11259 static const CommandType 11260 *Commands[ApplyMenus] = 11261 { 11262 FileCommands, 11263 EditCommands, 11264 TransformCommands, 11265 EnhanceCommands, 11266 EffectsCommands, 11267 FXCommands, 11268 MiscellanyCommands 11269 }; 11270 11271 char 11272 command[MaxTextExtent], 11273 text[MaxTextExtent]; 11274 11275 CommandType 11276 command_type; 11277 11278 Cursor 11279 cursor; 11280 11281 Image 11282 *roi_image; 11283 11284 int 11285 entry, 11286 id, 11287 x, 11288 y; 11289 11290 MagickRealType 11291 scale_factor; 11292 11293 MagickProgressMonitor 11294 progress_monitor; 11295 11296 RectangleInfo 11297 crop_info, 11298 highlight_info, 11299 roi_info; 11300 11301 unsigned int 11302 height, 11303 width; 11304 11305 size_t 11306 state; 11307 11308 XEvent 11309 event; 11310 11311 /* 11312 Map Command widget. 11313 */ 11314 (void) CloneString(&windows->command.name,"ROI"); 11315 windows->command.data=0; 11316 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL); 11317 (void) XMapRaised(display,windows->command.id); 11318 XClientMessage(display,windows->image.id,windows->im_protocols, 11319 windows->im_update_widget,CurrentTime); 11320 /* 11321 Track pointer until button 1 is pressed. 11322 */ 11323 XQueryPosition(display,windows->image.id,&x,&y); 11324 (void) XSelectInput(display,windows->image.id, 11325 windows->image.attributes.event_mask | PointerMotionMask); 11326 roi_info.x=(ssize_t) windows->image.x+x; 11327 roi_info.y=(ssize_t) windows->image.y+y; 11328 roi_info.width=0; 11329 roi_info.height=0; 11330 cursor=XCreateFontCursor(display,XC_fleur); 11331 state=DefaultState; 11332 do 11333 { 11334 if (windows->info.mapped != MagickFalse) 11335 { 11336 /* 11337 Display pointer position. 11338 */ 11339 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 11340 (long) roi_info.x,(long) roi_info.y); 11341 XInfoWidget(display,windows,text); 11342 } 11343 /* 11344 Wait for next event. 11345 */ 11346 XScreenEvent(display,windows,&event); 11347 if (event.xany.window == windows->command.id) 11348 { 11349 /* 11350 Select a command from the Command widget. 11351 */ 11352 id=XCommandWidget(display,windows,ROIMenu,&event); 11353 if (id < 0) 11354 continue; 11355 switch (ROICommands[id]) 11356 { 11357 case ROIHelpCommand: 11358 { 11359 XTextViewWidget(display,resource_info,windows,MagickFalse, 11360 "Help Viewer - Region of Interest",ImageROIHelp); 11361 break; 11362 } 11363 case ROIDismissCommand: 11364 { 11365 /* 11366 Prematurely exit. 11367 */ 11368 state|=EscapeState; 11369 state|=ExitState; 11370 break; 11371 } 11372 default: 11373 break; 11374 } 11375 continue; 11376 } 11377 switch (event.type) 11378 { 11379 case ButtonPress: 11380 { 11381 if (event.xbutton.button != Button1) 11382 break; 11383 if (event.xbutton.window != windows->image.id) 11384 break; 11385 /* 11386 Note first corner of region of interest rectangle-- exit loop. 11387 */ 11388 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11389 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11390 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11391 state|=ExitState; 11392 break; 11393 } 11394 case ButtonRelease: 11395 break; 11396 case Expose: 11397 break; 11398 case KeyPress: 11399 { 11400 KeySym 11401 key_symbol; 11402 11403 if (event.xkey.window != windows->image.id) 11404 break; 11405 /* 11406 Respond to a user key press. 11407 */ 11408 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11409 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11410 switch ((int) key_symbol) 11411 { 11412 case XK_Escape: 11413 case XK_F20: 11414 { 11415 /* 11416 Prematurely exit. 11417 */ 11418 state|=EscapeState; 11419 state|=ExitState; 11420 break; 11421 } 11422 case XK_F1: 11423 case XK_Help: 11424 { 11425 XTextViewWidget(display,resource_info,windows,MagickFalse, 11426 "Help Viewer - Region of Interest",ImageROIHelp); 11427 break; 11428 } 11429 default: 11430 { 11431 (void) XBell(display,0); 11432 break; 11433 } 11434 } 11435 break; 11436 } 11437 case MotionNotify: 11438 { 11439 /* 11440 Map and unmap Info widget as text cursor crosses its boundaries. 11441 */ 11442 x=event.xmotion.x; 11443 y=event.xmotion.y; 11444 if (windows->info.mapped != MagickFalse) 11445 { 11446 if ((x < (int) (windows->info.x+windows->info.width)) && 11447 (y < (int) (windows->info.y+windows->info.height))) 11448 (void) XWithdrawWindow(display,windows->info.id, 11449 windows->info.screen); 11450 } 11451 else 11452 if ((x > (int) (windows->info.x+windows->info.width)) || 11453 (y > (int) (windows->info.y+windows->info.height))) 11454 (void) XMapWindow(display,windows->info.id); 11455 roi_info.x=(ssize_t) windows->image.x+x; 11456 roi_info.y=(ssize_t) windows->image.y+y; 11457 break; 11458 } 11459 default: 11460 break; 11461 } 11462 } while ((state & ExitState) == 0); 11463 (void) XSelectInput(display,windows->image.id, 11464 windows->image.attributes.event_mask); 11465 if ((state & EscapeState) != 0) 11466 { 11467 /* 11468 User want to exit without region of interest. 11469 */ 11470 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11471 (void) XFreeCursor(display,cursor); 11472 return(MagickTrue); 11473 } 11474 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11475 do 11476 { 11477 /* 11478 Size rectangle as pointer moves until the mouse button is released. 11479 */ 11480 x=(int) roi_info.x; 11481 y=(int) roi_info.y; 11482 roi_info.width=0; 11483 roi_info.height=0; 11484 state=DefaultState; 11485 do 11486 { 11487 highlight_info=roi_info; 11488 highlight_info.x=roi_info.x-windows->image.x; 11489 highlight_info.y=roi_info.y-windows->image.y; 11490 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11491 { 11492 /* 11493 Display info and draw region of interest rectangle. 11494 */ 11495 if (windows->info.mapped == MagickFalse) 11496 (void) XMapWindow(display,windows->info.id); 11497 (void) FormatLocaleString(text,MaxTextExtent, 11498 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11499 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11500 XInfoWidget(display,windows,text); 11501 XHighlightRectangle(display,windows->image.id, 11502 windows->image.highlight_context,&highlight_info); 11503 } 11504 else 11505 if (windows->info.mapped != MagickFalse) 11506 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11507 /* 11508 Wait for next event. 11509 */ 11510 XScreenEvent(display,windows,&event); 11511 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11512 XHighlightRectangle(display,windows->image.id, 11513 windows->image.highlight_context,&highlight_info); 11514 switch (event.type) 11515 { 11516 case ButtonPress: 11517 { 11518 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11519 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11520 break; 11521 } 11522 case ButtonRelease: 11523 { 11524 /* 11525 User has committed to region of interest rectangle. 11526 */ 11527 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11528 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11529 XSetCursorState(display,windows,MagickFalse); 11530 state|=ExitState; 11531 if (LocaleCompare(windows->command.name,"Apply") == 0) 11532 break; 11533 (void) CloneString(&windows->command.name,"Apply"); 11534 windows->command.data=ApplyMenus; 11535 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL); 11536 break; 11537 } 11538 case Expose: 11539 break; 11540 case MotionNotify: 11541 { 11542 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11543 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11544 } 11545 default: 11546 break; 11547 } 11548 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) || 11549 ((state & ExitState) != 0)) 11550 { 11551 /* 11552 Check boundary conditions. 11553 */ 11554 if (roi_info.x < 0) 11555 roi_info.x=0; 11556 else 11557 if (roi_info.x > (ssize_t) windows->image.ximage->width) 11558 roi_info.x=(ssize_t) windows->image.ximage->width; 11559 if ((int) roi_info.x < x) 11560 roi_info.width=(unsigned int) (x-roi_info.x); 11561 else 11562 { 11563 roi_info.width=(unsigned int) (roi_info.x-x); 11564 roi_info.x=(ssize_t) x; 11565 } 11566 if (roi_info.y < 0) 11567 roi_info.y=0; 11568 else 11569 if (roi_info.y > (ssize_t) windows->image.ximage->height) 11570 roi_info.y=(ssize_t) windows->image.ximage->height; 11571 if ((int) roi_info.y < y) 11572 roi_info.height=(unsigned int) (y-roi_info.y); 11573 else 11574 { 11575 roi_info.height=(unsigned int) (roi_info.y-y); 11576 roi_info.y=(ssize_t) y; 11577 } 11578 } 11579 } while ((state & ExitState) == 0); 11580 /* 11581 Wait for user to grab a corner of the rectangle or press return. 11582 */ 11583 state=DefaultState; 11584 command_type=NullCommand; 11585 (void) XMapWindow(display,windows->info.id); 11586 do 11587 { 11588 if (windows->info.mapped != MagickFalse) 11589 { 11590 /* 11591 Display pointer position. 11592 */ 11593 (void) FormatLocaleString(text,MaxTextExtent, 11594 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11595 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11596 XInfoWidget(display,windows,text); 11597 } 11598 highlight_info=roi_info; 11599 highlight_info.x=roi_info.x-windows->image.x; 11600 highlight_info.y=roi_info.y-windows->image.y; 11601 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11602 { 11603 state|=EscapeState; 11604 state|=ExitState; 11605 break; 11606 } 11607 if ((state & UpdateRegionState) != 0) 11608 { 11609 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11610 switch (command_type) 11611 { 11612 case UndoCommand: 11613 case RedoCommand: 11614 { 11615 (void) XMagickCommand(display,resource_info,windows,command_type, 11616 image,exception); 11617 break; 11618 } 11619 default: 11620 { 11621 /* 11622 Region of interest is relative to image configuration. 11623 */ 11624 progress_monitor=SetImageProgressMonitor(*image, 11625 (MagickProgressMonitor) NULL,(*image)->client_data); 11626 crop_info=roi_info; 11627 width=(unsigned int) (*image)->columns; 11628 height=(unsigned int) (*image)->rows; 11629 x=0; 11630 y=0; 11631 if (windows->image.crop_geometry != (char *) NULL) 11632 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11633 &width,&height); 11634 scale_factor=(MagickRealType) width/windows->image.ximage->width; 11635 crop_info.x+=x; 11636 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11637 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11638 scale_factor=(MagickRealType) 11639 height/windows->image.ximage->height; 11640 crop_info.y+=y; 11641 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11642 crop_info.height=(unsigned int) 11643 (scale_factor*crop_info.height+0.5); 11644 roi_image=CropImage(*image,&crop_info,exception); 11645 (void) SetImageProgressMonitor(*image,progress_monitor, 11646 (*image)->client_data); 11647 if (roi_image == (Image *) NULL) 11648 continue; 11649 /* 11650 Apply image processing technique to the region of interest. 11651 */ 11652 windows->image.orphan=MagickTrue; 11653 (void) XMagickCommand(display,resource_info,windows,command_type, 11654 &roi_image,exception); 11655 progress_monitor=SetImageProgressMonitor(*image, 11656 (MagickProgressMonitor) NULL,(*image)->client_data); 11657 (void) XMagickCommand(display,resource_info,windows, 11658 SaveToUndoBufferCommand,image,exception); 11659 windows->image.orphan=MagickFalse; 11660 (void) CompositeImage(*image,CopyCompositeOp,roi_image, 11661 crop_info.x,crop_info.y,exception); 11662 roi_image=DestroyImage(roi_image); 11663 (void) SetImageProgressMonitor(*image,progress_monitor, 11664 (*image)->client_data); 11665 break; 11666 } 11667 } 11668 if (command_type != InfoCommand) 11669 { 11670 XConfigureImageColormap(display,resource_info,windows,*image); 11671 (void) XConfigureImage(display,resource_info,windows,*image,exception); 11672 } 11673 XCheckRefreshWindows(display,windows); 11674 XInfoWidget(display,windows,text); 11675 (void) XSetFunction(display,windows->image.highlight_context, 11676 GXinvert); 11677 state&=(~UpdateRegionState); 11678 } 11679 XHighlightRectangle(display,windows->image.id, 11680 windows->image.highlight_context,&highlight_info); 11681 XScreenEvent(display,windows,&event); 11682 if (event.xany.window == windows->command.id) 11683 { 11684 /* 11685 Select a command from the Command widget. 11686 */ 11687 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11688 command_type=NullCommand; 11689 id=XCommandWidget(display,windows,ApplyMenu,&event); 11690 if (id >= 0) 11691 { 11692 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent); 11693 command_type=ApplyCommands[id]; 11694 if (id < ApplyMenus) 11695 { 11696 /* 11697 Select a command from a pop-up menu. 11698 */ 11699 entry=XMenuWidget(display,windows,ApplyMenu[id], 11700 (const char **) Menus[id],command); 11701 if (entry >= 0) 11702 { 11703 (void) CopyMagickString(command,Menus[id][entry], 11704 MaxTextExtent); 11705 command_type=Commands[id][entry]; 11706 } 11707 } 11708 } 11709 (void) XSetFunction(display,windows->image.highlight_context, 11710 GXinvert); 11711 XHighlightRectangle(display,windows->image.id, 11712 windows->image.highlight_context,&highlight_info); 11713 if (command_type == HelpCommand) 11714 { 11715 (void) XSetFunction(display,windows->image.highlight_context, 11716 GXcopy); 11717 XTextViewWidget(display,resource_info,windows,MagickFalse, 11718 "Help Viewer - Region of Interest",ImageROIHelp); 11719 (void) XSetFunction(display,windows->image.highlight_context, 11720 GXinvert); 11721 continue; 11722 } 11723 if (command_type == QuitCommand) 11724 { 11725 /* 11726 exit. 11727 */ 11728 state|=EscapeState; 11729 state|=ExitState; 11730 continue; 11731 } 11732 if (command_type != NullCommand) 11733 state|=UpdateRegionState; 11734 continue; 11735 } 11736 XHighlightRectangle(display,windows->image.id, 11737 windows->image.highlight_context,&highlight_info); 11738 switch (event.type) 11739 { 11740 case ButtonPress: 11741 { 11742 x=windows->image.x; 11743 y=windows->image.y; 11744 if (event.xbutton.button != Button1) 11745 break; 11746 if (event.xbutton.window != windows->image.id) 11747 break; 11748 x=windows->image.x+event.xbutton.x; 11749 y=windows->image.y+event.xbutton.y; 11750 if ((x < (int) (roi_info.x+RoiDelta)) && 11751 (x > (int) (roi_info.x-RoiDelta)) && 11752 (y < (int) (roi_info.y+RoiDelta)) && 11753 (y > (int) (roi_info.y-RoiDelta))) 11754 { 11755 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11756 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11757 state|=UpdateConfigurationState; 11758 break; 11759 } 11760 if ((x < (int) (roi_info.x+RoiDelta)) && 11761 (x > (int) (roi_info.x-RoiDelta)) && 11762 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11763 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11764 { 11765 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11766 state|=UpdateConfigurationState; 11767 break; 11768 } 11769 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11770 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11771 (y < (int) (roi_info.y+RoiDelta)) && 11772 (y > (int) (roi_info.y-RoiDelta))) 11773 { 11774 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11775 state|=UpdateConfigurationState; 11776 break; 11777 } 11778 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11779 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11780 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11781 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11782 { 11783 state|=UpdateConfigurationState; 11784 break; 11785 } 11786 } 11787 case ButtonRelease: 11788 { 11789 if (event.xbutton.window == windows->pan.id) 11790 if ((highlight_info.x != crop_info.x-windows->image.x) || 11791 (highlight_info.y != crop_info.y-windows->image.y)) 11792 XHighlightRectangle(display,windows->image.id, 11793 windows->image.highlight_context,&highlight_info); 11794 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11795 event.xbutton.time); 11796 break; 11797 } 11798 case Expose: 11799 { 11800 if (event.xexpose.window == windows->image.id) 11801 if (event.xexpose.count == 0) 11802 { 11803 event.xexpose.x=(int) highlight_info.x; 11804 event.xexpose.y=(int) highlight_info.y; 11805 event.xexpose.width=(int) highlight_info.width; 11806 event.xexpose.height=(int) highlight_info.height; 11807 XRefreshWindow(display,&windows->image,&event); 11808 } 11809 if (event.xexpose.window == windows->info.id) 11810 if (event.xexpose.count == 0) 11811 XInfoWidget(display,windows,text); 11812 break; 11813 } 11814 case KeyPress: 11815 { 11816 KeySym 11817 key_symbol; 11818 11819 if (event.xkey.window != windows->image.id) 11820 break; 11821 /* 11822 Respond to a user key press. 11823 */ 11824 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11825 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11826 switch ((int) key_symbol) 11827 { 11828 case XK_Shift_L: 11829 case XK_Shift_R: 11830 break; 11831 case XK_Escape: 11832 case XK_F20: 11833 state|=EscapeState; 11834 case XK_Return: 11835 { 11836 state|=ExitState; 11837 break; 11838 } 11839 case XK_Home: 11840 case XK_KP_Home: 11841 { 11842 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11843 roi_info.y=(ssize_t) (windows->image.height/2L- 11844 roi_info.height/2L); 11845 break; 11846 } 11847 case XK_Left: 11848 case XK_KP_Left: 11849 { 11850 roi_info.x--; 11851 break; 11852 } 11853 case XK_Up: 11854 case XK_KP_Up: 11855 case XK_Next: 11856 { 11857 roi_info.y--; 11858 break; 11859 } 11860 case XK_Right: 11861 case XK_KP_Right: 11862 { 11863 roi_info.x++; 11864 break; 11865 } 11866 case XK_Prior: 11867 case XK_Down: 11868 case XK_KP_Down: 11869 { 11870 roi_info.y++; 11871 break; 11872 } 11873 case XK_F1: 11874 case XK_Help: 11875 { 11876 (void) XSetFunction(display,windows->image.highlight_context, 11877 GXcopy); 11878 XTextViewWidget(display,resource_info,windows,MagickFalse, 11879 "Help Viewer - Region of Interest",ImageROIHelp); 11880 (void) XSetFunction(display,windows->image.highlight_context, 11881 GXinvert); 11882 break; 11883 } 11884 default: 11885 { 11886 command_type=XImageWindowCommand(display,resource_info,windows, 11887 event.xkey.state,key_symbol,image,exception); 11888 if (command_type != NullCommand) 11889 state|=UpdateRegionState; 11890 break; 11891 } 11892 } 11893 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11894 event.xkey.time); 11895 break; 11896 } 11897 case KeyRelease: 11898 break; 11899 case MotionNotify: 11900 { 11901 if (event.xbutton.window != windows->image.id) 11902 break; 11903 /* 11904 Map and unmap Info widget as text cursor crosses its boundaries. 11905 */ 11906 x=event.xmotion.x; 11907 y=event.xmotion.y; 11908 if (windows->info.mapped != MagickFalse) 11909 { 11910 if ((x < (int) (windows->info.x+windows->info.width)) && 11911 (y < (int) (windows->info.y+windows->info.height))) 11912 (void) XWithdrawWindow(display,windows->info.id, 11913 windows->info.screen); 11914 } 11915 else 11916 if ((x > (int) (windows->info.x+windows->info.width)) || 11917 (y > (int) (windows->info.y+windows->info.height))) 11918 (void) XMapWindow(display,windows->info.id); 11919 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11920 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11921 break; 11922 } 11923 case SelectionRequest: 11924 { 11925 XSelectionEvent 11926 notify; 11927 11928 XSelectionRequestEvent 11929 *request; 11930 11931 /* 11932 Set primary selection. 11933 */ 11934 (void) FormatLocaleString(text,MaxTextExtent, 11935 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11936 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11937 request=(&(event.xselectionrequest)); 11938 (void) XChangeProperty(request->display,request->requestor, 11939 request->property,request->target,8,PropModeReplace, 11940 (unsigned char *) text,(int) strlen(text)); 11941 notify.type=SelectionNotify; 11942 notify.display=request->display; 11943 notify.requestor=request->requestor; 11944 notify.selection=request->selection; 11945 notify.target=request->target; 11946 notify.time=request->time; 11947 if (request->property == None) 11948 notify.property=request->target; 11949 else 11950 notify.property=request->property; 11951 (void) XSendEvent(request->display,request->requestor,False,0, 11952 (XEvent *) ¬ify); 11953 } 11954 default: 11955 break; 11956 } 11957 if ((state & UpdateConfigurationState) != 0) 11958 { 11959 (void) XPutBackEvent(display,&event); 11960 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11961 break; 11962 } 11963 } while ((state & ExitState) == 0); 11964 } while ((state & ExitState) == 0); 11965 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11966 XSetCursorState(display,windows,MagickFalse); 11967 if ((state & EscapeState) != 0) 11968 return(MagickTrue); 11969 return(MagickTrue); 11970} 11971 11972/* 11973%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11974% % 11975% % 11976% % 11977+ X R o t a t e I m a g e % 11978% % 11979% % 11980% % 11981%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11982% 11983% XRotateImage() rotates the X image. If the degrees parameter if zero, the 11984% rotation angle is computed from the slope of a line drawn by the user. 11985% 11986% The format of the XRotateImage method is: 11987% 11988% MagickBooleanType XRotateImage(Display *display, 11989% XResourceInfo *resource_info,XWindows *windows,double degrees, 11990% Image **image,ExceptionInfo *exception) 11991% 11992% A description of each parameter follows: 11993% 11994% o display: Specifies a connection to an X server; returned from 11995% XOpenDisplay. 11996% 11997% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11998% 11999% o windows: Specifies a pointer to a XWindows structure. 12000% 12001% o degrees: Specifies the number of degrees to rotate the image. 12002% 12003% o image: the image. 12004% 12005% o exception: return any errors or warnings in this structure. 12006% 12007*/ 12008static MagickBooleanType XRotateImage(Display *display, 12009 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image, 12010 ExceptionInfo *exception) 12011{ 12012 static const char 12013 *RotateMenu[] = 12014 { 12015 "Pixel Color", 12016 "Direction", 12017 "Help", 12018 "Dismiss", 12019 (char *) NULL 12020 }; 12021 12022 static ModeType 12023 direction = HorizontalRotateCommand; 12024 12025 static const ModeType 12026 DirectionCommands[] = 12027 { 12028 HorizontalRotateCommand, 12029 VerticalRotateCommand 12030 }, 12031 RotateCommands[] = 12032 { 12033 RotateColorCommand, 12034 RotateDirectionCommand, 12035 RotateHelpCommand, 12036 RotateDismissCommand 12037 }; 12038 12039 static unsigned int 12040 pen_id = 0; 12041 12042 char 12043 command[MaxTextExtent], 12044 text[MaxTextExtent]; 12045 12046 Image 12047 *rotate_image; 12048 12049 int 12050 id, 12051 x, 12052 y; 12053 12054 MagickRealType 12055 normalized_degrees; 12056 12057 register int 12058 i; 12059 12060 unsigned int 12061 height, 12062 rotations, 12063 width; 12064 12065 if (degrees == 0.0) 12066 { 12067 unsigned int 12068 distance; 12069 12070 size_t 12071 state; 12072 12073 XEvent 12074 event; 12075 12076 XSegment 12077 rotate_info; 12078 12079 /* 12080 Map Command widget. 12081 */ 12082 (void) CloneString(&windows->command.name,"Rotate"); 12083 windows->command.data=2; 12084 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 12085 (void) XMapRaised(display,windows->command.id); 12086 XClientMessage(display,windows->image.id,windows->im_protocols, 12087 windows->im_update_widget,CurrentTime); 12088 /* 12089 Wait for first button press. 12090 */ 12091 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12092 XQueryPosition(display,windows->image.id,&x,&y); 12093 rotate_info.x1=x; 12094 rotate_info.y1=y; 12095 rotate_info.x2=x; 12096 rotate_info.y2=y; 12097 state=DefaultState; 12098 do 12099 { 12100 XHighlightLine(display,windows->image.id, 12101 windows->image.highlight_context,&rotate_info); 12102 /* 12103 Wait for next event. 12104 */ 12105 XScreenEvent(display,windows,&event); 12106 XHighlightLine(display,windows->image.id, 12107 windows->image.highlight_context,&rotate_info); 12108 if (event.xany.window == windows->command.id) 12109 { 12110 /* 12111 Select a command from the Command widget. 12112 */ 12113 id=XCommandWidget(display,windows,RotateMenu,&event); 12114 if (id < 0) 12115 continue; 12116 (void) XSetFunction(display,windows->image.highlight_context, 12117 GXcopy); 12118 switch (RotateCommands[id]) 12119 { 12120 case RotateColorCommand: 12121 { 12122 const char 12123 *ColorMenu[MaxNumberPens]; 12124 12125 int 12126 pen_number; 12127 12128 XColor 12129 color; 12130 12131 /* 12132 Initialize menu selections. 12133 */ 12134 for (i=0; i < (int) (MaxNumberPens-2); i++) 12135 ColorMenu[i]=resource_info->pen_colors[i]; 12136 ColorMenu[MaxNumberPens-2]="Browser..."; 12137 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12138 /* 12139 Select a pen color from the pop-up menu. 12140 */ 12141 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12142 (const char **) ColorMenu,command); 12143 if (pen_number < 0) 12144 break; 12145 if (pen_number == (MaxNumberPens-2)) 12146 { 12147 static char 12148 color_name[MaxTextExtent] = "gray"; 12149 12150 /* 12151 Select a pen color from a dialog. 12152 */ 12153 resource_info->pen_colors[pen_number]=color_name; 12154 XColorBrowserWidget(display,windows,"Select",color_name); 12155 if (*color_name == '\0') 12156 break; 12157 } 12158 /* 12159 Set pen color. 12160 */ 12161 (void) XParseColor(display,windows->map_info->colormap, 12162 resource_info->pen_colors[pen_number],&color); 12163 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12164 (unsigned int) MaxColors,&color); 12165 windows->pixel_info->pen_colors[pen_number]=color; 12166 pen_id=(unsigned int) pen_number; 12167 break; 12168 } 12169 case RotateDirectionCommand: 12170 { 12171 static const char 12172 *Directions[] = 12173 { 12174 "horizontal", 12175 "vertical", 12176 (char *) NULL, 12177 }; 12178 12179 /* 12180 Select a command from the pop-up menu. 12181 */ 12182 id=XMenuWidget(display,windows,RotateMenu[id], 12183 Directions,command); 12184 if (id >= 0) 12185 direction=DirectionCommands[id]; 12186 break; 12187 } 12188 case RotateHelpCommand: 12189 { 12190 XTextViewWidget(display,resource_info,windows,MagickFalse, 12191 "Help Viewer - Image Rotation",ImageRotateHelp); 12192 break; 12193 } 12194 case RotateDismissCommand: 12195 { 12196 /* 12197 Prematurely exit. 12198 */ 12199 state|=EscapeState; 12200 state|=ExitState; 12201 break; 12202 } 12203 default: 12204 break; 12205 } 12206 (void) XSetFunction(display,windows->image.highlight_context, 12207 GXinvert); 12208 continue; 12209 } 12210 switch (event.type) 12211 { 12212 case ButtonPress: 12213 { 12214 if (event.xbutton.button != Button1) 12215 break; 12216 if (event.xbutton.window != windows->image.id) 12217 break; 12218 /* 12219 exit loop. 12220 */ 12221 (void) XSetFunction(display,windows->image.highlight_context, 12222 GXcopy); 12223 rotate_info.x1=event.xbutton.x; 12224 rotate_info.y1=event.xbutton.y; 12225 state|=ExitState; 12226 break; 12227 } 12228 case ButtonRelease: 12229 break; 12230 case Expose: 12231 break; 12232 case KeyPress: 12233 { 12234 char 12235 command[MaxTextExtent]; 12236 12237 KeySym 12238 key_symbol; 12239 12240 if (event.xkey.window != windows->image.id) 12241 break; 12242 /* 12243 Respond to a user key press. 12244 */ 12245 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12246 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12247 switch ((int) key_symbol) 12248 { 12249 case XK_Escape: 12250 case XK_F20: 12251 { 12252 /* 12253 Prematurely exit. 12254 */ 12255 state|=EscapeState; 12256 state|=ExitState; 12257 break; 12258 } 12259 case XK_F1: 12260 case XK_Help: 12261 { 12262 (void) XSetFunction(display,windows->image.highlight_context, 12263 GXcopy); 12264 XTextViewWidget(display,resource_info,windows,MagickFalse, 12265 "Help Viewer - Image Rotation",ImageRotateHelp); 12266 (void) XSetFunction(display,windows->image.highlight_context, 12267 GXinvert); 12268 break; 12269 } 12270 default: 12271 { 12272 (void) XBell(display,0); 12273 break; 12274 } 12275 } 12276 break; 12277 } 12278 case MotionNotify: 12279 { 12280 rotate_info.x1=event.xmotion.x; 12281 rotate_info.y1=event.xmotion.y; 12282 } 12283 } 12284 rotate_info.x2=rotate_info.x1; 12285 rotate_info.y2=rotate_info.y1; 12286 if (direction == HorizontalRotateCommand) 12287 rotate_info.x2+=32; 12288 else 12289 rotate_info.y2-=32; 12290 } while ((state & ExitState) == 0); 12291 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12292 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12293 if ((state & EscapeState) != 0) 12294 return(MagickTrue); 12295 /* 12296 Draw line as pointer moves until the mouse button is released. 12297 */ 12298 distance=0; 12299 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12300 state=DefaultState; 12301 do 12302 { 12303 if (distance > 9) 12304 { 12305 /* 12306 Display info and draw rotation line. 12307 */ 12308 if (windows->info.mapped == MagickFalse) 12309 (void) XMapWindow(display,windows->info.id); 12310 (void) FormatLocaleString(text,MaxTextExtent," %g", 12311 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12312 XInfoWidget(display,windows,text); 12313 XHighlightLine(display,windows->image.id, 12314 windows->image.highlight_context,&rotate_info); 12315 } 12316 else 12317 if (windows->info.mapped != MagickFalse) 12318 (void) XWithdrawWindow(display,windows->info.id, 12319 windows->info.screen); 12320 /* 12321 Wait for next event. 12322 */ 12323 XScreenEvent(display,windows,&event); 12324 if (distance > 9) 12325 XHighlightLine(display,windows->image.id, 12326 windows->image.highlight_context,&rotate_info); 12327 switch (event.type) 12328 { 12329 case ButtonPress: 12330 break; 12331 case ButtonRelease: 12332 { 12333 /* 12334 User has committed to rotation line. 12335 */ 12336 rotate_info.x2=event.xbutton.x; 12337 rotate_info.y2=event.xbutton.y; 12338 state|=ExitState; 12339 break; 12340 } 12341 case Expose: 12342 break; 12343 case MotionNotify: 12344 { 12345 rotate_info.x2=event.xmotion.x; 12346 rotate_info.y2=event.xmotion.y; 12347 } 12348 default: 12349 break; 12350 } 12351 /* 12352 Check boundary conditions. 12353 */ 12354 if (rotate_info.x2 < 0) 12355 rotate_info.x2=0; 12356 else 12357 if (rotate_info.x2 > (int) windows->image.width) 12358 rotate_info.x2=(short) windows->image.width; 12359 if (rotate_info.y2 < 0) 12360 rotate_info.y2=0; 12361 else 12362 if (rotate_info.y2 > (int) windows->image.height) 12363 rotate_info.y2=(short) windows->image.height; 12364 /* 12365 Compute rotation angle from the slope of the line. 12366 */ 12367 degrees=0.0; 12368 distance=(unsigned int) 12369 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12370 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12371 if (distance > 9) 12372 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12373 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12374 } while ((state & ExitState) == 0); 12375 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12376 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12377 if (distance <= 9) 12378 return(MagickTrue); 12379 } 12380 if (direction == VerticalRotateCommand) 12381 degrees-=90.0; 12382 if (degrees == 0.0) 12383 return(MagickTrue); 12384 /* 12385 Rotate image. 12386 */ 12387 normalized_degrees=degrees; 12388 while (normalized_degrees < -45.0) 12389 normalized_degrees+=360.0; 12390 for (rotations=0; normalized_degrees > 45.0; rotations++) 12391 normalized_degrees-=90.0; 12392 if (normalized_degrees != 0.0) 12393 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 12394 exception); 12395 XSetCursorState(display,windows,MagickTrue); 12396 XCheckRefreshWindows(display,windows); 12397 (*image)->background_color.red=ScaleShortToQuantum( 12398 windows->pixel_info->pen_colors[pen_id].red); 12399 (*image)->background_color.green=ScaleShortToQuantum( 12400 windows->pixel_info->pen_colors[pen_id].green); 12401 (*image)->background_color.blue=ScaleShortToQuantum( 12402 windows->pixel_info->pen_colors[pen_id].blue); 12403 rotate_image=RotateImage(*image,degrees,exception); 12404 XSetCursorState(display,windows,MagickFalse); 12405 if (rotate_image == (Image *) NULL) 12406 return(MagickFalse); 12407 *image=DestroyImage(*image); 12408 *image=rotate_image; 12409 if (windows->image.crop_geometry != (char *) NULL) 12410 { 12411 /* 12412 Rotate crop geometry. 12413 */ 12414 width=(unsigned int) (*image)->columns; 12415 height=(unsigned int) (*image)->rows; 12416 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12417 switch (rotations % 4) 12418 { 12419 default: 12420 case 0: 12421 break; 12422 case 1: 12423 { 12424 /* 12425 Rotate 90 degrees. 12426 */ 12427 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12428 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12429 (int) height-y,x); 12430 break; 12431 } 12432 case 2: 12433 { 12434 /* 12435 Rotate 180 degrees. 12436 */ 12437 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12438 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12439 break; 12440 } 12441 case 3: 12442 { 12443 /* 12444 Rotate 270 degrees. 12445 */ 12446 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12447 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12448 break; 12449 } 12450 } 12451 } 12452 if (windows->image.orphan != MagickFalse) 12453 return(MagickTrue); 12454 if (normalized_degrees != 0.0) 12455 { 12456 /* 12457 Update image colormap. 12458 */ 12459 windows->image.window_changes.width=(int) (*image)->columns; 12460 windows->image.window_changes.height=(int) (*image)->rows; 12461 if (windows->image.crop_geometry != (char *) NULL) 12462 { 12463 /* 12464 Obtain dimensions of image from crop geometry. 12465 */ 12466 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12467 &width,&height); 12468 windows->image.window_changes.width=(int) width; 12469 windows->image.window_changes.height=(int) height; 12470 } 12471 XConfigureImageColormap(display,resource_info,windows,*image); 12472 } 12473 else 12474 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12475 { 12476 windows->image.window_changes.width=windows->image.ximage->height; 12477 windows->image.window_changes.height=windows->image.ximage->width; 12478 } 12479 /* 12480 Update image configuration. 12481 */ 12482 (void) XConfigureImage(display,resource_info,windows,*image,exception); 12483 return(MagickTrue); 12484} 12485 12486/* 12487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12488% % 12489% % 12490% % 12491+ X S a v e I m a g e % 12492% % 12493% % 12494% % 12495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12496% 12497% XSaveImage() saves an image to a file. 12498% 12499% The format of the XSaveImage method is: 12500% 12501% MagickBooleanType XSaveImage(Display *display, 12502% XResourceInfo *resource_info,XWindows *windows,Image *image, 12503% ExceptionInfo *exception) 12504% 12505% A description of each parameter follows: 12506% 12507% o display: Specifies a connection to an X server; returned from 12508% XOpenDisplay. 12509% 12510% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12511% 12512% o windows: Specifies a pointer to a XWindows structure. 12513% 12514% o image: the image. 12515% 12516% o exception: return any errors or warnings in this structure. 12517% 12518*/ 12519static MagickBooleanType XSaveImage(Display *display, 12520 XResourceInfo *resource_info,XWindows *windows,Image *image, 12521 ExceptionInfo *exception) 12522{ 12523 char 12524 filename[MaxTextExtent], 12525 geometry[MaxTextExtent]; 12526 12527 Image 12528 *save_image; 12529 12530 ImageInfo 12531 *image_info; 12532 12533 MagickStatusType 12534 status; 12535 12536 /* 12537 Request file name from user. 12538 */ 12539 if (resource_info->write_filename != (char *) NULL) 12540 (void) CopyMagickString(filename,resource_info->write_filename, 12541 MaxTextExtent); 12542 else 12543 { 12544 char 12545 path[MaxTextExtent]; 12546 12547 int 12548 status; 12549 12550 GetPathComponent(image->filename,HeadPath,path); 12551 GetPathComponent(image->filename,TailPath,filename); 12552 if (*path != '\0') 12553 { 12554 status=chdir(path); 12555 if (status == -1) 12556 (void) ThrowMagickException(exception,GetMagickModule(), 12557 FileOpenError,"UnableToOpenFile","%s",path); 12558 } 12559 } 12560 XFileBrowserWidget(display,windows,"Save",filename); 12561 if (*filename == '\0') 12562 return(MagickTrue); 12563 if (IsPathAccessible(filename) != MagickFalse) 12564 { 12565 int 12566 status; 12567 12568 /* 12569 File exists-- seek user's permission before overwriting. 12570 */ 12571 status=XConfirmWidget(display,windows,"Overwrite",filename); 12572 if (status <= 0) 12573 return(MagickTrue); 12574 } 12575 image_info=CloneImageInfo(resource_info->image_info); 12576 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 12577 (void) SetImageInfo(image_info,1,exception); 12578 if ((LocaleCompare(image_info->magick,"JPEG") == 0) || 12579 (LocaleCompare(image_info->magick,"JPG") == 0)) 12580 { 12581 char 12582 quality[MaxTextExtent]; 12583 12584 int 12585 status; 12586 12587 /* 12588 Request JPEG quality from user. 12589 */ 12590 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double) 12591 image->quality); 12592 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", 12593 quality); 12594 if (*quality == '\0') 12595 return(MagickTrue); 12596 image->quality=StringToUnsignedLong(quality); 12597 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace; 12598 } 12599 if ((LocaleCompare(image_info->magick,"EPS") == 0) || 12600 (LocaleCompare(image_info->magick,"PDF") == 0) || 12601 (LocaleCompare(image_info->magick,"PS") == 0) || 12602 (LocaleCompare(image_info->magick,"PS2") == 0)) 12603 { 12604 char 12605 geometry[MaxTextExtent]; 12606 12607 /* 12608 Request page geometry from user. 12609 */ 12610 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12611 if (LocaleCompare(image_info->magick,"PDF") == 0) 12612 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12613 if (image_info->page != (char *) NULL) 12614 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 12615 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 12616 "Select page geometry:",geometry); 12617 if (*geometry != '\0') 12618 image_info->page=GetPageGeometry(geometry); 12619 } 12620 /* 12621 Apply image transforms. 12622 */ 12623 XSetCursorState(display,windows,MagickTrue); 12624 XCheckRefreshWindows(display,windows); 12625 save_image=CloneImage(image,0,0,MagickTrue,exception); 12626 if (save_image == (Image *) NULL) 12627 return(MagickFalse); 12628 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 12629 windows->image.ximage->width,windows->image.ximage->height); 12630 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry, 12631 exception); 12632 /* 12633 Write image. 12634 */ 12635 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent); 12636 status=WriteImage(image_info,save_image,exception); 12637 if (status != MagickFalse) 12638 image->taint=MagickFalse; 12639 save_image=DestroyImage(save_image); 12640 image_info=DestroyImageInfo(image_info); 12641 XSetCursorState(display,windows,MagickFalse); 12642 return(status != 0 ? MagickTrue : MagickFalse); 12643} 12644 12645/* 12646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12647% % 12648% % 12649% % 12650+ X S c r e e n E v e n t % 12651% % 12652% % 12653% % 12654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12655% 12656% XScreenEvent() handles global events associated with the Pan and Magnify 12657% windows. 12658% 12659% The format of the XScreenEvent function is: 12660% 12661% void XScreenEvent(Display *display,XWindows *windows,XEvent *event) 12662% 12663% A description of each parameter follows: 12664% 12665% o display: Specifies a pointer to the Display structure; returned from 12666% XOpenDisplay. 12667% 12668% o windows: Specifies a pointer to a XWindows structure. 12669% 12670% o event: Specifies a pointer to a X11 XEvent structure. 12671% 12672% 12673*/ 12674 12675#if defined(__cplusplus) || defined(c_plusplus) 12676extern "C" { 12677#endif 12678 12679static int XPredicate(Display *magick_unused(display),XEvent *event,char *data) 12680{ 12681 register XWindows 12682 *windows; 12683 12684 windows=(XWindows *) data; 12685 if ((event->type == ClientMessage) && 12686 (event->xclient.window == windows->image.id)) 12687 return(MagickFalse); 12688 return(MagickTrue); 12689} 12690 12691#if defined(__cplusplus) || defined(c_plusplus) 12692} 12693#endif 12694 12695static void XScreenEvent(Display *display,XWindows *windows,XEvent *event) 12696{ 12697 register int 12698 x, 12699 y; 12700 12701 (void) XIfEvent(display,event,XPredicate,(char *) windows); 12702 if (event->xany.window == windows->command.id) 12703 return; 12704 switch (event->type) 12705 { 12706 case ButtonPress: 12707 case ButtonRelease: 12708 { 12709 if ((event->xbutton.button == Button3) && 12710 (event->xbutton.state & Mod1Mask)) 12711 { 12712 /* 12713 Convert Alt-Button3 to Button2. 12714 */ 12715 event->xbutton.button=Button2; 12716 event->xbutton.state&=(~Mod1Mask); 12717 } 12718 if (event->xbutton.window == windows->backdrop.id) 12719 { 12720 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent, 12721 event->xbutton.time); 12722 break; 12723 } 12724 if (event->xbutton.window == windows->pan.id) 12725 { 12726 XPanImage(display,windows,event); 12727 break; 12728 } 12729 if (event->xbutton.window == windows->image.id) 12730 if (event->xbutton.button == Button2) 12731 { 12732 /* 12733 Update magnified image. 12734 */ 12735 x=event->xbutton.x; 12736 y=event->xbutton.y; 12737 if (x < 0) 12738 x=0; 12739 else 12740 if (x >= (int) windows->image.width) 12741 x=(int) (windows->image.width-1); 12742 windows->magnify.x=(int) windows->image.x+x; 12743 if (y < 0) 12744 y=0; 12745 else 12746 if (y >= (int) windows->image.height) 12747 y=(int) (windows->image.height-1); 12748 windows->magnify.y=windows->image.y+y; 12749 if (windows->magnify.mapped == MagickFalse) 12750 (void) XMapRaised(display,windows->magnify.id); 12751 XMakeMagnifyImage(display,windows); 12752 if (event->type == ButtonRelease) 12753 (void) XWithdrawWindow(display,windows->info.id, 12754 windows->info.screen); 12755 break; 12756 } 12757 break; 12758 } 12759 case ClientMessage: 12760 { 12761 /* 12762 If client window delete message, exit. 12763 */ 12764 if (event->xclient.message_type != windows->wm_protocols) 12765 break; 12766 if (*event->xclient.data.l != (long) windows->wm_delete_window) 12767 break; 12768 if (event->xclient.window == windows->magnify.id) 12769 { 12770 (void) XWithdrawWindow(display,windows->magnify.id, 12771 windows->magnify.screen); 12772 break; 12773 } 12774 break; 12775 } 12776 case ConfigureNotify: 12777 { 12778 if (event->xconfigure.window == windows->magnify.id) 12779 { 12780 unsigned int 12781 magnify; 12782 12783 /* 12784 Magnify window has a new configuration. 12785 */ 12786 windows->magnify.width=(unsigned int) event->xconfigure.width; 12787 windows->magnify.height=(unsigned int) event->xconfigure.height; 12788 if (windows->magnify.mapped == MagickFalse) 12789 break; 12790 magnify=1; 12791 while ((int) magnify <= event->xconfigure.width) 12792 magnify<<=1; 12793 while ((int) magnify <= event->xconfigure.height) 12794 magnify<<=1; 12795 magnify>>=1; 12796 if (((int) magnify != event->xconfigure.width) || 12797 ((int) magnify != event->xconfigure.height)) 12798 { 12799 XWindowChanges 12800 window_changes; 12801 12802 window_changes.width=(int) magnify; 12803 window_changes.height=(int) magnify; 12804 (void) XReconfigureWMWindow(display,windows->magnify.id, 12805 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 12806 &window_changes); 12807 break; 12808 } 12809 XMakeMagnifyImage(display,windows); 12810 break; 12811 } 12812 break; 12813 } 12814 case Expose: 12815 { 12816 if (event->xexpose.window == windows->image.id) 12817 { 12818 XRefreshWindow(display,&windows->image,event); 12819 break; 12820 } 12821 if (event->xexpose.window == windows->pan.id) 12822 if (event->xexpose.count == 0) 12823 { 12824 XDrawPanRectangle(display,windows); 12825 break; 12826 } 12827 if (event->xexpose.window == windows->magnify.id) 12828 if (event->xexpose.count == 0) 12829 { 12830 XMakeMagnifyImage(display,windows); 12831 break; 12832 } 12833 break; 12834 } 12835 case KeyPress: 12836 { 12837 char 12838 command[MaxTextExtent]; 12839 12840 KeySym 12841 key_symbol; 12842 12843 if (event->xkey.window != windows->magnify.id) 12844 break; 12845 /* 12846 Respond to a user key press. 12847 */ 12848 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int) 12849 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12850 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol); 12851 break; 12852 } 12853 case MapNotify: 12854 { 12855 if (event->xmap.window == windows->magnify.id) 12856 { 12857 windows->magnify.mapped=MagickTrue; 12858 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12859 break; 12860 } 12861 if (event->xmap.window == windows->info.id) 12862 { 12863 windows->info.mapped=MagickTrue; 12864 break; 12865 } 12866 break; 12867 } 12868 case MotionNotify: 12869 { 12870 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; 12871 if (event->xmotion.window == windows->image.id) 12872 if (windows->magnify.mapped != MagickFalse) 12873 { 12874 /* 12875 Update magnified image. 12876 */ 12877 x=event->xmotion.x; 12878 y=event->xmotion.y; 12879 if (x < 0) 12880 x=0; 12881 else 12882 if (x >= (int) windows->image.width) 12883 x=(int) (windows->image.width-1); 12884 windows->magnify.x=(int) windows->image.x+x; 12885 if (y < 0) 12886 y=0; 12887 else 12888 if (y >= (int) windows->image.height) 12889 y=(int) (windows->image.height-1); 12890 windows->magnify.y=windows->image.y+y; 12891 XMakeMagnifyImage(display,windows); 12892 } 12893 break; 12894 } 12895 case UnmapNotify: 12896 { 12897 if (event->xunmap.window == windows->magnify.id) 12898 { 12899 windows->magnify.mapped=MagickFalse; 12900 break; 12901 } 12902 if (event->xunmap.window == windows->info.id) 12903 { 12904 windows->info.mapped=MagickFalse; 12905 break; 12906 } 12907 break; 12908 } 12909 default: 12910 break; 12911 } 12912} 12913 12914/* 12915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12916% % 12917% % 12918% % 12919+ X S e t C r o p G e o m e t r y % 12920% % 12921% % 12922% % 12923%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12924% 12925% XSetCropGeometry() accepts a cropping geometry relative to the Image window 12926% and translates it to a cropping geometry relative to the image. 12927% 12928% The format of the XSetCropGeometry method is: 12929% 12930% void XSetCropGeometry(Display *display,XWindows *windows, 12931% RectangleInfo *crop_info,Image *image) 12932% 12933% A description of each parameter follows: 12934% 12935% o display: Specifies a connection to an X server; returned from 12936% XOpenDisplay. 12937% 12938% o windows: Specifies a pointer to a XWindows structure. 12939% 12940% o crop_info: A pointer to a RectangleInfo that defines a region of the 12941% Image window to crop. 12942% 12943% o image: the image. 12944% 12945*/ 12946static void XSetCropGeometry(Display *display,XWindows *windows, 12947 RectangleInfo *crop_info,Image *image) 12948{ 12949 char 12950 text[MaxTextExtent]; 12951 12952 int 12953 x, 12954 y; 12955 12956 MagickRealType 12957 scale_factor; 12958 12959 unsigned int 12960 height, 12961 width; 12962 12963 if (windows->info.mapped != MagickFalse) 12964 { 12965 /* 12966 Display info on cropping rectangle. 12967 */ 12968 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g", 12969 (double) crop_info->width,(double) crop_info->height,(double) 12970 crop_info->x,(double) crop_info->y); 12971 XInfoWidget(display,windows,text); 12972 } 12973 /* 12974 Cropping geometry is relative to any previous crop geometry. 12975 */ 12976 x=0; 12977 y=0; 12978 width=(unsigned int) image->columns; 12979 height=(unsigned int) image->rows; 12980 if (windows->image.crop_geometry != (char *) NULL) 12981 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12982 else 12983 windows->image.crop_geometry=AcquireString((char *) NULL); 12984 /* 12985 Define the crop geometry string from the cropping rectangle. 12986 */ 12987 scale_factor=(MagickRealType) width/windows->image.ximage->width; 12988 if (crop_info->x > 0) 12989 x+=(int) (scale_factor*crop_info->x+0.5); 12990 width=(unsigned int) (scale_factor*crop_info->width+0.5); 12991 if (width == 0) 12992 width=1; 12993 scale_factor=(MagickRealType) height/windows->image.ximage->height; 12994 if (crop_info->y > 0) 12995 y+=(int) (scale_factor*crop_info->y+0.5); 12996 height=(unsigned int) (scale_factor*crop_info->height+0.5); 12997 if (height == 0) 12998 height=1; 12999 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 13000 "%ux%u%+d%+d",width,height,x,y); 13001} 13002 13003/* 13004%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13005% % 13006% % 13007% % 13008+ X T i l e I m a g e % 13009% % 13010% % 13011% % 13012%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13013% 13014% XTileImage() loads or deletes a selected tile from a visual image directory. 13015% The load or delete command is chosen from a menu. 13016% 13017% The format of the XTileImage method is: 13018% 13019% Image *XTileImage(Display *display,XResourceInfo *resource_info, 13020% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13021% 13022% A description of each parameter follows: 13023% 13024% o tile_image: XTileImage reads or deletes the tile image 13025% and returns it. A null image is returned if an error occurs. 13026% 13027% o display: Specifies a connection to an X server; returned from 13028% XOpenDisplay. 13029% 13030% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13031% 13032% o windows: Specifies a pointer to a XWindows structure. 13033% 13034% o image: the image; returned from ReadImage. 13035% 13036% o event: Specifies a pointer to a XEvent structure. If it is NULL, 13037% the entire image is refreshed. 13038% 13039% o exception: return any errors or warnings in this structure. 13040% 13041*/ 13042static Image *XTileImage(Display *display,XResourceInfo *resource_info, 13043 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13044{ 13045 static const char 13046 *VerbMenu[] = 13047 { 13048 "Load", 13049 "Next", 13050 "Former", 13051 "Delete", 13052 "Update", 13053 (char *) NULL, 13054 }; 13055 13056 static const ModeType 13057 TileCommands[] = 13058 { 13059 TileLoadCommand, 13060 TileNextCommand, 13061 TileFormerCommand, 13062 TileDeleteCommand, 13063 TileUpdateCommand 13064 }; 13065 13066 char 13067 command[MaxTextExtent], 13068 filename[MaxTextExtent]; 13069 13070 Image 13071 *tile_image; 13072 13073 int 13074 id, 13075 status, 13076 tile, 13077 x, 13078 y; 13079 13080 MagickRealType 13081 scale_factor; 13082 13083 register char 13084 *p, 13085 *q; 13086 13087 register int 13088 i; 13089 13090 unsigned int 13091 height, 13092 width; 13093 13094 /* 13095 Tile image is relative to montage image configuration. 13096 */ 13097 x=0; 13098 y=0; 13099 width=(unsigned int) image->columns; 13100 height=(unsigned int) image->rows; 13101 if (windows->image.crop_geometry != (char *) NULL) 13102 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13103 scale_factor=(MagickRealType) width/windows->image.ximage->width; 13104 event->xbutton.x+=windows->image.x; 13105 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5); 13106 scale_factor=(MagickRealType) height/windows->image.ximage->height; 13107 event->xbutton.y+=windows->image.y; 13108 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5); 13109 /* 13110 Determine size and location of each tile in the visual image directory. 13111 */ 13112 width=(unsigned int) image->columns; 13113 height=(unsigned int) image->rows; 13114 x=0; 13115 y=0; 13116 (void) XParseGeometry(image->montage,&x,&y,&width,&height); 13117 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+ 13118 (event->xbutton.x-x)/width; 13119 if (tile < 0) 13120 { 13121 /* 13122 Button press is outside any tile. 13123 */ 13124 (void) XBell(display,0); 13125 return((Image *) NULL); 13126 } 13127 /* 13128 Determine file name from the tile directory. 13129 */ 13130 p=image->directory; 13131 for (i=tile; (i != 0) && (*p != '\0'); ) 13132 { 13133 if (*p == '\n') 13134 i--; 13135 p++; 13136 } 13137 if (*p == '\0') 13138 { 13139 /* 13140 Button press is outside any tile. 13141 */ 13142 (void) XBell(display,0); 13143 return((Image *) NULL); 13144 } 13145 /* 13146 Select a command from the pop-up menu. 13147 */ 13148 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command); 13149 if (id < 0) 13150 return((Image *) NULL); 13151 q=p; 13152 while ((*q != '\n') && (*q != '\0')) 13153 q++; 13154 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13155 /* 13156 Perform command for the selected tile. 13157 */ 13158 XSetCursorState(display,windows,MagickTrue); 13159 XCheckRefreshWindows(display,windows); 13160 tile_image=NewImageList(); 13161 switch (TileCommands[id]) 13162 { 13163 case TileLoadCommand: 13164 { 13165 /* 13166 Load tile image. 13167 */ 13168 XCheckRefreshWindows(display,windows); 13169 (void) CopyMagickString(resource_info->image_info->magick,"MIFF", 13170 MaxTextExtent); 13171 (void) CopyMagickString(resource_info->image_info->filename,filename, 13172 MaxTextExtent); 13173 tile_image=ReadImage(resource_info->image_info,exception); 13174 CatchException(exception); 13175 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13176 break; 13177 } 13178 case TileNextCommand: 13179 { 13180 /* 13181 Display next image. 13182 */ 13183 XClientMessage(display,windows->image.id,windows->im_protocols, 13184 windows->im_next_image,CurrentTime); 13185 break; 13186 } 13187 case TileFormerCommand: 13188 { 13189 /* 13190 Display former image. 13191 */ 13192 XClientMessage(display,windows->image.id,windows->im_protocols, 13193 windows->im_former_image,CurrentTime); 13194 break; 13195 } 13196 case TileDeleteCommand: 13197 { 13198 /* 13199 Delete tile image. 13200 */ 13201 if (IsPathAccessible(filename) == MagickFalse) 13202 { 13203 XNoticeWidget(display,windows,"Image file does not exist:",filename); 13204 break; 13205 } 13206 status=XConfirmWidget(display,windows,"Really delete tile",filename); 13207 if (status <= 0) 13208 break; 13209 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse; 13210 if (status != MagickFalse) 13211 { 13212 XNoticeWidget(display,windows,"Unable to delete image file:", 13213 filename); 13214 break; 13215 } 13216 } 13217 case TileUpdateCommand: 13218 { 13219 int 13220 x_offset, 13221 y_offset; 13222 13223 PixelInfo 13224 pixel; 13225 13226 Quantum 13227 virtual_pixel[MaxPixelChannels]; 13228 13229 register int 13230 j; 13231 13232 register Quantum 13233 *s; 13234 13235 /* 13236 Ensure all the images exist. 13237 */ 13238 tile=0; 13239 GetPixelInfo(image,&pixel); 13240 for (p=image->directory; *p != '\0'; p++) 13241 { 13242 CacheView 13243 *image_view; 13244 13245 q=p; 13246 while ((*q != '\n') && (*q != '\0')) 13247 q++; 13248 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13249 p=q; 13250 if (IsPathAccessible(filename) != MagickFalse) 13251 { 13252 tile++; 13253 continue; 13254 } 13255 /* 13256 Overwrite tile with background color. 13257 */ 13258 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x); 13259 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y); 13260 image_view=AcquireCacheView(image); 13261 (void) GetOneCacheViewVirtualPixel(image_view,0,0,virtual_pixel, 13262 exception); 13263 pixel.red=virtual_pixel[RedPixelChannel]; 13264 pixel.green=virtual_pixel[GreenPixelChannel]; 13265 pixel.blue=virtual_pixel[BluePixelChannel]; 13266 pixel.alpha=virtual_pixel[AlphaPixelChannel]; 13267 for (i=0; i < (int) height; i++) 13268 { 13269 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t) 13270 y_offset+i,width,1,exception); 13271 if (s == (Quantum *) NULL) 13272 break; 13273 for (j=0; j < (int) width; j++) 13274 { 13275 SetPixelPixelInfo(image,&pixel,s); 13276 s+=GetPixelChannels(image); 13277 } 13278 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 13279 break; 13280 } 13281 image_view=DestroyCacheView(image_view); 13282 tile++; 13283 } 13284 windows->image.window_changes.width=(int) image->columns; 13285 windows->image.window_changes.height=(int) image->rows; 13286 XConfigureImageColormap(display,resource_info,windows,image); 13287 (void) XConfigureImage(display,resource_info,windows,image,exception); 13288 break; 13289 } 13290 default: 13291 break; 13292 } 13293 XSetCursorState(display,windows,MagickFalse); 13294 return(tile_image); 13295} 13296 13297/* 13298%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13299% % 13300% % 13301% % 13302+ X T r a n s l a t e I m a g e % 13303% % 13304% % 13305% % 13306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13307% 13308% XTranslateImage() translates the image within an Image window by one pixel 13309% as specified by the key symbol. If the image has a `montage string the 13310% translation is respect to the width and height contained within the string. 13311% 13312% The format of the XTranslateImage method is: 13313% 13314% void XTranslateImage(Display *display,XWindows *windows, 13315% Image *image,const KeySym key_symbol) 13316% 13317% A description of each parameter follows: 13318% 13319% o display: Specifies a connection to an X server; returned from 13320% XOpenDisplay. 13321% 13322% o windows: Specifies a pointer to a XWindows structure. 13323% 13324% o image: the image. 13325% 13326% o key_symbol: Specifies a KeySym which indicates which side of the image 13327% to trim. 13328% 13329*/ 13330static void XTranslateImage(Display *display,XWindows *windows, 13331 Image *image,const KeySym key_symbol) 13332{ 13333 char 13334 text[MaxTextExtent]; 13335 13336 int 13337 x, 13338 y; 13339 13340 unsigned int 13341 x_offset, 13342 y_offset; 13343 13344 /* 13345 User specified a pan position offset. 13346 */ 13347 x_offset=windows->image.width; 13348 y_offset=windows->image.height; 13349 if (image->montage != (char *) NULL) 13350 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset); 13351 switch ((int) key_symbol) 13352 { 13353 case XK_Home: 13354 case XK_KP_Home: 13355 { 13356 windows->image.x=(int) windows->image.width/2; 13357 windows->image.y=(int) windows->image.height/2; 13358 break; 13359 } 13360 case XK_Left: 13361 case XK_KP_Left: 13362 { 13363 windows->image.x-=x_offset; 13364 break; 13365 } 13366 case XK_Next: 13367 case XK_Up: 13368 case XK_KP_Up: 13369 { 13370 windows->image.y-=y_offset; 13371 break; 13372 } 13373 case XK_Right: 13374 case XK_KP_Right: 13375 { 13376 windows->image.x+=x_offset; 13377 break; 13378 } 13379 case XK_Prior: 13380 case XK_Down: 13381 case XK_KP_Down: 13382 { 13383 windows->image.y+=y_offset; 13384 break; 13385 } 13386 default: 13387 return; 13388 } 13389 /* 13390 Check boundary conditions. 13391 */ 13392 if (windows->image.x < 0) 13393 windows->image.x=0; 13394 else 13395 if ((int) (windows->image.x+windows->image.width) > 13396 windows->image.ximage->width) 13397 windows->image.x=(int) windows->image.ximage->width-windows->image.width; 13398 if (windows->image.y < 0) 13399 windows->image.y=0; 13400 else 13401 if ((int) (windows->image.y+windows->image.height) > 13402 windows->image.ximage->height) 13403 windows->image.y=(int) windows->image.ximage->height-windows->image.height; 13404 /* 13405 Refresh Image window. 13406 */ 13407 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 13408 windows->image.width,windows->image.height,windows->image.x, 13409 windows->image.y); 13410 XInfoWidget(display,windows,text); 13411 XCheckRefreshWindows(display,windows); 13412 XDrawPanRectangle(display,windows); 13413 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 13414 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13415} 13416 13417/* 13418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13419% % 13420% % 13421% % 13422+ X T r i m I m a g e % 13423% % 13424% % 13425% % 13426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13427% 13428% XTrimImage() trims the edges from the Image window. 13429% 13430% The format of the XTrimImage method is: 13431% 13432% MagickBooleanType XTrimImage(Display *display, 13433% XResourceInfo *resource_info,XWindows *windows,Image *image, 13434% ExceptionInfo *exception) 13435% 13436% A description of each parameter follows: 13437% 13438% o display: Specifies a connection to an X server; returned from 13439% XOpenDisplay. 13440% 13441% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13442% 13443% o windows: Specifies a pointer to a XWindows structure. 13444% 13445% o image: the image. 13446% 13447% o exception: return any errors or warnings in this structure. 13448% 13449*/ 13450static MagickBooleanType XTrimImage(Display *display, 13451 XResourceInfo *resource_info,XWindows *windows,Image *image, 13452 ExceptionInfo *exception) 13453{ 13454 RectangleInfo 13455 trim_info; 13456 13457 register int 13458 x, 13459 y; 13460 13461 size_t 13462 background, 13463 pixel; 13464 13465 /* 13466 Trim edges from image. 13467 */ 13468 XSetCursorState(display,windows,MagickTrue); 13469 XCheckRefreshWindows(display,windows); 13470 /* 13471 Crop the left edge. 13472 */ 13473 background=XGetPixel(windows->image.ximage,0,0); 13474 trim_info.width=(size_t) windows->image.ximage->width; 13475 for (x=0; x < windows->image.ximage->width; x++) 13476 { 13477 for (y=0; y < windows->image.ximage->height; y++) 13478 { 13479 pixel=XGetPixel(windows->image.ximage,x,y); 13480 if (pixel != background) 13481 break; 13482 } 13483 if (y < windows->image.ximage->height) 13484 break; 13485 } 13486 trim_info.x=(ssize_t) x; 13487 if (trim_info.x == (ssize_t) windows->image.ximage->width) 13488 { 13489 XSetCursorState(display,windows,MagickFalse); 13490 return(MagickFalse); 13491 } 13492 /* 13493 Crop the right edge. 13494 */ 13495 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0); 13496 for (x=windows->image.ximage->width-1; x != 0; 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.width=(size_t) (x-trim_info.x+1); 13508 /* 13509 Crop the top edge. 13510 */ 13511 background=XGetPixel(windows->image.ximage,0,0); 13512 trim_info.height=(size_t) windows->image.ximage->height; 13513 for (y=0; y < windows->image.ximage->height; y++) 13514 { 13515 for (x=0; x < windows->image.ximage->width; x++) 13516 { 13517 pixel=XGetPixel(windows->image.ximage,x,y); 13518 if (pixel != background) 13519 break; 13520 } 13521 if (x < windows->image.ximage->width) 13522 break; 13523 } 13524 trim_info.y=(ssize_t) y; 13525 /* 13526 Crop the bottom edge. 13527 */ 13528 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1); 13529 for (y=windows->image.ximage->height-1; y != 0; y--) 13530 { 13531 for (x=0; x < windows->image.ximage->width; x++) 13532 { 13533 pixel=XGetPixel(windows->image.ximage,x,y); 13534 if (pixel != background) 13535 break; 13536 } 13537 if (x < windows->image.ximage->width) 13538 break; 13539 } 13540 trim_info.height=(size_t) y-trim_info.y+1; 13541 if (((unsigned int) trim_info.width != windows->image.width) || 13542 ((unsigned int) trim_info.height != windows->image.height)) 13543 { 13544 /* 13545 Reconfigure Image window as defined by the trimming rectangle. 13546 */ 13547 XSetCropGeometry(display,windows,&trim_info,image); 13548 windows->image.window_changes.width=(int) trim_info.width; 13549 windows->image.window_changes.height=(int) trim_info.height; 13550 (void) XConfigureImage(display,resource_info,windows,image,exception); 13551 } 13552 XSetCursorState(display,windows,MagickFalse); 13553 return(MagickTrue); 13554} 13555 13556/* 13557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13558% % 13559% % 13560% % 13561+ X V i s u a l D i r e c t o r y I m a g e % 13562% % 13563% % 13564% % 13565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13566% 13567% XVisualDirectoryImage() creates a Visual Image Directory. 13568% 13569% The format of the XVisualDirectoryImage method is: 13570% 13571% Image *XVisualDirectoryImage(Display *display, 13572% XResourceInfo *resource_info,XWindows *windows, 13573% ExceptionInfo *exception) 13574% 13575% A description of each parameter follows: 13576% 13577% o display: Specifies a connection to an X server; returned from 13578% XOpenDisplay. 13579% 13580% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13581% 13582% o windows: Specifies a pointer to a XWindows structure. 13583% 13584% o exception: return any errors or warnings in this structure. 13585% 13586*/ 13587static Image *XVisualDirectoryImage(Display *display, 13588 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception) 13589{ 13590#define TileImageTag "Scale/Image" 13591#define XClientName "montage" 13592 13593 char 13594 **filelist; 13595 13596 Image 13597 *images, 13598 *montage_image, 13599 *next_image, 13600 *thumbnail_image; 13601 13602 ImageInfo 13603 *read_info; 13604 13605 int 13606 number_files; 13607 13608 MagickBooleanType 13609 backdrop; 13610 13611 MagickStatusType 13612 status; 13613 13614 MontageInfo 13615 *montage_info; 13616 13617 RectangleInfo 13618 geometry; 13619 13620 register int 13621 i; 13622 13623 static char 13624 filename[MaxTextExtent] = "\0", 13625 filenames[MaxTextExtent] = "*"; 13626 13627 XResourceInfo 13628 background_resources; 13629 13630 /* 13631 Request file name from user. 13632 */ 13633 XFileBrowserWidget(display,windows,"Directory",filenames); 13634 if (*filenames == '\0') 13635 return((Image *) NULL); 13636 /* 13637 Expand the filenames. 13638 */ 13639 filelist=(char **) AcquireMagickMemory(sizeof(*filelist)); 13640 if (filelist == (char **) NULL) 13641 { 13642 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13643 filenames); 13644 return((Image *) NULL); 13645 } 13646 number_files=1; 13647 filelist[0]=filenames; 13648 status=ExpandFilenames(&number_files,&filelist); 13649 if ((status == MagickFalse) || (number_files == 0)) 13650 { 13651 if (number_files == 0) 13652 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames) 13653 else 13654 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13655 filenames); 13656 return((Image *) NULL); 13657 } 13658 /* 13659 Set image background resources. 13660 */ 13661 background_resources=(*resource_info); 13662 background_resources.window_id=AcquireString(""); 13663 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent, 13664 "0x%lx",windows->image.id); 13665 background_resources.backdrop=MagickTrue; 13666 /* 13667 Read each image and convert them to a tile. 13668 */ 13669 backdrop=(windows->visual_info->klass == TrueColor) || 13670 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse; 13671 read_info=CloneImageInfo(resource_info->image_info); 13672 (void) SetImageOption(read_info,"jpeg:size","120x120"); 13673 (void) CloneString(&read_info->size,DefaultTileGeometry); 13674 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 13675 (void *) NULL); 13676 images=NewImageList(); 13677 XSetCursorState(display,windows,MagickTrue); 13678 XCheckRefreshWindows(display,windows); 13679 for (i=0; i < (int) number_files; i++) 13680 { 13681 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent); 13682 filelist[i]=DestroyString(filelist[i]); 13683 *read_info->magick='\0'; 13684 next_image=ReadImage(read_info,exception); 13685 CatchException(exception); 13686 if (next_image != (Image *) NULL) 13687 { 13688 (void) DeleteImageProperty(next_image,"label"); 13689 (void) SetImageProperty(next_image,"label",InterpretImageProperties( 13690 read_info,next_image,DefaultTileLabel,exception),exception); 13691 (void) ParseRegionGeometry(next_image,read_info->size,&geometry, 13692 exception); 13693 thumbnail_image=ThumbnailImage(next_image,geometry.width, 13694 geometry.height,exception); 13695 if (thumbnail_image != (Image *) NULL) 13696 { 13697 next_image=DestroyImage(next_image); 13698 next_image=thumbnail_image; 13699 } 13700 if (backdrop) 13701 { 13702 (void) XDisplayBackgroundImage(display,&background_resources, 13703 next_image,exception); 13704 XSetCursorState(display,windows,MagickTrue); 13705 } 13706 AppendImageToList(&images,next_image); 13707 if (images->progress_monitor != (MagickProgressMonitor) NULL) 13708 { 13709 MagickBooleanType 13710 proceed; 13711 13712 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i, 13713 (MagickSizeType) number_files); 13714 if (proceed == MagickFalse) 13715 break; 13716 } 13717 } 13718 } 13719 filelist=(char **) RelinquishMagickMemory(filelist); 13720 if (images == (Image *) NULL) 13721 { 13722 read_info=DestroyImageInfo(read_info); 13723 XSetCursorState(display,windows,MagickFalse); 13724 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames); 13725 return((Image *) NULL); 13726 } 13727 /* 13728 Create the Visual Image Directory. 13729 */ 13730 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL); 13731 montage_info->pointsize=10; 13732 if (resource_info->font != (char *) NULL) 13733 (void) CloneString(&montage_info->font,resource_info->font); 13734 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent); 13735 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList( 13736 images),exception); 13737 images=DestroyImageList(images); 13738 montage_info=DestroyMontageInfo(montage_info); 13739 read_info=DestroyImageInfo(read_info); 13740 XSetCursorState(display,windows,MagickFalse); 13741 if (montage_image == (Image *) NULL) 13742 return(montage_image); 13743 XClientMessage(display,windows->image.id,windows->im_protocols, 13744 windows->im_next_image,CurrentTime); 13745 return(montage_image); 13746} 13747 13748/* 13749%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13750% % 13751% % 13752% % 13753% X D i s p l a y B a c k g r o u n d I m a g e % 13754% % 13755% % 13756% % 13757%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13758% 13759% XDisplayBackgroundImage() displays an image in the background of a window. 13760% 13761% The format of the XDisplayBackgroundImage method is: 13762% 13763% MagickBooleanType XDisplayBackgroundImage(Display *display, 13764% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13765% 13766% A description of each parameter follows: 13767% 13768% o display: Specifies a connection to an X server; returned from 13769% XOpenDisplay. 13770% 13771% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13772% 13773% o image: the image. 13774% 13775% o exception: return any errors or warnings in this structure. 13776% 13777*/ 13778MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display, 13779 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13780{ 13781 char 13782 geometry[MaxTextExtent], 13783 visual_type[MaxTextExtent]; 13784 13785 int 13786 height, 13787 status, 13788 width; 13789 13790 RectangleInfo 13791 geometry_info; 13792 13793 static XPixelInfo 13794 pixel; 13795 13796 static XStandardColormap 13797 *map_info; 13798 13799 static XVisualInfo 13800 *visual_info = (XVisualInfo *) NULL; 13801 13802 static XWindowInfo 13803 window_info; 13804 13805 size_t 13806 delay; 13807 13808 Window 13809 root_window; 13810 13811 XGCValues 13812 context_values; 13813 13814 XResourceInfo 13815 resources; 13816 13817 XWindowAttributes 13818 window_attributes; 13819 13820 /* 13821 Determine target window. 13822 */ 13823 assert(image != (Image *) NULL); 13824 assert(image->signature == MagickSignature); 13825 if (image->debug != MagickFalse) 13826 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 13827 resources=(*resource_info); 13828 window_info.id=(Window) NULL; 13829 root_window=XRootWindow(display,XDefaultScreen(display)); 13830 if (LocaleCompare(resources.window_id,"root") == 0) 13831 window_info.id=root_window; 13832 else 13833 { 13834 if (isdigit((unsigned char) *resources.window_id) != 0) 13835 window_info.id=XWindowByID(display,root_window, 13836 (Window) strtol((char *) resources.window_id,(char **) NULL,0)); 13837 if (window_info.id == (Window) NULL) 13838 window_info.id=XWindowByName(display,root_window,resources.window_id); 13839 } 13840 if (window_info.id == (Window) NULL) 13841 { 13842 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists", 13843 resources.window_id); 13844 return(MagickFalse); 13845 } 13846 /* 13847 Determine window visual id. 13848 */ 13849 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); 13850 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); 13851 (void) CopyMagickString(visual_type,"default",MaxTextExtent); 13852 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13853 if (status != 0) 13854 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx", 13855 XVisualIDFromVisual(window_attributes.visual)); 13856 if (visual_info == (XVisualInfo *) NULL) 13857 { 13858 /* 13859 Allocate standard colormap. 13860 */ 13861 map_info=XAllocStandardColormap(); 13862 if (map_info == (XStandardColormap *) NULL) 13863 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", 13864 image->filename); 13865 map_info->colormap=(Colormap) NULL; 13866 pixel.pixels=(unsigned long *) NULL; 13867 /* 13868 Initialize visual info. 13869 */ 13870 resources.map_type=(char *) NULL; 13871 resources.visual_type=visual_type; 13872 visual_info=XBestVisualInfo(display,map_info,&resources); 13873 if (visual_info == (XVisualInfo *) NULL) 13874 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", 13875 resources.visual_type); 13876 /* 13877 Initialize window info. 13878 */ 13879 window_info.ximage=(XImage *) NULL; 13880 window_info.matte_image=(XImage *) NULL; 13881 window_info.pixmap=(Pixmap) NULL; 13882 window_info.matte_pixmap=(Pixmap) NULL; 13883 } 13884 /* 13885 Free previous root colors. 13886 */ 13887 if (window_info.id == root_window) 13888 (void) XDestroyWindowColors(display,root_window); 13889 /* 13890 Initialize Standard Colormap. 13891 */ 13892 resources.colormap=SharedColormap; 13893 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel); 13894 /* 13895 Graphic context superclass. 13896 */ 13897 context_values.background=pixel.background_color.pixel; 13898 context_values.foreground=pixel.foreground_color.pixel; 13899 pixel.annotate_context=XCreateGC(display,window_info.id, 13900 (size_t) (GCBackground | GCForeground),&context_values); 13901 if (pixel.annotate_context == (GC) NULL) 13902 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 13903 image->filename); 13904 /* 13905 Initialize Image window attributes. 13906 */ 13907 window_info.name=AcquireString("\0"); 13908 window_info.icon_name=AcquireString("\0"); 13909 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, 13910 &resources,&window_info); 13911 /* 13912 Create the X image. 13913 */ 13914 window_info.width=(unsigned int) image->columns; 13915 window_info.height=(unsigned int) image->rows; 13916 if ((image->columns != window_info.width) || 13917 (image->rows != window_info.height)) 13918 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13919 image->filename); 13920 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>", 13921 window_attributes.width,window_attributes.height); 13922 geometry_info.width=window_info.width; 13923 geometry_info.height=window_info.height; 13924 geometry_info.x=(ssize_t) window_info.x; 13925 geometry_info.y=(ssize_t) window_info.y; 13926 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 13927 &geometry_info.width,&geometry_info.height); 13928 window_info.width=(unsigned int) geometry_info.width; 13929 window_info.height=(unsigned int) geometry_info.height; 13930 window_info.x=(int) geometry_info.x; 13931 window_info.y=(int) geometry_info.y; 13932 status=XMakeImage(display,&resources,&window_info,image,window_info.width, 13933 window_info.height,exception); 13934 if (status == MagickFalse) 13935 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13936 image->filename); 13937 window_info.x=0; 13938 window_info.y=0; 13939 if (image->debug != MagickFalse) 13940 { 13941 (void) LogMagickEvent(X11Event,GetMagickModule(), 13942 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene, 13943 (double) image->columns,(double) image->rows); 13944 if (image->colors != 0) 13945 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 13946 image->colors); 13947 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick); 13948 } 13949 /* 13950 Adjust image dimensions as specified by backdrop or geometry options. 13951 */ 13952 width=(int) window_info.width; 13953 height=(int) window_info.height; 13954 if (resources.backdrop != MagickFalse) 13955 { 13956 /* 13957 Center image on window. 13958 */ 13959 window_info.x=(window_attributes.width/2)- 13960 (window_info.ximage->width/2); 13961 window_info.y=(window_attributes.height/2)- 13962 (window_info.ximage->height/2); 13963 width=window_attributes.width; 13964 height=window_attributes.height; 13965 } 13966 if ((resources.image_geometry != (char *) NULL) && 13967 (*resources.image_geometry != '\0')) 13968 { 13969 char 13970 default_geometry[MaxTextExtent]; 13971 13972 int 13973 flags, 13974 gravity; 13975 13976 XSizeHints 13977 *size_hints; 13978 13979 /* 13980 User specified geometry. 13981 */ 13982 size_hints=XAllocSizeHints(); 13983 if (size_hints == (XSizeHints *) NULL) 13984 ThrowXWindowFatalException(ResourceLimitFatalError, 13985 "MemoryAllocationFailed",image->filename); 13986 size_hints->flags=0L; 13987 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d", 13988 width,height); 13989 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, 13990 default_geometry,window_info.border_width,size_hints,&window_info.x, 13991 &window_info.y,&width,&height,&gravity); 13992 if (flags & (XValue | YValue)) 13993 { 13994 width=window_attributes.width; 13995 height=window_attributes.height; 13996 } 13997 (void) XFree((void *) size_hints); 13998 } 13999 /* 14000 Create the X pixmap. 14001 */ 14002 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, 14003 (unsigned int) height,window_info.depth); 14004 if (window_info.pixmap == (Pixmap) NULL) 14005 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", 14006 image->filename); 14007 /* 14008 Display pixmap on the window. 14009 */ 14010 if (((unsigned int) width > window_info.width) || 14011 ((unsigned int) height > window_info.height)) 14012 (void) XFillRectangle(display,window_info.pixmap, 14013 window_info.annotate_context,0,0,(unsigned int) width, 14014 (unsigned int) height); 14015 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, 14016 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int) 14017 window_info.width,(unsigned int) window_info.height); 14018 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); 14019 (void) XClearWindow(display,window_info.id); 14020 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); 14021 XDelay(display,delay == 0UL ? 10UL : delay); 14022 (void) XSync(display,MagickFalse); 14023 return(window_info.id == root_window ? MagickTrue : MagickFalse); 14024} 14025 14026/* 14027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14028% % 14029% % 14030% % 14031+ X D i s p l a y I m a g e % 14032% % 14033% % 14034% % 14035%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14036% 14037% XDisplayImage() displays an image via X11. A new image is created and 14038% returned if the user interactively transforms the displayed image. 14039% 14040% The format of the XDisplayImage method is: 14041% 14042% Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14043% char **argv,int argc,Image **image,size_t *state, 14044% ExceptionInfo *exception) 14045% 14046% A description of each parameter follows: 14047% 14048% o nexus: Method XDisplayImage returns an image when the 14049% user chooses 'Open Image' from the command menu or picks a tile 14050% from the image directory. Otherwise a null image is returned. 14051% 14052% o display: Specifies a connection to an X server; returned from 14053% XOpenDisplay. 14054% 14055% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 14056% 14057% o argv: Specifies the application's argument list. 14058% 14059% o argc: Specifies the number of arguments. 14060% 14061% o image: Specifies an address to an address of an Image structure; 14062% 14063% o exception: return any errors or warnings in this structure. 14064% 14065*/ 14066MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14067 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception) 14068{ 14069#define MagnifySize 256 /* must be a power of 2 */ 14070#define MagickMenus 10 14071#define MagickTitle "Commands" 14072 14073 static const char 14074 *CommandMenu[] = 14075 { 14076 "File", 14077 "Edit", 14078 "View", 14079 "Transform", 14080 "Enhance", 14081 "Effects", 14082 "F/X", 14083 "Image Edit", 14084 "Miscellany", 14085 "Help", 14086 (char *) NULL 14087 }, 14088 *FileMenu[] = 14089 { 14090 "Open...", 14091 "Next", 14092 "Former", 14093 "Select...", 14094 "Save...", 14095 "Print...", 14096 "Delete...", 14097 "New...", 14098 "Visual Directory...", 14099 "Quit", 14100 (char *) NULL 14101 }, 14102 *EditMenu[] = 14103 { 14104 "Undo", 14105 "Redo", 14106 "Cut", 14107 "Copy", 14108 "Paste", 14109 (char *) NULL 14110 }, 14111 *ViewMenu[] = 14112 { 14113 "Half Size", 14114 "Original Size", 14115 "Double Size", 14116 "Resize...", 14117 "Apply", 14118 "Refresh", 14119 "Restore", 14120 (char *) NULL 14121 }, 14122 *TransformMenu[] = 14123 { 14124 "Crop", 14125 "Chop", 14126 "Flop", 14127 "Flip", 14128 "Rotate Right", 14129 "Rotate Left", 14130 "Rotate...", 14131 "Shear...", 14132 "Roll...", 14133 "Trim Edges", 14134 (char *) NULL 14135 }, 14136 *EnhanceMenu[] = 14137 { 14138 "Hue...", 14139 "Saturation...", 14140 "Brightness...", 14141 "Gamma...", 14142 "Spiff", 14143 "Dull", 14144 "Contrast Stretch...", 14145 "Sigmoidal Contrast...", 14146 "Normalize", 14147 "Equalize", 14148 "Negate", 14149 "Grayscale", 14150 "Map...", 14151 "Quantize...", 14152 (char *) NULL 14153 }, 14154 *EffectsMenu[] = 14155 { 14156 "Despeckle", 14157 "Emboss", 14158 "Reduce Noise", 14159 "Add Noise...", 14160 "Sharpen...", 14161 "Blur...", 14162 "Threshold...", 14163 "Edge Detect...", 14164 "Spread...", 14165 "Shade...", 14166 "Raise...", 14167 "Segment...", 14168 (char *) NULL 14169 }, 14170 *FXMenu[] = 14171 { 14172 "Solarize...", 14173 "Sepia Tone...", 14174 "Swirl...", 14175 "Implode...", 14176 "Vignette...", 14177 "Wave...", 14178 "Oil Paint...", 14179 "Charcoal Draw...", 14180 (char *) NULL 14181 }, 14182 *ImageEditMenu[] = 14183 { 14184 "Annotate...", 14185 "Draw...", 14186 "Color...", 14187 "Matte...", 14188 "Composite...", 14189 "Add Border...", 14190 "Add Frame...", 14191 "Comment...", 14192 "Launch...", 14193 "Region of Interest...", 14194 (char *) NULL 14195 }, 14196 *MiscellanyMenu[] = 14197 { 14198 "Image Info", 14199 "Zoom Image", 14200 "Show Preview...", 14201 "Show Histogram", 14202 "Show Matte", 14203 "Background...", 14204 "Slide Show...", 14205 "Preferences...", 14206 (char *) NULL 14207 }, 14208 *HelpMenu[] = 14209 { 14210 "Overview", 14211 "Browse Documentation", 14212 "About Display", 14213 (char *) NULL 14214 }, 14215 *ShortCutsMenu[] = 14216 { 14217 "Next", 14218 "Former", 14219 "Open...", 14220 "Save...", 14221 "Print...", 14222 "Undo", 14223 "Restore", 14224 "Image Info", 14225 "Quit", 14226 (char *) NULL 14227 }, 14228 *VirtualMenu[] = 14229 { 14230 "Image Info", 14231 "Print", 14232 "Next", 14233 "Quit", 14234 (char *) NULL 14235 }; 14236 14237 static const char 14238 **Menus[MagickMenus] = 14239 { 14240 FileMenu, 14241 EditMenu, 14242 ViewMenu, 14243 TransformMenu, 14244 EnhanceMenu, 14245 EffectsMenu, 14246 FXMenu, 14247 ImageEditMenu, 14248 MiscellanyMenu, 14249 HelpMenu 14250 }; 14251 14252 static CommandType 14253 CommandMenus[] = 14254 { 14255 NullCommand, 14256 NullCommand, 14257 NullCommand, 14258 NullCommand, 14259 NullCommand, 14260 NullCommand, 14261 NullCommand, 14262 NullCommand, 14263 NullCommand, 14264 NullCommand, 14265 }, 14266 FileCommands[] = 14267 { 14268 OpenCommand, 14269 NextCommand, 14270 FormerCommand, 14271 SelectCommand, 14272 SaveCommand, 14273 PrintCommand, 14274 DeleteCommand, 14275 NewCommand, 14276 VisualDirectoryCommand, 14277 QuitCommand 14278 }, 14279 EditCommands[] = 14280 { 14281 UndoCommand, 14282 RedoCommand, 14283 CutCommand, 14284 CopyCommand, 14285 PasteCommand 14286 }, 14287 ViewCommands[] = 14288 { 14289 HalfSizeCommand, 14290 OriginalSizeCommand, 14291 DoubleSizeCommand, 14292 ResizeCommand, 14293 ApplyCommand, 14294 RefreshCommand, 14295 RestoreCommand 14296 }, 14297 TransformCommands[] = 14298 { 14299 CropCommand, 14300 ChopCommand, 14301 FlopCommand, 14302 FlipCommand, 14303 RotateRightCommand, 14304 RotateLeftCommand, 14305 RotateCommand, 14306 ShearCommand, 14307 RollCommand, 14308 TrimCommand 14309 }, 14310 EnhanceCommands[] = 14311 { 14312 HueCommand, 14313 SaturationCommand, 14314 BrightnessCommand, 14315 GammaCommand, 14316 SpiffCommand, 14317 DullCommand, 14318 ContrastStretchCommand, 14319 SigmoidalContrastCommand, 14320 NormalizeCommand, 14321 EqualizeCommand, 14322 NegateCommand, 14323 GrayscaleCommand, 14324 MapCommand, 14325 QuantizeCommand 14326 }, 14327 EffectsCommands[] = 14328 { 14329 DespeckleCommand, 14330 EmbossCommand, 14331 ReduceNoiseCommand, 14332 AddNoiseCommand, 14333 SharpenCommand, 14334 BlurCommand, 14335 ThresholdCommand, 14336 EdgeDetectCommand, 14337 SpreadCommand, 14338 ShadeCommand, 14339 RaiseCommand, 14340 SegmentCommand 14341 }, 14342 FXCommands[] = 14343 { 14344 SolarizeCommand, 14345 SepiaToneCommand, 14346 SwirlCommand, 14347 ImplodeCommand, 14348 VignetteCommand, 14349 WaveCommand, 14350 OilPaintCommand, 14351 CharcoalDrawCommand 14352 }, 14353 ImageEditCommands[] = 14354 { 14355 AnnotateCommand, 14356 DrawCommand, 14357 ColorCommand, 14358 MatteCommand, 14359 CompositeCommand, 14360 AddBorderCommand, 14361 AddFrameCommand, 14362 CommentCommand, 14363 LaunchCommand, 14364 RegionofInterestCommand 14365 }, 14366 MiscellanyCommands[] = 14367 { 14368 InfoCommand, 14369 ZoomCommand, 14370 ShowPreviewCommand, 14371 ShowHistogramCommand, 14372 ShowMatteCommand, 14373 BackgroundCommand, 14374 SlideShowCommand, 14375 PreferencesCommand 14376 }, 14377 HelpCommands[] = 14378 { 14379 HelpCommand, 14380 BrowseDocumentationCommand, 14381 VersionCommand 14382 }, 14383 ShortCutsCommands[] = 14384 { 14385 NextCommand, 14386 FormerCommand, 14387 OpenCommand, 14388 SaveCommand, 14389 PrintCommand, 14390 UndoCommand, 14391 RestoreCommand, 14392 InfoCommand, 14393 QuitCommand 14394 }, 14395 VirtualCommands[] = 14396 { 14397 InfoCommand, 14398 PrintCommand, 14399 NextCommand, 14400 QuitCommand 14401 }; 14402 14403 static CommandType 14404 *Commands[MagickMenus] = 14405 { 14406 FileCommands, 14407 EditCommands, 14408 ViewCommands, 14409 TransformCommands, 14410 EnhanceCommands, 14411 EffectsCommands, 14412 FXCommands, 14413 ImageEditCommands, 14414 MiscellanyCommands, 14415 HelpCommands 14416 }; 14417 14418 char 14419 command[MaxTextExtent], 14420 *directory, 14421 geometry[MaxTextExtent], 14422 resource_name[MaxTextExtent]; 14423 14424 CommandType 14425 command_type; 14426 14427 Image 14428 *display_image, 14429 *nexus; 14430 14431 int 14432 entry, 14433 id; 14434 14435 KeySym 14436 key_symbol; 14437 14438 MagickStatusType 14439 context_mask, 14440 status; 14441 14442 RectangleInfo 14443 geometry_info; 14444 14445 register int 14446 i; 14447 14448 static char 14449 working_directory[MaxTextExtent]; 14450 14451 static XPoint 14452 vid_info; 14453 14454 static XWindowInfo 14455 *magick_windows[MaxXWindows]; 14456 14457 static unsigned int 14458 number_windows; 14459 14460 struct stat 14461 attributes; 14462 14463 time_t 14464 timer, 14465 timestamp, 14466 update_time; 14467 14468 unsigned int 14469 height, 14470 width; 14471 14472 size_t 14473 delay; 14474 14475 WarningHandler 14476 warning_handler; 14477 14478 Window 14479 root_window; 14480 14481 XClassHint 14482 *class_hints; 14483 14484 XEvent 14485 event; 14486 14487 XFontStruct 14488 *font_info; 14489 14490 XGCValues 14491 context_values; 14492 14493 XPixelInfo 14494 *icon_pixel, 14495 *pixel; 14496 14497 XResourceInfo 14498 *icon_resources; 14499 14500 XStandardColormap 14501 *icon_map, 14502 *map_info; 14503 14504 XVisualInfo 14505 *icon_visual, 14506 *visual_info; 14507 14508 XWindowChanges 14509 window_changes; 14510 14511 XWindows 14512 *windows; 14513 14514 XWMHints 14515 *manager_hints; 14516 14517 assert(image != (Image **) NULL); 14518 assert((*image)->signature == MagickSignature); 14519 if ((*image)->debug != MagickFalse) 14520 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 14521 display_image=(*image); 14522 warning_handler=(WarningHandler) NULL; 14523 windows=XSetWindows((XWindows *) ~0); 14524 if (windows != (XWindows *) NULL) 14525 { 14526 int 14527 status; 14528 14529 status=chdir(working_directory); 14530 if (status == -1) 14531 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 14532 "UnableToOpenFile","%s",working_directory); 14533 warning_handler=resource_info->display_warnings ? 14534 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14535 warning_handler=resource_info->display_warnings ? 14536 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14537 } 14538 else 14539 { 14540 /* 14541 Allocate windows structure. 14542 */ 14543 resource_info->colors=display_image->colors; 14544 windows=XSetWindows(XInitializeWindows(display,resource_info)); 14545 if (windows == (XWindows *) NULL) 14546 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow", 14547 (*image)->filename); 14548 /* 14549 Initialize window id's. 14550 */ 14551 number_windows=0; 14552 magick_windows[number_windows++]=(&windows->icon); 14553 magick_windows[number_windows++]=(&windows->backdrop); 14554 magick_windows[number_windows++]=(&windows->image); 14555 magick_windows[number_windows++]=(&windows->info); 14556 magick_windows[number_windows++]=(&windows->command); 14557 magick_windows[number_windows++]=(&windows->widget); 14558 magick_windows[number_windows++]=(&windows->popup); 14559 magick_windows[number_windows++]=(&windows->magnify); 14560 magick_windows[number_windows++]=(&windows->pan); 14561 for (i=0; i < (int) number_windows; i++) 14562 magick_windows[i]->id=(Window) NULL; 14563 vid_info.x=0; 14564 vid_info.y=0; 14565 } 14566 /* 14567 Initialize font info. 14568 */ 14569 if (windows->font_info != (XFontStruct *) NULL) 14570 (void) XFreeFont(display,windows->font_info); 14571 windows->font_info=XBestFont(display,resource_info,MagickFalse); 14572 if (windows->font_info == (XFontStruct *) NULL) 14573 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", 14574 resource_info->font); 14575 /* 14576 Initialize Standard Colormap. 14577 */ 14578 map_info=windows->map_info; 14579 icon_map=windows->icon_map; 14580 visual_info=windows->visual_info; 14581 icon_visual=windows->icon_visual; 14582 pixel=windows->pixel_info; 14583 icon_pixel=windows->icon_pixel; 14584 font_info=windows->font_info; 14585 icon_resources=windows->icon_resources; 14586 class_hints=windows->class_hints; 14587 manager_hints=windows->manager_hints; 14588 root_window=XRootWindow(display,visual_info->screen); 14589 nexus=NewImageList(); 14590 if (display_image->debug != MagickFalse) 14591 { 14592 (void) LogMagickEvent(X11Event,GetMagickModule(), 14593 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename, 14594 (double) display_image->scene,(double) display_image->columns, 14595 (double) display_image->rows); 14596 if (display_image->colors != 0) 14597 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 14598 display_image->colors); 14599 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", 14600 display_image->magick); 14601 } 14602 XMakeStandardColormap(display,visual_info,resource_info,display_image, 14603 map_info,pixel); 14604 display_image->taint=MagickFalse; 14605 /* 14606 Initialize graphic context. 14607 */ 14608 windows->context.id=(Window) NULL; 14609 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14610 resource_info,&windows->context); 14611 (void) CloneString(&class_hints->res_name,resource_info->client_name); 14612 (void) CloneString(&class_hints->res_class,resource_info->client_name); 14613 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]); 14614 manager_hints->flags=InputHint | StateHint; 14615 manager_hints->input=MagickFalse; 14616 manager_hints->initial_state=WithdrawnState; 14617 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14618 &windows->context); 14619 if (display_image->debug != MagickFalse) 14620 (void) LogMagickEvent(X11Event,GetMagickModule(), 14621 "Window id: 0x%lx (context)",windows->context.id); 14622 context_values.background=pixel->background_color.pixel; 14623 context_values.font=font_info->fid; 14624 context_values.foreground=pixel->foreground_color.pixel; 14625 context_values.graphics_exposures=MagickFalse; 14626 context_mask=(MagickStatusType) 14627 (GCBackground | GCFont | GCForeground | GCGraphicsExposures); 14628 if (pixel->annotate_context != (GC) NULL) 14629 (void) XFreeGC(display,pixel->annotate_context); 14630 pixel->annotate_context=XCreateGC(display,windows->context.id, 14631 context_mask,&context_values); 14632 if (pixel->annotate_context == (GC) NULL) 14633 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14634 display_image->filename); 14635 context_values.background=pixel->depth_color.pixel; 14636 if (pixel->widget_context != (GC) NULL) 14637 (void) XFreeGC(display,pixel->widget_context); 14638 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask, 14639 &context_values); 14640 if (pixel->widget_context == (GC) NULL) 14641 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14642 display_image->filename); 14643 context_values.background=pixel->foreground_color.pixel; 14644 context_values.foreground=pixel->background_color.pixel; 14645 context_values.plane_mask=context_values.background ^ 14646 context_values.foreground; 14647 if (pixel->highlight_context != (GC) NULL) 14648 (void) XFreeGC(display,pixel->highlight_context); 14649 pixel->highlight_context=XCreateGC(display,windows->context.id, 14650 (size_t) (context_mask | GCPlaneMask),&context_values); 14651 if (pixel->highlight_context == (GC) NULL) 14652 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14653 display_image->filename); 14654 (void) XDestroyWindow(display,windows->context.id); 14655 /* 14656 Initialize icon window. 14657 */ 14658 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, 14659 icon_resources,&windows->icon); 14660 windows->icon.geometry=resource_info->icon_geometry; 14661 XBestIconSize(display,&windows->icon,display_image); 14662 windows->icon.attributes.colormap=XDefaultColormap(display, 14663 icon_visual->screen); 14664 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; 14665 manager_hints->flags=InputHint | StateHint; 14666 manager_hints->input=MagickFalse; 14667 manager_hints->initial_state=IconicState; 14668 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14669 &windows->icon); 14670 if (display_image->debug != MagickFalse) 14671 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", 14672 windows->icon.id); 14673 /* 14674 Initialize graphic context for icon window. 14675 */ 14676 if (icon_pixel->annotate_context != (GC) NULL) 14677 (void) XFreeGC(display,icon_pixel->annotate_context); 14678 context_values.background=icon_pixel->background_color.pixel; 14679 context_values.foreground=icon_pixel->foreground_color.pixel; 14680 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, 14681 (size_t) (GCBackground | GCForeground),&context_values); 14682 if (icon_pixel->annotate_context == (GC) NULL) 14683 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14684 display_image->filename); 14685 windows->icon.annotate_context=icon_pixel->annotate_context; 14686 /* 14687 Initialize Image window. 14688 */ 14689 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14690 &windows->image); 14691 windows->image.shape=MagickTrue; /* non-rectangular shape hint */ 14692 if (resource_info->use_shared_memory == MagickFalse) 14693 windows->image.shared_memory=MagickFalse; 14694 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState)) 14695 { 14696 char 14697 *title; 14698 14699 title=InterpretImageProperties(resource_info->image_info,display_image, 14700 resource_info->title,exception); 14701 (void) CopyMagickString(windows->image.name,title,MaxTextExtent); 14702 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent); 14703 title=DestroyString(title); 14704 } 14705 else 14706 { 14707 char 14708 filename[MaxTextExtent]; 14709 14710 /* 14711 Window name is the base of the filename. 14712 */ 14713 GetPathComponent(display_image->magick_filename,TailPath,filename); 14714 if (display_image->scene == 0) 14715 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14716 "%s: %s",MagickPackageName,filename); 14717 else 14718 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14719 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename, 14720 (double) display_image->scene,(double) GetImageListLength( 14721 display_image)); 14722 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent); 14723 } 14724 if (resource_info->immutable) 14725 windows->image.immutable=MagickTrue; 14726 windows->image.use_pixmap=resource_info->use_pixmap; 14727 windows->image.geometry=resource_info->image_geometry; 14728 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 14729 XDisplayWidth(display,visual_info->screen), 14730 XDisplayHeight(display,visual_info->screen)); 14731 geometry_info.width=display_image->columns; 14732 geometry_info.height=display_image->rows; 14733 geometry_info.x=0; 14734 geometry_info.y=0; 14735 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 14736 &geometry_info.width,&geometry_info.height); 14737 windows->image.width=(unsigned int) geometry_info.width; 14738 windows->image.height=(unsigned int) geometry_info.height; 14739 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14740 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14741 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14742 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; 14743 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14744 resource_info,&windows->backdrop); 14745 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) 14746 { 14747 /* 14748 Initialize backdrop window. 14749 */ 14750 windows->backdrop.x=0; 14751 windows->backdrop.y=0; 14752 (void) CloneString(&windows->backdrop.name,"Backdrop"); 14753 windows->backdrop.flags=(size_t) (USSize | USPosition); 14754 windows->backdrop.width=(unsigned int) 14755 XDisplayWidth(display,visual_info->screen); 14756 windows->backdrop.height=(unsigned int) 14757 XDisplayHeight(display,visual_info->screen); 14758 windows->backdrop.border_width=0; 14759 windows->backdrop.immutable=MagickTrue; 14760 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | 14761 ButtonReleaseMask; 14762 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | 14763 StructureNotifyMask; 14764 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14765 manager_hints->icon_window=windows->icon.id; 14766 manager_hints->input=MagickTrue; 14767 manager_hints->initial_state=resource_info->iconic ? IconicState : 14768 NormalState; 14769 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14770 &windows->backdrop); 14771 if (display_image->debug != MagickFalse) 14772 (void) LogMagickEvent(X11Event,GetMagickModule(), 14773 "Window id: 0x%lx (backdrop)",windows->backdrop.id); 14774 (void) XMapWindow(display,windows->backdrop.id); 14775 (void) XClearWindow(display,windows->backdrop.id); 14776 if (windows->image.id != (Window) NULL) 14777 { 14778 (void) XDestroyWindow(display,windows->image.id); 14779 windows->image.id=(Window) NULL; 14780 } 14781 /* 14782 Position image in the center the backdrop. 14783 */ 14784 windows->image.flags|=USPosition; 14785 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- 14786 (windows->image.width/2); 14787 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- 14788 (windows->image.height/2); 14789 } 14790 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14791 manager_hints->icon_window=windows->icon.id; 14792 manager_hints->input=MagickTrue; 14793 manager_hints->initial_state=resource_info->iconic ? IconicState : 14794 NormalState; 14795 if (windows->group_leader.id != (Window) NULL) 14796 { 14797 /* 14798 Follow the leader. 14799 */ 14800 manager_hints->flags|=WindowGroupHint; 14801 manager_hints->window_group=windows->group_leader.id; 14802 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); 14803 if (display_image->debug != MagickFalse) 14804 (void) LogMagickEvent(X11Event,GetMagickModule(), 14805 "Window id: 0x%lx (group leader)",windows->group_leader.id); 14806 } 14807 XMakeWindow(display, 14808 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), 14809 argv,argc,class_hints,manager_hints,&windows->image); 14810 (void) XChangeProperty(display,windows->image.id,windows->im_protocols, 14811 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); 14812 if (windows->group_leader.id != (Window) NULL) 14813 (void) XSetTransientForHint(display,windows->image.id, 14814 windows->group_leader.id); 14815 if (display_image->debug != MagickFalse) 14816 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", 14817 windows->image.id); 14818 /* 14819 Initialize Info widget. 14820 */ 14821 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14822 &windows->info); 14823 (void) CloneString(&windows->info.name,"Info"); 14824 (void) CloneString(&windows->info.icon_name,"Info"); 14825 windows->info.border_width=1; 14826 windows->info.x=2; 14827 windows->info.y=2; 14828 windows->info.flags|=PPosition; 14829 windows->info.attributes.win_gravity=UnmapGravity; 14830 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | 14831 StructureNotifyMask; 14832 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14833 manager_hints->input=MagickFalse; 14834 manager_hints->initial_state=NormalState; 14835 manager_hints->window_group=windows->image.id; 14836 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, 14837 &windows->info); 14838 windows->info.highlight_stipple=XCreateBitmapFromData(display, 14839 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14840 windows->info.shadow_stipple=XCreateBitmapFromData(display, 14841 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14842 (void) XSetTransientForHint(display,windows->info.id,windows->image.id); 14843 if (windows->image.mapped != MagickFalse) 14844 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14845 if (display_image->debug != MagickFalse) 14846 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", 14847 windows->info.id); 14848 /* 14849 Initialize Command widget. 14850 */ 14851 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14852 resource_info,&windows->command); 14853 windows->command.data=MagickMenus; 14854 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); 14855 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command", 14856 resource_info->client_name); 14857 windows->command.geometry=XGetResourceClass(resource_info->resource_database, 14858 resource_name,"geometry",(char *) NULL); 14859 (void) CloneString(&windows->command.name,MagickTitle); 14860 windows->command.border_width=0; 14861 windows->command.flags|=PPosition; 14862 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14863 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | 14864 OwnerGrabButtonMask | StructureNotifyMask; 14865 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14866 manager_hints->input=MagickTrue; 14867 manager_hints->initial_state=NormalState; 14868 manager_hints->window_group=windows->image.id; 14869 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14870 &windows->command); 14871 windows->command.highlight_stipple=XCreateBitmapFromData(display, 14872 windows->command.id,(char *) HighlightBitmap,HighlightWidth, 14873 HighlightHeight); 14874 windows->command.shadow_stipple=XCreateBitmapFromData(display, 14875 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14876 (void) XSetTransientForHint(display,windows->command.id,windows->image.id); 14877 if (windows->command.mapped != MagickFalse) 14878 (void) XMapRaised(display,windows->command.id); 14879 if (display_image->debug != MagickFalse) 14880 (void) LogMagickEvent(X11Event,GetMagickModule(), 14881 "Window id: 0x%lx (command)",windows->command.id); 14882 /* 14883 Initialize Widget window. 14884 */ 14885 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14886 resource_info,&windows->widget); 14887 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget", 14888 resource_info->client_name); 14889 windows->widget.geometry=XGetResourceClass(resource_info->resource_database, 14890 resource_name,"geometry",(char *) NULL); 14891 windows->widget.border_width=0; 14892 windows->widget.flags|=PPosition; 14893 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14894 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14895 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14896 StructureNotifyMask; 14897 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14898 manager_hints->input=MagickTrue; 14899 manager_hints->initial_state=NormalState; 14900 manager_hints->window_group=windows->image.id; 14901 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14902 &windows->widget); 14903 windows->widget.highlight_stipple=XCreateBitmapFromData(display, 14904 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14905 windows->widget.shadow_stipple=XCreateBitmapFromData(display, 14906 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14907 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); 14908 if (display_image->debug != MagickFalse) 14909 (void) LogMagickEvent(X11Event,GetMagickModule(), 14910 "Window id: 0x%lx (widget)",windows->widget.id); 14911 /* 14912 Initialize popup window. 14913 */ 14914 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14915 resource_info,&windows->popup); 14916 windows->popup.border_width=0; 14917 windows->popup.flags|=PPosition; 14918 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14919 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14920 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask; 14921 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14922 manager_hints->input=MagickTrue; 14923 manager_hints->initial_state=NormalState; 14924 manager_hints->window_group=windows->image.id; 14925 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14926 &windows->popup); 14927 windows->popup.highlight_stipple=XCreateBitmapFromData(display, 14928 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14929 windows->popup.shadow_stipple=XCreateBitmapFromData(display, 14930 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14931 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); 14932 if (display_image->debug != MagickFalse) 14933 (void) LogMagickEvent(X11Event,GetMagickModule(), 14934 "Window id: 0x%lx (pop up)",windows->popup.id); 14935 /* 14936 Initialize Magnify window and cursor. 14937 */ 14938 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14939 resource_info,&windows->magnify); 14940 if (resource_info->use_shared_memory == MagickFalse) 14941 windows->magnify.shared_memory=MagickFalse; 14942 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify", 14943 resource_info->client_name); 14944 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database, 14945 resource_name,"geometry",(char *) NULL); 14946 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX", 14947 resource_info->magnify); 14948 if (windows->magnify.cursor != (Cursor) NULL) 14949 (void) XFreeCursor(display,windows->magnify.cursor); 14950 windows->magnify.cursor=XMakeCursor(display,windows->image.id, 14951 map_info->colormap,resource_info->background_color, 14952 resource_info->foreground_color); 14953 if (windows->magnify.cursor == (Cursor) NULL) 14954 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor", 14955 display_image->filename); 14956 windows->magnify.width=MagnifySize; 14957 windows->magnify.height=MagnifySize; 14958 windows->magnify.flags|=PPosition; 14959 windows->magnify.min_width=MagnifySize; 14960 windows->magnify.min_height=MagnifySize; 14961 windows->magnify.width_inc=MagnifySize; 14962 windows->magnify.height_inc=MagnifySize; 14963 windows->magnify.data=resource_info->magnify; 14964 windows->magnify.attributes.cursor=windows->magnify.cursor; 14965 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask | 14966 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask | 14967 StructureNotifyMask; 14968 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14969 manager_hints->input=MagickTrue; 14970 manager_hints->initial_state=NormalState; 14971 manager_hints->window_group=windows->image.id; 14972 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14973 &windows->magnify); 14974 if (display_image->debug != MagickFalse) 14975 (void) LogMagickEvent(X11Event,GetMagickModule(), 14976 "Window id: 0x%lx (magnify)",windows->magnify.id); 14977 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id); 14978 /* 14979 Initialize panning window. 14980 */ 14981 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14982 resource_info,&windows->pan); 14983 (void) CloneString(&windows->pan.name,"Pan Icon"); 14984 windows->pan.width=windows->icon.width; 14985 windows->pan.height=windows->icon.height; 14986 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan", 14987 resource_info->client_name); 14988 windows->pan.geometry=XGetResourceClass(resource_info->resource_database, 14989 resource_name,"geometry",(char *) NULL); 14990 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 14991 &windows->pan.width,&windows->pan.height); 14992 windows->pan.flags|=PPosition; 14993 windows->pan.immutable=MagickTrue; 14994 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14995 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask | 14996 StructureNotifyMask; 14997 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14998 manager_hints->input=MagickFalse; 14999 manager_hints->initial_state=NormalState; 15000 manager_hints->window_group=windows->image.id; 15001 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 15002 &windows->pan); 15003 if (display_image->debug != MagickFalse) 15004 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)", 15005 windows->pan.id); 15006 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id); 15007 if (windows->info.mapped != MagickFalse) 15008 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15009 if ((windows->image.mapped == MagickFalse) || 15010 (windows->backdrop.id != (Window) NULL)) 15011 (void) XMapWindow(display,windows->image.id); 15012 /* 15013 Set our progress monitor and warning handlers. 15014 */ 15015 if (warning_handler == (WarningHandler) NULL) 15016 { 15017 warning_handler=resource_info->display_warnings ? 15018 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 15019 warning_handler=resource_info->display_warnings ? 15020 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 15021 } 15022 /* 15023 Initialize Image and Magnify X images. 15024 */ 15025 windows->image.x=0; 15026 windows->image.y=0; 15027 windows->magnify.shape=MagickFalse; 15028 width=(unsigned int) display_image->columns; 15029 height=(unsigned int) display_image->rows; 15030 if ((display_image->columns != width) || (display_image->rows != height)) 15031 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15032 display_image->filename); 15033 status=XMakeImage(display,resource_info,&windows->image,display_image, 15034 width,height,exception); 15035 if (status == MagickFalse) 15036 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15037 display_image->filename); 15038 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL, 15039 windows->magnify.width,windows->magnify.height,exception); 15040 if (status == MagickFalse) 15041 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15042 display_image->filename); 15043 if (windows->magnify.mapped != MagickFalse) 15044 (void) XMapRaised(display,windows->magnify.id); 15045 if (windows->pan.mapped != MagickFalse) 15046 (void) XMapRaised(display,windows->pan.id); 15047 windows->image.window_changes.width=(int) display_image->columns; 15048 windows->image.window_changes.height=(int) display_image->rows; 15049 (void) XConfigureImage(display,resource_info,windows,display_image,exception); 15050 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15051 (void) XSync(display,MagickFalse); 15052 /* 15053 Respond to events. 15054 */ 15055 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L); 15056 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15057 update_time=0; 15058 if (resource_info->update != MagickFalse) 15059 { 15060 MagickBooleanType 15061 status; 15062 15063 /* 15064 Determine when file data was last modified. 15065 */ 15066 status=GetPathAttributes(display_image->filename,&attributes); 15067 if (status != MagickFalse) 15068 update_time=attributes.st_mtime; 15069 } 15070 *state&=(~FormerImageState); 15071 *state&=(~MontageImageState); 15072 *state&=(~NextImageState); 15073 do 15074 { 15075 /* 15076 Handle a window event. 15077 */ 15078 if (windows->image.mapped != MagickFalse) 15079 if ((display_image->delay != 0) || (resource_info->update != 0)) 15080 { 15081 if (timer < time((time_t *) NULL)) 15082 { 15083 if (resource_info->update == MagickFalse) 15084 *state|=NextImageState | ExitState; 15085 else 15086 { 15087 MagickBooleanType 15088 status; 15089 15090 /* 15091 Determine if image file was modified. 15092 */ 15093 status=GetPathAttributes(display_image->filename,&attributes); 15094 if (status != MagickFalse) 15095 if (update_time != attributes.st_mtime) 15096 { 15097 /* 15098 Redisplay image. 15099 */ 15100 (void) FormatLocaleString( 15101 resource_info->image_info->filename,MaxTextExtent, 15102 "%s:%s",display_image->magick, 15103 display_image->filename); 15104 nexus=ReadImage(resource_info->image_info, 15105 &display_image->exception); 15106 if (nexus != (Image *) NULL) 15107 { 15108 nexus=DestroyImage(nexus); 15109 *state|=NextImageState | ExitState; 15110 } 15111 } 15112 delay=display_image->delay/MagickMax( 15113 display_image->ticks_per_second,1L); 15114 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15115 } 15116 } 15117 if (XEventsQueued(display,QueuedAfterFlush) == 0) 15118 { 15119 /* 15120 Do not block if delay > 0. 15121 */ 15122 XDelay(display,SuspendTime << 2); 15123 continue; 15124 } 15125 } 15126 timestamp=time((time_t *) NULL); 15127 (void) XNextEvent(display,&event); 15128 if (windows->image.stasis == MagickFalse) 15129 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15130 MagickTrue : MagickFalse; 15131 if (windows->magnify.stasis == MagickFalse) 15132 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15133 MagickTrue : MagickFalse; 15134 if (event.xany.window == windows->command.id) 15135 { 15136 /* 15137 Select a command from the Command widget. 15138 */ 15139 id=XCommandWidget(display,windows,CommandMenu,&event); 15140 if (id < 0) 15141 continue; 15142 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent); 15143 command_type=CommandMenus[id]; 15144 if (id < MagickMenus) 15145 { 15146 /* 15147 Select a command from a pop-up menu. 15148 */ 15149 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15150 command); 15151 if (entry < 0) 15152 continue; 15153 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent); 15154 command_type=Commands[id][entry]; 15155 } 15156 if (command_type != NullCommand) 15157 nexus=XMagickCommand(display,resource_info,windows,command_type, 15158 &display_image,exception); 15159 continue; 15160 } 15161 switch (event.type) 15162 { 15163 case ButtonPress: 15164 { 15165 if (display_image->debug != MagickFalse) 15166 (void) LogMagickEvent(X11Event,GetMagickModule(), 15167 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15168 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15169 if ((event.xbutton.button == Button3) && 15170 (event.xbutton.state & Mod1Mask)) 15171 { 15172 /* 15173 Convert Alt-Button3 to Button2. 15174 */ 15175 event.xbutton.button=Button2; 15176 event.xbutton.state&=(~Mod1Mask); 15177 } 15178 if (event.xbutton.window == windows->backdrop.id) 15179 { 15180 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15181 event.xbutton.time); 15182 break; 15183 } 15184 if (event.xbutton.window == windows->image.id) 15185 { 15186 switch (event.xbutton.button) 15187 { 15188 case Button1: 15189 { 15190 if (resource_info->immutable) 15191 { 15192 /* 15193 Select a command from the Virtual menu. 15194 */ 15195 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15196 command); 15197 if (entry >= 0) 15198 nexus=XMagickCommand(display,resource_info,windows, 15199 VirtualCommands[entry],&display_image,exception); 15200 break; 15201 } 15202 /* 15203 Map/unmap Command widget. 15204 */ 15205 if (windows->command.mapped != MagickFalse) 15206 (void) XWithdrawWindow(display,windows->command.id, 15207 windows->command.screen); 15208 else 15209 { 15210 (void) XCommandWidget(display,windows,CommandMenu, 15211 (XEvent *) NULL); 15212 (void) XMapRaised(display,windows->command.id); 15213 } 15214 break; 15215 } 15216 case Button2: 15217 { 15218 /* 15219 User pressed the image magnify button. 15220 */ 15221 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15222 &display_image,exception); 15223 XMagnifyImage(display,windows,&event); 15224 break; 15225 } 15226 case Button3: 15227 { 15228 if (resource_info->immutable) 15229 { 15230 /* 15231 Select a command from the Virtual menu. 15232 */ 15233 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15234 command); 15235 if (entry >= 0) 15236 nexus=XMagickCommand(display,resource_info,windows, 15237 VirtualCommands[entry],&display_image,exception); 15238 break; 15239 } 15240 if (display_image->montage != (char *) NULL) 15241 { 15242 /* 15243 Open or delete a tile from a visual image directory. 15244 */ 15245 nexus=XTileImage(display,resource_info,windows, 15246 display_image,&event,exception); 15247 if (nexus != (Image *) NULL) 15248 *state|=MontageImageState | NextImageState | ExitState; 15249 vid_info.x=(short int) windows->image.x; 15250 vid_info.y=(short int) windows->image.y; 15251 break; 15252 } 15253 /* 15254 Select a command from the Short Cuts menu. 15255 */ 15256 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15257 command); 15258 if (entry >= 0) 15259 nexus=XMagickCommand(display,resource_info,windows, 15260 ShortCutsCommands[entry],&display_image,exception); 15261 break; 15262 } 15263 case Button4: 15264 { 15265 /* 15266 Wheel up. 15267 */ 15268 XTranslateImage(display,windows,*image,XK_Up); 15269 break; 15270 } 15271 case Button5: 15272 { 15273 /* 15274 Wheel down. 15275 */ 15276 XTranslateImage(display,windows,*image,XK_Down); 15277 break; 15278 } 15279 default: 15280 break; 15281 } 15282 break; 15283 } 15284 if (event.xbutton.window == windows->magnify.id) 15285 { 15286 int 15287 factor; 15288 15289 static const char 15290 *MagnifyMenu[] = 15291 { 15292 "2", 15293 "4", 15294 "5", 15295 "6", 15296 "7", 15297 "8", 15298 "9", 15299 "3", 15300 (char *) NULL, 15301 }; 15302 15303 static KeySym 15304 MagnifyCommands[] = 15305 { 15306 XK_2, 15307 XK_4, 15308 XK_5, 15309 XK_6, 15310 XK_7, 15311 XK_8, 15312 XK_9, 15313 XK_3 15314 }; 15315 15316 /* 15317 Select a magnify factor from the pop-up menu. 15318 */ 15319 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15320 if (factor >= 0) 15321 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]); 15322 break; 15323 } 15324 if (event.xbutton.window == windows->pan.id) 15325 { 15326 switch (event.xbutton.button) 15327 { 15328 case Button4: 15329 { 15330 /* 15331 Wheel up. 15332 */ 15333 XTranslateImage(display,windows,*image,XK_Up); 15334 break; 15335 } 15336 case Button5: 15337 { 15338 /* 15339 Wheel down. 15340 */ 15341 XTranslateImage(display,windows,*image,XK_Down); 15342 break; 15343 } 15344 default: 15345 { 15346 XPanImage(display,windows,&event); 15347 break; 15348 } 15349 } 15350 break; 15351 } 15352 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15353 1L); 15354 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15355 break; 15356 } 15357 case ButtonRelease: 15358 { 15359 if (display_image->debug != MagickFalse) 15360 (void) LogMagickEvent(X11Event,GetMagickModule(), 15361 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15362 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15363 break; 15364 } 15365 case ClientMessage: 15366 { 15367 if (display_image->debug != MagickFalse) 15368 (void) LogMagickEvent(X11Event,GetMagickModule(), 15369 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15370 event.xclient.message_type,event.xclient.format,(unsigned long) 15371 event.xclient.data.l[0]); 15372 if (event.xclient.message_type == windows->im_protocols) 15373 { 15374 if (*event.xclient.data.l == (long) windows->im_update_widget) 15375 { 15376 (void) CloneString(&windows->command.name,MagickTitle); 15377 windows->command.data=MagickMenus; 15378 (void) XCommandWidget(display,windows,CommandMenu, 15379 (XEvent *) NULL); 15380 break; 15381 } 15382 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15383 { 15384 /* 15385 Update graphic context and window colormap. 15386 */ 15387 for (i=0; i < (int) number_windows; i++) 15388 { 15389 if (magick_windows[i]->id == windows->icon.id) 15390 continue; 15391 context_values.background=pixel->background_color.pixel; 15392 context_values.foreground=pixel->foreground_color.pixel; 15393 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15394 context_mask,&context_values); 15395 (void) XChangeGC(display,magick_windows[i]->widget_context, 15396 context_mask,&context_values); 15397 context_values.background=pixel->foreground_color.pixel; 15398 context_values.foreground=pixel->background_color.pixel; 15399 context_values.plane_mask=context_values.background ^ 15400 context_values.foreground; 15401 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15402 (size_t) (context_mask | GCPlaneMask), 15403 &context_values); 15404 magick_windows[i]->attributes.background_pixel= 15405 pixel->background_color.pixel; 15406 magick_windows[i]->attributes.border_pixel= 15407 pixel->border_color.pixel; 15408 magick_windows[i]->attributes.colormap=map_info->colormap; 15409 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15410 (unsigned long) magick_windows[i]->mask, 15411 &magick_windows[i]->attributes); 15412 } 15413 if (windows->pan.mapped != MagickFalse) 15414 { 15415 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15416 windows->pan.pixmap); 15417 (void) XClearWindow(display,windows->pan.id); 15418 XDrawPanRectangle(display,windows); 15419 } 15420 if (windows->backdrop.id != (Window) NULL) 15421 (void) XInstallColormap(display,map_info->colormap); 15422 break; 15423 } 15424 if (*event.xclient.data.l == (long) windows->im_former_image) 15425 { 15426 *state|=FormerImageState | ExitState; 15427 break; 15428 } 15429 if (*event.xclient.data.l == (long) windows->im_next_image) 15430 { 15431 *state|=NextImageState | ExitState; 15432 break; 15433 } 15434 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15435 { 15436 *state|=RetainColorsState; 15437 break; 15438 } 15439 if (*event.xclient.data.l == (long) windows->im_exit) 15440 { 15441 *state|=ExitState; 15442 break; 15443 } 15444 break; 15445 } 15446 if (event.xclient.message_type == windows->dnd_protocols) 15447 { 15448 Atom 15449 selection, 15450 type; 15451 15452 int 15453 format, 15454 status; 15455 15456 unsigned char 15457 *data; 15458 15459 unsigned long 15460 after, 15461 length; 15462 15463 /* 15464 Display image named by the Drag-and-Drop selection. 15465 */ 15466 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15467 break; 15468 selection=XInternAtom(display,"DndSelection",MagickFalse); 15469 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15470 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15471 &length,&after,&data); 15472 if ((status != Success) || (length == 0)) 15473 break; 15474 if (*event.xclient.data.l == 2) 15475 { 15476 /* 15477 Offix DND. 15478 */ 15479 (void) CopyMagickString(resource_info->image_info->filename, 15480 (char *) data,MaxTextExtent); 15481 } 15482 else 15483 { 15484 /* 15485 XDND. 15486 */ 15487 if (strncmp((char *) data, "file:", 5) != 0) 15488 { 15489 (void) XFree((void *) data); 15490 break; 15491 } 15492 (void) CopyMagickString(resource_info->image_info->filename, 15493 ((char *) data)+5,MaxTextExtent); 15494 } 15495 nexus=ReadImage(resource_info->image_info, 15496 &display_image->exception); 15497 CatchException(&display_image->exception); 15498 if (nexus != (Image *) NULL) 15499 *state|=NextImageState | ExitState; 15500 (void) XFree((void *) data); 15501 break; 15502 } 15503 /* 15504 If client window delete message, exit. 15505 */ 15506 if (event.xclient.message_type != windows->wm_protocols) 15507 break; 15508 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15509 break; 15510 (void) XWithdrawWindow(display,event.xclient.window, 15511 visual_info->screen); 15512 if (event.xclient.window == windows->image.id) 15513 { 15514 *state|=ExitState; 15515 break; 15516 } 15517 if (event.xclient.window == windows->pan.id) 15518 { 15519 /* 15520 Restore original image size when pan window is deleted. 15521 */ 15522 windows->image.window_changes.width=windows->image.ximage->width; 15523 windows->image.window_changes.height=windows->image.ximage->height; 15524 (void) XConfigureImage(display,resource_info,windows, 15525 display_image,exception); 15526 } 15527 break; 15528 } 15529 case ConfigureNotify: 15530 { 15531 if (display_image->debug != MagickFalse) 15532 (void) LogMagickEvent(X11Event,GetMagickModule(), 15533 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15534 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15535 event.xconfigure.y,event.xconfigure.send_event); 15536 if (event.xconfigure.window == windows->image.id) 15537 { 15538 /* 15539 Image window has a new configuration. 15540 */ 15541 if (event.xconfigure.send_event != 0) 15542 { 15543 XWindowChanges 15544 window_changes; 15545 15546 /* 15547 Position the transient windows relative of the Image window. 15548 */ 15549 if (windows->command.geometry == (char *) NULL) 15550 if (windows->command.mapped == MagickFalse) 15551 { 15552 windows->command.x=event.xconfigure.x- 15553 windows->command.width-25; 15554 windows->command.y=event.xconfigure.y; 15555 XConstrainWindowPosition(display,&windows->command); 15556 window_changes.x=windows->command.x; 15557 window_changes.y=windows->command.y; 15558 (void) XReconfigureWMWindow(display,windows->command.id, 15559 windows->command.screen,(unsigned int) (CWX | CWY), 15560 &window_changes); 15561 } 15562 if (windows->widget.geometry == (char *) NULL) 15563 if (windows->widget.mapped == MagickFalse) 15564 { 15565 windows->widget.x=event.xconfigure.x+ 15566 event.xconfigure.width/10; 15567 windows->widget.y=event.xconfigure.y+ 15568 event.xconfigure.height/10; 15569 XConstrainWindowPosition(display,&windows->widget); 15570 window_changes.x=windows->widget.x; 15571 window_changes.y=windows->widget.y; 15572 (void) XReconfigureWMWindow(display,windows->widget.id, 15573 windows->widget.screen,(unsigned int) (CWX | CWY), 15574 &window_changes); 15575 } 15576 if (windows->magnify.geometry == (char *) NULL) 15577 if (windows->magnify.mapped == MagickFalse) 15578 { 15579 windows->magnify.x=event.xconfigure.x+ 15580 event.xconfigure.width+25; 15581 windows->magnify.y=event.xconfigure.y; 15582 XConstrainWindowPosition(display,&windows->magnify); 15583 window_changes.x=windows->magnify.x; 15584 window_changes.y=windows->magnify.y; 15585 (void) XReconfigureWMWindow(display,windows->magnify.id, 15586 windows->magnify.screen,(unsigned int) (CWX | CWY), 15587 &window_changes); 15588 } 15589 if (windows->pan.geometry == (char *) NULL) 15590 if (windows->pan.mapped == MagickFalse) 15591 { 15592 windows->pan.x=event.xconfigure.x+ 15593 event.xconfigure.width+25; 15594 windows->pan.y=event.xconfigure.y+ 15595 windows->magnify.height+50; 15596 XConstrainWindowPosition(display,&windows->pan); 15597 window_changes.x=windows->pan.x; 15598 window_changes.y=windows->pan.y; 15599 (void) XReconfigureWMWindow(display,windows->pan.id, 15600 windows->pan.screen,(unsigned int) (CWX | CWY), 15601 &window_changes); 15602 } 15603 } 15604 if ((event.xconfigure.width == (int) windows->image.width) && 15605 (event.xconfigure.height == (int) windows->image.height)) 15606 break; 15607 windows->image.width=(unsigned int) event.xconfigure.width; 15608 windows->image.height=(unsigned int) event.xconfigure.height; 15609 windows->image.x=0; 15610 windows->image.y=0; 15611 if (display_image->montage != (char *) NULL) 15612 { 15613 windows->image.x=vid_info.x; 15614 windows->image.y=vid_info.y; 15615 } 15616 if ((windows->image.mapped != MagickFalse) && 15617 (windows->image.stasis != MagickFalse)) 15618 { 15619 /* 15620 Update image window configuration. 15621 */ 15622 windows->image.window_changes.width=event.xconfigure.width; 15623 windows->image.window_changes.height=event.xconfigure.height; 15624 (void) XConfigureImage(display,resource_info,windows, 15625 display_image,exception); 15626 } 15627 /* 15628 Update pan window configuration. 15629 */ 15630 if ((event.xconfigure.width < windows->image.ximage->width) || 15631 (event.xconfigure.height < windows->image.ximage->height)) 15632 { 15633 (void) XMapRaised(display,windows->pan.id); 15634 XDrawPanRectangle(display,windows); 15635 } 15636 else 15637 if (windows->pan.mapped != MagickFalse) 15638 (void) XWithdrawWindow(display,windows->pan.id, 15639 windows->pan.screen); 15640 break; 15641 } 15642 if (event.xconfigure.window == windows->magnify.id) 15643 { 15644 unsigned int 15645 magnify; 15646 15647 /* 15648 Magnify window has a new configuration. 15649 */ 15650 windows->magnify.width=(unsigned int) event.xconfigure.width; 15651 windows->magnify.height=(unsigned int) event.xconfigure.height; 15652 if (windows->magnify.mapped == MagickFalse) 15653 break; 15654 magnify=1; 15655 while ((int) magnify <= event.xconfigure.width) 15656 magnify<<=1; 15657 while ((int) magnify <= event.xconfigure.height) 15658 magnify<<=1; 15659 magnify>>=1; 15660 if (((int) magnify != event.xconfigure.width) || 15661 ((int) magnify != event.xconfigure.height)) 15662 { 15663 window_changes.width=(int) magnify; 15664 window_changes.height=(int) magnify; 15665 (void) XReconfigureWMWindow(display,windows->magnify.id, 15666 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15667 &window_changes); 15668 break; 15669 } 15670 if ((windows->magnify.mapped != MagickFalse) && 15671 (windows->magnify.stasis != MagickFalse)) 15672 { 15673 status=XMakeImage(display,resource_info,&windows->magnify, 15674 display_image,windows->magnify.width,windows->magnify.height, 15675 exception); 15676 XMakeMagnifyImage(display,windows); 15677 } 15678 break; 15679 } 15680 if ((windows->magnify.mapped != MagickFalse) && 15681 (event.xconfigure.window == windows->pan.id)) 15682 { 15683 /* 15684 Pan icon window has a new configuration. 15685 */ 15686 if (event.xconfigure.send_event != 0) 15687 { 15688 windows->pan.x=event.xconfigure.x; 15689 windows->pan.y=event.xconfigure.y; 15690 } 15691 windows->pan.width=(unsigned int) event.xconfigure.width; 15692 windows->pan.height=(unsigned int) event.xconfigure.height; 15693 break; 15694 } 15695 if (event.xconfigure.window == windows->icon.id) 15696 { 15697 /* 15698 Icon window has a new configuration. 15699 */ 15700 windows->icon.width=(unsigned int) event.xconfigure.width; 15701 windows->icon.height=(unsigned int) event.xconfigure.height; 15702 break; 15703 } 15704 break; 15705 } 15706 case DestroyNotify: 15707 { 15708 /* 15709 Group leader has exited. 15710 */ 15711 if (display_image->debug != MagickFalse) 15712 (void) LogMagickEvent(X11Event,GetMagickModule(), 15713 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15714 if (event.xdestroywindow.window == windows->group_leader.id) 15715 { 15716 *state|=ExitState; 15717 break; 15718 } 15719 break; 15720 } 15721 case EnterNotify: 15722 { 15723 /* 15724 Selectively install colormap. 15725 */ 15726 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15727 if (event.xcrossing.mode != NotifyUngrab) 15728 XInstallColormap(display,map_info->colormap); 15729 break; 15730 } 15731 case Expose: 15732 { 15733 if (display_image->debug != MagickFalse) 15734 (void) LogMagickEvent(X11Event,GetMagickModule(), 15735 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15736 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15737 event.xexpose.y); 15738 /* 15739 Refresh windows that are now exposed. 15740 */ 15741 if ((event.xexpose.window == windows->image.id) && 15742 (windows->image.mapped != MagickFalse)) 15743 { 15744 XRefreshWindow(display,&windows->image,&event); 15745 delay=display_image->delay/MagickMax( 15746 display_image->ticks_per_second,1L); 15747 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15748 break; 15749 } 15750 if ((event.xexpose.window == windows->magnify.id) && 15751 (windows->magnify.mapped != MagickFalse)) 15752 { 15753 XMakeMagnifyImage(display,windows); 15754 break; 15755 } 15756 if (event.xexpose.window == windows->pan.id) 15757 { 15758 XDrawPanRectangle(display,windows); 15759 break; 15760 } 15761 if (event.xexpose.window == windows->icon.id) 15762 { 15763 XRefreshWindow(display,&windows->icon,&event); 15764 break; 15765 } 15766 break; 15767 } 15768 case KeyPress: 15769 { 15770 int 15771 length; 15772 15773 /* 15774 Respond to a user key press. 15775 */ 15776 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15777 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15778 *(command+length)='\0'; 15779 if (display_image->debug != MagickFalse) 15780 (void) LogMagickEvent(X11Event,GetMagickModule(), 15781 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15782 key_symbol,command); 15783 if (event.xkey.window == windows->image.id) 15784 { 15785 command_type=XImageWindowCommand(display,resource_info,windows, 15786 event.xkey.state,key_symbol,&display_image,exception); 15787 if (command_type != NullCommand) 15788 nexus=XMagickCommand(display,resource_info,windows,command_type, 15789 &display_image,exception); 15790 } 15791 if (event.xkey.window == windows->magnify.id) 15792 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol); 15793 if (event.xkey.window == windows->pan.id) 15794 { 15795 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15796 (void) XWithdrawWindow(display,windows->pan.id, 15797 windows->pan.screen); 15798 else 15799 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15800 XTextViewWidget(display,resource_info,windows,MagickFalse, 15801 "Help Viewer - Image Pan",ImagePanHelp); 15802 else 15803 XTranslateImage(display,windows,*image,key_symbol); 15804 } 15805 delay=display_image->delay/MagickMax( 15806 display_image->ticks_per_second,1L); 15807 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15808 break; 15809 } 15810 case KeyRelease: 15811 { 15812 /* 15813 Respond to a user key release. 15814 */ 15815 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15816 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15817 if (display_image->debug != MagickFalse) 15818 (void) LogMagickEvent(X11Event,GetMagickModule(), 15819 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15820 break; 15821 } 15822 case LeaveNotify: 15823 { 15824 /* 15825 Selectively uninstall colormap. 15826 */ 15827 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15828 if (event.xcrossing.mode != NotifyUngrab) 15829 XUninstallColormap(display,map_info->colormap); 15830 break; 15831 } 15832 case MapNotify: 15833 { 15834 if (display_image->debug != MagickFalse) 15835 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15836 event.xmap.window); 15837 if (event.xmap.window == windows->backdrop.id) 15838 { 15839 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15840 CurrentTime); 15841 windows->backdrop.mapped=MagickTrue; 15842 break; 15843 } 15844 if (event.xmap.window == windows->image.id) 15845 { 15846 if (windows->backdrop.id != (Window) NULL) 15847 (void) XInstallColormap(display,map_info->colormap); 15848 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15849 { 15850 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15851 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15852 } 15853 if (((int) windows->image.width < windows->image.ximage->width) || 15854 ((int) windows->image.height < windows->image.ximage->height)) 15855 (void) XMapRaised(display,windows->pan.id); 15856 windows->image.mapped=MagickTrue; 15857 break; 15858 } 15859 if (event.xmap.window == windows->magnify.id) 15860 { 15861 XMakeMagnifyImage(display,windows); 15862 windows->magnify.mapped=MagickTrue; 15863 (void) XWithdrawWindow(display,windows->info.id, 15864 windows->info.screen); 15865 break; 15866 } 15867 if (event.xmap.window == windows->pan.id) 15868 { 15869 XMakePanImage(display,resource_info,windows,display_image, 15870 exception); 15871 windows->pan.mapped=MagickTrue; 15872 break; 15873 } 15874 if (event.xmap.window == windows->info.id) 15875 { 15876 windows->info.mapped=MagickTrue; 15877 break; 15878 } 15879 if (event.xmap.window == windows->icon.id) 15880 { 15881 MagickBooleanType 15882 taint; 15883 15884 /* 15885 Create an icon image. 15886 */ 15887 taint=display_image->taint; 15888 XMakeStandardColormap(display,icon_visual,icon_resources, 15889 display_image,icon_map,icon_pixel); 15890 (void) XMakeImage(display,icon_resources,&windows->icon, 15891 display_image,windows->icon.width,windows->icon.height, 15892 exception); 15893 display_image->taint=taint; 15894 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15895 windows->icon.pixmap); 15896 (void) XClearWindow(display,windows->icon.id); 15897 (void) XWithdrawWindow(display,windows->info.id, 15898 windows->info.screen); 15899 windows->icon.mapped=MagickTrue; 15900 break; 15901 } 15902 if (event.xmap.window == windows->command.id) 15903 { 15904 windows->command.mapped=MagickTrue; 15905 break; 15906 } 15907 if (event.xmap.window == windows->popup.id) 15908 { 15909 windows->popup.mapped=MagickTrue; 15910 break; 15911 } 15912 if (event.xmap.window == windows->widget.id) 15913 { 15914 windows->widget.mapped=MagickTrue; 15915 break; 15916 } 15917 break; 15918 } 15919 case MappingNotify: 15920 { 15921 (void) XRefreshKeyboardMapping(&event.xmapping); 15922 break; 15923 } 15924 case NoExpose: 15925 break; 15926 case PropertyNotify: 15927 { 15928 Atom 15929 type; 15930 15931 int 15932 format, 15933 status; 15934 15935 unsigned char 15936 *data; 15937 15938 unsigned long 15939 after, 15940 length; 15941 15942 if (display_image->debug != MagickFalse) 15943 (void) LogMagickEvent(X11Event,GetMagickModule(), 15944 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15945 event.xproperty.atom,event.xproperty.state); 15946 if (event.xproperty.atom != windows->im_remote_command) 15947 break; 15948 /* 15949 Display image named by the remote command protocol. 15950 */ 15951 status=XGetWindowProperty(display,event.xproperty.window, 15952 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom) 15953 AnyPropertyType,&type,&format,&length,&after,&data); 15954 if ((status != Success) || (length == 0)) 15955 break; 15956 if (LocaleCompare((char *) data,"-quit") == 0) 15957 { 15958 XClientMessage(display,windows->image.id,windows->im_protocols, 15959 windows->im_exit,CurrentTime); 15960 (void) XFree((void *) data); 15961 break; 15962 } 15963 (void) CopyMagickString(resource_info->image_info->filename, 15964 (char *) data,MaxTextExtent); 15965 (void) XFree((void *) data); 15966 nexus=ReadImage(resource_info->image_info,&display_image->exception); 15967 CatchException(&display_image->exception); 15968 if (nexus != (Image *) NULL) 15969 *state|=NextImageState | ExitState; 15970 break; 15971 } 15972 case ReparentNotify: 15973 { 15974 if (display_image->debug != MagickFalse) 15975 (void) LogMagickEvent(X11Event,GetMagickModule(), 15976 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 15977 event.xreparent.window); 15978 break; 15979 } 15980 case UnmapNotify: 15981 { 15982 if (display_image->debug != MagickFalse) 15983 (void) LogMagickEvent(X11Event,GetMagickModule(), 15984 "Unmap Notify: 0x%lx",event.xunmap.window); 15985 if (event.xunmap.window == windows->backdrop.id) 15986 { 15987 windows->backdrop.mapped=MagickFalse; 15988 break; 15989 } 15990 if (event.xunmap.window == windows->image.id) 15991 { 15992 windows->image.mapped=MagickFalse; 15993 break; 15994 } 15995 if (event.xunmap.window == windows->magnify.id) 15996 { 15997 windows->magnify.mapped=MagickFalse; 15998 break; 15999 } 16000 if (event.xunmap.window == windows->pan.id) 16001 { 16002 windows->pan.mapped=MagickFalse; 16003 break; 16004 } 16005 if (event.xunmap.window == windows->info.id) 16006 { 16007 windows->info.mapped=MagickFalse; 16008 break; 16009 } 16010 if (event.xunmap.window == windows->icon.id) 16011 { 16012 if (map_info->colormap == icon_map->colormap) 16013 XConfigureImageColormap(display,resource_info,windows, 16014 display_image); 16015 (void) XFreeStandardColormap(display,icon_visual,icon_map, 16016 icon_pixel); 16017 windows->icon.mapped=MagickFalse; 16018 break; 16019 } 16020 if (event.xunmap.window == windows->command.id) 16021 { 16022 windows->command.mapped=MagickFalse; 16023 break; 16024 } 16025 if (event.xunmap.window == windows->popup.id) 16026 { 16027 if (windows->backdrop.id != (Window) NULL) 16028 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16029 CurrentTime); 16030 windows->popup.mapped=MagickFalse; 16031 break; 16032 } 16033 if (event.xunmap.window == windows->widget.id) 16034 { 16035 if (windows->backdrop.id != (Window) NULL) 16036 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16037 CurrentTime); 16038 windows->widget.mapped=MagickFalse; 16039 break; 16040 } 16041 break; 16042 } 16043 default: 16044 { 16045 if (display_image->debug != MagickFalse) 16046 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 16047 event.type); 16048 break; 16049 } 16050 } 16051 } while (!(*state & ExitState)); 16052 if ((*state & ExitState) == 0) 16053 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 16054 &display_image,exception); 16055 else 16056 if (resource_info->confirm_edit != MagickFalse) 16057 { 16058 /* 16059 Query user if image has changed. 16060 */ 16061 if ((resource_info->immutable == MagickFalse) && 16062 (display_image->taint != MagickFalse)) 16063 { 16064 int 16065 status; 16066 16067 status=XConfirmWidget(display,windows,"Your image changed.", 16068 "Do you want to save it"); 16069 if (status == 0) 16070 *state&=(~ExitState); 16071 else 16072 if (status > 0) 16073 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 16074 &display_image,exception); 16075 } 16076 } 16077 if ((windows->visual_info->klass == GrayScale) || 16078 (windows->visual_info->klass == PseudoColor) || 16079 (windows->visual_info->klass == DirectColor)) 16080 { 16081 /* 16082 Withdraw pan and Magnify window. 16083 */ 16084 if (windows->info.mapped != MagickFalse) 16085 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 16086 if (windows->magnify.mapped != MagickFalse) 16087 (void) XWithdrawWindow(display,windows->magnify.id, 16088 windows->magnify.screen); 16089 if (windows->command.mapped != MagickFalse) 16090 (void) XWithdrawWindow(display,windows->command.id, 16091 windows->command.screen); 16092 } 16093 if (windows->pan.mapped != MagickFalse) 16094 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 16095 if (resource_info->backdrop == MagickFalse) 16096 if (windows->backdrop.mapped) 16097 { 16098 (void) XWithdrawWindow(display,windows->backdrop.id, 16099 windows->backdrop.screen); 16100 (void) XDestroyWindow(display,windows->backdrop.id); 16101 windows->backdrop.id=(Window) NULL; 16102 (void) XWithdrawWindow(display,windows->image.id, 16103 windows->image.screen); 16104 (void) XDestroyWindow(display,windows->image.id); 16105 windows->image.id=(Window) NULL; 16106 } 16107 XSetCursorState(display,windows,MagickTrue); 16108 XCheckRefreshWindows(display,windows); 16109 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 16110 *state&=(~ExitState); 16111 if (*state & ExitState) 16112 { 16113 /* 16114 Free Standard Colormap. 16115 */ 16116 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 16117 if (resource_info->map_type == (char *) NULL) 16118 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 16119 /* 16120 Free X resources. 16121 */ 16122 if (resource_info->copy_image != (Image *) NULL) 16123 { 16124 resource_info->copy_image=DestroyImage(resource_info->copy_image); 16125 resource_info->copy_image=NewImageList(); 16126 } 16127 DestroyXResources(); 16128 } 16129 (void) XSync(display,MagickFalse); 16130 /* 16131 Restore our progress monitor and warning handlers. 16132 */ 16133 (void) SetErrorHandler(warning_handler); 16134 (void) SetWarningHandler(warning_handler); 16135 /* 16136 Change to home directory. 16137 */ 16138 directory=getcwd(working_directory,MaxTextExtent); 16139 (void) directory; 16140 { 16141 int 16142 status; 16143 16144 status=chdir(resource_info->home_directory); 16145 if (status == -1) 16146 (void) ThrowMagickException(&display_image->exception,GetMagickModule(), 16147 FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory); 16148 } 16149 *image=display_image; 16150 return(nexus); 16151} 16152#else 16153 16154/* 16155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16156% % 16157% % 16158% % 16159+ D i s p l a y I m a g e s % 16160% % 16161% % 16162% % 16163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16164% 16165% DisplayImages() displays an image sequence to any X window screen. It 16166% returns a value other than 0 if successful. Check the exception member 16167% of image to determine the reason for any failure. 16168% 16169% The format of the DisplayImages method is: 16170% 16171% MagickBooleanType DisplayImages(const ImageInfo *image_info, 16172% Image *images,ExceptionInfo *exception) 16173% 16174% A description of each parameter follows: 16175% 16176% o image_info: the image info. 16177% 16178% o image: the image. 16179% 16180% o exception: return any errors or warnings in this structure. 16181% 16182*/ 16183MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16184 Image *image,ExceptionInfo *exception) 16185{ 16186 assert(image_info != (const ImageInfo *) NULL); 16187 assert(image_info->signature == MagickSignature); 16188 assert(image != (Image *) NULL); 16189 assert(image->signature == MagickSignature); 16190 if (image->debug != MagickFalse) 16191 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16192 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16193 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image->filename); 16194 return(MagickFalse); 16195} 16196 16197/* 16198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16199% % 16200% % 16201% % 16202+ R e m o t e D i s p l a y C o m m a n d % 16203% % 16204% % 16205% % 16206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16207% 16208% RemoteDisplayCommand() encourages a remote display program to display the 16209% specified image filename. 16210% 16211% The format of the RemoteDisplayCommand method is: 16212% 16213% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16214% const char *window,const char *filename,ExceptionInfo *exception) 16215% 16216% A description of each parameter follows: 16217% 16218% o image_info: the image info. 16219% 16220% o window: Specifies the name or id of an X window. 16221% 16222% o filename: the name of the image filename to display. 16223% 16224% o exception: return any errors or warnings in this structure. 16225% 16226*/ 16227MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16228 const char *window,const char *filename,ExceptionInfo *exception) 16229{ 16230 assert(image_info != (const ImageInfo *) NULL); 16231 assert(image_info->signature == MagickSignature); 16232 assert(filename != (char *) NULL); 16233 (void) window; 16234 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16235 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16236 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename); 16237 return(MagickFalse); 16238} 16239#endif 16240