display.c revision 803640d20a6a664315eddfff6f8531d0c5e0871d
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% DDDD IIIII SSSSS PPPP L AAA Y Y % 7% D D I SS P P L A A Y Y % 8% D D I SSS PPPP L AAAAA Y % 9% D D I SS P L A A Y % 10% DDDD IIIII SSSSS P LLLLL A A Y % 11% % 12% % 13% MagickCore Methods to Interactively Display and Edit an Image % 14% % 15% Software Design % 16% John Cristy % 17% July 1992 % 18% % 19% % 20% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization % 21% dedicated to making software imaging solutions freely available. % 22% % 23% You may not use this file except in compliance with the License. You may % 24% obtain a copy of the License at % 25% % 26% http://www.imagemagick.org/script/license.php % 27% % 28% Unless required by applicable law or agreed to in writing, software % 29% distributed under the License is distributed on an "AS IS" BASIS, % 30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31% See the License for the specific language governing permissions and % 32% limitations under the License. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 36% 37*/ 38 39/* 40 Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/artifact.h" 44#include "MagickCore/blob.h" 45#include "MagickCore/cache.h" 46#include "MagickCore/cache-private.h" 47#include "MagickCore/client.h" 48#include "MagickCore/color.h" 49#include "MagickCore/colorspace.h" 50#include "MagickCore/composite.h" 51#include "MagickCore/constitute.h" 52#include "MagickCore/decorate.h" 53#include "MagickCore/delegate.h" 54#include "MagickCore/display.h" 55#include "MagickCore/display-private.h" 56#include "MagickCore/draw.h" 57#include "MagickCore/effect.h" 58#include "MagickCore/enhance.h" 59#include "MagickCore/exception.h" 60#include "MagickCore/exception-private.h" 61#include "MagickCore/fx.h" 62#include "MagickCore/geometry.h" 63#include "MagickCore/image.h" 64#include "MagickCore/image-private.h" 65#include "MagickCore/list.h" 66#include "MagickCore/log.h" 67#include "MagickCore/magick.h" 68#include "MagickCore/memory_.h" 69#include "MagickCore/monitor.h" 70#include "MagickCore/monitor-private.h" 71#include "MagickCore/montage.h" 72#include "MagickCore/option.h" 73#include "MagickCore/paint.h" 74#include "MagickCore/pixel.h" 75#include "MagickCore/pixel-accessor.h" 76#include "MagickCore/PreRvIcccm.h" 77#include "MagickCore/property.h" 78#include "MagickCore/quantum.h" 79#include "MagickCore/quantum-private.h" 80#include "MagickCore/resize.h" 81#include "MagickCore/resource_.h" 82#include "MagickCore/shear.h" 83#include "MagickCore/segment.h" 84#include "MagickCore/string_.h" 85#include "MagickCore/string-private.h" 86#include "MagickCore/transform.h" 87#include "MagickCore/threshold.h" 88#include "MagickCore/utility.h" 89#include "MagickCore/utility-private.h" 90#include "MagickCore/version.h" 91#include "MagickCore/widget.h" 92#include "MagickCore/widget-private.h" 93#include "MagickCore/xwindow.h" 94#include "MagickCore/xwindow-private.h" 95 96#if defined(MAGICKCORE_X11_DELEGATE) 97/* 98 Define declarations. 99*/ 100#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L) 101 102/* 103 Constant declarations. 104*/ 105static const unsigned char 106 HighlightBitmap[8] = 107 { 108 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 109 }, 110 OpaqueBitmap[8] = 111 { 112 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 113 }, 114 ShadowBitmap[8] = 115 { 116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 117 }; 118 119static const char 120 *PageSizes[] = 121 { 122 "Letter", 123 "Tabloid", 124 "Ledger", 125 "Legal", 126 "Statement", 127 "Executive", 128 "A3", 129 "A4", 130 "A5", 131 "B4", 132 "B5", 133 "Folio", 134 "Quarto", 135 "10x14", 136 (char *) NULL 137 }; 138 139/* 140 Help widget declarations. 141*/ 142static const char 143 *ImageAnnotateHelp[] = 144 { 145 "In annotate mode, the Command widget has these options:", 146 "", 147 " Font Name", 148 " fixed", 149 " variable", 150 " 5x8", 151 " 6x10", 152 " 7x13bold", 153 " 8x13bold", 154 " 9x15bold", 155 " 10x20", 156 " 12x24", 157 " Browser...", 158 " Font Color", 159 " black", 160 " blue", 161 " cyan", 162 " green", 163 " gray", 164 " red", 165 " magenta", 166 " yellow", 167 " white", 168 " transparent", 169 " Browser...", 170 " Font Color", 171 " black", 172 " blue", 173 " cyan", 174 " green", 175 " gray", 176 " red", 177 " magenta", 178 " yellow", 179 " white", 180 " transparent", 181 " Browser...", 182 " Rotate Text", 183 " -90", 184 " -45", 185 " -30", 186 " 0", 187 " 30", 188 " 45", 189 " 90", 190 " 180", 191 " Dialog...", 192 " Help", 193 " Dismiss", 194 "", 195 "Choose a font name from the Font Name sub-menu. Additional", 196 "font names can be specified with the font browser. You can", 197 "change the menu names by setting the X resources font1", 198 "through font9.", 199 "", 200 "Choose a font color from the Font Color sub-menu.", 201 "Additional font colors can be specified with the color", 202 "browser. You can change the menu colors by setting the X", 203 "resources pen1 through pen9.", 204 "", 205 "If you select the color browser and press Grab, you can", 206 "choose the font color by moving the pointer to the desired", 207 "color on the screen and press any button.", 208 "", 209 "If you choose to rotate the text, choose Rotate Text from the", 210 "menu and select an angle. Typically you will only want to", 211 "rotate one line of text at a time. Depending on the angle you", 212 "choose, subsequent lines may end up overwriting each other.", 213 "", 214 "Choosing a font and its color is optional. The default font", 215 "is fixed and the default color is black. However, you must", 216 "choose a location to begin entering text and press button 1.", 217 "An underscore character will appear at the location of the", 218 "pointer. The cursor changes to a pencil to indicate you are", 219 "in text mode. To exit immediately, press Dismiss.", 220 "", 221 "In text mode, any key presses will display the character at", 222 "the location of the underscore and advance the underscore", 223 "cursor. Enter your text and once completed press Apply to", 224 "finish your image annotation. To correct errors press BACK", 225 "SPACE. To delete an entire line of text, press DELETE. Any", 226 "text that exceeds the boundaries of the image window is", 227 "automagically continued onto the next line.", 228 "", 229 "The actual color you request for the font is saved in the", 230 "image. However, the color that appears in your image window", 231 "may be different. For example, on a monochrome screen the", 232 "text will appear black or white even if you choose the color", 233 "red as the font color. However, the image saved to a file", 234 "with -write is written with red lettering. To assure the", 235 "correct color text in the final image, any PseudoClass image", 236 "is promoted to DirectClass (see miff(5)). To force a", 237 "PseudoClass image to remain PseudoClass, use -colors.", 238 (char *) NULL, 239 }, 240 *ImageChopHelp[] = 241 { 242 "In chop mode, the Command widget has these options:", 243 "", 244 " Direction", 245 " horizontal", 246 " vertical", 247 " Help", 248 " Dismiss", 249 "", 250 "If the you choose the horizontal direction (this the", 251 "default), the area of the image between the two horizontal", 252 "endpoints of the chop line is removed. Otherwise, the area", 253 "of the image between the two vertical endpoints of the chop", 254 "line is removed.", 255 "", 256 "Select a location within the image window to begin your chop,", 257 "press and hold any button. Next, move the pointer to", 258 "another location in the image. As you move a line will", 259 "connect the initial location and the pointer. When you", 260 "release the button, the area within the image to chop is", 261 "determined by which direction you choose from the Command", 262 "widget.", 263 "", 264 "To cancel the image chopping, move the pointer back to the", 265 "starting point of the line and release the button.", 266 (char *) NULL, 267 }, 268 *ImageColorEditHelp[] = 269 { 270 "In color edit mode, the Command widget has these options:", 271 "", 272 " Method", 273 " point", 274 " replace", 275 " floodfill", 276 " filltoborder", 277 " reset", 278 " Pixel Color", 279 " black", 280 " blue", 281 " cyan", 282 " green", 283 " gray", 284 " red", 285 " magenta", 286 " yellow", 287 " white", 288 " Browser...", 289 " Border Color", 290 " black", 291 " blue", 292 " cyan", 293 " green", 294 " gray", 295 " red", 296 " magenta", 297 " yellow", 298 " white", 299 " Browser...", 300 " Fuzz", 301 " 0%", 302 " 2%", 303 " 5%", 304 " 10%", 305 " 15%", 306 " Dialog...", 307 " Undo", 308 " Help", 309 " Dismiss", 310 "", 311 "Choose a color editing method from the Method sub-menu", 312 "of the Command widget. The point method recolors any pixel", 313 "selected with the pointer until the button is released. The", 314 "replace method recolors any pixel that matches the color of", 315 "the pixel you select with a button press. Floodfill recolors", 316 "any pixel that matches the color of the pixel you select with", 317 "a button press and is a neighbor. Whereas filltoborder recolors", 318 "any neighbor pixel that is not the border color. Finally reset", 319 "changes the entire image to the designated color.", 320 "", 321 "Next, choose a pixel color from the Pixel Color sub-menu.", 322 "Additional pixel colors can be specified with the color", 323 "browser. You can change the menu colors by setting the X", 324 "resources pen1 through pen9.", 325 "", 326 "Now press button 1 to select a pixel within the image window", 327 "to change its color. Additional pixels may be recolored as", 328 "prescribed by the method you choose.", 329 "", 330 "If the Magnify widget is mapped, it can be helpful in positioning", 331 "your pointer within the image (refer to button 2).", 332 "", 333 "The actual color you request for the pixels is saved in the", 334 "image. However, the color that appears in your image window", 335 "may be different. For example, on a monochrome screen the", 336 "pixel will appear black or white even if you choose the", 337 "color red as the pixel color. However, the image saved to a", 338 "file with -write is written with red pixels. To assure the", 339 "correct color text in the final image, any PseudoClass image", 340 "is promoted to DirectClass (see miff(5)). To force a", 341 "PseudoClass image to remain PseudoClass, use -colors.", 342 (char *) NULL, 343 }, 344 *ImageCompositeHelp[] = 345 { 346 "First a widget window is displayed requesting you to enter an", 347 "image name. Press Composite, Grab or type a file name.", 348 "Press Cancel if you choose not to create a composite image.", 349 "When you choose Grab, move the pointer to the desired window", 350 "and press any button.", 351 "", 352 "If the Composite image does not have any matte information,", 353 "you are informed and the file browser is displayed again.", 354 "Enter the name of a mask image. The image is typically", 355 "grayscale and the same size as the composite image. If the", 356 "image is not grayscale, it is converted to grayscale and the", 357 "resulting intensities are used as matte information.", 358 "", 359 "A small window appears showing the location of the cursor in", 360 "the image window. You are now in composite mode. To exit", 361 "immediately, press Dismiss. In composite mode, the Command", 362 "widget has these options:", 363 "", 364 " Operators", 365 " Over", 366 " In", 367 " Out", 368 " Atop", 369 " Xor", 370 " Plus", 371 " Minus", 372 " Add", 373 " Subtract", 374 " Difference", 375 " Multiply", 376 " Bumpmap", 377 " Copy", 378 " CopyRed", 379 " CopyGreen", 380 " CopyBlue", 381 " CopyOpacity", 382 " Clear", 383 " Dissolve", 384 " Displace", 385 " Help", 386 " Dismiss", 387 "", 388 "Choose a composite operation from the Operators sub-menu of", 389 "the Command widget. How each operator behaves is described", 390 "below. Image window is the image currently displayed on", 391 "your X server and image is the image obtained with the File", 392 "Browser widget.", 393 "", 394 "Over The result is the union of the two image shapes,", 395 " with image obscuring image window in the region of", 396 " overlap.", 397 "", 398 "In The result is simply image cut by the shape of", 399 " image window. None of the image data of image", 400 " window is in the result.", 401 "", 402 "Out The resulting image is image with the shape of", 403 " image window cut out.", 404 "", 405 "Atop The result is the same shape as image image window,", 406 " with image obscuring image window where the image", 407 " shapes overlap. Note this differs from over", 408 " because the portion of image outside image window's", 409 " shape does not appear in the result.", 410 "", 411 "Xor The result is the image data from both image and", 412 " image window that is outside the overlap region.", 413 " The overlap region is blank.", 414 "", 415 "Plus The result is just the sum of the image data.", 416 " Output values are cropped to QuantumRange (no overflow).", 417 "", 418 "Minus The result of image - image window, with underflow", 419 " cropped to zero.", 420 "", 421 "Add The result of image + image window, with overflow", 422 " wrapping around (mod 256).", 423 "", 424 "Subtract The result of image - image window, with underflow", 425 " wrapping around (mod 256). The add and subtract", 426 " operators can be used to perform reversible", 427 " transformations.", 428 "", 429 "Difference", 430 " The result of abs(image - image window). This", 431 " useful for comparing two very similar images.", 432 "", 433 "Multiply", 434 " The result of image * image window. This", 435 " useful for the creation of drop-shadows.", 436 "", 437 "Bumpmap The result of surface normals from image * image", 438 " window.", 439 "", 440 "Copy The resulting image is image window replaced with", 441 " image. Here the matte information is ignored.", 442 "", 443 "CopyRed The red layer of the image window is replace with", 444 " the red layer of the image. The other layers are", 445 " untouched.", 446 "", 447 "CopyGreen", 448 " The green layer of the image window is replace with", 449 " the green layer of the image. The other layers are", 450 " untouched.", 451 "", 452 "CopyBlue The blue layer of the image window is replace with", 453 " the blue layer of the image. The other layers are", 454 " untouched.", 455 "", 456 "CopyOpacity", 457 " The matte layer of the image window is replace with", 458 " the matte layer of the image. The other layers are", 459 " untouched.", 460 "", 461 "The image compositor requires a matte, or alpha channel in", 462 "the image for some operations. This extra channel usually", 463 "defines a mask which represents a sort of a cookie-cutter", 464 "for the image. This the case when matte is opaque (full", 465 "coverage) for pixels inside the shape, zero outside, and", 466 "between 0 and QuantumRange on the boundary. If image does not", 467 "have a matte channel, it is initialized with 0 for any pixel", 468 "matching in color to pixel location (0,0), otherwise QuantumRange.", 469 "", 470 "If you choose Dissolve, the composite operator becomes Over. The", 471 "image matte channel percent transparency is initialized to factor.", 472 "The image window is initialized to (100-factor). Where factor is the", 473 "value you specify in the Dialog widget.", 474 "", 475 "Displace shifts the image pixels as defined by a displacement", 476 "map. With this option, image is used as a displacement map.", 477 "Black, within the displacement map, is a maximum positive", 478 "displacement. White is a maximum negative displacement and", 479 "middle gray is neutral. The displacement is scaled to determine", 480 "the pixel shift. By default, the displacement applies in both the", 481 "horizontal and vertical directions. However, if you specify a mask,", 482 "image is the horizontal X displacement and mask the vertical Y", 483 "displacement.", 484 "", 485 "Note that matte information for image window is not retained", 486 "for colormapped X server visuals (e.g. StaticColor,", 487 "StaticColor, GrayScale, PseudoColor). Correct compositing", 488 "behavior may require a TrueColor or DirectColor visual or a", 489 "Standard Colormap.", 490 "", 491 "Choosing a composite operator is optional. The default", 492 "operator is replace. However, you must choose a location to", 493 "composite your image and press button 1. Press and hold the", 494 "button before releasing and an outline of the image will", 495 "appear to help you identify your location.", 496 "", 497 "The actual colors of the composite image is saved. However,", 498 "the color that appears in image window may be different.", 499 "For example, on a monochrome screen image window will appear", 500 "black or white even though your composited image may have", 501 "many colors. If the image is saved to a file it is written", 502 "with the correct colors. To assure the correct colors are", 503 "saved in the final image, any PseudoClass image is promoted", 504 "to DirectClass (see miff(5)). To force a PseudoClass image", 505 "to remain PseudoClass, use -colors.", 506 (char *) NULL, 507 }, 508 *ImageCutHelp[] = 509 { 510 "In cut mode, the Command widget has these options:", 511 "", 512 " Help", 513 " Dismiss", 514 "", 515 "To define a cut region, press button 1 and drag. The", 516 "cut region is defined by a highlighted rectangle that", 517 "expands or contracts as it follows the pointer. Once you", 518 "are satisfied with the cut region, release the button.", 519 "You are now in rectify mode. In rectify mode, the Command", 520 "widget has these options:", 521 "", 522 " Cut", 523 " Help", 524 " Dismiss", 525 "", 526 "You can make adjustments by moving the pointer to one of the", 527 "cut rectangle corners, pressing a button, and dragging.", 528 "Finally, press Cut to commit your copy region. To", 529 "exit without cutting the image, press Dismiss.", 530 (char *) NULL, 531 }, 532 *ImageCopyHelp[] = 533 { 534 "In copy mode, the Command widget has these options:", 535 "", 536 " Help", 537 " Dismiss", 538 "", 539 "To define a copy region, press button 1 and drag. The", 540 "copy region is defined by a highlighted rectangle that", 541 "expands or contracts as it follows the pointer. Once you", 542 "are satisfied with the copy region, release the button.", 543 "You are now in rectify mode. In rectify mode, the Command", 544 "widget has these options:", 545 "", 546 " Copy", 547 " Help", 548 " Dismiss", 549 "", 550 "You can make adjustments by moving the pointer to one of the", 551 "copy rectangle corners, pressing a button, and dragging.", 552 "Finally, press Copy to commit your copy region. To", 553 "exit without copying the image, press Dismiss.", 554 (char *) NULL, 555 }, 556 *ImageCropHelp[] = 557 { 558 "In crop mode, the Command widget has these options:", 559 "", 560 " Help", 561 " Dismiss", 562 "", 563 "To define a cropping region, press button 1 and drag. The", 564 "cropping region is defined by a highlighted rectangle that", 565 "expands or contracts as it follows the pointer. Once you", 566 "are satisfied with the cropping region, release the button.", 567 "You are now in rectify mode. In rectify mode, the Command", 568 "widget has these options:", 569 "", 570 " Crop", 571 " Help", 572 " Dismiss", 573 "", 574 "You can make adjustments by moving the pointer to one of the", 575 "cropping rectangle corners, pressing a button, and dragging.", 576 "Finally, press Crop to commit your cropping region. To", 577 "exit without cropping the image, press Dismiss.", 578 (char *) NULL, 579 }, 580 *ImageDrawHelp[] = 581 { 582 "The cursor changes to a crosshair to indicate you are in", 583 "draw mode. To exit immediately, press Dismiss. In draw mode,", 584 "the Command widget has these options:", 585 "", 586 " Element", 587 " point", 588 " line", 589 " rectangle", 590 " fill rectangle", 591 " circle", 592 " fill circle", 593 " ellipse", 594 " fill ellipse", 595 " polygon", 596 " fill polygon", 597 " Color", 598 " black", 599 " blue", 600 " cyan", 601 " green", 602 " gray", 603 " red", 604 " magenta", 605 " yellow", 606 " white", 607 " transparent", 608 " Browser...", 609 " Stipple", 610 " Brick", 611 " Diagonal", 612 " Scales", 613 " Vertical", 614 " Wavy", 615 " Translucent", 616 " Opaque", 617 " Open...", 618 " Width", 619 " 1", 620 " 2", 621 " 4", 622 " 8", 623 " 16", 624 " Dialog...", 625 " Undo", 626 " Help", 627 " Dismiss", 628 "", 629 "Choose a drawing primitive from the Element sub-menu.", 630 "", 631 "Choose a color from the Color sub-menu. Additional", 632 "colors can be specified with the color browser.", 633 "", 634 "If you choose the color browser and press Grab, you can", 635 "select the color by moving the pointer to the desired", 636 "color on the screen and press any button. The transparent", 637 "color updates the image matte channel and is useful for", 638 "image compositing.", 639 "", 640 "Choose a stipple, if appropriate, from the Stipple sub-menu.", 641 "Additional stipples can be specified with the file browser.", 642 "Stipples obtained from the file browser must be on disk in the", 643 "X11 bitmap format.", 644 "", 645 "Choose a width, if appropriate, from the Width sub-menu. To", 646 "choose a specific width select the Dialog widget.", 647 "", 648 "Choose a point in the Image window and press button 1 and", 649 "hold. Next, move the pointer to another location in the", 650 "image. As you move, a line connects the initial location and", 651 "the pointer. When you release the button, the image is", 652 "updated with the primitive you just drew. For polygons, the", 653 "image is updated when you press and release the button without", 654 "moving the pointer.", 655 "", 656 "To cancel image drawing, move the pointer back to the", 657 "starting point of the line and release the button.", 658 (char *) NULL, 659 }, 660 *DisplayHelp[] = 661 { 662 "BUTTONS", 663 " The effects of each button press is described below. Three", 664 " buttons are required. If you have a two button mouse,", 665 " button 1 and 3 are returned. Press ALT and button 3 to", 666 " simulate button 2.", 667 "", 668 " 1 Press this button to map or unmap the Command widget.", 669 "", 670 " 2 Press and drag to define a region of the image to", 671 " magnify.", 672 "", 673 " 3 Press and drag to choose from a select set of commands.", 674 " This button behaves differently if the image being", 675 " displayed is a visual image directory. Here, choose a", 676 " particular tile of the directory and press this button and", 677 " drag to select a command from a pop-up menu. Choose from", 678 " these menu items:", 679 "", 680 " Open", 681 " Next", 682 " Former", 683 " Delete", 684 " Update", 685 "", 686 " If you choose Open, the image represented by the tile is", 687 " displayed. To return to the visual image directory, choose", 688 " Next from the Command widget. Next and Former moves to the", 689 " next or former image respectively. Choose Delete to delete", 690 " a particular image tile. Finally, choose Update to", 691 " synchronize all the image tiles with their respective", 692 " images.", 693 "", 694 "COMMAND WIDGET", 695 " The Command widget lists a number of sub-menus and commands.", 696 " They are", 697 "", 698 " File", 699 " Open...", 700 " Next", 701 " Former", 702 " Select...", 703 " Save...", 704 " Print...", 705 " Delete...", 706 " New...", 707 " Visual Directory...", 708 " Quit", 709 " Edit", 710 " Undo", 711 " Redo", 712 " Cut", 713 " Copy", 714 " Paste", 715 " View", 716 " Half Size", 717 " Original Size", 718 " Double Size", 719 " Resize...", 720 " Apply", 721 " Refresh", 722 " Restore", 723 " Transform", 724 " Crop", 725 " Chop", 726 " Flop", 727 " Flip", 728 " Rotate Right", 729 " Rotate Left", 730 " Rotate...", 731 " Shear...", 732 " Roll...", 733 " Trim Edges", 734 " Enhance", 735 " Brightness...", 736 " Saturation...", 737 " Hue...", 738 " Gamma...", 739 " Sharpen...", 740 " Dull", 741 " Contrast Stretch...", 742 " Sigmoidal Contrast...", 743 " Normalize", 744 " Equalize", 745 " Negate", 746 " Grayscale", 747 " Map...", 748 " Quantize...", 749 " Effects", 750 " Despeckle", 751 " Emboss", 752 " Reduce Noise", 753 " Add Noise", 754 " Sharpen...", 755 " Blur...", 756 " Threshold...", 757 " Edge Detect...", 758 " Spread...", 759 " Shade...", 760 " Painting...", 761 " Segment...", 762 " F/X", 763 " Solarize...", 764 " Sepia Tone...", 765 " Swirl...", 766 " Implode...", 767 " Vignette...", 768 " Wave...", 769 " Oil Painting...", 770 " Charcoal Drawing...", 771 " Image Edit", 772 " Annotate...", 773 " Draw...", 774 " Color...", 775 " Matte...", 776 " Composite...", 777 " Add Border...", 778 " Add Frame...", 779 " Comment...", 780 " Launch...", 781 " Region of Interest...", 782 " Miscellany", 783 " Image Info", 784 " Zoom Image", 785 " Show Preview...", 786 " Show Histogram", 787 " Show Matte", 788 " Background...", 789 " Slide Show", 790 " Preferences...", 791 " Help", 792 " Overview", 793 " Browse Documentation", 794 " About Display", 795 "", 796 " Menu items with a indented triangle have a sub-menu. They", 797 " are represented above as the indented items. To access a", 798 " sub-menu item, move the pointer to the appropriate menu and", 799 " press a button and drag. When you find the desired sub-menu", 800 " item, release the button and the command is executed. Move", 801 " the pointer away from the sub-menu if you decide not to", 802 " execute a particular command.", 803 "", 804 "KEYBOARD ACCELERATORS", 805 " Accelerators are one or two key presses that effect a", 806 " particular command. The keyboard accelerators that", 807 " display(1) understands is:", 808 "", 809 " Ctl+O Press to open an image from a file.", 810 "", 811 " space Press to display the next image.", 812 "", 813 " If the image is a multi-paged document such as a Postscript", 814 " document, you can skip ahead several pages by preceding", 815 " this command with a number. For example to display the", 816 " third page beyond the current page, press 3<space>.", 817 "", 818 " backspace Press to display the former image.", 819 "", 820 " If the image is a multi-paged document such as a Postscript", 821 " document, you can skip behind several pages by preceding", 822 " this command with a number. For example to display the", 823 " third page preceding the current page, press 3<backspace>.", 824 "", 825 " Ctl+S Press to write the image to a file.", 826 "", 827 " Ctl+P Press to print the image to a Postscript printer.", 828 "", 829 " Ctl+D Press to delete an image file.", 830 "", 831 " Ctl+N Press to create a blank canvas.", 832 "", 833 " Ctl+Q Press to discard all images and exit program.", 834 "", 835 " Ctl+Z Press to undo last image transformation.", 836 "", 837 " Ctl+R Press to redo last image transformation.", 838 "", 839 " Ctl+X Press to cut a region of the image.", 840 "", 841 " Ctl+C Press to copy a region of the image.", 842 "", 843 " Ctl+V Press to paste a region to the image.", 844 "", 845 " < Press to half the image size.", 846 "", 847 " - Press to return to the original image size.", 848 "", 849 " > Press to double the image size.", 850 "", 851 " % Press to resize the image to a width and height you", 852 " specify.", 853 "", 854 "Cmd-A Press to make any image transformations permanent." 855 "", 856 " By default, any image size transformations are applied", 857 " to the original image to create the image displayed on", 858 " the X server. However, the transformations are not", 859 " permanent (i.e. the original image does not change", 860 " size only the X image does). For example, if you", 861 " press > the X image will appear to double in size,", 862 " but the original image will in fact remain the same size.", 863 " To force the original image to double in size, press >", 864 " followed by Cmd-A.", 865 "", 866 " @ Press to refresh the image window.", 867 "", 868 " C Press to cut out a rectangular region of the image.", 869 "", 870 " [ Press to chop the image.", 871 "", 872 " H Press to flop image in the horizontal direction.", 873 "", 874 " V Press to flip image in the vertical direction.", 875 "", 876 " / Press to rotate the image 90 degrees clockwise.", 877 "", 878 " \\ Press to rotate the image 90 degrees counter-clockwise.", 879 "", 880 " * Press to rotate the image the number of degrees you", 881 " specify.", 882 "", 883 " S Press to shear the image the number of degrees you", 884 " specify.", 885 "", 886 " R Press to roll the image.", 887 "", 888 " T Press to trim the image edges.", 889 "", 890 " Shft-H Press to vary the image hue.", 891 "", 892 " Shft-S Press to vary the color saturation.", 893 "", 894 " Shft-L Press to vary the color brightness.", 895 "", 896 " Shft-G Press to gamma correct the image.", 897 "", 898 " Shft-C Press to sharpen the image contrast.", 899 "", 900 " Shft-Z Press to dull the image contrast.", 901 "", 902 " = Press to perform histogram equalization on the image.", 903 "", 904 " Shft-N Press to perform histogram normalization on the image.", 905 "", 906 " Shft-~ Press to negate the colors of the image.", 907 "", 908 " . Press to convert the image colors to gray.", 909 "", 910 " Shft-# Press to set the maximum number of unique colors in the", 911 " image.", 912 "", 913 " F2 Press to reduce the speckles in an image.", 914 "", 915 " F3 Press to eliminate peak noise from an image.", 916 "", 917 " F4 Press to add noise to an image.", 918 "", 919 " F5 Press to sharpen an image.", 920 "", 921 " F6 Press to delete an image file.", 922 "", 923 " F7 Press to threshold the image.", 924 "", 925 " F8 Press to detect edges within an image.", 926 "", 927 " F9 Press to emboss an image.", 928 "", 929 " F10 Press to displace pixels by a random amount.", 930 "", 931 " F11 Press to negate all pixels above the threshold level.", 932 "", 933 " F12 Press to shade the image using a distant light source.", 934 "", 935 " F13 Press to lighten or darken image edges to create a 3-D effect.", 936 "", 937 " F14 Press to segment the image by color.", 938 "", 939 " Meta-S Press to swirl image pixels about the center.", 940 "", 941 " Meta-I Press to implode image pixels about the center.", 942 "", 943 " Meta-W Press to alter an image along a sine wave.", 944 "", 945 " Meta-P Press to simulate an oil painting.", 946 "", 947 " Meta-C Press to simulate a charcoal drawing.", 948 "", 949 " Alt-A Press to annotate the image with text.", 950 "", 951 " Alt-D Press to draw on an image.", 952 "", 953 " Alt-P Press to edit an image pixel color.", 954 "", 955 " Alt-M Press to edit the image matte information.", 956 "", 957 " Alt-V Press to composite the image with another.", 958 "", 959 " Alt-B Press to add a border to the image.", 960 "", 961 " Alt-F Press to add an ornamental border to the image.", 962 "", 963 " Alt-Shft-!", 964 " Press to add an image comment.", 965 "", 966 " Ctl-A Press to apply image processing techniques to a region", 967 " of interest.", 968 "", 969 " Shft-? Press to display information about the image.", 970 "", 971 " Shft-+ Press to map the zoom image window.", 972 "", 973 " Shft-P Press to preview an image enhancement, effect, or f/x.", 974 "", 975 " F1 Press to display helpful information about display(1).", 976 "", 977 " Find Press to browse documentation about ImageMagick.", 978 "", 979 " 1-9 Press to change the level of magnification.", 980 "", 981 " Use the arrow keys to move the image one pixel up, down,", 982 " left, or right within the magnify window. Be sure to first", 983 " map the magnify window by pressing button 2.", 984 "", 985 " Press ALT and one of the arrow keys to trim off one pixel", 986 " from any side of the image.", 987 (char *) NULL, 988 }, 989 *ImageMatteEditHelp[] = 990 { 991 "Matte information within an image is useful for some", 992 "operations such as image compositing (See IMAGE", 993 "COMPOSITING). This extra channel usually defines a mask", 994 "which represents a sort of a cookie-cutter for the image.", 995 "This the case when matte is opaque (full coverage) for", 996 "pixels inside the shape, zero outside, and between 0 and", 997 "QuantumRange on the boundary.", 998 "", 999 "A small window appears showing the location of the cursor in", 1000 "the image window. You are now in matte edit mode. To exit", 1001 "immediately, press Dismiss. In matte edit mode, the Command", 1002 "widget has these options:", 1003 "", 1004 " Method", 1005 " point", 1006 " replace", 1007 " floodfill", 1008 " filltoborder", 1009 " reset", 1010 " Border Color", 1011 " black", 1012 " blue", 1013 " cyan", 1014 " green", 1015 " gray", 1016 " red", 1017 " magenta", 1018 " yellow", 1019 " white", 1020 " Browser...", 1021 " Fuzz", 1022 " 0%", 1023 " 2%", 1024 " 5%", 1025 " 10%", 1026 " 15%", 1027 " Dialog...", 1028 " Matte", 1029 " Opaque", 1030 " Transparent", 1031 " Dialog...", 1032 " Undo", 1033 " Help", 1034 " Dismiss", 1035 "", 1036 "Choose a matte editing method from the Method sub-menu of", 1037 "the Command widget. The point method changes the matte value", 1038 "of any pixel selected with the pointer until the button is", 1039 "is released. The replace method changes the matte value of", 1040 "any pixel that matches the color of the pixel you select with", 1041 "a button press. Floodfill changes the matte value of any pixel", 1042 "that matches the color of the pixel you select with a button", 1043 "press and is a neighbor. Whereas filltoborder changes the matte", 1044 "value any neighbor pixel that is not the border color. Finally", 1045 "reset changes the entire image to the designated matte value.", 1046 "", 1047 "Choose Matte Value and pick Opaque or Transarent. For other values", 1048 "select the Dialog entry. Here a dialog appears requesting a matte", 1049 "value. The value you select is assigned as the opacity value of the", 1050 "selected pixel or pixels.", 1051 "", 1052 "Now, press any button to select a pixel within the image", 1053 "window to change its matte value.", 1054 "", 1055 "If the Magnify widget is mapped, it can be helpful in positioning", 1056 "your pointer within the image (refer to button 2).", 1057 "", 1058 "Matte information is only valid in a DirectClass image.", 1059 "Therefore, any PseudoClass image is promoted to DirectClass", 1060 "(see miff(5)). Note that matte information for PseudoClass", 1061 "is not retained for colormapped X server visuals (e.g.", 1062 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you", 1063 "immediately save your image to a file (refer to Write).", 1064 "Correct matte editing behavior may require a TrueColor or", 1065 "DirectColor visual or a Standard Colormap.", 1066 (char *) NULL, 1067 }, 1068 *ImagePanHelp[] = 1069 { 1070 "When an image exceeds the width or height of the X server", 1071 "screen, display maps a small panning icon. The rectangle", 1072 "within the panning icon shows the area that is currently", 1073 "displayed in the image window. To pan about the image,", 1074 "press any button and drag the pointer within the panning", 1075 "icon. The pan rectangle moves with the pointer and the", 1076 "image window is updated to reflect the location of the", 1077 "rectangle within the panning icon. When you have selected", 1078 "the area of the image you wish to view, release the button.", 1079 "", 1080 "Use the arrow keys to pan the image one pixel up, down,", 1081 "left, or right within the image window.", 1082 "", 1083 "The panning icon is withdrawn if the image becomes smaller", 1084 "than the dimensions of the X server screen.", 1085 (char *) NULL, 1086 }, 1087 *ImagePasteHelp[] = 1088 { 1089 "A small window appears showing the location of the cursor in", 1090 "the image window. You are now in paste mode. To exit", 1091 "immediately, press Dismiss. In paste mode, the Command", 1092 "widget has these options:", 1093 "", 1094 " Operators", 1095 " over", 1096 " in", 1097 " out", 1098 " atop", 1099 " xor", 1100 " plus", 1101 " minus", 1102 " add", 1103 " subtract", 1104 " difference", 1105 " replace", 1106 " Help", 1107 " Dismiss", 1108 "", 1109 "Choose a composite operation from the Operators sub-menu of", 1110 "the Command widget. How each operator behaves is described", 1111 "below. Image window is the image currently displayed on", 1112 "your X server and image is the image obtained with the File", 1113 "Browser widget.", 1114 "", 1115 "Over The result is the union of the two image shapes,", 1116 " with image obscuring image window in the region of", 1117 " overlap.", 1118 "", 1119 "In The result is simply image cut by the shape of", 1120 " image window. None of the image data of image", 1121 " window is in the result.", 1122 "", 1123 "Out The resulting image is image with the shape of", 1124 " image window cut out.", 1125 "", 1126 "Atop The result is the same shape as image image window,", 1127 " with image obscuring image window where the image", 1128 " shapes overlap. Note this differs from over", 1129 " because the portion of image outside image window's", 1130 " shape does not appear in the result.", 1131 "", 1132 "Xor The result is the image data from both image and", 1133 " image window that is outside the overlap region.", 1134 " The overlap region is blank.", 1135 "", 1136 "Plus The result is just the sum of the image data.", 1137 " Output values are cropped to QuantumRange (no overflow).", 1138 " This operation is independent of the matte", 1139 " channels.", 1140 "", 1141 "Minus The result of image - image window, with underflow", 1142 " cropped to zero.", 1143 "", 1144 "Add The result of image + image window, with overflow", 1145 " wrapping around (mod 256).", 1146 "", 1147 "Subtract The result of image - image window, with underflow", 1148 " wrapping around (mod 256). The add and subtract", 1149 " operators can be used to perform reversible", 1150 " transformations.", 1151 "", 1152 "Difference", 1153 " The result of abs(image - image window). This", 1154 " useful for comparing two very similar images.", 1155 "", 1156 "Copy The resulting image is image window replaced with", 1157 " image. Here the matte information is ignored.", 1158 "", 1159 "CopyRed The red layer of the image window is replace with", 1160 " the red layer of the image. The other layers are", 1161 " untouched.", 1162 "", 1163 "CopyGreen", 1164 " The green layer of the image window is replace with", 1165 " the green layer of the image. The other layers are", 1166 " untouched.", 1167 "", 1168 "CopyBlue The blue layer of the image window is replace with", 1169 " the blue layer of the image. The other layers are", 1170 " untouched.", 1171 "", 1172 "CopyOpacity", 1173 " The matte layer of the image window is replace with", 1174 " the matte layer of the image. The other layers are", 1175 " untouched.", 1176 "", 1177 "The image compositor requires a matte, or alpha channel in", 1178 "the image for some operations. This extra channel usually", 1179 "defines a mask which represents a sort of a cookie-cutter", 1180 "for the image. This the case when matte is opaque (full", 1181 "coverage) for pixels inside the shape, zero outside, and", 1182 "between 0 and QuantumRange on the boundary. If image does not", 1183 "have a matte channel, it is initialized with 0 for any pixel", 1184 "matching in color to pixel location (0,0), otherwise QuantumRange.", 1185 "", 1186 "Note that matte information for image window is not retained", 1187 "for colormapped X server visuals (e.g. StaticColor,", 1188 "StaticColor, GrayScale, PseudoColor). Correct compositing", 1189 "behavior may require a TrueColor or DirectColor visual or a", 1190 "Standard Colormap.", 1191 "", 1192 "Choosing a composite operator is optional. The default", 1193 "operator is replace. However, you must choose a location to", 1194 "paste your image and press button 1. Press and hold the", 1195 "button before releasing and an outline of the image will", 1196 "appear to help you identify your location.", 1197 "", 1198 "The actual colors of the pasted image is saved. However,", 1199 "the color that appears in image window may be different.", 1200 "For example, on a monochrome screen image window will appear", 1201 "black or white even though your pasted image may have", 1202 "many colors. If the image is saved to a file it is written", 1203 "with the correct colors. To assure the correct colors are", 1204 "saved in the final image, any PseudoClass image is promoted", 1205 "to DirectClass (see miff(5)). To force a PseudoClass image", 1206 "to remain PseudoClass, use -colors.", 1207 (char *) NULL, 1208 }, 1209 *ImageROIHelp[] = 1210 { 1211 "In region of interest mode, the Command widget has these", 1212 "options:", 1213 "", 1214 " Help", 1215 " Dismiss", 1216 "", 1217 "To define a region of interest, press button 1 and drag.", 1218 "The region of interest is defined by a highlighted rectangle", 1219 "that expands or contracts as it follows the pointer. Once", 1220 "you are satisfied with the region of interest, release the", 1221 "button. You are now in apply mode. In apply mode the", 1222 "Command widget has these options:", 1223 "", 1224 " File", 1225 " Save...", 1226 " Print...", 1227 " Edit", 1228 " Undo", 1229 " Redo", 1230 " Transform", 1231 " Flop", 1232 " Flip", 1233 " Rotate Right", 1234 " Rotate Left", 1235 " Enhance", 1236 " Hue...", 1237 " Saturation...", 1238 " Brightness...", 1239 " Gamma...", 1240 " Spiff", 1241 " Dull", 1242 " Contrast Stretch", 1243 " Sigmoidal Contrast...", 1244 " Normalize", 1245 " Equalize", 1246 " Negate", 1247 " Grayscale", 1248 " Map...", 1249 " Quantize...", 1250 " Effects", 1251 " Despeckle", 1252 " Emboss", 1253 " Reduce Noise", 1254 " Sharpen...", 1255 " Blur...", 1256 " Threshold...", 1257 " Edge Detect...", 1258 " Spread...", 1259 " Shade...", 1260 " Raise...", 1261 " Segment...", 1262 " F/X", 1263 " Solarize...", 1264 " Sepia Tone...", 1265 " Swirl...", 1266 " Implode...", 1267 " Vignette...", 1268 " Wave...", 1269 " Oil Painting...", 1270 " Charcoal Drawing...", 1271 " Miscellany", 1272 " Image Info", 1273 " Zoom Image", 1274 " Show Preview...", 1275 " Show Histogram", 1276 " Show Matte", 1277 " Help", 1278 " Dismiss", 1279 "", 1280 "You can make adjustments to the region of interest by moving", 1281 "the pointer to one of the rectangle corners, pressing a", 1282 "button, and dragging. Finally, choose an image processing", 1283 "technique from the Command widget. You can choose more than", 1284 "one image processing technique to apply to an area.", 1285 "Alternatively, you can move the region of interest before", 1286 "applying another image processing technique. To exit, press", 1287 "Dismiss.", 1288 (char *) NULL, 1289 }, 1290 *ImageRotateHelp[] = 1291 { 1292 "In rotate mode, the Command widget has these options:", 1293 "", 1294 " Pixel Color", 1295 " black", 1296 " blue", 1297 " cyan", 1298 " green", 1299 " gray", 1300 " red", 1301 " magenta", 1302 " yellow", 1303 " white", 1304 " Browser...", 1305 " Direction", 1306 " horizontal", 1307 " vertical", 1308 " Help", 1309 " Dismiss", 1310 "", 1311 "Choose a background color from the Pixel Color sub-menu.", 1312 "Additional background colors can be specified with the color", 1313 "browser. You can change the menu colors by setting the X", 1314 "resources pen1 through pen9.", 1315 "", 1316 "If you choose the color browser and press Grab, you can", 1317 "select the background color by moving the pointer to the", 1318 "desired color on the screen and press any button.", 1319 "", 1320 "Choose a point in the image window and press this button and", 1321 "hold. Next, move the pointer to another location in the", 1322 "image. As you move a line connects the initial location and", 1323 "the pointer. When you release the button, the degree of", 1324 "image rotation is determined by the slope of the line you", 1325 "just drew. The slope is relative to the direction you", 1326 "choose from the Direction sub-menu of the Command widget.", 1327 "", 1328 "To cancel the image rotation, move the pointer back to the", 1329 "starting point of the line and release the button.", 1330 (char *) NULL, 1331 }; 1332 1333/* 1334 Enumeration declarations. 1335*/ 1336typedef enum 1337{ 1338 CopyMode, 1339 CropMode, 1340 CutMode 1341} ClipboardMode; 1342 1343typedef enum 1344{ 1345 OpenCommand, 1346 NextCommand, 1347 FormerCommand, 1348 SelectCommand, 1349 SaveCommand, 1350 PrintCommand, 1351 DeleteCommand, 1352 NewCommand, 1353 VisualDirectoryCommand, 1354 QuitCommand, 1355 UndoCommand, 1356 RedoCommand, 1357 CutCommand, 1358 CopyCommand, 1359 PasteCommand, 1360 HalfSizeCommand, 1361 OriginalSizeCommand, 1362 DoubleSizeCommand, 1363 ResizeCommand, 1364 ApplyCommand, 1365 RefreshCommand, 1366 RestoreCommand, 1367 CropCommand, 1368 ChopCommand, 1369 FlopCommand, 1370 FlipCommand, 1371 RotateRightCommand, 1372 RotateLeftCommand, 1373 RotateCommand, 1374 ShearCommand, 1375 RollCommand, 1376 TrimCommand, 1377 HueCommand, 1378 SaturationCommand, 1379 BrightnessCommand, 1380 GammaCommand, 1381 SpiffCommand, 1382 DullCommand, 1383 ContrastStretchCommand, 1384 SigmoidalContrastCommand, 1385 NormalizeCommand, 1386 EqualizeCommand, 1387 NegateCommand, 1388 GrayscaleCommand, 1389 MapCommand, 1390 QuantizeCommand, 1391 DespeckleCommand, 1392 EmbossCommand, 1393 ReduceNoiseCommand, 1394 AddNoiseCommand, 1395 SharpenCommand, 1396 BlurCommand, 1397 ThresholdCommand, 1398 EdgeDetectCommand, 1399 SpreadCommand, 1400 ShadeCommand, 1401 RaiseCommand, 1402 SegmentCommand, 1403 SolarizeCommand, 1404 SepiaToneCommand, 1405 SwirlCommand, 1406 ImplodeCommand, 1407 VignetteCommand, 1408 WaveCommand, 1409 OilPaintCommand, 1410 CharcoalDrawCommand, 1411 AnnotateCommand, 1412 DrawCommand, 1413 ColorCommand, 1414 MatteCommand, 1415 CompositeCommand, 1416 AddBorderCommand, 1417 AddFrameCommand, 1418 CommentCommand, 1419 LaunchCommand, 1420 RegionofInterestCommand, 1421 ROIHelpCommand, 1422 ROIDismissCommand, 1423 InfoCommand, 1424 ZoomCommand, 1425 ShowPreviewCommand, 1426 ShowHistogramCommand, 1427 ShowMatteCommand, 1428 BackgroundCommand, 1429 SlideShowCommand, 1430 PreferencesCommand, 1431 HelpCommand, 1432 BrowseDocumentationCommand, 1433 VersionCommand, 1434 SaveToUndoBufferCommand, 1435 FreeBuffersCommand, 1436 NullCommand 1437} CommandType; 1438 1439typedef enum 1440{ 1441 AnnotateNameCommand, 1442 AnnotateFontColorCommand, 1443 AnnotateBackgroundColorCommand, 1444 AnnotateRotateCommand, 1445 AnnotateHelpCommand, 1446 AnnotateDismissCommand, 1447 TextHelpCommand, 1448 TextApplyCommand, 1449 ChopDirectionCommand, 1450 ChopHelpCommand, 1451 ChopDismissCommand, 1452 HorizontalChopCommand, 1453 VerticalChopCommand, 1454 ColorEditMethodCommand, 1455 ColorEditColorCommand, 1456 ColorEditBorderCommand, 1457 ColorEditFuzzCommand, 1458 ColorEditUndoCommand, 1459 ColorEditHelpCommand, 1460 ColorEditDismissCommand, 1461 CompositeOperatorsCommand, 1462 CompositeDissolveCommand, 1463 CompositeDisplaceCommand, 1464 CompositeHelpCommand, 1465 CompositeDismissCommand, 1466 CropHelpCommand, 1467 CropDismissCommand, 1468 RectifyCopyCommand, 1469 RectifyHelpCommand, 1470 RectifyDismissCommand, 1471 DrawElementCommand, 1472 DrawColorCommand, 1473 DrawStippleCommand, 1474 DrawWidthCommand, 1475 DrawUndoCommand, 1476 DrawHelpCommand, 1477 DrawDismissCommand, 1478 MatteEditMethod, 1479 MatteEditBorderCommand, 1480 MatteEditFuzzCommand, 1481 MatteEditValueCommand, 1482 MatteEditUndoCommand, 1483 MatteEditHelpCommand, 1484 MatteEditDismissCommand, 1485 PasteOperatorsCommand, 1486 PasteHelpCommand, 1487 PasteDismissCommand, 1488 RotateColorCommand, 1489 RotateDirectionCommand, 1490 RotateCropCommand, 1491 RotateSharpenCommand, 1492 RotateHelpCommand, 1493 RotateDismissCommand, 1494 HorizontalRotateCommand, 1495 VerticalRotateCommand, 1496 TileLoadCommand, 1497 TileNextCommand, 1498 TileFormerCommand, 1499 TileDeleteCommand, 1500 TileUpdateCommand 1501} ModeType; 1502 1503/* 1504 Stipples. 1505*/ 1506#define BricksWidth 20 1507#define BricksHeight 20 1508#define DiagonalWidth 16 1509#define DiagonalHeight 16 1510#define HighlightWidth 8 1511#define HighlightHeight 8 1512#define OpaqueWidth 8 1513#define OpaqueHeight 8 1514#define ScalesWidth 16 1515#define ScalesHeight 16 1516#define ShadowWidth 8 1517#define ShadowHeight 8 1518#define VerticalWidth 16 1519#define VerticalHeight 16 1520#define WavyWidth 16 1521#define WavyHeight 16 1522 1523/* 1524 Constant declaration. 1525*/ 1526static const int 1527 RoiDelta = 8; 1528 1529static const unsigned char 1530 BricksBitmap[] = 1531 { 1532 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 1533 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 1534 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 1535 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 1536 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01 1537 }, 1538 DiagonalBitmap[] = 1539 { 1540 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 1541 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 1542 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22 1543 }, 1544 ScalesBitmap[] = 1545 { 1546 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80, 1547 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 1548 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e 1549 }, 1550 VerticalBitmap[] = 1551 { 1552 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1553 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1554 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 1555 }, 1556 WavyBitmap[] = 1557 { 1558 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff, 1559 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf, 1560 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f 1561 }; 1562 1563/* 1564 Function prototypes. 1565*/ 1566static CommandType 1567 XImageWindowCommand(Display *,XResourceInfo *,XWindows *, 1568 const MagickStatusType,KeySym,Image **,ExceptionInfo *); 1569 1570static Image 1571 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType, 1572 Image **,ExceptionInfo *), 1573 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType), 1574 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *, 1575 ExceptionInfo *), 1576 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *, 1577 ExceptionInfo *); 1578 1579static MagickBooleanType 1580 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *, 1581 ExceptionInfo *), 1582 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **, 1583 ExceptionInfo *), 1584 XChopImage(Display *,XResourceInfo *,XWindows *,Image **, 1585 ExceptionInfo *), 1586 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode, 1587 ExceptionInfo *), 1588 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1589 ExceptionInfo *), 1590 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *, 1591 ExceptionInfo *), 1592 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1593 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1594 ExceptionInfo *), 1595 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1596 ExceptionInfo *), 1597 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1598 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1599 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **, 1600 ExceptionInfo *), 1601 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *), 1602 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1603 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *); 1604 1605static void 1606 XDrawPanRectangle(Display *,XWindows *), 1607 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **, 1608 ExceptionInfo *), 1609 XMagnifyImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1610 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1611 XPanImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1612 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType, 1613 const KeySym,ExceptionInfo *), 1614 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *), 1615 XScreenEvent(Display *,XWindows *,XEvent *,ExceptionInfo *), 1616 XTranslateImage(Display *,XWindows *,Image *,const KeySym); 1617 1618/* 1619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1620% % 1621% % 1622% % 1623% D i s p l a y I m a g e s % 1624% % 1625% % 1626% % 1627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1628% 1629% DisplayImages() displays an image sequence to any X window screen. It 1630% returns a value other than 0 if successful. Check the exception member 1631% of image to determine the reason for any failure. 1632% 1633% The format of the DisplayImages method is: 1634% 1635% MagickBooleanType DisplayImages(const ImageInfo *image_info, 1636% Image *images,ExceptionInfo *exception) 1637% 1638% A description of each parameter follows: 1639% 1640% o image_info: the image info. 1641% 1642% o image: the image. 1643% 1644% o exception: return any errors or warnings in this structure. 1645% 1646*/ 1647MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 1648 Image *images,ExceptionInfo *exception) 1649{ 1650 char 1651 *argv[1]; 1652 1653 Display 1654 *display; 1655 1656 Image 1657 *image; 1658 1659 register ssize_t 1660 i; 1661 1662 size_t 1663 state; 1664 1665 XrmDatabase 1666 resource_database; 1667 1668 XResourceInfo 1669 resource_info; 1670 1671 assert(image_info != (const ImageInfo *) NULL); 1672 assert(image_info->signature == MagickSignature); 1673 assert(images != (Image *) NULL); 1674 assert(images->signature == MagickSignature); 1675 if (images->debug != MagickFalse) 1676 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 1677 display=XOpenDisplay(image_info->server_name); 1678 if (display == (Display *) NULL) 1679 { 1680 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1681 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1682 return(MagickFalse); 1683 } 1684 if (exception->severity != UndefinedException) 1685 CatchException(exception); 1686 (void) XSetErrorHandler(XError); 1687 resource_database=XGetResourceDatabase(display,GetClientName()); 1688 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info)); 1689 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info); 1690 if (image_info->page != (char *) NULL) 1691 resource_info.image_geometry=AcquireString(image_info->page); 1692 resource_info.immutable=MagickTrue; 1693 argv[0]=AcquireString(GetClientName()); 1694 state=DefaultState; 1695 for (i=0; (state & ExitState) == 0; i++) 1696 { 1697 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations)) 1698 break; 1699 image=GetImageFromList(images,i % GetImageListLength(images)); 1700 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception); 1701 } 1702 SetErrorHandler((ErrorHandler) NULL); 1703 SetWarningHandler((WarningHandler) NULL); 1704 argv[0]=DestroyString(argv[0]); 1705 (void) XCloseDisplay(display); 1706 XDestroyResourceInfo(&resource_info); 1707 if (exception->severity != UndefinedException) 1708 return(MagickFalse); 1709 return(MagickTrue); 1710} 1711 1712/* 1713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1714% % 1715% % 1716% % 1717% R e m o t e D i s p l a y C o m m a n d % 1718% % 1719% % 1720% % 1721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1722% 1723% RemoteDisplayCommand() encourages a remote display program to display the 1724% specified image filename. 1725% 1726% The format of the RemoteDisplayCommand method is: 1727% 1728% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1729% const char *window,const char *filename,ExceptionInfo *exception) 1730% 1731% A description of each parameter follows: 1732% 1733% o image_info: the image info. 1734% 1735% o window: Specifies the name or id of an X window. 1736% 1737% o filename: the name of the image filename to display. 1738% 1739% o exception: return any errors or warnings in this structure. 1740% 1741*/ 1742MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1743 const char *window,const char *filename,ExceptionInfo *exception) 1744{ 1745 Display 1746 *display; 1747 1748 MagickStatusType 1749 status; 1750 1751 assert(image_info != (const ImageInfo *) NULL); 1752 assert(image_info->signature == MagickSignature); 1753 assert(filename != (char *) NULL); 1754 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 1755 display=XOpenDisplay(image_info->server_name); 1756 if (display == (Display *) NULL) 1757 { 1758 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1759 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1760 return(MagickFalse); 1761 } 1762 (void) XSetErrorHandler(XError); 1763 status=XRemoteCommand(display,window,filename); 1764 (void) XCloseDisplay(display); 1765 return(status != 0 ? MagickTrue : MagickFalse); 1766} 1767 1768/* 1769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1770% % 1771% % 1772% % 1773+ X A n n o t a t e E d i t I m a g e % 1774% % 1775% % 1776% % 1777%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1778% 1779% XAnnotateEditImage() annotates the image with text. 1780% 1781% The format of the XAnnotateEditImage method is: 1782% 1783% MagickBooleanType XAnnotateEditImage(Display *display, 1784% XResourceInfo *resource_info,XWindows *windows,Image *image, 1785% ExceptionInfo *exception) 1786% 1787% A description of each parameter follows: 1788% 1789% o display: Specifies a connection to an X server; returned from 1790% XOpenDisplay. 1791% 1792% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 1793% 1794% o windows: Specifies a pointer to a XWindows structure. 1795% 1796% o image: the image; returned from ReadImage. 1797% 1798*/ 1799 1800static inline ssize_t MagickMax(const ssize_t x,const ssize_t y) 1801{ 1802 if (x > y) 1803 return(x); 1804 return(y); 1805} 1806 1807static inline ssize_t MagickMin(const ssize_t x,const ssize_t y) 1808{ 1809 if (x < y) 1810 return(x); 1811 return(y); 1812} 1813 1814static MagickBooleanType XAnnotateEditImage(Display *display, 1815 XResourceInfo *resource_info,XWindows *windows,Image *image, 1816 ExceptionInfo *exception) 1817{ 1818 static const char 1819 *AnnotateMenu[] = 1820 { 1821 "Font Name", 1822 "Font Color", 1823 "Box Color", 1824 "Rotate Text", 1825 "Help", 1826 "Dismiss", 1827 (char *) NULL 1828 }, 1829 *TextMenu[] = 1830 { 1831 "Help", 1832 "Apply", 1833 (char *) NULL 1834 }; 1835 1836 static const ModeType 1837 AnnotateCommands[] = 1838 { 1839 AnnotateNameCommand, 1840 AnnotateFontColorCommand, 1841 AnnotateBackgroundColorCommand, 1842 AnnotateRotateCommand, 1843 AnnotateHelpCommand, 1844 AnnotateDismissCommand 1845 }, 1846 TextCommands[] = 1847 { 1848 TextHelpCommand, 1849 TextApplyCommand 1850 }; 1851 1852 static MagickBooleanType 1853 transparent_box = MagickTrue, 1854 transparent_pen = MagickFalse; 1855 1856 static MagickRealType 1857 degrees = 0.0; 1858 1859 static unsigned int 1860 box_id = MaxNumberPens-2, 1861 font_id = 0, 1862 pen_id = 0; 1863 1864 char 1865 command[MaxTextExtent], 1866 text[MaxTextExtent]; 1867 1868 const char 1869 *ColorMenu[MaxNumberPens+1]; 1870 1871 Cursor 1872 cursor; 1873 1874 GC 1875 annotate_context; 1876 1877 int 1878 id, 1879 pen_number, 1880 status, 1881 x, 1882 y; 1883 1884 KeySym 1885 key_symbol; 1886 1887 register char 1888 *p; 1889 1890 register ssize_t 1891 i; 1892 1893 unsigned int 1894 height, 1895 width; 1896 1897 size_t 1898 state; 1899 1900 XAnnotateInfo 1901 *annotate_info, 1902 *previous_info; 1903 1904 XColor 1905 color; 1906 1907 XFontStruct 1908 *font_info; 1909 1910 XEvent 1911 event, 1912 text_event; 1913 1914 /* 1915 Map Command widget. 1916 */ 1917 (void) CloneString(&windows->command.name,"Annotate"); 1918 windows->command.data=4; 1919 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL); 1920 (void) XMapRaised(display,windows->command.id); 1921 XClientMessage(display,windows->image.id,windows->im_protocols, 1922 windows->im_update_widget,CurrentTime); 1923 /* 1924 Track pointer until button 1 is pressed. 1925 */ 1926 XQueryPosition(display,windows->image.id,&x,&y); 1927 (void) XSelectInput(display,windows->image.id, 1928 windows->image.attributes.event_mask | PointerMotionMask); 1929 cursor=XCreateFontCursor(display,XC_left_side); 1930 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1931 state=DefaultState; 1932 do 1933 { 1934 if (windows->info.mapped != MagickFalse) 1935 { 1936 /* 1937 Display pointer position. 1938 */ 1939 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 1940 x+windows->image.x,y+windows->image.y); 1941 XInfoWidget(display,windows,text); 1942 } 1943 /* 1944 Wait for next event. 1945 */ 1946 XScreenEvent(display,windows,&event,exception); 1947 if (event.xany.window == windows->command.id) 1948 { 1949 /* 1950 Select a command from the Command widget. 1951 */ 1952 id=XCommandWidget(display,windows,AnnotateMenu,&event); 1953 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1954 if (id < 0) 1955 continue; 1956 switch (AnnotateCommands[id]) 1957 { 1958 case AnnotateNameCommand: 1959 { 1960 const char 1961 *FontMenu[MaxNumberFonts]; 1962 1963 int 1964 font_number; 1965 1966 /* 1967 Initialize menu selections. 1968 */ 1969 for (i=0; i < MaxNumberFonts; i++) 1970 FontMenu[i]=resource_info->font_name[i]; 1971 FontMenu[MaxNumberFonts-2]="Browser..."; 1972 FontMenu[MaxNumberFonts-1]=(const char *) NULL; 1973 /* 1974 Select a font name from the pop-up menu. 1975 */ 1976 font_number=XMenuWidget(display,windows,AnnotateMenu[id], 1977 (const char **) FontMenu,command); 1978 if (font_number < 0) 1979 break; 1980 if (font_number == (MaxNumberFonts-2)) 1981 { 1982 static char 1983 font_name[MaxTextExtent] = "fixed"; 1984 1985 /* 1986 Select a font name from a browser. 1987 */ 1988 resource_info->font_name[font_number]=font_name; 1989 XFontBrowserWidget(display,windows,"Select",font_name); 1990 if (*font_name == '\0') 1991 break; 1992 } 1993 /* 1994 Initialize font info. 1995 */ 1996 font_info=XLoadQueryFont(display,resource_info->font_name[ 1997 font_number]); 1998 if (font_info == (XFontStruct *) NULL) 1999 { 2000 XNoticeWidget(display,windows,"Unable to load font:", 2001 resource_info->font_name[font_number]); 2002 break; 2003 } 2004 font_id=(unsigned int) font_number; 2005 (void) XFreeFont(display,font_info); 2006 break; 2007 } 2008 case AnnotateFontColorCommand: 2009 { 2010 /* 2011 Initialize menu selections. 2012 */ 2013 for (i=0; i < (int) (MaxNumberPens-2); i++) 2014 ColorMenu[i]=resource_info->pen_colors[i]; 2015 ColorMenu[MaxNumberPens-2]="transparent"; 2016 ColorMenu[MaxNumberPens-1]="Browser..."; 2017 ColorMenu[MaxNumberPens]=(const char *) NULL; 2018 /* 2019 Select a pen color from the pop-up menu. 2020 */ 2021 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2022 (const char **) ColorMenu,command); 2023 if (pen_number < 0) 2024 break; 2025 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue : 2026 MagickFalse; 2027 if (transparent_pen != MagickFalse) 2028 break; 2029 if (pen_number == (MaxNumberPens-1)) 2030 { 2031 static char 2032 color_name[MaxTextExtent] = "gray"; 2033 2034 /* 2035 Select a pen color from a dialog. 2036 */ 2037 resource_info->pen_colors[pen_number]=color_name; 2038 XColorBrowserWidget(display,windows,"Select",color_name); 2039 if (*color_name == '\0') 2040 break; 2041 } 2042 /* 2043 Set pen color. 2044 */ 2045 (void) XParseColor(display,windows->map_info->colormap, 2046 resource_info->pen_colors[pen_number],&color); 2047 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2048 (unsigned int) MaxColors,&color); 2049 windows->pixel_info->pen_colors[pen_number]=color; 2050 pen_id=(unsigned int) pen_number; 2051 break; 2052 } 2053 case AnnotateBackgroundColorCommand: 2054 { 2055 /* 2056 Initialize menu selections. 2057 */ 2058 for (i=0; i < (int) (MaxNumberPens-2); i++) 2059 ColorMenu[i]=resource_info->pen_colors[i]; 2060 ColorMenu[MaxNumberPens-2]="transparent"; 2061 ColorMenu[MaxNumberPens-1]="Browser..."; 2062 ColorMenu[MaxNumberPens]=(const char *) NULL; 2063 /* 2064 Select a pen color from the pop-up menu. 2065 */ 2066 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2067 (const char **) ColorMenu,command); 2068 if (pen_number < 0) 2069 break; 2070 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue : 2071 MagickFalse; 2072 if (transparent_box != MagickFalse) 2073 break; 2074 if (pen_number == (MaxNumberPens-1)) 2075 { 2076 static char 2077 color_name[MaxTextExtent] = "gray"; 2078 2079 /* 2080 Select a pen color from a dialog. 2081 */ 2082 resource_info->pen_colors[pen_number]=color_name; 2083 XColorBrowserWidget(display,windows,"Select",color_name); 2084 if (*color_name == '\0') 2085 break; 2086 } 2087 /* 2088 Set pen color. 2089 */ 2090 (void) XParseColor(display,windows->map_info->colormap, 2091 resource_info->pen_colors[pen_number],&color); 2092 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2093 (unsigned int) MaxColors,&color); 2094 windows->pixel_info->pen_colors[pen_number]=color; 2095 box_id=(unsigned int) pen_number; 2096 break; 2097 } 2098 case AnnotateRotateCommand: 2099 { 2100 int 2101 entry; 2102 2103 static char 2104 angle[MaxTextExtent] = "30.0"; 2105 2106 static const char 2107 *RotateMenu[] = 2108 { 2109 "-90", 2110 "-45", 2111 "-30", 2112 "0", 2113 "30", 2114 "45", 2115 "90", 2116 "180", 2117 "Dialog...", 2118 (char *) NULL, 2119 }; 2120 2121 /* 2122 Select a command from the pop-up menu. 2123 */ 2124 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu, 2125 command); 2126 if (entry < 0) 2127 break; 2128 if (entry != 8) 2129 { 2130 degrees=StringToDouble(RotateMenu[entry],(char **) NULL); 2131 break; 2132 } 2133 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:", 2134 angle); 2135 if (*angle == '\0') 2136 break; 2137 degrees=StringToDouble(angle,(char **) NULL); 2138 break; 2139 } 2140 case AnnotateHelpCommand: 2141 { 2142 XTextViewWidget(display,resource_info,windows,MagickFalse, 2143 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2144 break; 2145 } 2146 case AnnotateDismissCommand: 2147 { 2148 /* 2149 Prematurely exit. 2150 */ 2151 state|=EscapeState; 2152 state|=ExitState; 2153 break; 2154 } 2155 default: 2156 break; 2157 } 2158 continue; 2159 } 2160 switch (event.type) 2161 { 2162 case ButtonPress: 2163 { 2164 if (event.xbutton.button != Button1) 2165 break; 2166 if (event.xbutton.window != windows->image.id) 2167 break; 2168 /* 2169 Change to text entering mode. 2170 */ 2171 x=event.xbutton.x; 2172 y=event.xbutton.y; 2173 state|=ExitState; 2174 break; 2175 } 2176 case ButtonRelease: 2177 break; 2178 case Expose: 2179 break; 2180 case KeyPress: 2181 { 2182 if (event.xkey.window != windows->image.id) 2183 break; 2184 /* 2185 Respond to a user key press. 2186 */ 2187 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2188 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2189 switch ((int) key_symbol) 2190 { 2191 case XK_Escape: 2192 case XK_F20: 2193 { 2194 /* 2195 Prematurely exit. 2196 */ 2197 state|=EscapeState; 2198 state|=ExitState; 2199 break; 2200 } 2201 case XK_F1: 2202 case XK_Help: 2203 { 2204 XTextViewWidget(display,resource_info,windows,MagickFalse, 2205 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2206 break; 2207 } 2208 default: 2209 { 2210 (void) XBell(display,0); 2211 break; 2212 } 2213 } 2214 break; 2215 } 2216 case MotionNotify: 2217 { 2218 /* 2219 Map and unmap Info widget as cursor crosses its boundaries. 2220 */ 2221 x=event.xmotion.x; 2222 y=event.xmotion.y; 2223 if (windows->info.mapped != MagickFalse) 2224 { 2225 if ((x < (int) (windows->info.x+windows->info.width)) && 2226 (y < (int) (windows->info.y+windows->info.height))) 2227 (void) XWithdrawWindow(display,windows->info.id, 2228 windows->info.screen); 2229 } 2230 else 2231 if ((x > (int) (windows->info.x+windows->info.width)) || 2232 (y > (int) (windows->info.y+windows->info.height))) 2233 (void) XMapWindow(display,windows->info.id); 2234 break; 2235 } 2236 default: 2237 break; 2238 } 2239 } while ((state & ExitState) == 0); 2240 (void) XSelectInput(display,windows->image.id, 2241 windows->image.attributes.event_mask); 2242 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 2243 if ((state & EscapeState) != 0) 2244 return(MagickTrue); 2245 /* 2246 Set font info and check boundary conditions. 2247 */ 2248 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]); 2249 if (font_info == (XFontStruct *) NULL) 2250 { 2251 XNoticeWidget(display,windows,"Unable to load font:", 2252 resource_info->font_name[font_id]); 2253 font_info=windows->font_info; 2254 } 2255 if ((x+font_info->max_bounds.width) >= (int) windows->image.width) 2256 x=(int) windows->image.width-font_info->max_bounds.width; 2257 if (y < (int) (font_info->ascent+font_info->descent)) 2258 y=(int) font_info->ascent+font_info->descent; 2259 if (((int) font_info->max_bounds.width > (int) windows->image.width) || 2260 ((font_info->ascent+font_info->descent) >= (int) windows->image.height)) 2261 return(MagickFalse); 2262 /* 2263 Initialize annotate structure. 2264 */ 2265 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info)); 2266 if (annotate_info == (XAnnotateInfo *) NULL) 2267 return(MagickFalse); 2268 XGetAnnotateInfo(annotate_info); 2269 annotate_info->x=x; 2270 annotate_info->y=y; 2271 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse)) 2272 annotate_info->stencil=OpaqueStencil; 2273 else 2274 if (transparent_box == MagickFalse) 2275 annotate_info->stencil=BackgroundStencil; 2276 else 2277 annotate_info->stencil=ForegroundStencil; 2278 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent; 2279 annotate_info->degrees=degrees; 2280 annotate_info->font_info=font_info; 2281 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2282 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL, 2283 sizeof(*annotate_info->text)); 2284 if (annotate_info->text == (char *) NULL) 2285 return(MagickFalse); 2286 /* 2287 Create cursor and set graphic context. 2288 */ 2289 cursor=XCreateFontCursor(display,XC_pencil); 2290 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2291 annotate_context=windows->image.annotate_context; 2292 (void) XSetFont(display,annotate_context,font_info->fid); 2293 (void) XSetBackground(display,annotate_context, 2294 windows->pixel_info->pen_colors[box_id].pixel); 2295 (void) XSetForeground(display,annotate_context, 2296 windows->pixel_info->pen_colors[pen_id].pixel); 2297 /* 2298 Begin annotating the image with text. 2299 */ 2300 (void) CloneString(&windows->command.name,"Text"); 2301 windows->command.data=0; 2302 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL); 2303 state=DefaultState; 2304 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2305 text_event.xexpose.width=(int) font_info->max_bounds.width; 2306 text_event.xexpose.height=font_info->max_bounds.ascent+ 2307 font_info->max_bounds.descent; 2308 p=annotate_info->text; 2309 do 2310 { 2311 /* 2312 Display text cursor. 2313 */ 2314 *p='\0'; 2315 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2316 /* 2317 Wait for next event. 2318 */ 2319 XScreenEvent(display,windows,&event,exception); 2320 if (event.xany.window == windows->command.id) 2321 { 2322 /* 2323 Select a command from the Command widget. 2324 */ 2325 (void) XSetBackground(display,annotate_context, 2326 windows->pixel_info->background_color.pixel); 2327 (void) XSetForeground(display,annotate_context, 2328 windows->pixel_info->foreground_color.pixel); 2329 id=XCommandWidget(display,windows,AnnotateMenu,&event); 2330 (void) XSetBackground(display,annotate_context, 2331 windows->pixel_info->pen_colors[box_id].pixel); 2332 (void) XSetForeground(display,annotate_context, 2333 windows->pixel_info->pen_colors[pen_id].pixel); 2334 if (id < 0) 2335 continue; 2336 switch (TextCommands[id]) 2337 { 2338 case TextHelpCommand: 2339 { 2340 XTextViewWidget(display,resource_info,windows,MagickFalse, 2341 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2342 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2343 break; 2344 } 2345 case TextApplyCommand: 2346 { 2347 /* 2348 Finished annotating. 2349 */ 2350 annotate_info->width=(unsigned int) XTextWidth(font_info, 2351 annotate_info->text,(int) strlen(annotate_info->text)); 2352 XRefreshWindow(display,&windows->image,&text_event); 2353 state|=ExitState; 2354 break; 2355 } 2356 default: 2357 break; 2358 } 2359 continue; 2360 } 2361 /* 2362 Erase text cursor. 2363 */ 2364 text_event.xexpose.x=x; 2365 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2366 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y, 2367 (unsigned int) text_event.xexpose.width,(unsigned int) 2368 text_event.xexpose.height,MagickFalse); 2369 XRefreshWindow(display,&windows->image,&text_event); 2370 switch (event.type) 2371 { 2372 case ButtonPress: 2373 { 2374 if (event.xbutton.window != windows->image.id) 2375 break; 2376 if (event.xbutton.button == Button2) 2377 { 2378 /* 2379 Request primary selection. 2380 */ 2381 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, 2382 windows->image.id,CurrentTime); 2383 break; 2384 } 2385 break; 2386 } 2387 case Expose: 2388 { 2389 if (event.xexpose.count == 0) 2390 { 2391 XAnnotateInfo 2392 *text_info; 2393 2394 /* 2395 Refresh Image window. 2396 */ 2397 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 2398 text_info=annotate_info; 2399 while (text_info != (XAnnotateInfo *) NULL) 2400 { 2401 if (annotate_info->stencil == ForegroundStencil) 2402 (void) XDrawString(display,windows->image.id,annotate_context, 2403 text_info->x,text_info->y,text_info->text, 2404 (int) strlen(text_info->text)); 2405 else 2406 (void) XDrawImageString(display,windows->image.id, 2407 annotate_context,text_info->x,text_info->y,text_info->text, 2408 (int) strlen(text_info->text)); 2409 text_info=text_info->previous; 2410 } 2411 (void) XDrawString(display,windows->image.id,annotate_context, 2412 x,y,"_",1); 2413 } 2414 break; 2415 } 2416 case KeyPress: 2417 { 2418 int 2419 length; 2420 2421 if (event.xkey.window != windows->image.id) 2422 break; 2423 /* 2424 Respond to a user key press. 2425 */ 2426 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 2427 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2428 *(command+length)='\0'; 2429 if (((event.xkey.state & ControlMask) != 0) || 2430 ((event.xkey.state & Mod1Mask) != 0)) 2431 state|=ModifierState; 2432 if ((state & ModifierState) != 0) 2433 switch ((int) key_symbol) 2434 { 2435 case XK_u: 2436 case XK_U: 2437 { 2438 key_symbol=DeleteCommand; 2439 break; 2440 } 2441 default: 2442 break; 2443 } 2444 switch ((int) key_symbol) 2445 { 2446 case XK_BackSpace: 2447 { 2448 /* 2449 Erase one character. 2450 */ 2451 if (p == annotate_info->text) 2452 { 2453 if (annotate_info->previous == (XAnnotateInfo *) NULL) 2454 break; 2455 else 2456 { 2457 /* 2458 Go to end of the previous line of text. 2459 */ 2460 annotate_info=annotate_info->previous; 2461 p=annotate_info->text; 2462 x=annotate_info->x+annotate_info->width; 2463 y=annotate_info->y; 2464 if (annotate_info->width != 0) 2465 p+=strlen(annotate_info->text); 2466 break; 2467 } 2468 } 2469 p--; 2470 x-=XTextWidth(font_info,p,1); 2471 text_event.xexpose.x=x; 2472 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2473 XRefreshWindow(display,&windows->image,&text_event); 2474 break; 2475 } 2476 case XK_bracketleft: 2477 { 2478 key_symbol=XK_Escape; 2479 break; 2480 } 2481 case DeleteCommand: 2482 { 2483 /* 2484 Erase the entire line of text. 2485 */ 2486 while (p != annotate_info->text) 2487 { 2488 p--; 2489 x-=XTextWidth(font_info,p,1); 2490 text_event.xexpose.x=x; 2491 XRefreshWindow(display,&windows->image,&text_event); 2492 } 2493 break; 2494 } 2495 case XK_Escape: 2496 case XK_F20: 2497 { 2498 /* 2499 Finished annotating. 2500 */ 2501 annotate_info->width=(unsigned int) XTextWidth(font_info, 2502 annotate_info->text,(int) strlen(annotate_info->text)); 2503 XRefreshWindow(display,&windows->image,&text_event); 2504 state|=ExitState; 2505 break; 2506 } 2507 default: 2508 { 2509 /* 2510 Draw a single character on the Image window. 2511 */ 2512 if ((state & ModifierState) != 0) 2513 break; 2514 if (*command == '\0') 2515 break; 2516 *p=(*command); 2517 if (annotate_info->stencil == ForegroundStencil) 2518 (void) XDrawString(display,windows->image.id,annotate_context, 2519 x,y,p,1); 2520 else 2521 (void) XDrawImageString(display,windows->image.id, 2522 annotate_context,x,y,p,1); 2523 x+=XTextWidth(font_info,p,1); 2524 p++; 2525 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2526 break; 2527 } 2528 case XK_Return: 2529 case XK_KP_Enter: 2530 { 2531 /* 2532 Advance to the next line of text. 2533 */ 2534 *p='\0'; 2535 annotate_info->width=(unsigned int) XTextWidth(font_info, 2536 annotate_info->text,(int) strlen(annotate_info->text)); 2537 if (annotate_info->next != (XAnnotateInfo *) NULL) 2538 { 2539 /* 2540 Line of text already exists. 2541 */ 2542 annotate_info=annotate_info->next; 2543 x=annotate_info->x; 2544 y=annotate_info->y; 2545 p=annotate_info->text; 2546 break; 2547 } 2548 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2549 sizeof(*annotate_info->next)); 2550 if (annotate_info->next == (XAnnotateInfo *) NULL) 2551 return(MagickFalse); 2552 *annotate_info->next=(*annotate_info); 2553 annotate_info->next->previous=annotate_info; 2554 annotate_info=annotate_info->next; 2555 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2556 windows->image.width/MagickMax((ssize_t) 2557 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2558 if (annotate_info->text == (char *) NULL) 2559 return(MagickFalse); 2560 annotate_info->y+=annotate_info->height; 2561 if (annotate_info->y > (int) windows->image.height) 2562 annotate_info->y=(int) annotate_info->height; 2563 annotate_info->next=(XAnnotateInfo *) NULL; 2564 x=annotate_info->x; 2565 y=annotate_info->y; 2566 p=annotate_info->text; 2567 break; 2568 } 2569 } 2570 break; 2571 } 2572 case KeyRelease: 2573 { 2574 /* 2575 Respond to a user key release. 2576 */ 2577 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2578 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2579 state&=(~ModifierState); 2580 break; 2581 } 2582 case SelectionNotify: 2583 { 2584 Atom 2585 type; 2586 2587 int 2588 format; 2589 2590 unsigned char 2591 *data; 2592 2593 unsigned long 2594 after, 2595 length; 2596 2597 /* 2598 Obtain response from primary selection. 2599 */ 2600 if (event.xselection.property == (Atom) None) 2601 break; 2602 status=XGetWindowProperty(display,event.xselection.requestor, 2603 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING, 2604 &type,&format,&length,&after,&data); 2605 if ((status != Success) || (type != XA_STRING) || (format == 32) || 2606 (length == 0)) 2607 break; 2608 /* 2609 Annotate Image window with primary selection. 2610 */ 2611 for (i=0; i < (ssize_t) length; i++) 2612 { 2613 if ((char) data[i] != '\n') 2614 { 2615 /* 2616 Draw a single character on the Image window. 2617 */ 2618 *p=(char) data[i]; 2619 (void) XDrawString(display,windows->image.id,annotate_context, 2620 x,y,p,1); 2621 x+=XTextWidth(font_info,p,1); 2622 p++; 2623 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2624 continue; 2625 } 2626 /* 2627 Advance to the next line of text. 2628 */ 2629 *p='\0'; 2630 annotate_info->width=(unsigned int) XTextWidth(font_info, 2631 annotate_info->text,(int) strlen(annotate_info->text)); 2632 if (annotate_info->next != (XAnnotateInfo *) NULL) 2633 { 2634 /* 2635 Line of text already exists. 2636 */ 2637 annotate_info=annotate_info->next; 2638 x=annotate_info->x; 2639 y=annotate_info->y; 2640 p=annotate_info->text; 2641 continue; 2642 } 2643 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2644 sizeof(*annotate_info->next)); 2645 if (annotate_info->next == (XAnnotateInfo *) NULL) 2646 return(MagickFalse); 2647 *annotate_info->next=(*annotate_info); 2648 annotate_info->next->previous=annotate_info; 2649 annotate_info=annotate_info->next; 2650 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2651 windows->image.width/MagickMax((ssize_t) 2652 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2653 if (annotate_info->text == (char *) NULL) 2654 return(MagickFalse); 2655 annotate_info->y+=annotate_info->height; 2656 if (annotate_info->y > (int) windows->image.height) 2657 annotate_info->y=(int) annotate_info->height; 2658 annotate_info->next=(XAnnotateInfo *) NULL; 2659 x=annotate_info->x; 2660 y=annotate_info->y; 2661 p=annotate_info->text; 2662 } 2663 (void) XFree((void *) data); 2664 break; 2665 } 2666 default: 2667 break; 2668 } 2669 } while ((state & ExitState) == 0); 2670 (void) XFreeCursor(display,cursor); 2671 /* 2672 Annotation is relative to image configuration. 2673 */ 2674 width=(unsigned int) image->columns; 2675 height=(unsigned int) image->rows; 2676 x=0; 2677 y=0; 2678 if (windows->image.crop_geometry != (char *) NULL) 2679 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 2680 /* 2681 Initialize annotated image. 2682 */ 2683 XSetCursorState(display,windows,MagickTrue); 2684 XCheckRefreshWindows(display,windows); 2685 while (annotate_info != (XAnnotateInfo *) NULL) 2686 { 2687 if (annotate_info->width == 0) 2688 { 2689 /* 2690 No text on this line-- go to the next line of text. 2691 */ 2692 previous_info=annotate_info->previous; 2693 annotate_info->text=(char *) 2694 RelinquishMagickMemory(annotate_info->text); 2695 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2696 annotate_info=previous_info; 2697 continue; 2698 } 2699 /* 2700 Determine pixel index for box and pen color. 2701 */ 2702 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id]; 2703 if (windows->pixel_info->colors != 0) 2704 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2705 if (windows->pixel_info->pixels[i] == 2706 windows->pixel_info->pen_colors[box_id].pixel) 2707 { 2708 windows->pixel_info->box_index=(unsigned short) i; 2709 break; 2710 } 2711 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 2712 if (windows->pixel_info->colors != 0) 2713 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2714 if (windows->pixel_info->pixels[i] == 2715 windows->pixel_info->pen_colors[pen_id].pixel) 2716 { 2717 windows->pixel_info->pen_index=(unsigned short) i; 2718 break; 2719 } 2720 /* 2721 Define the annotate geometry string. 2722 */ 2723 annotate_info->x=(int) 2724 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width; 2725 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+ 2726 windows->image.y)/windows->image.ximage->height; 2727 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent, 2728 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width, 2729 height*annotate_info->height/windows->image.ximage->height, 2730 annotate_info->x+x,annotate_info->y+y); 2731 /* 2732 Annotate image with text. 2733 */ 2734 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image, 2735 exception); 2736 if (status == 0) 2737 return(MagickFalse); 2738 /* 2739 Free up memory. 2740 */ 2741 previous_info=annotate_info->previous; 2742 annotate_info->text=DestroyString(annotate_info->text); 2743 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2744 annotate_info=previous_info; 2745 } 2746 (void) XSetForeground(display,annotate_context, 2747 windows->pixel_info->foreground_color.pixel); 2748 (void) XSetBackground(display,annotate_context, 2749 windows->pixel_info->background_color.pixel); 2750 (void) XSetFont(display,annotate_context,windows->font_info->fid); 2751 XSetCursorState(display,windows,MagickFalse); 2752 (void) XFreeFont(display,font_info); 2753 /* 2754 Update image configuration. 2755 */ 2756 XConfigureImageColormap(display,resource_info,windows,image,exception); 2757 (void) XConfigureImage(display,resource_info,windows,image,exception); 2758 return(MagickTrue); 2759} 2760 2761/* 2762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2763% % 2764% % 2765% % 2766+ X B a c k g r o u n d I m a g e % 2767% % 2768% % 2769% % 2770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2771% 2772% XBackgroundImage() displays the image in the background of a window. 2773% 2774% The format of the XBackgroundImage method is: 2775% 2776% MagickBooleanType XBackgroundImage(Display *display, 2777% XResourceInfo *resource_info,XWindows *windows,Image **image, 2778% ExceptionInfo *exception) 2779% 2780% A description of each parameter follows: 2781% 2782% o display: Specifies a connection to an X server; returned from 2783% XOpenDisplay. 2784% 2785% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2786% 2787% o windows: Specifies a pointer to a XWindows structure. 2788% 2789% o image: the image. 2790% 2791% o exception: return any errors or warnings in this structure. 2792% 2793*/ 2794static MagickBooleanType XBackgroundImage(Display *display, 2795 XResourceInfo *resource_info,XWindows *windows,Image **image, 2796 ExceptionInfo *exception) 2797{ 2798#define BackgroundImageTag "Background/Image" 2799 2800 int 2801 status; 2802 2803 static char 2804 window_id[MaxTextExtent] = "root"; 2805 2806 XResourceInfo 2807 background_resources; 2808 2809 /* 2810 Put image in background. 2811 */ 2812 status=XDialogWidget(display,windows,"Background", 2813 "Enter window id (id 0x00 selects window with pointer):",window_id); 2814 if (*window_id == '\0') 2815 return(MagickFalse); 2816 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 2817 exception); 2818 XInfoWidget(display,windows,BackgroundImageTag); 2819 XSetCursorState(display,windows,MagickTrue); 2820 XCheckRefreshWindows(display,windows); 2821 background_resources=(*resource_info); 2822 background_resources.window_id=window_id; 2823 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse; 2824 status=XDisplayBackgroundImage(display,&background_resources,*image, 2825 exception); 2826 if (status != MagickFalse) 2827 XClientMessage(display,windows->image.id,windows->im_protocols, 2828 windows->im_retain_colors,CurrentTime); 2829 XSetCursorState(display,windows,MagickFalse); 2830 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image, 2831 exception); 2832 return(MagickTrue); 2833} 2834 2835/* 2836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2837% % 2838% % 2839% % 2840+ X C h o p I m a g e % 2841% % 2842% % 2843% % 2844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2845% 2846% XChopImage() chops the X image. 2847% 2848% The format of the XChopImage method is: 2849% 2850% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info, 2851% XWindows *windows,Image **image,ExceptionInfo *exception) 2852% 2853% A description of each parameter follows: 2854% 2855% o display: Specifies a connection to an X server; returned from 2856% XOpenDisplay. 2857% 2858% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2859% 2860% o windows: Specifies a pointer to a XWindows structure. 2861% 2862% o image: the image. 2863% 2864% o exception: return any errors or warnings in this structure. 2865% 2866*/ 2867static MagickBooleanType XChopImage(Display *display, 2868 XResourceInfo *resource_info,XWindows *windows,Image **image, 2869 ExceptionInfo *exception) 2870{ 2871 static const char 2872 *ChopMenu[] = 2873 { 2874 "Direction", 2875 "Help", 2876 "Dismiss", 2877 (char *) NULL 2878 }; 2879 2880 static ModeType 2881 direction = HorizontalChopCommand; 2882 2883 static const ModeType 2884 ChopCommands[] = 2885 { 2886 ChopDirectionCommand, 2887 ChopHelpCommand, 2888 ChopDismissCommand 2889 }, 2890 DirectionCommands[] = 2891 { 2892 HorizontalChopCommand, 2893 VerticalChopCommand 2894 }; 2895 2896 char 2897 text[MaxTextExtent]; 2898 2899 Image 2900 *chop_image; 2901 2902 int 2903 id, 2904 x, 2905 y; 2906 2907 MagickRealType 2908 scale_factor; 2909 2910 RectangleInfo 2911 chop_info; 2912 2913 unsigned int 2914 distance, 2915 height, 2916 width; 2917 2918 size_t 2919 state; 2920 2921 XEvent 2922 event; 2923 2924 XSegment 2925 segment_info; 2926 2927 /* 2928 Map Command widget. 2929 */ 2930 (void) CloneString(&windows->command.name,"Chop"); 2931 windows->command.data=1; 2932 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL); 2933 (void) XMapRaised(display,windows->command.id); 2934 XClientMessage(display,windows->image.id,windows->im_protocols, 2935 windows->im_update_widget,CurrentTime); 2936 /* 2937 Track pointer until button 1 is pressed. 2938 */ 2939 XQueryPosition(display,windows->image.id,&x,&y); 2940 (void) XSelectInput(display,windows->image.id, 2941 windows->image.attributes.event_mask | PointerMotionMask); 2942 state=DefaultState; 2943 do 2944 { 2945 if (windows->info.mapped != MagickFalse) 2946 { 2947 /* 2948 Display pointer position. 2949 */ 2950 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 2951 x+windows->image.x,y+windows->image.y); 2952 XInfoWidget(display,windows,text); 2953 } 2954 /* 2955 Wait for next event. 2956 */ 2957 XScreenEvent(display,windows,&event,exception); 2958 if (event.xany.window == windows->command.id) 2959 { 2960 /* 2961 Select a command from the Command widget. 2962 */ 2963 id=XCommandWidget(display,windows,ChopMenu,&event); 2964 if (id < 0) 2965 continue; 2966 switch (ChopCommands[id]) 2967 { 2968 case ChopDirectionCommand: 2969 { 2970 char 2971 command[MaxTextExtent]; 2972 2973 static const char 2974 *Directions[] = 2975 { 2976 "horizontal", 2977 "vertical", 2978 (char *) NULL, 2979 }; 2980 2981 /* 2982 Select a command from the pop-up menu. 2983 */ 2984 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 2985 if (id >= 0) 2986 direction=DirectionCommands[id]; 2987 break; 2988 } 2989 case ChopHelpCommand: 2990 { 2991 XTextViewWidget(display,resource_info,windows,MagickFalse, 2992 "Help Viewer - Image Chop",ImageChopHelp); 2993 break; 2994 } 2995 case ChopDismissCommand: 2996 { 2997 /* 2998 Prematurely exit. 2999 */ 3000 state|=EscapeState; 3001 state|=ExitState; 3002 break; 3003 } 3004 default: 3005 break; 3006 } 3007 continue; 3008 } 3009 switch (event.type) 3010 { 3011 case ButtonPress: 3012 { 3013 if (event.xbutton.button != Button1) 3014 break; 3015 if (event.xbutton.window != windows->image.id) 3016 break; 3017 /* 3018 User has committed to start point of chopping line. 3019 */ 3020 segment_info.x1=(short int) event.xbutton.x; 3021 segment_info.x2=(short int) event.xbutton.x; 3022 segment_info.y1=(short int) event.xbutton.y; 3023 segment_info.y2=(short int) event.xbutton.y; 3024 state|=ExitState; 3025 break; 3026 } 3027 case ButtonRelease: 3028 break; 3029 case Expose: 3030 break; 3031 case KeyPress: 3032 { 3033 char 3034 command[MaxTextExtent]; 3035 3036 KeySym 3037 key_symbol; 3038 3039 if (event.xkey.window != windows->image.id) 3040 break; 3041 /* 3042 Respond to a user key press. 3043 */ 3044 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3045 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3046 switch ((int) key_symbol) 3047 { 3048 case XK_Escape: 3049 case XK_F20: 3050 { 3051 /* 3052 Prematurely exit. 3053 */ 3054 state|=EscapeState; 3055 state|=ExitState; 3056 break; 3057 } 3058 case XK_F1: 3059 case XK_Help: 3060 { 3061 (void) XSetFunction(display,windows->image.highlight_context, 3062 GXcopy); 3063 XTextViewWidget(display,resource_info,windows,MagickFalse, 3064 "Help Viewer - Image Chop",ImageChopHelp); 3065 (void) XSetFunction(display,windows->image.highlight_context, 3066 GXinvert); 3067 break; 3068 } 3069 default: 3070 { 3071 (void) XBell(display,0); 3072 break; 3073 } 3074 } 3075 break; 3076 } 3077 case MotionNotify: 3078 { 3079 /* 3080 Map and unmap Info widget as text cursor crosses its boundaries. 3081 */ 3082 x=event.xmotion.x; 3083 y=event.xmotion.y; 3084 if (windows->info.mapped != MagickFalse) 3085 { 3086 if ((x < (int) (windows->info.x+windows->info.width)) && 3087 (y < (int) (windows->info.y+windows->info.height))) 3088 (void) XWithdrawWindow(display,windows->info.id, 3089 windows->info.screen); 3090 } 3091 else 3092 if ((x > (int) (windows->info.x+windows->info.width)) || 3093 (y > (int) (windows->info.y+windows->info.height))) 3094 (void) XMapWindow(display,windows->info.id); 3095 } 3096 } 3097 } while ((state & ExitState) == 0); 3098 (void) XSelectInput(display,windows->image.id, 3099 windows->image.attributes.event_mask); 3100 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3101 if ((state & EscapeState) != 0) 3102 return(MagickTrue); 3103 /* 3104 Draw line as pointer moves until the mouse button is released. 3105 */ 3106 chop_info.width=0; 3107 chop_info.height=0; 3108 chop_info.x=0; 3109 chop_info.y=0; 3110 distance=0; 3111 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3112 state=DefaultState; 3113 do 3114 { 3115 if (distance > 9) 3116 { 3117 /* 3118 Display info and draw chopping line. 3119 */ 3120 if (windows->info.mapped == MagickFalse) 3121 (void) XMapWindow(display,windows->info.id); 3122 (void) FormatLocaleString(text,MaxTextExtent, 3123 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 3124 chop_info.height,(double) chop_info.x,(double) chop_info.y); 3125 XInfoWidget(display,windows,text); 3126 XHighlightLine(display,windows->image.id, 3127 windows->image.highlight_context,&segment_info); 3128 } 3129 else 3130 if (windows->info.mapped != MagickFalse) 3131 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3132 /* 3133 Wait for next event. 3134 */ 3135 XScreenEvent(display,windows,&event,exception); 3136 if (distance > 9) 3137 XHighlightLine(display,windows->image.id, 3138 windows->image.highlight_context,&segment_info); 3139 switch (event.type) 3140 { 3141 case ButtonPress: 3142 { 3143 segment_info.x2=(short int) event.xmotion.x; 3144 segment_info.y2=(short int) event.xmotion.y; 3145 break; 3146 } 3147 case ButtonRelease: 3148 { 3149 /* 3150 User has committed to chopping line. 3151 */ 3152 segment_info.x2=(short int) event.xbutton.x; 3153 segment_info.y2=(short int) event.xbutton.y; 3154 state|=ExitState; 3155 break; 3156 } 3157 case Expose: 3158 break; 3159 case MotionNotify: 3160 { 3161 segment_info.x2=(short int) event.xmotion.x; 3162 segment_info.y2=(short int) event.xmotion.y; 3163 } 3164 default: 3165 break; 3166 } 3167 /* 3168 Check boundary conditions. 3169 */ 3170 if (segment_info.x2 < 0) 3171 segment_info.x2=0; 3172 else 3173 if (segment_info.x2 > windows->image.ximage->width) 3174 segment_info.x2=windows->image.ximage->width; 3175 if (segment_info.y2 < 0) 3176 segment_info.y2=0; 3177 else 3178 if (segment_info.y2 > windows->image.ximage->height) 3179 segment_info.y2=windows->image.ximage->height; 3180 distance=(unsigned int) 3181 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 3182 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 3183 /* 3184 Compute chopping geometry. 3185 */ 3186 if (direction == HorizontalChopCommand) 3187 { 3188 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 3189 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 3190 chop_info.height=0; 3191 chop_info.y=0; 3192 if (segment_info.x1 > (int) segment_info.x2) 3193 { 3194 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 3195 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 3196 } 3197 } 3198 else 3199 { 3200 chop_info.width=0; 3201 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 3202 chop_info.x=0; 3203 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 3204 if (segment_info.y1 > segment_info.y2) 3205 { 3206 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 3207 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 3208 } 3209 } 3210 } while ((state & ExitState) == 0); 3211 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 3212 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3213 if (distance <= 9) 3214 return(MagickTrue); 3215 /* 3216 Image chopping is relative to image configuration. 3217 */ 3218 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 3219 exception); 3220 XSetCursorState(display,windows,MagickTrue); 3221 XCheckRefreshWindows(display,windows); 3222 windows->image.window_changes.width=windows->image.ximage->width- 3223 (unsigned int) chop_info.width; 3224 windows->image.window_changes.height=windows->image.ximage->height- 3225 (unsigned int) chop_info.height; 3226 width=(unsigned int) (*image)->columns; 3227 height=(unsigned int) (*image)->rows; 3228 x=0; 3229 y=0; 3230 if (windows->image.crop_geometry != (char *) NULL) 3231 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 3232 scale_factor=(MagickRealType) width/windows->image.ximage->width; 3233 chop_info.x+=x; 3234 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 3235 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 3236 scale_factor=(MagickRealType) height/windows->image.ximage->height; 3237 chop_info.y+=y; 3238 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 3239 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 3240 /* 3241 Chop image. 3242 */ 3243 chop_image=ChopImage(*image,&chop_info,exception); 3244 XSetCursorState(display,windows,MagickFalse); 3245 if (chop_image == (Image *) NULL) 3246 return(MagickFalse); 3247 *image=DestroyImage(*image); 3248 *image=chop_image; 3249 /* 3250 Update image configuration. 3251 */ 3252 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3253 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3254 return(MagickTrue); 3255} 3256 3257/* 3258%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3259% % 3260% % 3261% % 3262+ X C o l o r E d i t I m a g e % 3263% % 3264% % 3265% % 3266%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3267% 3268% XColorEditImage() allows the user to interactively change the color of one 3269% pixel for a DirectColor image or one colormap entry for a PseudoClass image. 3270% 3271% The format of the XColorEditImage method is: 3272% 3273% MagickBooleanType XColorEditImage(Display *display, 3274% XResourceInfo *resource_info,XWindows *windows,Image **image, 3275% ExceptionInfo *exception) 3276% 3277% A description of each parameter follows: 3278% 3279% o display: Specifies a connection to an X server; returned from 3280% XOpenDisplay. 3281% 3282% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3283% 3284% o windows: Specifies a pointer to a XWindows structure. 3285% 3286% o image: the image; returned from ReadImage. 3287% 3288% o exception: return any errors or warnings in this structure. 3289% 3290*/ 3291static MagickBooleanType XColorEditImage(Display *display, 3292 XResourceInfo *resource_info,XWindows *windows,Image **image, 3293 ExceptionInfo *exception) 3294{ 3295 static const char 3296 *ColorEditMenu[] = 3297 { 3298 "Method", 3299 "Pixel Color", 3300 "Border Color", 3301 "Fuzz", 3302 "Undo", 3303 "Help", 3304 "Dismiss", 3305 (char *) NULL 3306 }; 3307 3308 static const ModeType 3309 ColorEditCommands[] = 3310 { 3311 ColorEditMethodCommand, 3312 ColorEditColorCommand, 3313 ColorEditBorderCommand, 3314 ColorEditFuzzCommand, 3315 ColorEditUndoCommand, 3316 ColorEditHelpCommand, 3317 ColorEditDismissCommand 3318 }; 3319 3320 static PaintMethod 3321 method = PointMethod; 3322 3323 static unsigned int 3324 pen_id = 0; 3325 3326 static XColor 3327 border_color = { 0, 0, 0, 0, 0, 0 }; 3328 3329 char 3330 command[MaxTextExtent], 3331 text[MaxTextExtent]; 3332 3333 Cursor 3334 cursor; 3335 3336 int 3337 entry, 3338 id, 3339 x, 3340 x_offset, 3341 y, 3342 y_offset; 3343 3344 register Quantum 3345 *q; 3346 3347 register ssize_t 3348 i; 3349 3350 unsigned int 3351 height, 3352 width; 3353 3354 size_t 3355 state; 3356 3357 XColor 3358 color; 3359 3360 XEvent 3361 event; 3362 3363 /* 3364 Map Command widget. 3365 */ 3366 (void) CloneString(&windows->command.name,"Color Edit"); 3367 windows->command.data=4; 3368 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 3369 (void) XMapRaised(display,windows->command.id); 3370 XClientMessage(display,windows->image.id,windows->im_protocols, 3371 windows->im_update_widget,CurrentTime); 3372 /* 3373 Make cursor. 3374 */ 3375 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 3376 resource_info->background_color,resource_info->foreground_color); 3377 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3378 /* 3379 Track pointer until button 1 is pressed. 3380 */ 3381 XQueryPosition(display,windows->image.id,&x,&y); 3382 (void) XSelectInput(display,windows->image.id, 3383 windows->image.attributes.event_mask | PointerMotionMask); 3384 state=DefaultState; 3385 do 3386 { 3387 if (windows->info.mapped != MagickFalse) 3388 { 3389 /* 3390 Display pointer position. 3391 */ 3392 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 3393 x+windows->image.x,y+windows->image.y); 3394 XInfoWidget(display,windows,text); 3395 } 3396 /* 3397 Wait for next event. 3398 */ 3399 XScreenEvent(display,windows,&event,exception); 3400 if (event.xany.window == windows->command.id) 3401 { 3402 /* 3403 Select a command from the Command widget. 3404 */ 3405 id=XCommandWidget(display,windows,ColorEditMenu,&event); 3406 if (id < 0) 3407 { 3408 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3409 continue; 3410 } 3411 switch (ColorEditCommands[id]) 3412 { 3413 case ColorEditMethodCommand: 3414 { 3415 char 3416 **methods; 3417 3418 /* 3419 Select a method from the pop-up menu. 3420 */ 3421 methods=(char **) GetCommandOptions(MagickMethodOptions); 3422 if (methods == (char **) NULL) 3423 break; 3424 entry=XMenuWidget(display,windows,ColorEditMenu[id], 3425 (const char **) methods,command); 3426 if (entry >= 0) 3427 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 3428 MagickFalse,methods[entry]); 3429 methods=DestroyStringList(methods); 3430 break; 3431 } 3432 case ColorEditColorCommand: 3433 { 3434 const char 3435 *ColorMenu[MaxNumberPens]; 3436 3437 int 3438 pen_number; 3439 3440 /* 3441 Initialize menu selections. 3442 */ 3443 for (i=0; i < (int) (MaxNumberPens-2); i++) 3444 ColorMenu[i]=resource_info->pen_colors[i]; 3445 ColorMenu[MaxNumberPens-2]="Browser..."; 3446 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3447 /* 3448 Select a pen color from the pop-up menu. 3449 */ 3450 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3451 (const char **) ColorMenu,command); 3452 if (pen_number < 0) 3453 break; 3454 if (pen_number == (MaxNumberPens-2)) 3455 { 3456 static char 3457 color_name[MaxTextExtent] = "gray"; 3458 3459 /* 3460 Select a pen color from a dialog. 3461 */ 3462 resource_info->pen_colors[pen_number]=color_name; 3463 XColorBrowserWidget(display,windows,"Select",color_name); 3464 if (*color_name == '\0') 3465 break; 3466 } 3467 /* 3468 Set pen color. 3469 */ 3470 (void) XParseColor(display,windows->map_info->colormap, 3471 resource_info->pen_colors[pen_number],&color); 3472 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 3473 (unsigned int) MaxColors,&color); 3474 windows->pixel_info->pen_colors[pen_number]=color; 3475 pen_id=(unsigned int) pen_number; 3476 break; 3477 } 3478 case ColorEditBorderCommand: 3479 { 3480 const char 3481 *ColorMenu[MaxNumberPens]; 3482 3483 int 3484 pen_number; 3485 3486 /* 3487 Initialize menu selections. 3488 */ 3489 for (i=0; i < (int) (MaxNumberPens-2); i++) 3490 ColorMenu[i]=resource_info->pen_colors[i]; 3491 ColorMenu[MaxNumberPens-2]="Browser..."; 3492 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3493 /* 3494 Select a pen color from the pop-up menu. 3495 */ 3496 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3497 (const char **) ColorMenu,command); 3498 if (pen_number < 0) 3499 break; 3500 if (pen_number == (MaxNumberPens-2)) 3501 { 3502 static char 3503 color_name[MaxTextExtent] = "gray"; 3504 3505 /* 3506 Select a pen color from a dialog. 3507 */ 3508 resource_info->pen_colors[pen_number]=color_name; 3509 XColorBrowserWidget(display,windows,"Select",color_name); 3510 if (*color_name == '\0') 3511 break; 3512 } 3513 /* 3514 Set border color. 3515 */ 3516 (void) XParseColor(display,windows->map_info->colormap, 3517 resource_info->pen_colors[pen_number],&border_color); 3518 break; 3519 } 3520 case ColorEditFuzzCommand: 3521 { 3522 static char 3523 fuzz[MaxTextExtent]; 3524 3525 static const char 3526 *FuzzMenu[] = 3527 { 3528 "0%", 3529 "2%", 3530 "5%", 3531 "10%", 3532 "15%", 3533 "Dialog...", 3534 (char *) NULL, 3535 }; 3536 3537 /* 3538 Select a command from the pop-up menu. 3539 */ 3540 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 3541 command); 3542 if (entry < 0) 3543 break; 3544 if (entry != 5) 3545 { 3546 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 3547 QuantumRange+1.0); 3548 break; 3549 } 3550 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 3551 (void) XDialogWidget(display,windows,"Ok", 3552 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 3553 if (*fuzz == '\0') 3554 break; 3555 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 3556 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 3557 1.0); 3558 break; 3559 } 3560 case ColorEditUndoCommand: 3561 { 3562 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 3563 image,exception); 3564 break; 3565 } 3566 case ColorEditHelpCommand: 3567 default: 3568 { 3569 XTextViewWidget(display,resource_info,windows,MagickFalse, 3570 "Help Viewer - Image Annotation",ImageColorEditHelp); 3571 break; 3572 } 3573 case ColorEditDismissCommand: 3574 { 3575 /* 3576 Prematurely exit. 3577 */ 3578 state|=EscapeState; 3579 state|=ExitState; 3580 break; 3581 } 3582 } 3583 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3584 continue; 3585 } 3586 switch (event.type) 3587 { 3588 case ButtonPress: 3589 { 3590 if (event.xbutton.button != Button1) 3591 break; 3592 if ((event.xbutton.window != windows->image.id) && 3593 (event.xbutton.window != windows->magnify.id)) 3594 break; 3595 /* 3596 exit loop. 3597 */ 3598 x=event.xbutton.x; 3599 y=event.xbutton.y; 3600 (void) XMagickCommand(display,resource_info,windows, 3601 SaveToUndoBufferCommand,image,exception); 3602 state|=UpdateConfigurationState; 3603 break; 3604 } 3605 case ButtonRelease: 3606 { 3607 if (event.xbutton.button != Button1) 3608 break; 3609 if ((event.xbutton.window != windows->image.id) && 3610 (event.xbutton.window != windows->magnify.id)) 3611 break; 3612 /* 3613 Update colormap information. 3614 */ 3615 x=event.xbutton.x; 3616 y=event.xbutton.y; 3617 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3618 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3619 XInfoWidget(display,windows,text); 3620 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3621 state&=(~UpdateConfigurationState); 3622 break; 3623 } 3624 case Expose: 3625 break; 3626 case KeyPress: 3627 { 3628 KeySym 3629 key_symbol; 3630 3631 if (event.xkey.window == windows->magnify.id) 3632 { 3633 Window 3634 window; 3635 3636 window=windows->magnify.id; 3637 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 3638 } 3639 if (event.xkey.window != windows->image.id) 3640 break; 3641 /* 3642 Respond to a user key press. 3643 */ 3644 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3645 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3646 switch ((int) key_symbol) 3647 { 3648 case XK_Escape: 3649 case XK_F20: 3650 { 3651 /* 3652 Prematurely exit. 3653 */ 3654 state|=ExitState; 3655 break; 3656 } 3657 case XK_F1: 3658 case XK_Help: 3659 { 3660 XTextViewWidget(display,resource_info,windows,MagickFalse, 3661 "Help Viewer - Image Annotation",ImageColorEditHelp); 3662 break; 3663 } 3664 default: 3665 { 3666 (void) XBell(display,0); 3667 break; 3668 } 3669 } 3670 break; 3671 } 3672 case MotionNotify: 3673 { 3674 /* 3675 Map and unmap Info widget as cursor crosses its boundaries. 3676 */ 3677 x=event.xmotion.x; 3678 y=event.xmotion.y; 3679 if (windows->info.mapped != MagickFalse) 3680 { 3681 if ((x < (int) (windows->info.x+windows->info.width)) && 3682 (y < (int) (windows->info.y+windows->info.height))) 3683 (void) XWithdrawWindow(display,windows->info.id, 3684 windows->info.screen); 3685 } 3686 else 3687 if ((x > (int) (windows->info.x+windows->info.width)) || 3688 (y > (int) (windows->info.y+windows->info.height))) 3689 (void) XMapWindow(display,windows->info.id); 3690 break; 3691 } 3692 default: 3693 break; 3694 } 3695 if (event.xany.window == windows->magnify.id) 3696 { 3697 x=windows->magnify.x-windows->image.x; 3698 y=windows->magnify.y-windows->image.y; 3699 } 3700 x_offset=x; 3701 y_offset=y; 3702 if ((state & UpdateConfigurationState) != 0) 3703 { 3704 CacheView 3705 *image_view; 3706 3707 int 3708 x, 3709 y; 3710 3711 /* 3712 Pixel edit is relative to image configuration. 3713 */ 3714 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 3715 MagickTrue); 3716 color=windows->pixel_info->pen_colors[pen_id]; 3717 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 3718 width=(unsigned int) (*image)->columns; 3719 height=(unsigned int) (*image)->rows; 3720 x=0; 3721 y=0; 3722 if (windows->image.crop_geometry != (char *) NULL) 3723 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 3724 &width,&height); 3725 x_offset=(int) 3726 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 3727 y_offset=(int) 3728 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 3729 if ((x_offset < 0) || (y_offset < 0)) 3730 continue; 3731 if ((x_offset >= (int) (*image)->columns) || 3732 (y_offset >= (int) (*image)->rows)) 3733 continue; 3734 image_view=AcquireCacheView(*image); 3735 switch (method) 3736 { 3737 case PointMethod: 3738 default: 3739 { 3740 /* 3741 Update color information using point algorithm. 3742 */ 3743 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3744 return(MagickFalse); 3745 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 3746 (ssize_t) y_offset,1,1,exception); 3747 if (q == (Quantum *) NULL) 3748 break; 3749 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3750 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3751 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3752 (void) SyncCacheViewAuthenticPixels(image_view,exception); 3753 break; 3754 } 3755 case ReplaceMethod: 3756 { 3757 PixelInfo 3758 pixel, 3759 target; 3760 3761 Quantum 3762 virtual_pixel[CompositePixelChannel]; 3763 3764 /* 3765 Update color information using replace algorithm. 3766 */ 3767 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 3768 (ssize_t) y_offset,virtual_pixel,exception); 3769 target.red=virtual_pixel[RedPixelChannel]; 3770 target.green=virtual_pixel[GreenPixelChannel]; 3771 target.blue=virtual_pixel[BluePixelChannel]; 3772 target.alpha=virtual_pixel[AlphaPixelChannel]; 3773 if ((*image)->storage_class == DirectClass) 3774 { 3775 for (y=0; y < (int) (*image)->rows; y++) 3776 { 3777 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3778 (*image)->columns,1,exception); 3779 if (q == (Quantum *) NULL) 3780 break; 3781 for (x=0; x < (int) (*image)->columns; x++) 3782 { 3783 GetPixelInfoPixel(*image,q,&pixel); 3784 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 3785 { 3786 SetPixelRed(*image,ScaleShortToQuantum( 3787 color.red),q); 3788 SetPixelGreen(*image,ScaleShortToQuantum( 3789 color.green),q); 3790 SetPixelBlue(*image,ScaleShortToQuantum( 3791 color.blue),q); 3792 } 3793 q+=GetPixelChannels(*image); 3794 } 3795 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3796 break; 3797 } 3798 } 3799 else 3800 { 3801 for (i=0; i < (ssize_t) (*image)->colors; i++) 3802 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target)) 3803 { 3804 (*image)->colormap[i].red=ScaleShortToQuantum( 3805 color.red); 3806 (*image)->colormap[i].green=ScaleShortToQuantum( 3807 color.green); 3808 (*image)->colormap[i].blue=ScaleShortToQuantum( 3809 color.blue); 3810 } 3811 (void) SyncImage(*image,exception); 3812 } 3813 break; 3814 } 3815 case FloodfillMethod: 3816 case FillToBorderMethod: 3817 { 3818 DrawInfo 3819 *draw_info; 3820 3821 PixelInfo 3822 target; 3823 3824 /* 3825 Update color information using floodfill algorithm. 3826 */ 3827 (void) GetOneVirtualMagickPixel(*image, 3828 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 3829 y_offset,&target,exception); 3830 if (method == FillToBorderMethod) 3831 { 3832 target.red=(MagickRealType) 3833 ScaleShortToQuantum(border_color.red); 3834 target.green=(MagickRealType) 3835 ScaleShortToQuantum(border_color.green); 3836 target.blue=(MagickRealType) 3837 ScaleShortToQuantum(border_color.blue); 3838 } 3839 draw_info=CloneDrawInfo(resource_info->image_info, 3840 (DrawInfo *) NULL); 3841 (void) QueryColorCompliance(resource_info->pen_colors[pen_id], 3842 AllCompliance,&draw_info->fill,exception); 3843 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 3844 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 3845 MagickFalse : MagickTrue,exception); 3846 draw_info=DestroyDrawInfo(draw_info); 3847 break; 3848 } 3849 case ResetMethod: 3850 { 3851 /* 3852 Update color information using reset algorithm. 3853 */ 3854 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3855 return(MagickFalse); 3856 for (y=0; y < (int) (*image)->rows; y++) 3857 { 3858 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3859 (*image)->columns,1,exception); 3860 if (q == (Quantum *) NULL) 3861 break; 3862 for (x=0; x < (int) (*image)->columns; x++) 3863 { 3864 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3865 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3866 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3867 q+=GetPixelChannels(*image); 3868 } 3869 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3870 break; 3871 } 3872 break; 3873 } 3874 } 3875 image_view=DestroyCacheView(image_view); 3876 state&=(~UpdateConfigurationState); 3877 } 3878 } while ((state & ExitState) == 0); 3879 (void) XSelectInput(display,windows->image.id, 3880 windows->image.attributes.event_mask); 3881 XSetCursorState(display,windows,MagickFalse); 3882 (void) XFreeCursor(display,cursor); 3883 return(MagickTrue); 3884} 3885 3886/* 3887%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3888% % 3889% % 3890% % 3891+ X C o m p o s i t e I m a g e % 3892% % 3893% % 3894% % 3895%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3896% 3897% XCompositeImage() requests an image name from the user, reads the image and 3898% composites it with the X window image at a location the user chooses with 3899% the pointer. 3900% 3901% The format of the XCompositeImage method is: 3902% 3903% MagickBooleanType XCompositeImage(Display *display, 3904% XResourceInfo *resource_info,XWindows *windows,Image *image, 3905% ExceptionInfo *exception) 3906% 3907% A description of each parameter follows: 3908% 3909% o display: Specifies a connection to an X server; returned from 3910% XOpenDisplay. 3911% 3912% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3913% 3914% o windows: Specifies a pointer to a XWindows structure. 3915% 3916% o image: the image; returned from ReadImage. 3917% 3918% o exception: return any errors or warnings in this structure. 3919% 3920*/ 3921static MagickBooleanType XCompositeImage(Display *display, 3922 XResourceInfo *resource_info,XWindows *windows,Image *image, 3923 ExceptionInfo *exception) 3924{ 3925 static char 3926 displacement_geometry[MaxTextExtent] = "30x30", 3927 filename[MaxTextExtent] = "\0"; 3928 3929 static const char 3930 *CompositeMenu[] = 3931 { 3932 "Operators", 3933 "Dissolve", 3934 "Displace", 3935 "Help", 3936 "Dismiss", 3937 (char *) NULL 3938 }; 3939 3940 static CompositeOperator 3941 compose = CopyCompositeOp; 3942 3943 static const ModeType 3944 CompositeCommands[] = 3945 { 3946 CompositeOperatorsCommand, 3947 CompositeDissolveCommand, 3948 CompositeDisplaceCommand, 3949 CompositeHelpCommand, 3950 CompositeDismissCommand 3951 }; 3952 3953 char 3954 text[MaxTextExtent]; 3955 3956 Cursor 3957 cursor; 3958 3959 Image 3960 *composite_image; 3961 3962 int 3963 entry, 3964 id, 3965 x, 3966 y; 3967 3968 MagickRealType 3969 blend, 3970 scale_factor; 3971 3972 RectangleInfo 3973 highlight_info, 3974 composite_info; 3975 3976 unsigned int 3977 height, 3978 width; 3979 3980 size_t 3981 state; 3982 3983 XEvent 3984 event; 3985 3986 /* 3987 Request image file name from user. 3988 */ 3989 XFileBrowserWidget(display,windows,"Composite",filename); 3990 if (*filename == '\0') 3991 return(MagickTrue); 3992 /* 3993 Read image. 3994 */ 3995 XSetCursorState(display,windows,MagickTrue); 3996 XCheckRefreshWindows(display,windows); 3997 (void) CopyMagickString(resource_info->image_info->filename,filename, 3998 MaxTextExtent); 3999 composite_image=ReadImage(resource_info->image_info,exception); 4000 CatchException(exception); 4001 XSetCursorState(display,windows,MagickFalse); 4002 if (composite_image == (Image *) NULL) 4003 return(MagickFalse); 4004 /* 4005 Map Command widget. 4006 */ 4007 (void) CloneString(&windows->command.name,"Composite"); 4008 windows->command.data=1; 4009 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 4010 (void) XMapRaised(display,windows->command.id); 4011 XClientMessage(display,windows->image.id,windows->im_protocols, 4012 windows->im_update_widget,CurrentTime); 4013 /* 4014 Track pointer until button 1 is pressed. 4015 */ 4016 XQueryPosition(display,windows->image.id,&x,&y); 4017 (void) XSelectInput(display,windows->image.id, 4018 windows->image.attributes.event_mask | PointerMotionMask); 4019 composite_info.x=(ssize_t) windows->image.x+x; 4020 composite_info.y=(ssize_t) windows->image.y+y; 4021 composite_info.width=0; 4022 composite_info.height=0; 4023 cursor=XCreateFontCursor(display,XC_ul_angle); 4024 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4025 blend=0.0; 4026 state=DefaultState; 4027 do 4028 { 4029 if (windows->info.mapped != MagickFalse) 4030 { 4031 /* 4032 Display pointer position. 4033 */ 4034 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4035 (long) composite_info.x,(long) composite_info.y); 4036 XInfoWidget(display,windows,text); 4037 } 4038 highlight_info=composite_info; 4039 highlight_info.x=composite_info.x-windows->image.x; 4040 highlight_info.y=composite_info.y-windows->image.y; 4041 XHighlightRectangle(display,windows->image.id, 4042 windows->image.highlight_context,&highlight_info); 4043 /* 4044 Wait for next event. 4045 */ 4046 XScreenEvent(display,windows,&event,exception); 4047 XHighlightRectangle(display,windows->image.id, 4048 windows->image.highlight_context,&highlight_info); 4049 if (event.xany.window == windows->command.id) 4050 { 4051 /* 4052 Select a command from the Command widget. 4053 */ 4054 id=XCommandWidget(display,windows,CompositeMenu,&event); 4055 if (id < 0) 4056 continue; 4057 switch (CompositeCommands[id]) 4058 { 4059 case CompositeOperatorsCommand: 4060 { 4061 char 4062 command[MaxTextExtent], 4063 **operators; 4064 4065 /* 4066 Select a command from the pop-up menu. 4067 */ 4068 operators=GetCommandOptions(MagickComposeOptions); 4069 if (operators == (char **) NULL) 4070 break; 4071 entry=XMenuWidget(display,windows,CompositeMenu[id], 4072 (const char **) operators,command); 4073 if (entry >= 0) 4074 compose=(CompositeOperator) ParseCommandOption( 4075 MagickComposeOptions,MagickFalse,operators[entry]); 4076 operators=DestroyStringList(operators); 4077 break; 4078 } 4079 case CompositeDissolveCommand: 4080 { 4081 static char 4082 factor[MaxTextExtent] = "20.0"; 4083 4084 /* 4085 Dissolve the two images a given percent. 4086 */ 4087 (void) XSetFunction(display,windows->image.highlight_context, 4088 GXcopy); 4089 (void) XDialogWidget(display,windows,"Dissolve", 4090 "Enter the blend factor (0.0 - 99.9%):",factor); 4091 (void) XSetFunction(display,windows->image.highlight_context, 4092 GXinvert); 4093 if (*factor == '\0') 4094 break; 4095 blend=StringToDouble(factor,(char **) NULL); 4096 compose=DissolveCompositeOp; 4097 break; 4098 } 4099 case CompositeDisplaceCommand: 4100 { 4101 /* 4102 Get horizontal and vertical scale displacement geometry. 4103 */ 4104 (void) XSetFunction(display,windows->image.highlight_context, 4105 GXcopy); 4106 (void) XDialogWidget(display,windows,"Displace", 4107 "Enter the horizontal and vertical scale:",displacement_geometry); 4108 (void) XSetFunction(display,windows->image.highlight_context, 4109 GXinvert); 4110 if (*displacement_geometry == '\0') 4111 break; 4112 compose=DisplaceCompositeOp; 4113 break; 4114 } 4115 case CompositeHelpCommand: 4116 { 4117 (void) XSetFunction(display,windows->image.highlight_context, 4118 GXcopy); 4119 XTextViewWidget(display,resource_info,windows,MagickFalse, 4120 "Help Viewer - Image Composite",ImageCompositeHelp); 4121 (void) XSetFunction(display,windows->image.highlight_context, 4122 GXinvert); 4123 break; 4124 } 4125 case CompositeDismissCommand: 4126 { 4127 /* 4128 Prematurely exit. 4129 */ 4130 state|=EscapeState; 4131 state|=ExitState; 4132 break; 4133 } 4134 default: 4135 break; 4136 } 4137 continue; 4138 } 4139 switch (event.type) 4140 { 4141 case ButtonPress: 4142 { 4143 if (image->debug != MagickFalse) 4144 (void) LogMagickEvent(X11Event,GetMagickModule(), 4145 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 4146 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4147 if (event.xbutton.button != Button1) 4148 break; 4149 if (event.xbutton.window != windows->image.id) 4150 break; 4151 /* 4152 Change cursor. 4153 */ 4154 composite_info.width=composite_image->columns; 4155 composite_info.height=composite_image->rows; 4156 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4157 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4158 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4159 break; 4160 } 4161 case ButtonRelease: 4162 { 4163 if (image->debug != MagickFalse) 4164 (void) LogMagickEvent(X11Event,GetMagickModule(), 4165 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 4166 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4167 if (event.xbutton.button != Button1) 4168 break; 4169 if (event.xbutton.window != windows->image.id) 4170 break; 4171 if ((composite_info.width != 0) && (composite_info.height != 0)) 4172 { 4173 /* 4174 User has selected the location of the composite image. 4175 */ 4176 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4177 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4178 state|=ExitState; 4179 } 4180 break; 4181 } 4182 case Expose: 4183 break; 4184 case KeyPress: 4185 { 4186 char 4187 command[MaxTextExtent]; 4188 4189 KeySym 4190 key_symbol; 4191 4192 int 4193 length; 4194 4195 if (event.xkey.window != windows->image.id) 4196 break; 4197 /* 4198 Respond to a user key press. 4199 */ 4200 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 4201 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4202 *(command+length)='\0'; 4203 if (image->debug != MagickFalse) 4204 (void) LogMagickEvent(X11Event,GetMagickModule(), 4205 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 4206 switch ((int) key_symbol) 4207 { 4208 case XK_Escape: 4209 case XK_F20: 4210 { 4211 /* 4212 Prematurely exit. 4213 */ 4214 composite_image=DestroyImage(composite_image); 4215 state|=EscapeState; 4216 state|=ExitState; 4217 break; 4218 } 4219 case XK_F1: 4220 case XK_Help: 4221 { 4222 (void) XSetFunction(display,windows->image.highlight_context, 4223 GXcopy); 4224 XTextViewWidget(display,resource_info,windows,MagickFalse, 4225 "Help Viewer - Image Composite",ImageCompositeHelp); 4226 (void) XSetFunction(display,windows->image.highlight_context, 4227 GXinvert); 4228 break; 4229 } 4230 default: 4231 { 4232 (void) XBell(display,0); 4233 break; 4234 } 4235 } 4236 break; 4237 } 4238 case MotionNotify: 4239 { 4240 /* 4241 Map and unmap Info widget as text cursor crosses its boundaries. 4242 */ 4243 x=event.xmotion.x; 4244 y=event.xmotion.y; 4245 if (windows->info.mapped != MagickFalse) 4246 { 4247 if ((x < (int) (windows->info.x+windows->info.width)) && 4248 (y < (int) (windows->info.y+windows->info.height))) 4249 (void) XWithdrawWindow(display,windows->info.id, 4250 windows->info.screen); 4251 } 4252 else 4253 if ((x > (int) (windows->info.x+windows->info.width)) || 4254 (y > (int) (windows->info.y+windows->info.height))) 4255 (void) XMapWindow(display,windows->info.id); 4256 composite_info.x=(ssize_t) windows->image.x+x; 4257 composite_info.y=(ssize_t) windows->image.y+y; 4258 break; 4259 } 4260 default: 4261 { 4262 if (image->debug != MagickFalse) 4263 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 4264 event.type); 4265 break; 4266 } 4267 } 4268 } while ((state & ExitState) == 0); 4269 (void) XSelectInput(display,windows->image.id, 4270 windows->image.attributes.event_mask); 4271 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4272 XSetCursorState(display,windows,MagickFalse); 4273 (void) XFreeCursor(display,cursor); 4274 if ((state & EscapeState) != 0) 4275 return(MagickTrue); 4276 /* 4277 Image compositing is relative to image configuration. 4278 */ 4279 XSetCursorState(display,windows,MagickTrue); 4280 XCheckRefreshWindows(display,windows); 4281 width=(unsigned int) image->columns; 4282 height=(unsigned int) image->rows; 4283 x=0; 4284 y=0; 4285 if (windows->image.crop_geometry != (char *) NULL) 4286 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 4287 scale_factor=(MagickRealType) width/windows->image.ximage->width; 4288 composite_info.x+=x; 4289 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 4290 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 4291 scale_factor=(MagickRealType) height/windows->image.ximage->height; 4292 composite_info.y+=y; 4293 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 4294 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 4295 if ((composite_info.width != composite_image->columns) || 4296 (composite_info.height != composite_image->rows)) 4297 { 4298 Image 4299 *resize_image; 4300 4301 /* 4302 Scale composite image. 4303 */ 4304 resize_image=ResizeImage(composite_image,composite_info.width, 4305 composite_info.height,composite_image->filter,composite_image->blur, 4306 exception); 4307 composite_image=DestroyImage(composite_image); 4308 if (resize_image == (Image *) NULL) 4309 { 4310 XSetCursorState(display,windows,MagickFalse); 4311 return(MagickFalse); 4312 } 4313 composite_image=resize_image; 4314 } 4315 if (compose == DisplaceCompositeOp) 4316 (void) SetImageArtifact(composite_image,"compose:args", 4317 displacement_geometry); 4318 if (blend != 0.0) 4319 { 4320 CacheView 4321 *image_view; 4322 4323 int 4324 y; 4325 4326 Quantum 4327 opacity; 4328 4329 register int 4330 x; 4331 4332 register Quantum 4333 *q; 4334 4335 /* 4336 Create mattes for blending. 4337 */ 4338 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception); 4339 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)- 4340 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100); 4341 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 4342 return(MagickFalse); 4343 image->matte=MagickTrue; 4344 image_view=AcquireCacheView(image); 4345 for (y=0; y < (int) image->rows; y++) 4346 { 4347 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 4348 exception); 4349 if (q == (Quantum *) NULL) 4350 break; 4351 for (x=0; x < (int) image->columns; x++) 4352 { 4353 SetPixelAlpha(image,opacity,q); 4354 q+=GetPixelChannels(image); 4355 } 4356 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 4357 break; 4358 } 4359 image_view=DestroyCacheView(image_view); 4360 } 4361 /* 4362 Composite image with X Image window. 4363 */ 4364 (void) CompositeImage(image,compose,composite_image,composite_info.x, 4365 composite_info.y,exception); 4366 composite_image=DestroyImage(composite_image); 4367 XSetCursorState(display,windows,MagickFalse); 4368 /* 4369 Update image configuration. 4370 */ 4371 XConfigureImageColormap(display,resource_info,windows,image,exception); 4372 (void) XConfigureImage(display,resource_info,windows,image,exception); 4373 return(MagickTrue); 4374} 4375 4376/* 4377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4378% % 4379% % 4380% % 4381+ X C o n f i g u r e I m a g e % 4382% % 4383% % 4384% % 4385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4386% 4387% XConfigureImage() creates a new X image. It also notifies the window 4388% manager of the new image size and configures the transient widows. 4389% 4390% The format of the XConfigureImage method is: 4391% 4392% MagickBooleanType XConfigureImage(Display *display, 4393% XResourceInfo *resource_info,XWindows *windows,Image *image, 4394% ExceptionInfo *exception) 4395% 4396% A description of each parameter follows: 4397% 4398% o display: Specifies a connection to an X server; returned from 4399% XOpenDisplay. 4400% 4401% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4402% 4403% o windows: Specifies a pointer to a XWindows structure. 4404% 4405% o image: the image. 4406% 4407% o exception: return any errors or warnings in this structure. 4408% 4409% o exception: return any errors or warnings in this structure. 4410% 4411*/ 4412static MagickBooleanType XConfigureImage(Display *display, 4413 XResourceInfo *resource_info,XWindows *windows,Image *image, 4414 ExceptionInfo *exception) 4415{ 4416 char 4417 geometry[MaxTextExtent]; 4418 4419 MagickStatusType 4420 status; 4421 4422 size_t 4423 mask, 4424 height, 4425 width; 4426 4427 ssize_t 4428 x, 4429 y; 4430 4431 XSizeHints 4432 *size_hints; 4433 4434 XWindowChanges 4435 window_changes; 4436 4437 /* 4438 Dismiss if window dimensions are zero. 4439 */ 4440 width=(unsigned int) windows->image.window_changes.width; 4441 height=(unsigned int) windows->image.window_changes.height; 4442 if (image->debug != MagickFalse) 4443 (void) LogMagickEvent(X11Event,GetMagickModule(), 4444 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 4445 windows->image.ximage->height,(double) width,(double) height); 4446 if ((width*height) == 0) 4447 return(MagickTrue); 4448 x=0; 4449 y=0; 4450 /* 4451 Resize image to fit Image window dimensions. 4452 */ 4453 XSetCursorState(display,windows,MagickTrue); 4454 (void) XFlush(display); 4455 if (((int) width != windows->image.ximage->width) || 4456 ((int) height != windows->image.ximage->height)) 4457 image->taint=MagickTrue; 4458 windows->magnify.x=(int) 4459 width*windows->magnify.x/windows->image.ximage->width; 4460 windows->magnify.y=(int) 4461 height*windows->magnify.y/windows->image.ximage->height; 4462 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 4463 windows->image.y=(int) 4464 (height*windows->image.y/windows->image.ximage->height); 4465 status=XMakeImage(display,resource_info,&windows->image,image, 4466 (unsigned int) width,(unsigned int) height,exception); 4467 if (status == MagickFalse) 4468 XNoticeWidget(display,windows,"Unable to configure X image:", 4469 windows->image.name); 4470 /* 4471 Notify window manager of the new configuration. 4472 */ 4473 if (resource_info->image_geometry != (char *) NULL) 4474 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!", 4475 resource_info->image_geometry); 4476 else 4477 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 4478 XDisplayWidth(display,windows->image.screen), 4479 XDisplayHeight(display,windows->image.screen)); 4480 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 4481 window_changes.width=(int) width; 4482 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 4483 window_changes.width=XDisplayWidth(display,windows->image.screen); 4484 window_changes.height=(int) height; 4485 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 4486 window_changes.height=XDisplayHeight(display,windows->image.screen); 4487 mask=(size_t) (CWWidth | CWHeight); 4488 if (resource_info->backdrop) 4489 { 4490 mask|=CWX | CWY; 4491 window_changes.x=(int) 4492 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 4493 window_changes.y=(int) 4494 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 4495 } 4496 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 4497 (unsigned int) mask,&window_changes); 4498 (void) XClearWindow(display,windows->image.id); 4499 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 4500 /* 4501 Update Magnify window configuration. 4502 */ 4503 if (windows->magnify.mapped != MagickFalse) 4504 XMakeMagnifyImage(display,windows,exception); 4505 windows->pan.crop_geometry=windows->image.crop_geometry; 4506 XBestIconSize(display,&windows->pan,image); 4507 while (((windows->pan.width << 1) < MaxIconSize) && 4508 ((windows->pan.height << 1) < MaxIconSize)) 4509 { 4510 windows->pan.width<<=1; 4511 windows->pan.height<<=1; 4512 } 4513 if (windows->pan.geometry != (char *) NULL) 4514 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 4515 &windows->pan.width,&windows->pan.height); 4516 window_changes.width=(int) windows->pan.width; 4517 window_changes.height=(int) windows->pan.height; 4518 size_hints=XAllocSizeHints(); 4519 if (size_hints != (XSizeHints *) NULL) 4520 { 4521 /* 4522 Set new size hints. 4523 */ 4524 size_hints->flags=PSize | PMinSize | PMaxSize; 4525 size_hints->width=window_changes.width; 4526 size_hints->height=window_changes.height; 4527 size_hints->min_width=size_hints->width; 4528 size_hints->min_height=size_hints->height; 4529 size_hints->max_width=size_hints->width; 4530 size_hints->max_height=size_hints->height; 4531 (void) XSetNormalHints(display,windows->pan.id,size_hints); 4532 (void) XFree((void *) size_hints); 4533 } 4534 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 4535 (unsigned int) (CWWidth | CWHeight),&window_changes); 4536 /* 4537 Update icon window configuration. 4538 */ 4539 windows->icon.crop_geometry=windows->image.crop_geometry; 4540 XBestIconSize(display,&windows->icon,image); 4541 window_changes.width=(int) windows->icon.width; 4542 window_changes.height=(int) windows->icon.height; 4543 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 4544 (unsigned int) (CWWidth | CWHeight),&window_changes); 4545 XSetCursorState(display,windows,MagickFalse); 4546 return(status != 0 ? MagickTrue : MagickFalse); 4547} 4548 4549/* 4550%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4551% % 4552% % 4553% % 4554+ X C r o p I m a g e % 4555% % 4556% % 4557% % 4558%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4559% 4560% XCropImage() allows the user to select a region of the image and crop, copy, 4561% or cut it. For copy or cut, the image can subsequently be composited onto 4562% the image with XPasteImage. 4563% 4564% The format of the XCropImage method is: 4565% 4566% MagickBooleanType XCropImage(Display *display, 4567% XResourceInfo *resource_info,XWindows *windows,Image *image, 4568% const ClipboardMode mode,ExceptionInfo *exception) 4569% 4570% A description of each parameter follows: 4571% 4572% o display: Specifies a connection to an X server; returned from 4573% XOpenDisplay. 4574% 4575% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4576% 4577% o windows: Specifies a pointer to a XWindows structure. 4578% 4579% o image: the image; returned from ReadImage. 4580% 4581% o mode: This unsigned value specified whether the image should be 4582% cropped, copied, or cut. 4583% 4584% o exception: return any errors or warnings in this structure. 4585% 4586*/ 4587static MagickBooleanType XCropImage(Display *display, 4588 XResourceInfo *resource_info,XWindows *windows,Image *image, 4589 const ClipboardMode mode,ExceptionInfo *exception) 4590{ 4591 static const char 4592 *CropModeMenu[] = 4593 { 4594 "Help", 4595 "Dismiss", 4596 (char *) NULL 4597 }, 4598 *RectifyModeMenu[] = 4599 { 4600 "Crop", 4601 "Help", 4602 "Dismiss", 4603 (char *) NULL 4604 }; 4605 4606 static const ModeType 4607 CropCommands[] = 4608 { 4609 CropHelpCommand, 4610 CropDismissCommand 4611 }, 4612 RectifyCommands[] = 4613 { 4614 RectifyCopyCommand, 4615 RectifyHelpCommand, 4616 RectifyDismissCommand 4617 }; 4618 4619 CacheView 4620 *image_view; 4621 4622 char 4623 command[MaxTextExtent], 4624 text[MaxTextExtent]; 4625 4626 Cursor 4627 cursor; 4628 4629 int 4630 id, 4631 x, 4632 y; 4633 4634 KeySym 4635 key_symbol; 4636 4637 Image 4638 *crop_image; 4639 4640 MagickRealType 4641 scale_factor; 4642 4643 RectangleInfo 4644 crop_info, 4645 highlight_info; 4646 4647 register Quantum 4648 *q; 4649 4650 unsigned int 4651 height, 4652 width; 4653 4654 size_t 4655 state; 4656 4657 XEvent 4658 event; 4659 4660 /* 4661 Map Command widget. 4662 */ 4663 switch (mode) 4664 { 4665 case CopyMode: 4666 { 4667 (void) CloneString(&windows->command.name,"Copy"); 4668 break; 4669 } 4670 case CropMode: 4671 { 4672 (void) CloneString(&windows->command.name,"Crop"); 4673 break; 4674 } 4675 case CutMode: 4676 { 4677 (void) CloneString(&windows->command.name,"Cut"); 4678 break; 4679 } 4680 } 4681 RectifyModeMenu[0]=windows->command.name; 4682 windows->command.data=0; 4683 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 4684 (void) XMapRaised(display,windows->command.id); 4685 XClientMessage(display,windows->image.id,windows->im_protocols, 4686 windows->im_update_widget,CurrentTime); 4687 /* 4688 Track pointer until button 1 is pressed. 4689 */ 4690 XQueryPosition(display,windows->image.id,&x,&y); 4691 (void) XSelectInput(display,windows->image.id, 4692 windows->image.attributes.event_mask | PointerMotionMask); 4693 crop_info.x=(ssize_t) windows->image.x+x; 4694 crop_info.y=(ssize_t) windows->image.y+y; 4695 crop_info.width=0; 4696 crop_info.height=0; 4697 cursor=XCreateFontCursor(display,XC_fleur); 4698 state=DefaultState; 4699 do 4700 { 4701 if (windows->info.mapped != MagickFalse) 4702 { 4703 /* 4704 Display pointer position. 4705 */ 4706 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4707 (long) crop_info.x,(long) crop_info.y); 4708 XInfoWidget(display,windows,text); 4709 } 4710 /* 4711 Wait for next event. 4712 */ 4713 XScreenEvent(display,windows,&event,exception); 4714 if (event.xany.window == windows->command.id) 4715 { 4716 /* 4717 Select a command from the Command widget. 4718 */ 4719 id=XCommandWidget(display,windows,CropModeMenu,&event); 4720 if (id < 0) 4721 continue; 4722 switch (CropCommands[id]) 4723 { 4724 case CropHelpCommand: 4725 { 4726 switch (mode) 4727 { 4728 case CopyMode: 4729 { 4730 XTextViewWidget(display,resource_info,windows,MagickFalse, 4731 "Help Viewer - Image Copy",ImageCopyHelp); 4732 break; 4733 } 4734 case CropMode: 4735 { 4736 XTextViewWidget(display,resource_info,windows,MagickFalse, 4737 "Help Viewer - Image Crop",ImageCropHelp); 4738 break; 4739 } 4740 case CutMode: 4741 { 4742 XTextViewWidget(display,resource_info,windows,MagickFalse, 4743 "Help Viewer - Image Cut",ImageCutHelp); 4744 break; 4745 } 4746 } 4747 break; 4748 } 4749 case CropDismissCommand: 4750 { 4751 /* 4752 Prematurely exit. 4753 */ 4754 state|=EscapeState; 4755 state|=ExitState; 4756 break; 4757 } 4758 default: 4759 break; 4760 } 4761 continue; 4762 } 4763 switch (event.type) 4764 { 4765 case ButtonPress: 4766 { 4767 if (event.xbutton.button != Button1) 4768 break; 4769 if (event.xbutton.window != windows->image.id) 4770 break; 4771 /* 4772 Note first corner of cropping rectangle-- exit loop. 4773 */ 4774 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4775 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4776 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4777 state|=ExitState; 4778 break; 4779 } 4780 case ButtonRelease: 4781 break; 4782 case Expose: 4783 break; 4784 case KeyPress: 4785 { 4786 if (event.xkey.window != windows->image.id) 4787 break; 4788 /* 4789 Respond to a user key press. 4790 */ 4791 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 4792 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4793 switch ((int) key_symbol) 4794 { 4795 case XK_Escape: 4796 case XK_F20: 4797 { 4798 /* 4799 Prematurely exit. 4800 */ 4801 state|=EscapeState; 4802 state|=ExitState; 4803 break; 4804 } 4805 case XK_F1: 4806 case XK_Help: 4807 { 4808 switch (mode) 4809 { 4810 case CopyMode: 4811 { 4812 XTextViewWidget(display,resource_info,windows,MagickFalse, 4813 "Help Viewer - Image Copy",ImageCopyHelp); 4814 break; 4815 } 4816 case CropMode: 4817 { 4818 XTextViewWidget(display,resource_info,windows,MagickFalse, 4819 "Help Viewer - Image Crop",ImageCropHelp); 4820 break; 4821 } 4822 case CutMode: 4823 { 4824 XTextViewWidget(display,resource_info,windows,MagickFalse, 4825 "Help Viewer - Image Cut",ImageCutHelp); 4826 break; 4827 } 4828 } 4829 break; 4830 } 4831 default: 4832 { 4833 (void) XBell(display,0); 4834 break; 4835 } 4836 } 4837 break; 4838 } 4839 case MotionNotify: 4840 { 4841 if (event.xmotion.window != windows->image.id) 4842 break; 4843 /* 4844 Map and unmap Info widget as text cursor crosses its boundaries. 4845 */ 4846 x=event.xmotion.x; 4847 y=event.xmotion.y; 4848 if (windows->info.mapped != MagickFalse) 4849 { 4850 if ((x < (int) (windows->info.x+windows->info.width)) && 4851 (y < (int) (windows->info.y+windows->info.height))) 4852 (void) XWithdrawWindow(display,windows->info.id, 4853 windows->info.screen); 4854 } 4855 else 4856 if ((x > (int) (windows->info.x+windows->info.width)) || 4857 (y > (int) (windows->info.y+windows->info.height))) 4858 (void) XMapWindow(display,windows->info.id); 4859 crop_info.x=(ssize_t) windows->image.x+x; 4860 crop_info.y=(ssize_t) windows->image.y+y; 4861 break; 4862 } 4863 default: 4864 break; 4865 } 4866 } while ((state & ExitState) == 0); 4867 (void) XSelectInput(display,windows->image.id, 4868 windows->image.attributes.event_mask); 4869 if ((state & EscapeState) != 0) 4870 { 4871 /* 4872 User want to exit without cropping. 4873 */ 4874 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4875 (void) XFreeCursor(display,cursor); 4876 return(MagickTrue); 4877 } 4878 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4879 do 4880 { 4881 /* 4882 Size rectangle as pointer moves until the mouse button is released. 4883 */ 4884 x=(int) crop_info.x; 4885 y=(int) crop_info.y; 4886 crop_info.width=0; 4887 crop_info.height=0; 4888 state=DefaultState; 4889 do 4890 { 4891 highlight_info=crop_info; 4892 highlight_info.x=crop_info.x-windows->image.x; 4893 highlight_info.y=crop_info.y-windows->image.y; 4894 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4895 { 4896 /* 4897 Display info and draw cropping rectangle. 4898 */ 4899 if (windows->info.mapped == MagickFalse) 4900 (void) XMapWindow(display,windows->info.id); 4901 (void) FormatLocaleString(text,MaxTextExtent, 4902 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4903 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4904 XInfoWidget(display,windows,text); 4905 XHighlightRectangle(display,windows->image.id, 4906 windows->image.highlight_context,&highlight_info); 4907 } 4908 else 4909 if (windows->info.mapped != MagickFalse) 4910 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4911 /* 4912 Wait for next event. 4913 */ 4914 XScreenEvent(display,windows,&event,exception); 4915 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4916 XHighlightRectangle(display,windows->image.id, 4917 windows->image.highlight_context,&highlight_info); 4918 switch (event.type) 4919 { 4920 case ButtonPress: 4921 { 4922 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4923 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4924 break; 4925 } 4926 case ButtonRelease: 4927 { 4928 /* 4929 User has committed to cropping rectangle. 4930 */ 4931 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4932 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4933 XSetCursorState(display,windows,MagickFalse); 4934 state|=ExitState; 4935 windows->command.data=0; 4936 (void) XCommandWidget(display,windows,RectifyModeMenu, 4937 (XEvent *) NULL); 4938 break; 4939 } 4940 case Expose: 4941 break; 4942 case MotionNotify: 4943 { 4944 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 4945 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 4946 } 4947 default: 4948 break; 4949 } 4950 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 4951 ((state & ExitState) != 0)) 4952 { 4953 /* 4954 Check boundary conditions. 4955 */ 4956 if (crop_info.x < 0) 4957 crop_info.x=0; 4958 else 4959 if (crop_info.x > (ssize_t) windows->image.ximage->width) 4960 crop_info.x=(ssize_t) windows->image.ximage->width; 4961 if ((int) crop_info.x < x) 4962 crop_info.width=(unsigned int) (x-crop_info.x); 4963 else 4964 { 4965 crop_info.width=(unsigned int) (crop_info.x-x); 4966 crop_info.x=(ssize_t) x; 4967 } 4968 if (crop_info.y < 0) 4969 crop_info.y=0; 4970 else 4971 if (crop_info.y > (ssize_t) windows->image.ximage->height) 4972 crop_info.y=(ssize_t) windows->image.ximage->height; 4973 if ((int) crop_info.y < y) 4974 crop_info.height=(unsigned int) (y-crop_info.y); 4975 else 4976 { 4977 crop_info.height=(unsigned int) (crop_info.y-y); 4978 crop_info.y=(ssize_t) y; 4979 } 4980 } 4981 } while ((state & ExitState) == 0); 4982 /* 4983 Wait for user to grab a corner of the rectangle or press return. 4984 */ 4985 state=DefaultState; 4986 (void) XMapWindow(display,windows->info.id); 4987 do 4988 { 4989 if (windows->info.mapped != MagickFalse) 4990 { 4991 /* 4992 Display pointer position. 4993 */ 4994 (void) FormatLocaleString(text,MaxTextExtent, 4995 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4996 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4997 XInfoWidget(display,windows,text); 4998 } 4999 highlight_info=crop_info; 5000 highlight_info.x=crop_info.x-windows->image.x; 5001 highlight_info.y=crop_info.y-windows->image.y; 5002 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 5003 { 5004 state|=EscapeState; 5005 state|=ExitState; 5006 break; 5007 } 5008 XHighlightRectangle(display,windows->image.id, 5009 windows->image.highlight_context,&highlight_info); 5010 XScreenEvent(display,windows,&event,exception); 5011 if (event.xany.window == windows->command.id) 5012 { 5013 /* 5014 Select a command from the Command widget. 5015 */ 5016 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5017 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 5018 (void) XSetFunction(display,windows->image.highlight_context, 5019 GXinvert); 5020 XHighlightRectangle(display,windows->image.id, 5021 windows->image.highlight_context,&highlight_info); 5022 if (id >= 0) 5023 switch (RectifyCommands[id]) 5024 { 5025 case RectifyCopyCommand: 5026 { 5027 state|=ExitState; 5028 break; 5029 } 5030 case RectifyHelpCommand: 5031 { 5032 (void) XSetFunction(display,windows->image.highlight_context, 5033 GXcopy); 5034 switch (mode) 5035 { 5036 case CopyMode: 5037 { 5038 XTextViewWidget(display,resource_info,windows,MagickFalse, 5039 "Help Viewer - Image Copy",ImageCopyHelp); 5040 break; 5041 } 5042 case CropMode: 5043 { 5044 XTextViewWidget(display,resource_info,windows,MagickFalse, 5045 "Help Viewer - Image Crop",ImageCropHelp); 5046 break; 5047 } 5048 case CutMode: 5049 { 5050 XTextViewWidget(display,resource_info,windows,MagickFalse, 5051 "Help Viewer - Image Cut",ImageCutHelp); 5052 break; 5053 } 5054 } 5055 (void) XSetFunction(display,windows->image.highlight_context, 5056 GXinvert); 5057 break; 5058 } 5059 case RectifyDismissCommand: 5060 { 5061 /* 5062 Prematurely exit. 5063 */ 5064 state|=EscapeState; 5065 state|=ExitState; 5066 break; 5067 } 5068 default: 5069 break; 5070 } 5071 continue; 5072 } 5073 XHighlightRectangle(display,windows->image.id, 5074 windows->image.highlight_context,&highlight_info); 5075 switch (event.type) 5076 { 5077 case ButtonPress: 5078 { 5079 if (event.xbutton.button != Button1) 5080 break; 5081 if (event.xbutton.window != windows->image.id) 5082 break; 5083 x=windows->image.x+event.xbutton.x; 5084 y=windows->image.y+event.xbutton.y; 5085 if ((x < (int) (crop_info.x+RoiDelta)) && 5086 (x > (int) (crop_info.x-RoiDelta)) && 5087 (y < (int) (crop_info.y+RoiDelta)) && 5088 (y > (int) (crop_info.y-RoiDelta))) 5089 { 5090 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5091 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5092 state|=UpdateConfigurationState; 5093 break; 5094 } 5095 if ((x < (int) (crop_info.x+RoiDelta)) && 5096 (x > (int) (crop_info.x-RoiDelta)) && 5097 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5098 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5099 { 5100 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5101 state|=UpdateConfigurationState; 5102 break; 5103 } 5104 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5105 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5106 (y < (int) (crop_info.y+RoiDelta)) && 5107 (y > (int) (crop_info.y-RoiDelta))) 5108 { 5109 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5110 state|=UpdateConfigurationState; 5111 break; 5112 } 5113 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5114 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5115 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5116 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5117 { 5118 state|=UpdateConfigurationState; 5119 break; 5120 } 5121 } 5122 case ButtonRelease: 5123 { 5124 if (event.xbutton.window == windows->pan.id) 5125 if ((highlight_info.x != crop_info.x-windows->image.x) || 5126 (highlight_info.y != crop_info.y-windows->image.y)) 5127 XHighlightRectangle(display,windows->image.id, 5128 windows->image.highlight_context,&highlight_info); 5129 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5130 event.xbutton.time); 5131 break; 5132 } 5133 case Expose: 5134 { 5135 if (event.xexpose.window == windows->image.id) 5136 if (event.xexpose.count == 0) 5137 { 5138 event.xexpose.x=(int) highlight_info.x; 5139 event.xexpose.y=(int) highlight_info.y; 5140 event.xexpose.width=(int) highlight_info.width; 5141 event.xexpose.height=(int) highlight_info.height; 5142 XRefreshWindow(display,&windows->image,&event); 5143 } 5144 if (event.xexpose.window == windows->info.id) 5145 if (event.xexpose.count == 0) 5146 XInfoWidget(display,windows,text); 5147 break; 5148 } 5149 case KeyPress: 5150 { 5151 if (event.xkey.window != windows->image.id) 5152 break; 5153 /* 5154 Respond to a user key press. 5155 */ 5156 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5157 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5158 switch ((int) key_symbol) 5159 { 5160 case XK_Escape: 5161 case XK_F20: 5162 state|=EscapeState; 5163 case XK_Return: 5164 { 5165 state|=ExitState; 5166 break; 5167 } 5168 case XK_Home: 5169 case XK_KP_Home: 5170 { 5171 crop_info.x=(ssize_t) (windows->image.width/2L- 5172 crop_info.width/2L); 5173 crop_info.y=(ssize_t) (windows->image.height/2L- 5174 crop_info.height/2L); 5175 break; 5176 } 5177 case XK_Left: 5178 case XK_KP_Left: 5179 { 5180 crop_info.x--; 5181 break; 5182 } 5183 case XK_Up: 5184 case XK_KP_Up: 5185 case XK_Next: 5186 { 5187 crop_info.y--; 5188 break; 5189 } 5190 case XK_Right: 5191 case XK_KP_Right: 5192 { 5193 crop_info.x++; 5194 break; 5195 } 5196 case XK_Prior: 5197 case XK_Down: 5198 case XK_KP_Down: 5199 { 5200 crop_info.y++; 5201 break; 5202 } 5203 case XK_F1: 5204 case XK_Help: 5205 { 5206 (void) XSetFunction(display,windows->image.highlight_context, 5207 GXcopy); 5208 switch (mode) 5209 { 5210 case CopyMode: 5211 { 5212 XTextViewWidget(display,resource_info,windows,MagickFalse, 5213 "Help Viewer - Image Copy",ImageCopyHelp); 5214 break; 5215 } 5216 case CropMode: 5217 { 5218 XTextViewWidget(display,resource_info,windows,MagickFalse, 5219 "Help Viewer - Image Cropg",ImageCropHelp); 5220 break; 5221 } 5222 case CutMode: 5223 { 5224 XTextViewWidget(display,resource_info,windows,MagickFalse, 5225 "Help Viewer - Image Cutg",ImageCutHelp); 5226 break; 5227 } 5228 } 5229 (void) XSetFunction(display,windows->image.highlight_context, 5230 GXinvert); 5231 break; 5232 } 5233 default: 5234 { 5235 (void) XBell(display,0); 5236 break; 5237 } 5238 } 5239 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5240 event.xkey.time); 5241 break; 5242 } 5243 case KeyRelease: 5244 break; 5245 case MotionNotify: 5246 { 5247 if (event.xmotion.window != windows->image.id) 5248 break; 5249 /* 5250 Map and unmap Info widget as text cursor crosses its boundaries. 5251 */ 5252 x=event.xmotion.x; 5253 y=event.xmotion.y; 5254 if (windows->info.mapped != MagickFalse) 5255 { 5256 if ((x < (int) (windows->info.x+windows->info.width)) && 5257 (y < (int) (windows->info.y+windows->info.height))) 5258 (void) XWithdrawWindow(display,windows->info.id, 5259 windows->info.screen); 5260 } 5261 else 5262 if ((x > (int) (windows->info.x+windows->info.width)) || 5263 (y > (int) (windows->info.y+windows->info.height))) 5264 (void) XMapWindow(display,windows->info.id); 5265 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 5266 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 5267 break; 5268 } 5269 case SelectionRequest: 5270 { 5271 XSelectionEvent 5272 notify; 5273 5274 XSelectionRequestEvent 5275 *request; 5276 5277 /* 5278 Set primary selection. 5279 */ 5280 (void) FormatLocaleString(text,MaxTextExtent, 5281 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 5282 crop_info.height,(double) crop_info.x,(double) crop_info.y); 5283 request=(&(event.xselectionrequest)); 5284 (void) XChangeProperty(request->display,request->requestor, 5285 request->property,request->target,8,PropModeReplace, 5286 (unsigned char *) text,(int) strlen(text)); 5287 notify.type=SelectionNotify; 5288 notify.display=request->display; 5289 notify.requestor=request->requestor; 5290 notify.selection=request->selection; 5291 notify.target=request->target; 5292 notify.time=request->time; 5293 if (request->property == None) 5294 notify.property=request->target; 5295 else 5296 notify.property=request->property; 5297 (void) XSendEvent(request->display,request->requestor,False,0, 5298 (XEvent *) ¬ify); 5299 } 5300 default: 5301 break; 5302 } 5303 if ((state & UpdateConfigurationState) != 0) 5304 { 5305 (void) XPutBackEvent(display,&event); 5306 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5307 break; 5308 } 5309 } while ((state & ExitState) == 0); 5310 } while ((state & ExitState) == 0); 5311 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5312 XSetCursorState(display,windows,MagickFalse); 5313 if ((state & EscapeState) != 0) 5314 return(MagickTrue); 5315 if (mode == CropMode) 5316 if (((int) crop_info.width != windows->image.ximage->width) || 5317 ((int) crop_info.height != windows->image.ximage->height)) 5318 { 5319 /* 5320 Reconfigure Image window as defined by cropping rectangle. 5321 */ 5322 XSetCropGeometry(display,windows,&crop_info,image); 5323 windows->image.window_changes.width=(int) crop_info.width; 5324 windows->image.window_changes.height=(int) crop_info.height; 5325 (void) XConfigureImage(display,resource_info,windows,image,exception); 5326 return(MagickTrue); 5327 } 5328 /* 5329 Copy image before applying image transforms. 5330 */ 5331 XSetCursorState(display,windows,MagickTrue); 5332 XCheckRefreshWindows(display,windows); 5333 width=(unsigned int) image->columns; 5334 height=(unsigned int) image->rows; 5335 x=0; 5336 y=0; 5337 if (windows->image.crop_geometry != (char *) NULL) 5338 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 5339 scale_factor=(MagickRealType) width/windows->image.ximage->width; 5340 crop_info.x+=x; 5341 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 5342 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 5343 scale_factor=(MagickRealType) height/windows->image.ximage->height; 5344 crop_info.y+=y; 5345 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 5346 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5); 5347 crop_image=CropImage(image,&crop_info,exception); 5348 XSetCursorState(display,windows,MagickFalse); 5349 if (crop_image == (Image *) NULL) 5350 return(MagickFalse); 5351 if (resource_info->copy_image != (Image *) NULL) 5352 resource_info->copy_image=DestroyImage(resource_info->copy_image); 5353 resource_info->copy_image=crop_image; 5354 if (mode == CopyMode) 5355 { 5356 (void) XConfigureImage(display,resource_info,windows,image,exception); 5357 return(MagickTrue); 5358 } 5359 /* 5360 Cut image. 5361 */ 5362 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 5363 return(MagickFalse); 5364 image->matte=MagickTrue; 5365 image_view=AcquireCacheView(image); 5366 for (y=0; y < (int) crop_info.height; y++) 5367 { 5368 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y, 5369 crop_info.width,1,exception); 5370 if (q == (Quantum *) NULL) 5371 break; 5372 for (x=0; x < (int) crop_info.width; x++) 5373 { 5374 SetPixelAlpha(image,TransparentAlpha,q); 5375 q+=GetPixelChannels(image); 5376 } 5377 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 5378 break; 5379 } 5380 image_view=DestroyCacheView(image_view); 5381 /* 5382 Update image configuration. 5383 */ 5384 XConfigureImageColormap(display,resource_info,windows,image,exception); 5385 (void) XConfigureImage(display,resource_info,windows,image,exception); 5386 return(MagickTrue); 5387} 5388 5389/* 5390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5391% % 5392% % 5393% % 5394+ X D r a w I m a g e % 5395% % 5396% % 5397% % 5398%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5399% 5400% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on 5401% the image. 5402% 5403% The format of the XDrawEditImage method is: 5404% 5405% MagickBooleanType XDrawEditImage(Display *display, 5406% XResourceInfo *resource_info,XWindows *windows,Image **image, 5407% ExceptionInfo *exception) 5408% 5409% A description of each parameter follows: 5410% 5411% o display: Specifies a connection to an X server; returned from 5412% XOpenDisplay. 5413% 5414% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 5415% 5416% o windows: Specifies a pointer to a XWindows structure. 5417% 5418% o image: the image. 5419% 5420% o exception: return any errors or warnings in this structure. 5421% 5422*/ 5423static MagickBooleanType XDrawEditImage(Display *display, 5424 XResourceInfo *resource_info,XWindows *windows,Image **image, 5425 ExceptionInfo *exception) 5426{ 5427 static const char 5428 *DrawMenu[] = 5429 { 5430 "Element", 5431 "Color", 5432 "Stipple", 5433 "Width", 5434 "Undo", 5435 "Help", 5436 "Dismiss", 5437 (char *) NULL 5438 }; 5439 5440 static ElementType 5441 element = PointElement; 5442 5443 static const ModeType 5444 DrawCommands[] = 5445 { 5446 DrawElementCommand, 5447 DrawColorCommand, 5448 DrawStippleCommand, 5449 DrawWidthCommand, 5450 DrawUndoCommand, 5451 DrawHelpCommand, 5452 DrawDismissCommand 5453 }; 5454 5455 static Pixmap 5456 stipple = (Pixmap) NULL; 5457 5458 static unsigned int 5459 pen_id = 0, 5460 line_width = 1; 5461 5462 char 5463 command[MaxTextExtent], 5464 text[MaxTextExtent]; 5465 5466 Cursor 5467 cursor; 5468 5469 int 5470 entry, 5471 id, 5472 number_coordinates, 5473 x, 5474 y; 5475 5476 MagickRealType 5477 degrees; 5478 5479 MagickStatusType 5480 status; 5481 5482 RectangleInfo 5483 rectangle_info; 5484 5485 register int 5486 i; 5487 5488 unsigned int 5489 distance, 5490 height, 5491 max_coordinates, 5492 width; 5493 5494 size_t 5495 state; 5496 5497 Window 5498 root_window; 5499 5500 XDrawInfo 5501 draw_info; 5502 5503 XEvent 5504 event; 5505 5506 XPoint 5507 *coordinate_info; 5508 5509 XSegment 5510 line_info; 5511 5512 /* 5513 Allocate polygon info. 5514 */ 5515 max_coordinates=2048; 5516 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates, 5517 sizeof(*coordinate_info)); 5518 if (coordinate_info == (XPoint *) NULL) 5519 { 5520 (void) ThrowMagickException(exception,GetMagickModule(), 5521 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 5522 return(MagickFalse); 5523 } 5524 /* 5525 Map Command widget. 5526 */ 5527 (void) CloneString(&windows->command.name,"Draw"); 5528 windows->command.data=4; 5529 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL); 5530 (void) XMapRaised(display,windows->command.id); 5531 XClientMessage(display,windows->image.id,windows->im_protocols, 5532 windows->im_update_widget,CurrentTime); 5533 /* 5534 Wait for first button press. 5535 */ 5536 root_window=XRootWindow(display,XDefaultScreen(display)); 5537 draw_info.stencil=OpaqueStencil; 5538 status=MagickTrue; 5539 cursor=XCreateFontCursor(display,XC_tcross); 5540 for ( ; ; ) 5541 { 5542 XQueryPosition(display,windows->image.id,&x,&y); 5543 (void) XSelectInput(display,windows->image.id, 5544 windows->image.attributes.event_mask | PointerMotionMask); 5545 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5546 state=DefaultState; 5547 do 5548 { 5549 if (windows->info.mapped != MagickFalse) 5550 { 5551 /* 5552 Display pointer position. 5553 */ 5554 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 5555 x+windows->image.x,y+windows->image.y); 5556 XInfoWidget(display,windows,text); 5557 } 5558 /* 5559 Wait for next event. 5560 */ 5561 XScreenEvent(display,windows,&event,exception); 5562 if (event.xany.window == windows->command.id) 5563 { 5564 /* 5565 Select a command from the Command widget. 5566 */ 5567 id=XCommandWidget(display,windows,DrawMenu,&event); 5568 if (id < 0) 5569 continue; 5570 switch (DrawCommands[id]) 5571 { 5572 case DrawElementCommand: 5573 { 5574 static const char 5575 *Elements[] = 5576 { 5577 "point", 5578 "line", 5579 "rectangle", 5580 "fill rectangle", 5581 "circle", 5582 "fill circle", 5583 "ellipse", 5584 "fill ellipse", 5585 "polygon", 5586 "fill polygon", 5587 (char *) NULL, 5588 }; 5589 5590 /* 5591 Select a command from the pop-up menu. 5592 */ 5593 element=(ElementType) (XMenuWidget(display,windows, 5594 DrawMenu[id],Elements,command)+1); 5595 break; 5596 } 5597 case DrawColorCommand: 5598 { 5599 const char 5600 *ColorMenu[MaxNumberPens+1]; 5601 5602 int 5603 pen_number; 5604 5605 MagickBooleanType 5606 transparent; 5607 5608 XColor 5609 color; 5610 5611 /* 5612 Initialize menu selections. 5613 */ 5614 for (i=0; i < (int) (MaxNumberPens-2); i++) 5615 ColorMenu[i]=resource_info->pen_colors[i]; 5616 ColorMenu[MaxNumberPens-2]="transparent"; 5617 ColorMenu[MaxNumberPens-1]="Browser..."; 5618 ColorMenu[MaxNumberPens]=(char *) NULL; 5619 /* 5620 Select a pen color from the pop-up menu. 5621 */ 5622 pen_number=XMenuWidget(display,windows,DrawMenu[id], 5623 (const char **) ColorMenu,command); 5624 if (pen_number < 0) 5625 break; 5626 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue : 5627 MagickFalse; 5628 if (transparent != MagickFalse) 5629 { 5630 draw_info.stencil=TransparentStencil; 5631 break; 5632 } 5633 if (pen_number == (MaxNumberPens-1)) 5634 { 5635 static char 5636 color_name[MaxTextExtent] = "gray"; 5637 5638 /* 5639 Select a pen color from a dialog. 5640 */ 5641 resource_info->pen_colors[pen_number]=color_name; 5642 XColorBrowserWidget(display,windows,"Select",color_name); 5643 if (*color_name == '\0') 5644 break; 5645 } 5646 /* 5647 Set pen color. 5648 */ 5649 (void) XParseColor(display,windows->map_info->colormap, 5650 resource_info->pen_colors[pen_number],&color); 5651 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 5652 (unsigned int) MaxColors,&color); 5653 windows->pixel_info->pen_colors[pen_number]=color; 5654 pen_id=(unsigned int) pen_number; 5655 draw_info.stencil=OpaqueStencil; 5656 break; 5657 } 5658 case DrawStippleCommand: 5659 { 5660 Image 5661 *stipple_image; 5662 5663 ImageInfo 5664 *image_info; 5665 5666 int 5667 status; 5668 5669 static char 5670 filename[MaxTextExtent] = "\0"; 5671 5672 static const char 5673 *StipplesMenu[] = 5674 { 5675 "Brick", 5676 "Diagonal", 5677 "Scales", 5678 "Vertical", 5679 "Wavy", 5680 "Translucent", 5681 "Opaque", 5682 (char *) NULL, 5683 (char *) NULL, 5684 }; 5685 5686 /* 5687 Select a command from the pop-up menu. 5688 */ 5689 StipplesMenu[7]="Open..."; 5690 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu, 5691 command); 5692 if (entry < 0) 5693 break; 5694 if (stipple != (Pixmap) NULL) 5695 (void) XFreePixmap(display,stipple); 5696 stipple=(Pixmap) NULL; 5697 if (entry != 7) 5698 { 5699 switch (entry) 5700 { 5701 case 0: 5702 { 5703 stipple=XCreateBitmapFromData(display,root_window, 5704 (char *) BricksBitmap,BricksWidth,BricksHeight); 5705 break; 5706 } 5707 case 1: 5708 { 5709 stipple=XCreateBitmapFromData(display,root_window, 5710 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight); 5711 break; 5712 } 5713 case 2: 5714 { 5715 stipple=XCreateBitmapFromData(display,root_window, 5716 (char *) ScalesBitmap,ScalesWidth,ScalesHeight); 5717 break; 5718 } 5719 case 3: 5720 { 5721 stipple=XCreateBitmapFromData(display,root_window, 5722 (char *) VerticalBitmap,VerticalWidth,VerticalHeight); 5723 break; 5724 } 5725 case 4: 5726 { 5727 stipple=XCreateBitmapFromData(display,root_window, 5728 (char *) WavyBitmap,WavyWidth,WavyHeight); 5729 break; 5730 } 5731 case 5: 5732 { 5733 stipple=XCreateBitmapFromData(display,root_window, 5734 (char *) HighlightBitmap,HighlightWidth, 5735 HighlightHeight); 5736 break; 5737 } 5738 case 6: 5739 default: 5740 { 5741 stipple=XCreateBitmapFromData(display,root_window, 5742 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight); 5743 break; 5744 } 5745 } 5746 break; 5747 } 5748 XFileBrowserWidget(display,windows,"Stipple",filename); 5749 if (*filename == '\0') 5750 break; 5751 /* 5752 Read image. 5753 */ 5754 XSetCursorState(display,windows,MagickTrue); 5755 XCheckRefreshWindows(display,windows); 5756 image_info=AcquireImageInfo(); 5757 (void) CopyMagickString(image_info->filename,filename, 5758 MaxTextExtent); 5759 stipple_image=ReadImage(image_info,exception); 5760 CatchException(exception); 5761 XSetCursorState(display,windows,MagickFalse); 5762 if (stipple_image == (Image *) NULL) 5763 break; 5764 (void) AcquireUniqueFileResource(filename); 5765 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent, 5766 "xbm:%s",filename); 5767 (void) WriteImage(image_info,stipple_image,exception); 5768 stipple_image=DestroyImage(stipple_image); 5769 image_info=DestroyImageInfo(image_info); 5770 status=XReadBitmapFile(display,root_window,filename,&width, 5771 &height,&stipple,&x,&y); 5772 (void) RelinquishUniqueFileResource(filename); 5773 if ((status != BitmapSuccess) != 0) 5774 XNoticeWidget(display,windows,"Unable to read X bitmap image:", 5775 filename); 5776 break; 5777 } 5778 case DrawWidthCommand: 5779 { 5780 static char 5781 width[MaxTextExtent] = "0"; 5782 5783 static const char 5784 *WidthsMenu[] = 5785 { 5786 "1", 5787 "2", 5788 "4", 5789 "8", 5790 "16", 5791 "Dialog...", 5792 (char *) NULL, 5793 }; 5794 5795 /* 5796 Select a command from the pop-up menu. 5797 */ 5798 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu, 5799 command); 5800 if (entry < 0) 5801 break; 5802 if (entry != 5) 5803 { 5804 line_width=(unsigned int) StringToUnsignedLong( 5805 WidthsMenu[entry]); 5806 break; 5807 } 5808 (void) XDialogWidget(display,windows,"Ok","Enter line width:", 5809 width); 5810 if (*width == '\0') 5811 break; 5812 line_width=(unsigned int) StringToUnsignedLong(width); 5813 break; 5814 } 5815 case DrawUndoCommand: 5816 { 5817 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 5818 image,exception); 5819 break; 5820 } 5821 case DrawHelpCommand: 5822 { 5823 XTextViewWidget(display,resource_info,windows,MagickFalse, 5824 "Help Viewer - Image Rotation",ImageDrawHelp); 5825 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5826 break; 5827 } 5828 case DrawDismissCommand: 5829 { 5830 /* 5831 Prematurely exit. 5832 */ 5833 state|=EscapeState; 5834 state|=ExitState; 5835 break; 5836 } 5837 default: 5838 break; 5839 } 5840 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5841 continue; 5842 } 5843 switch (event.type) 5844 { 5845 case ButtonPress: 5846 { 5847 if (event.xbutton.button != Button1) 5848 break; 5849 if (event.xbutton.window != windows->image.id) 5850 break; 5851 /* 5852 exit loop. 5853 */ 5854 x=event.xbutton.x; 5855 y=event.xbutton.y; 5856 state|=ExitState; 5857 break; 5858 } 5859 case ButtonRelease: 5860 break; 5861 case Expose: 5862 break; 5863 case KeyPress: 5864 { 5865 KeySym 5866 key_symbol; 5867 5868 if (event.xkey.window != windows->image.id) 5869 break; 5870 /* 5871 Respond to a user key press. 5872 */ 5873 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5874 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5875 switch ((int) key_symbol) 5876 { 5877 case XK_Escape: 5878 case XK_F20: 5879 { 5880 /* 5881 Prematurely exit. 5882 */ 5883 state|=EscapeState; 5884 state|=ExitState; 5885 break; 5886 } 5887 case XK_F1: 5888 case XK_Help: 5889 { 5890 XTextViewWidget(display,resource_info,windows,MagickFalse, 5891 "Help Viewer - Image Rotation",ImageDrawHelp); 5892 break; 5893 } 5894 default: 5895 { 5896 (void) XBell(display,0); 5897 break; 5898 } 5899 } 5900 break; 5901 } 5902 case MotionNotify: 5903 { 5904 /* 5905 Map and unmap Info widget as text cursor crosses its boundaries. 5906 */ 5907 x=event.xmotion.x; 5908 y=event.xmotion.y; 5909 if (windows->info.mapped != MagickFalse) 5910 { 5911 if ((x < (int) (windows->info.x+windows->info.width)) && 5912 (y < (int) (windows->info.y+windows->info.height))) 5913 (void) XWithdrawWindow(display,windows->info.id, 5914 windows->info.screen); 5915 } 5916 else 5917 if ((x > (int) (windows->info.x+windows->info.width)) || 5918 (y > (int) (windows->info.y+windows->info.height))) 5919 (void) XMapWindow(display,windows->info.id); 5920 break; 5921 } 5922 } 5923 } while ((state & ExitState) == 0); 5924 (void) XSelectInput(display,windows->image.id, 5925 windows->image.attributes.event_mask); 5926 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 5927 if ((state & EscapeState) != 0) 5928 break; 5929 /* 5930 Draw element as pointer moves until the button is released. 5931 */ 5932 distance=0; 5933 degrees=0.0; 5934 line_info.x1=x; 5935 line_info.y1=y; 5936 line_info.x2=x; 5937 line_info.y2=y; 5938 rectangle_info.x=(ssize_t) x; 5939 rectangle_info.y=(ssize_t) y; 5940 rectangle_info.width=0; 5941 rectangle_info.height=0; 5942 number_coordinates=1; 5943 coordinate_info->x=x; 5944 coordinate_info->y=y; 5945 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 5946 state=DefaultState; 5947 do 5948 { 5949 switch (element) 5950 { 5951 case PointElement: 5952 default: 5953 { 5954 if (number_coordinates > 1) 5955 { 5956 (void) XDrawLines(display,windows->image.id, 5957 windows->image.highlight_context,coordinate_info, 5958 number_coordinates,CoordModeOrigin); 5959 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d", 5960 coordinate_info[number_coordinates-1].x, 5961 coordinate_info[number_coordinates-1].y); 5962 XInfoWidget(display,windows,text); 5963 } 5964 break; 5965 } 5966 case LineElement: 5967 { 5968 if (distance > 9) 5969 { 5970 /* 5971 Display angle of the line. 5972 */ 5973 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 5974 line_info.y1),(double) (line_info.x2-line_info.x1))); 5975 (void) FormatLocaleString(text,MaxTextExtent," %g", 5976 (double) degrees); 5977 XInfoWidget(display,windows,text); 5978 XHighlightLine(display,windows->image.id, 5979 windows->image.highlight_context,&line_info); 5980 } 5981 else 5982 if (windows->info.mapped != MagickFalse) 5983 (void) XWithdrawWindow(display,windows->info.id, 5984 windows->info.screen); 5985 break; 5986 } 5987 case RectangleElement: 5988 case FillRectangleElement: 5989 { 5990 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5991 { 5992 /* 5993 Display info and draw drawing rectangle. 5994 */ 5995 (void) FormatLocaleString(text,MaxTextExtent, 5996 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5997 (double) rectangle_info.height,(double) rectangle_info.x, 5998 (double) rectangle_info.y); 5999 XInfoWidget(display,windows,text); 6000 XHighlightRectangle(display,windows->image.id, 6001 windows->image.highlight_context,&rectangle_info); 6002 } 6003 else 6004 if (windows->info.mapped != MagickFalse) 6005 (void) XWithdrawWindow(display,windows->info.id, 6006 windows->info.screen); 6007 break; 6008 } 6009 case CircleElement: 6010 case FillCircleElement: 6011 case EllipseElement: 6012 case FillEllipseElement: 6013 { 6014 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6015 { 6016 /* 6017 Display info and draw drawing rectangle. 6018 */ 6019 (void) FormatLocaleString(text,MaxTextExtent, 6020 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 6021 (double) rectangle_info.height,(double) rectangle_info.x, 6022 (double) rectangle_info.y); 6023 XInfoWidget(display,windows,text); 6024 XHighlightEllipse(display,windows->image.id, 6025 windows->image.highlight_context,&rectangle_info); 6026 } 6027 else 6028 if (windows->info.mapped != MagickFalse) 6029 (void) XWithdrawWindow(display,windows->info.id, 6030 windows->info.screen); 6031 break; 6032 } 6033 case PolygonElement: 6034 case FillPolygonElement: 6035 { 6036 if (number_coordinates > 1) 6037 (void) XDrawLines(display,windows->image.id, 6038 windows->image.highlight_context,coordinate_info, 6039 number_coordinates,CoordModeOrigin); 6040 if (distance > 9) 6041 { 6042 /* 6043 Display angle of the line. 6044 */ 6045 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 6046 line_info.y1),(double) (line_info.x2-line_info.x1))); 6047 (void) FormatLocaleString(text,MaxTextExtent," %g", 6048 (double) degrees); 6049 XInfoWidget(display,windows,text); 6050 XHighlightLine(display,windows->image.id, 6051 windows->image.highlight_context,&line_info); 6052 } 6053 else 6054 if (windows->info.mapped != MagickFalse) 6055 (void) XWithdrawWindow(display,windows->info.id, 6056 windows->info.screen); 6057 break; 6058 } 6059 } 6060 /* 6061 Wait for next event. 6062 */ 6063 XScreenEvent(display,windows,&event,exception); 6064 switch (element) 6065 { 6066 case PointElement: 6067 default: 6068 { 6069 if (number_coordinates > 1) 6070 (void) XDrawLines(display,windows->image.id, 6071 windows->image.highlight_context,coordinate_info, 6072 number_coordinates,CoordModeOrigin); 6073 break; 6074 } 6075 case LineElement: 6076 { 6077 if (distance > 9) 6078 XHighlightLine(display,windows->image.id, 6079 windows->image.highlight_context,&line_info); 6080 break; 6081 } 6082 case RectangleElement: 6083 case FillRectangleElement: 6084 { 6085 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6086 XHighlightRectangle(display,windows->image.id, 6087 windows->image.highlight_context,&rectangle_info); 6088 break; 6089 } 6090 case CircleElement: 6091 case FillCircleElement: 6092 case EllipseElement: 6093 case FillEllipseElement: 6094 { 6095 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6096 XHighlightEllipse(display,windows->image.id, 6097 windows->image.highlight_context,&rectangle_info); 6098 break; 6099 } 6100 case PolygonElement: 6101 case FillPolygonElement: 6102 { 6103 if (number_coordinates > 1) 6104 (void) XDrawLines(display,windows->image.id, 6105 windows->image.highlight_context,coordinate_info, 6106 number_coordinates,CoordModeOrigin); 6107 if (distance > 9) 6108 XHighlightLine(display,windows->image.id, 6109 windows->image.highlight_context,&line_info); 6110 break; 6111 } 6112 } 6113 switch (event.type) 6114 { 6115 case ButtonPress: 6116 break; 6117 case ButtonRelease: 6118 { 6119 /* 6120 User has committed to element. 6121 */ 6122 line_info.x2=event.xbutton.x; 6123 line_info.y2=event.xbutton.y; 6124 rectangle_info.x=(ssize_t) event.xbutton.x; 6125 rectangle_info.y=(ssize_t) event.xbutton.y; 6126 coordinate_info[number_coordinates].x=event.xbutton.x; 6127 coordinate_info[number_coordinates].y=event.xbutton.y; 6128 if (((element != PolygonElement) && 6129 (element != FillPolygonElement)) || (distance <= 9)) 6130 { 6131 state|=ExitState; 6132 break; 6133 } 6134 number_coordinates++; 6135 if (number_coordinates < (int) max_coordinates) 6136 { 6137 line_info.x1=event.xbutton.x; 6138 line_info.y1=event.xbutton.y; 6139 break; 6140 } 6141 max_coordinates<<=1; 6142 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6143 max_coordinates,sizeof(*coordinate_info)); 6144 if (coordinate_info == (XPoint *) NULL) 6145 (void) ThrowMagickException(exception,GetMagickModule(), 6146 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6147 break; 6148 } 6149 case Expose: 6150 break; 6151 case MotionNotify: 6152 { 6153 if (event.xmotion.window != windows->image.id) 6154 break; 6155 if (element != PointElement) 6156 { 6157 line_info.x2=event.xmotion.x; 6158 line_info.y2=event.xmotion.y; 6159 rectangle_info.x=(ssize_t) event.xmotion.x; 6160 rectangle_info.y=(ssize_t) event.xmotion.y; 6161 break; 6162 } 6163 coordinate_info[number_coordinates].x=event.xbutton.x; 6164 coordinate_info[number_coordinates].y=event.xbutton.y; 6165 number_coordinates++; 6166 if (number_coordinates < (int) max_coordinates) 6167 break; 6168 max_coordinates<<=1; 6169 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6170 max_coordinates,sizeof(*coordinate_info)); 6171 if (coordinate_info == (XPoint *) NULL) 6172 (void) ThrowMagickException(exception,GetMagickModule(), 6173 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6174 break; 6175 } 6176 default: 6177 break; 6178 } 6179 /* 6180 Check boundary conditions. 6181 */ 6182 if (line_info.x2 < 0) 6183 line_info.x2=0; 6184 else 6185 if (line_info.x2 > (int) windows->image.width) 6186 line_info.x2=(short) windows->image.width; 6187 if (line_info.y2 < 0) 6188 line_info.y2=0; 6189 else 6190 if (line_info.y2 > (int) windows->image.height) 6191 line_info.y2=(short) windows->image.height; 6192 distance=(unsigned int) 6193 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+ 6194 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1))); 6195 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) || 6196 ((state & ExitState) != 0)) 6197 { 6198 if (rectangle_info.x < 0) 6199 rectangle_info.x=0; 6200 else 6201 if (rectangle_info.x > (ssize_t) windows->image.width) 6202 rectangle_info.x=(ssize_t) windows->image.width; 6203 if ((int) rectangle_info.x < x) 6204 rectangle_info.width=(unsigned int) (x-rectangle_info.x); 6205 else 6206 { 6207 rectangle_info.width=(unsigned int) (rectangle_info.x-x); 6208 rectangle_info.x=(ssize_t) x; 6209 } 6210 if (rectangle_info.y < 0) 6211 rectangle_info.y=0; 6212 else 6213 if (rectangle_info.y > (ssize_t) windows->image.height) 6214 rectangle_info.y=(ssize_t) windows->image.height; 6215 if ((int) rectangle_info.y < y) 6216 rectangle_info.height=(unsigned int) (y-rectangle_info.y); 6217 else 6218 { 6219 rectangle_info.height=(unsigned int) (rectangle_info.y-y); 6220 rectangle_info.y=(ssize_t) y; 6221 } 6222 } 6223 } while ((state & ExitState) == 0); 6224 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 6225 if ((element == PointElement) || (element == PolygonElement) || 6226 (element == FillPolygonElement)) 6227 { 6228 /* 6229 Determine polygon bounding box. 6230 */ 6231 rectangle_info.x=(ssize_t) coordinate_info->x; 6232 rectangle_info.y=(ssize_t) coordinate_info->y; 6233 x=coordinate_info->x; 6234 y=coordinate_info->y; 6235 for (i=1; i < number_coordinates; i++) 6236 { 6237 if (coordinate_info[i].x > x) 6238 x=coordinate_info[i].x; 6239 if (coordinate_info[i].y > y) 6240 y=coordinate_info[i].y; 6241 if ((ssize_t) coordinate_info[i].x < rectangle_info.x) 6242 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0); 6243 if ((ssize_t) coordinate_info[i].y < rectangle_info.y) 6244 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0); 6245 } 6246 rectangle_info.width=(size_t) (x-rectangle_info.x); 6247 rectangle_info.height=(size_t) (y-rectangle_info.y); 6248 for (i=0; i < number_coordinates; i++) 6249 { 6250 coordinate_info[i].x-=rectangle_info.x; 6251 coordinate_info[i].y-=rectangle_info.y; 6252 } 6253 } 6254 else 6255 if (distance <= 9) 6256 continue; 6257 else 6258 if ((element == RectangleElement) || 6259 (element == CircleElement) || (element == EllipseElement)) 6260 { 6261 rectangle_info.width--; 6262 rectangle_info.height--; 6263 } 6264 /* 6265 Drawing is relative to image configuration. 6266 */ 6267 draw_info.x=(int) rectangle_info.x; 6268 draw_info.y=(int) rectangle_info.y; 6269 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand, 6270 image,exception); 6271 width=(unsigned int) (*image)->columns; 6272 height=(unsigned int) (*image)->rows; 6273 x=0; 6274 y=0; 6275 if (windows->image.crop_geometry != (char *) NULL) 6276 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 6277 draw_info.x+=windows->image.x-(line_width/2); 6278 if (draw_info.x < 0) 6279 draw_info.x=0; 6280 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width); 6281 draw_info.y+=windows->image.y-(line_width/2); 6282 if (draw_info.y < 0) 6283 draw_info.y=0; 6284 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height; 6285 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1); 6286 if (draw_info.width > (unsigned int) (*image)->columns) 6287 draw_info.width=(unsigned int) (*image)->columns; 6288 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1); 6289 if (draw_info.height > (unsigned int) (*image)->rows) 6290 draw_info.height=(unsigned int) (*image)->rows; 6291 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d", 6292 width*draw_info.width/windows->image.ximage->width, 6293 height*draw_info.height/windows->image.ximage->height, 6294 draw_info.x+x,draw_info.y+y); 6295 /* 6296 Initialize drawing attributes. 6297 */ 6298 draw_info.degrees=0.0; 6299 draw_info.element=element; 6300 draw_info.stipple=stipple; 6301 draw_info.line_width=line_width; 6302 draw_info.line_info=line_info; 6303 if (line_info.x1 > (int) (line_width/2)) 6304 draw_info.line_info.x1=(short) line_width/2; 6305 if (line_info.y1 > (int) (line_width/2)) 6306 draw_info.line_info.y1=(short) line_width/2; 6307 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2)); 6308 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2)); 6309 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0)) 6310 { 6311 draw_info.line_info.x2=(-draw_info.line_info.x2); 6312 draw_info.line_info.y2=(-draw_info.line_info.y2); 6313 } 6314 if (draw_info.line_info.x2 < 0) 6315 { 6316 draw_info.line_info.x2=(-draw_info.line_info.x2); 6317 Swap(draw_info.line_info.x1,draw_info.line_info.x2); 6318 } 6319 if (draw_info.line_info.y2 < 0) 6320 { 6321 draw_info.line_info.y2=(-draw_info.line_info.y2); 6322 Swap(draw_info.line_info.y1,draw_info.line_info.y2); 6323 } 6324 draw_info.rectangle_info=rectangle_info; 6325 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2)) 6326 draw_info.rectangle_info.x=(ssize_t) line_width/2; 6327 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2)) 6328 draw_info.rectangle_info.y=(ssize_t) line_width/2; 6329 draw_info.number_coordinates=(unsigned int) number_coordinates; 6330 draw_info.coordinate_info=coordinate_info; 6331 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 6332 /* 6333 Draw element on image. 6334 */ 6335 XSetCursorState(display,windows,MagickTrue); 6336 XCheckRefreshWindows(display,windows); 6337 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception); 6338 XSetCursorState(display,windows,MagickFalse); 6339 /* 6340 Update image colormap and return to image drawing. 6341 */ 6342 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6343 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6344 } 6345 XSetCursorState(display,windows,MagickFalse); 6346 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info); 6347 return(status != 0 ? MagickTrue : MagickFalse); 6348} 6349 6350/* 6351%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6352% % 6353% % 6354% % 6355+ X D r a w P a n R e c t a n g l e % 6356% % 6357% % 6358% % 6359%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6360% 6361% XDrawPanRectangle() draws a rectangle in the pan window. The pan window 6362% displays a zoom image and the rectangle shows which portion of the image is 6363% displayed in the Image window. 6364% 6365% The format of the XDrawPanRectangle method is: 6366% 6367% XDrawPanRectangle(Display *display,XWindows *windows) 6368% 6369% A description of each parameter follows: 6370% 6371% o display: Specifies a connection to an X server; returned from 6372% XOpenDisplay. 6373% 6374% o windows: Specifies a pointer to a XWindows structure. 6375% 6376*/ 6377static void XDrawPanRectangle(Display *display,XWindows *windows) 6378{ 6379 MagickRealType 6380 scale_factor; 6381 6382 RectangleInfo 6383 highlight_info; 6384 6385 /* 6386 Determine dimensions of the panning rectangle. 6387 */ 6388 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width; 6389 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5); 6390 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5); 6391 scale_factor=(MagickRealType) 6392 windows->pan.height/windows->image.ximage->height; 6393 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5); 6394 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5); 6395 /* 6396 Display the panning rectangle. 6397 */ 6398 (void) XClearWindow(display,windows->pan.id); 6399 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context, 6400 &highlight_info); 6401} 6402 6403/* 6404%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6405% % 6406% % 6407% % 6408+ X I m a g e C a c h e % 6409% % 6410% % 6411% % 6412%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6413% 6414% XImageCache() handles the creation, manipulation, and destruction of the 6415% image cache (undo and redo buffers). 6416% 6417% The format of the XImageCache method is: 6418% 6419% void XImageCache(Display *display,XResourceInfo *resource_info, 6420% XWindows *windows,const CommandType command,Image **image, 6421% ExceptionInfo *exception) 6422% 6423% A description of each parameter follows: 6424% 6425% o display: Specifies a connection to an X server; returned from 6426% XOpenDisplay. 6427% 6428% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6429% 6430% o windows: Specifies a pointer to a XWindows structure. 6431% 6432% o command: Specifies a command to perform. 6433% 6434% o image: the image; XImageCache may transform the image and return a new 6435% image pointer. 6436% 6437% o exception: return any errors or warnings in this structure. 6438% 6439*/ 6440static void XImageCache(Display *display,XResourceInfo *resource_info, 6441 XWindows *windows,const CommandType command,Image **image, 6442 ExceptionInfo *exception) 6443{ 6444 Image 6445 *cache_image; 6446 6447 static Image 6448 *redo_image = (Image *) NULL, 6449 *undo_image = (Image *) NULL; 6450 6451 switch (command) 6452 { 6453 case FreeBuffersCommand: 6454 { 6455 /* 6456 Free memory from the undo and redo cache. 6457 */ 6458 while (undo_image != (Image *) NULL) 6459 { 6460 cache_image=undo_image; 6461 undo_image=GetPreviousImageInList(undo_image); 6462 cache_image->list=DestroyImage(cache_image->list); 6463 cache_image=DestroyImage(cache_image); 6464 } 6465 undo_image=NewImageList(); 6466 if (redo_image != (Image *) NULL) 6467 redo_image=DestroyImage(redo_image); 6468 redo_image=NewImageList(); 6469 return; 6470 } 6471 case UndoCommand: 6472 { 6473 char 6474 image_geometry[MaxTextExtent]; 6475 6476 /* 6477 Undo the last image transformation. 6478 */ 6479 if (undo_image == (Image *) NULL) 6480 { 6481 (void) XBell(display,0); 6482 return; 6483 } 6484 cache_image=undo_image; 6485 undo_image=GetPreviousImageInList(undo_image); 6486 windows->image.window_changes.width=(int) cache_image->columns; 6487 windows->image.window_changes.height=(int) cache_image->rows; 6488 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 6489 windows->image.ximage->width,windows->image.ximage->height); 6490 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 6491 exception); 6492 if (windows->image.crop_geometry != (char *) NULL) 6493 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 6494 windows->image.crop_geometry); 6495 windows->image.crop_geometry=cache_image->geometry; 6496 if (redo_image != (Image *) NULL) 6497 redo_image=DestroyImage(redo_image); 6498 redo_image=(*image); 6499 *image=cache_image->list; 6500 cache_image=DestroyImage(cache_image); 6501 if (windows->image.orphan != MagickFalse) 6502 return; 6503 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6504 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6505 return; 6506 } 6507 case CutCommand: 6508 case PasteCommand: 6509 case ApplyCommand: 6510 case HalfSizeCommand: 6511 case OriginalSizeCommand: 6512 case DoubleSizeCommand: 6513 case ResizeCommand: 6514 case TrimCommand: 6515 case CropCommand: 6516 case ChopCommand: 6517 case FlipCommand: 6518 case FlopCommand: 6519 case RotateRightCommand: 6520 case RotateLeftCommand: 6521 case RotateCommand: 6522 case ShearCommand: 6523 case RollCommand: 6524 case NegateCommand: 6525 case ContrastStretchCommand: 6526 case SigmoidalContrastCommand: 6527 case NormalizeCommand: 6528 case EqualizeCommand: 6529 case HueCommand: 6530 case SaturationCommand: 6531 case BrightnessCommand: 6532 case GammaCommand: 6533 case SpiffCommand: 6534 case DullCommand: 6535 case GrayscaleCommand: 6536 case MapCommand: 6537 case QuantizeCommand: 6538 case DespeckleCommand: 6539 case EmbossCommand: 6540 case ReduceNoiseCommand: 6541 case AddNoiseCommand: 6542 case SharpenCommand: 6543 case BlurCommand: 6544 case ThresholdCommand: 6545 case EdgeDetectCommand: 6546 case SpreadCommand: 6547 case ShadeCommand: 6548 case RaiseCommand: 6549 case SegmentCommand: 6550 case SolarizeCommand: 6551 case SepiaToneCommand: 6552 case SwirlCommand: 6553 case ImplodeCommand: 6554 case VignetteCommand: 6555 case WaveCommand: 6556 case OilPaintCommand: 6557 case CharcoalDrawCommand: 6558 case AnnotateCommand: 6559 case AddBorderCommand: 6560 case AddFrameCommand: 6561 case CompositeCommand: 6562 case CommentCommand: 6563 case LaunchCommand: 6564 case RegionofInterestCommand: 6565 case SaveToUndoBufferCommand: 6566 case RedoCommand: 6567 { 6568 Image 6569 *previous_image; 6570 6571 ssize_t 6572 bytes; 6573 6574 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo)); 6575 if (undo_image != (Image *) NULL) 6576 { 6577 /* 6578 Ensure the undo cache has enough memory available. 6579 */ 6580 previous_image=undo_image; 6581 while (previous_image != (Image *) NULL) 6582 { 6583 bytes+=previous_image->list->columns*previous_image->list->rows* 6584 sizeof(PixelInfo); 6585 if (bytes <= (ssize_t) (resource_info->undo_cache << 20)) 6586 { 6587 previous_image=GetPreviousImageInList(previous_image); 6588 continue; 6589 } 6590 bytes-=previous_image->list->columns*previous_image->list->rows* 6591 sizeof(PixelInfo); 6592 if (previous_image == undo_image) 6593 undo_image=NewImageList(); 6594 else 6595 previous_image->next->previous=NewImageList(); 6596 break; 6597 } 6598 while (previous_image != (Image *) NULL) 6599 { 6600 /* 6601 Delete any excess memory from undo cache. 6602 */ 6603 cache_image=previous_image; 6604 previous_image=GetPreviousImageInList(previous_image); 6605 cache_image->list=DestroyImage(cache_image->list); 6606 cache_image=DestroyImage(cache_image); 6607 } 6608 } 6609 if (bytes > (ssize_t) (resource_info->undo_cache << 20)) 6610 break; 6611 /* 6612 Save image before transformations are applied. 6613 */ 6614 cache_image=AcquireImage((ImageInfo *) NULL,exception); 6615 if (cache_image == (Image *) NULL) 6616 break; 6617 XSetCursorState(display,windows,MagickTrue); 6618 XCheckRefreshWindows(display,windows); 6619 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception); 6620 XSetCursorState(display,windows,MagickFalse); 6621 if (cache_image->list == (Image *) NULL) 6622 { 6623 cache_image=DestroyImage(cache_image); 6624 break; 6625 } 6626 cache_image->columns=(size_t) windows->image.ximage->width; 6627 cache_image->rows=(size_t) windows->image.ximage->height; 6628 cache_image->geometry=windows->image.crop_geometry; 6629 if (windows->image.crop_geometry != (char *) NULL) 6630 { 6631 cache_image->geometry=AcquireString((char *) NULL); 6632 (void) CopyMagickString(cache_image->geometry, 6633 windows->image.crop_geometry,MaxTextExtent); 6634 } 6635 if (undo_image == (Image *) NULL) 6636 { 6637 undo_image=cache_image; 6638 break; 6639 } 6640 undo_image->next=cache_image; 6641 undo_image->next->previous=undo_image; 6642 undo_image=undo_image->next; 6643 break; 6644 } 6645 default: 6646 break; 6647 } 6648 if (command == RedoCommand) 6649 { 6650 /* 6651 Redo the last image transformation. 6652 */ 6653 if (redo_image == (Image *) NULL) 6654 { 6655 (void) XBell(display,0); 6656 return; 6657 } 6658 windows->image.window_changes.width=(int) redo_image->columns; 6659 windows->image.window_changes.height=(int) redo_image->rows; 6660 if (windows->image.crop_geometry != (char *) NULL) 6661 windows->image.crop_geometry=(char *) 6662 RelinquishMagickMemory(windows->image.crop_geometry); 6663 windows->image.crop_geometry=redo_image->geometry; 6664 *image=DestroyImage(*image); 6665 *image=redo_image; 6666 redo_image=NewImageList(); 6667 if (windows->image.orphan != MagickFalse) 6668 return; 6669 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6670 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6671 return; 6672 } 6673 if (command != InfoCommand) 6674 return; 6675 /* 6676 Display image info. 6677 */ 6678 XSetCursorState(display,windows,MagickTrue); 6679 XCheckRefreshWindows(display,windows); 6680 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception); 6681 XSetCursorState(display,windows,MagickFalse); 6682} 6683 6684/* 6685%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6686% % 6687% % 6688% % 6689+ X I m a g e W i n d o w C o m m a n d % 6690% % 6691% % 6692% % 6693%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6694% 6695% XImageWindowCommand() makes a transform to the image or Image window as 6696% specified by a user menu button or keyboard command. 6697% 6698% The format of the XImageWindowCommand method is: 6699% 6700% CommandType XImageWindowCommand(Display *display, 6701% XResourceInfo *resource_info,XWindows *windows, 6702% const MagickStatusType state,KeySym key_symbol,Image **image, 6703% ExceptionInfo *exception) 6704% 6705% A description of each parameter follows: 6706% 6707% o nexus: Method XImageWindowCommand returns an image when the 6708% user chooses 'Open Image' from the command menu. Otherwise a null 6709% image is returned. 6710% 6711% o display: Specifies a connection to an X server; returned from 6712% XOpenDisplay. 6713% 6714% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6715% 6716% o windows: Specifies a pointer to a XWindows structure. 6717% 6718% o state: key mask. 6719% 6720% o key_symbol: Specifies a command to perform. 6721% 6722% o image: the image; XImageWIndowCommand may transform the image and 6723% return a new image pointer. 6724% 6725% o exception: return any errors or warnings in this structure. 6726% 6727*/ 6728static CommandType XImageWindowCommand(Display *display, 6729 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state, 6730 KeySym key_symbol,Image **image,ExceptionInfo *exception) 6731{ 6732 static char 6733 delta[MaxTextExtent] = ""; 6734 6735 static const char 6736 Digits[] = "01234567890"; 6737 6738 static KeySym 6739 last_symbol = XK_0; 6740 6741 if ((key_symbol >= XK_0) && (key_symbol <= XK_9)) 6742 { 6743 if (((last_symbol < XK_0) || (last_symbol > XK_9))) 6744 { 6745 *delta='\0'; 6746 resource_info->quantum=1; 6747 } 6748 last_symbol=key_symbol; 6749 delta[strlen(delta)+1]='\0'; 6750 delta[strlen(delta)]=Digits[key_symbol-XK_0]; 6751 resource_info->quantum=StringToLong(delta); 6752 return(NullCommand); 6753 } 6754 last_symbol=key_symbol; 6755 if (resource_info->immutable) 6756 { 6757 /* 6758 Virtual image window has a restricted command set. 6759 */ 6760 switch (key_symbol) 6761 { 6762 case XK_question: 6763 return(InfoCommand); 6764 case XK_p: 6765 case XK_Print: 6766 return(PrintCommand); 6767 case XK_space: 6768 return(NextCommand); 6769 case XK_q: 6770 case XK_Escape: 6771 return(QuitCommand); 6772 default: 6773 break; 6774 } 6775 return(NullCommand); 6776 } 6777 switch ((int) key_symbol) 6778 { 6779 case XK_o: 6780 { 6781 if ((state & ControlMask) == 0) 6782 break; 6783 return(OpenCommand); 6784 } 6785 case XK_space: 6786 return(NextCommand); 6787 case XK_BackSpace: 6788 return(FormerCommand); 6789 case XK_s: 6790 { 6791 if ((state & Mod1Mask) != 0) 6792 return(SwirlCommand); 6793 if ((state & ControlMask) == 0) 6794 return(ShearCommand); 6795 return(SaveCommand); 6796 } 6797 case XK_p: 6798 case XK_Print: 6799 { 6800 if ((state & Mod1Mask) != 0) 6801 return(OilPaintCommand); 6802 if ((state & Mod4Mask) != 0) 6803 return(ColorCommand); 6804 if ((state & ControlMask) == 0) 6805 return(NullCommand); 6806 return(PrintCommand); 6807 } 6808 case XK_d: 6809 { 6810 if ((state & Mod4Mask) != 0) 6811 return(DrawCommand); 6812 if ((state & ControlMask) == 0) 6813 return(NullCommand); 6814 return(DeleteCommand); 6815 } 6816 case XK_Select: 6817 { 6818 if ((state & ControlMask) == 0) 6819 return(NullCommand); 6820 return(SelectCommand); 6821 } 6822 case XK_n: 6823 { 6824 if ((state & ControlMask) == 0) 6825 return(NullCommand); 6826 return(NewCommand); 6827 } 6828 case XK_q: 6829 case XK_Escape: 6830 return(QuitCommand); 6831 case XK_z: 6832 case XK_Undo: 6833 { 6834 if ((state & ControlMask) == 0) 6835 return(NullCommand); 6836 return(UndoCommand); 6837 } 6838 case XK_r: 6839 case XK_Redo: 6840 { 6841 if ((state & ControlMask) == 0) 6842 return(RollCommand); 6843 return(RedoCommand); 6844 } 6845 case XK_x: 6846 { 6847 if ((state & ControlMask) == 0) 6848 return(NullCommand); 6849 return(CutCommand); 6850 } 6851 case XK_c: 6852 { 6853 if ((state & Mod1Mask) != 0) 6854 return(CharcoalDrawCommand); 6855 if ((state & ControlMask) == 0) 6856 return(CropCommand); 6857 return(CopyCommand); 6858 } 6859 case XK_v: 6860 case XK_Insert: 6861 { 6862 if ((state & Mod4Mask) != 0) 6863 return(CompositeCommand); 6864 if ((state & ControlMask) == 0) 6865 return(FlipCommand); 6866 return(PasteCommand); 6867 } 6868 case XK_less: 6869 return(HalfSizeCommand); 6870 case XK_minus: 6871 return(OriginalSizeCommand); 6872 case XK_greater: 6873 return(DoubleSizeCommand); 6874 case XK_percent: 6875 return(ResizeCommand); 6876 case XK_at: 6877 return(RefreshCommand); 6878 case XK_bracketleft: 6879 return(ChopCommand); 6880 case XK_h: 6881 return(FlopCommand); 6882 case XK_slash: 6883 return(RotateRightCommand); 6884 case XK_backslash: 6885 return(RotateLeftCommand); 6886 case XK_asterisk: 6887 return(RotateCommand); 6888 case XK_t: 6889 return(TrimCommand); 6890 case XK_H: 6891 return(HueCommand); 6892 case XK_S: 6893 return(SaturationCommand); 6894 case XK_L: 6895 return(BrightnessCommand); 6896 case XK_G: 6897 return(GammaCommand); 6898 case XK_C: 6899 return(SpiffCommand); 6900 case XK_Z: 6901 return(DullCommand); 6902 case XK_N: 6903 return(NormalizeCommand); 6904 case XK_equal: 6905 return(EqualizeCommand); 6906 case XK_asciitilde: 6907 return(NegateCommand); 6908 case XK_period: 6909 return(GrayscaleCommand); 6910 case XK_numbersign: 6911 return(QuantizeCommand); 6912 case XK_F2: 6913 return(DespeckleCommand); 6914 case XK_F3: 6915 return(EmbossCommand); 6916 case XK_F4: 6917 return(ReduceNoiseCommand); 6918 case XK_F5: 6919 return(AddNoiseCommand); 6920 case XK_F6: 6921 return(SharpenCommand); 6922 case XK_F7: 6923 return(BlurCommand); 6924 case XK_F8: 6925 return(ThresholdCommand); 6926 case XK_F9: 6927 return(EdgeDetectCommand); 6928 case XK_F10: 6929 return(SpreadCommand); 6930 case XK_F11: 6931 return(ShadeCommand); 6932 case XK_F12: 6933 return(RaiseCommand); 6934 case XK_F13: 6935 return(SegmentCommand); 6936 case XK_i: 6937 { 6938 if ((state & Mod1Mask) == 0) 6939 return(NullCommand); 6940 return(ImplodeCommand); 6941 } 6942 case XK_w: 6943 { 6944 if ((state & Mod1Mask) == 0) 6945 return(NullCommand); 6946 return(WaveCommand); 6947 } 6948 case XK_m: 6949 { 6950 if ((state & Mod4Mask) == 0) 6951 return(NullCommand); 6952 return(MatteCommand); 6953 } 6954 case XK_b: 6955 { 6956 if ((state & Mod4Mask) == 0) 6957 return(NullCommand); 6958 return(AddBorderCommand); 6959 } 6960 case XK_f: 6961 { 6962 if ((state & Mod4Mask) == 0) 6963 return(NullCommand); 6964 return(AddFrameCommand); 6965 } 6966 case XK_exclam: 6967 { 6968 if ((state & Mod4Mask) == 0) 6969 return(NullCommand); 6970 return(CommentCommand); 6971 } 6972 case XK_a: 6973 { 6974 if ((state & Mod1Mask) != 0) 6975 return(ApplyCommand); 6976 if ((state & Mod4Mask) != 0) 6977 return(AnnotateCommand); 6978 if ((state & ControlMask) == 0) 6979 return(NullCommand); 6980 return(RegionofInterestCommand); 6981 } 6982 case XK_question: 6983 return(InfoCommand); 6984 case XK_plus: 6985 return(ZoomCommand); 6986 case XK_P: 6987 { 6988 if ((state & ShiftMask) == 0) 6989 return(NullCommand); 6990 return(ShowPreviewCommand); 6991 } 6992 case XK_Execute: 6993 return(LaunchCommand); 6994 case XK_F1: 6995 return(HelpCommand); 6996 case XK_Find: 6997 return(BrowseDocumentationCommand); 6998 case XK_Menu: 6999 { 7000 (void) XMapRaised(display,windows->command.id); 7001 return(NullCommand); 7002 } 7003 case XK_Next: 7004 case XK_Prior: 7005 case XK_Home: 7006 case XK_KP_Home: 7007 { 7008 XTranslateImage(display,windows,*image,key_symbol); 7009 return(NullCommand); 7010 } 7011 case XK_Up: 7012 case XK_KP_Up: 7013 case XK_Down: 7014 case XK_KP_Down: 7015 case XK_Left: 7016 case XK_KP_Left: 7017 case XK_Right: 7018 case XK_KP_Right: 7019 { 7020 if ((state & Mod1Mask) != 0) 7021 { 7022 RectangleInfo 7023 crop_info; 7024 7025 /* 7026 Trim one pixel from edge of image. 7027 */ 7028 crop_info.x=0; 7029 crop_info.y=0; 7030 crop_info.width=(size_t) windows->image.ximage->width; 7031 crop_info.height=(size_t) windows->image.ximage->height; 7032 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up)) 7033 { 7034 if (resource_info->quantum >= (int) crop_info.height) 7035 resource_info->quantum=(int) crop_info.height-1; 7036 crop_info.height-=resource_info->quantum; 7037 } 7038 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down)) 7039 { 7040 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y)) 7041 resource_info->quantum=(int) (crop_info.height-crop_info.y-1); 7042 crop_info.y+=resource_info->quantum; 7043 crop_info.height-=resource_info->quantum; 7044 } 7045 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left)) 7046 { 7047 if (resource_info->quantum >= (int) crop_info.width) 7048 resource_info->quantum=(int) crop_info.width-1; 7049 crop_info.width-=resource_info->quantum; 7050 } 7051 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right)) 7052 { 7053 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x)) 7054 resource_info->quantum=(int) (crop_info.width-crop_info.x-1); 7055 crop_info.x+=resource_info->quantum; 7056 crop_info.width-=resource_info->quantum; 7057 } 7058 if ((int) (windows->image.x+windows->image.width) > 7059 (int) crop_info.width) 7060 windows->image.x=(int) (crop_info.width-windows->image.width); 7061 if ((int) (windows->image.y+windows->image.height) > 7062 (int) crop_info.height) 7063 windows->image.y=(int) (crop_info.height-windows->image.height); 7064 XSetCropGeometry(display,windows,&crop_info,*image); 7065 windows->image.window_changes.width=(int) crop_info.width; 7066 windows->image.window_changes.height=(int) crop_info.height; 7067 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None); 7068 (void) XConfigureImage(display,resource_info,windows,*image, 7069 exception); 7070 return(NullCommand); 7071 } 7072 XTranslateImage(display,windows,*image,key_symbol); 7073 return(NullCommand); 7074 } 7075 default: 7076 return(NullCommand); 7077 } 7078 return(NullCommand); 7079} 7080 7081/* 7082%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7083% % 7084% % 7085% % 7086+ X M a g i c k C o m m a n d % 7087% % 7088% % 7089% % 7090%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7091% 7092% XMagickCommand() makes a transform to the image or Image window as 7093% specified by a user menu button or keyboard command. 7094% 7095% The format of the XMagickCommand method is: 7096% 7097% Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7098% XWindows *windows,const CommandType command,Image **image, 7099% ExceptionInfo *exception) 7100% 7101% A description of each parameter follows: 7102% 7103% o display: Specifies a connection to an X server; returned from 7104% XOpenDisplay. 7105% 7106% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 7107% 7108% o windows: Specifies a pointer to a XWindows structure. 7109% 7110% o command: Specifies a command to perform. 7111% 7112% o image: the image; XMagickCommand may transform the image and return a 7113% new image pointer. 7114% 7115% o exception: return any errors or warnings in this structure. 7116% 7117*/ 7118static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7119 XWindows *windows,const CommandType command,Image **image, 7120 ExceptionInfo *exception) 7121{ 7122 char 7123 filename[MaxTextExtent], 7124 geometry[MaxTextExtent], 7125 modulate_factors[MaxTextExtent]; 7126 7127 GeometryInfo 7128 geometry_info; 7129 7130 Image 7131 *nexus; 7132 7133 ImageInfo 7134 *image_info; 7135 7136 int 7137 x, 7138 y; 7139 7140 MagickStatusType 7141 flags, 7142 status; 7143 7144 QuantizeInfo 7145 quantize_info; 7146 7147 RectangleInfo 7148 page_geometry; 7149 7150 register int 7151 i; 7152 7153 static char 7154 color[MaxTextExtent] = "gray"; 7155 7156 unsigned int 7157 height, 7158 width; 7159 7160 /* 7161 Process user command. 7162 */ 7163 XCheckRefreshWindows(display,windows); 7164 XImageCache(display,resource_info,windows,command,image,exception); 7165 nexus=NewImageList(); 7166 windows->image.window_changes.width=windows->image.ximage->width; 7167 windows->image.window_changes.height=windows->image.ximage->height; 7168 image_info=CloneImageInfo(resource_info->image_info); 7169 SetGeometryInfo(&geometry_info); 7170 GetQuantizeInfo(&quantize_info); 7171 switch (command) 7172 { 7173 case OpenCommand: 7174 { 7175 /* 7176 Load image. 7177 */ 7178 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 7179 break; 7180 } 7181 case NextCommand: 7182 { 7183 /* 7184 Display next image. 7185 */ 7186 for (i=0; i < resource_info->quantum; i++) 7187 XClientMessage(display,windows->image.id,windows->im_protocols, 7188 windows->im_next_image,CurrentTime); 7189 break; 7190 } 7191 case FormerCommand: 7192 { 7193 /* 7194 Display former image. 7195 */ 7196 for (i=0; i < resource_info->quantum; i++) 7197 XClientMessage(display,windows->image.id,windows->im_protocols, 7198 windows->im_former_image,CurrentTime); 7199 break; 7200 } 7201 case SelectCommand: 7202 { 7203 int 7204 status; 7205 7206 /* 7207 Select image. 7208 */ 7209 status=chdir(resource_info->home_directory); 7210 if (status == -1) 7211 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 7212 "UnableToOpenFile","%s",resource_info->home_directory); 7213 nexus=XOpenImage(display,resource_info,windows,MagickTrue); 7214 break; 7215 } 7216 case SaveCommand: 7217 { 7218 /* 7219 Save image. 7220 */ 7221 status=XSaveImage(display,resource_info,windows,*image,exception); 7222 if (status == MagickFalse) 7223 { 7224 char 7225 message[MaxTextExtent]; 7226 7227 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7228 exception->reason != (char *) NULL ? exception->reason : "", 7229 exception->description != (char *) NULL ? exception->description : 7230 ""); 7231 XNoticeWidget(display,windows,"Unable to save file:",message); 7232 break; 7233 } 7234 break; 7235 } 7236 case PrintCommand: 7237 { 7238 /* 7239 Print image. 7240 */ 7241 status=XPrintImage(display,resource_info,windows,*image,exception); 7242 if (status == MagickFalse) 7243 { 7244 char 7245 message[MaxTextExtent]; 7246 7247 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7248 exception->reason != (char *) NULL ? exception->reason : "", 7249 exception->description != (char *) NULL ? exception->description : 7250 ""); 7251 XNoticeWidget(display,windows,"Unable to print file:",message); 7252 break; 7253 } 7254 break; 7255 } 7256 case DeleteCommand: 7257 { 7258 static char 7259 filename[MaxTextExtent] = "\0"; 7260 7261 /* 7262 Delete image file. 7263 */ 7264 XFileBrowserWidget(display,windows,"Delete",filename); 7265 if (*filename == '\0') 7266 break; 7267 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse; 7268 if (status != MagickFalse) 7269 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7270 break; 7271 } 7272 case NewCommand: 7273 { 7274 int 7275 status; 7276 7277 static char 7278 color[MaxTextExtent] = "gray", 7279 geometry[MaxTextExtent] = "640x480"; 7280 7281 static const char 7282 *format = "gradient"; 7283 7284 /* 7285 Query user for canvas geometry. 7286 */ 7287 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7288 geometry); 7289 if (*geometry == '\0') 7290 break; 7291 if (status == 0) 7292 format="xc"; 7293 XColorBrowserWidget(display,windows,"Select",color); 7294 if (*color == '\0') 7295 break; 7296 /* 7297 Create canvas. 7298 */ 7299 (void) FormatLocaleString(image_info->filename,MaxTextExtent, 7300 "%s:%s",format,color); 7301 (void) CloneString(&image_info->size,geometry); 7302 nexus=ReadImage(image_info,exception); 7303 CatchException(exception); 7304 XClientMessage(display,windows->image.id,windows->im_protocols, 7305 windows->im_next_image,CurrentTime); 7306 break; 7307 } 7308 case VisualDirectoryCommand: 7309 { 7310 /* 7311 Visual Image directory. 7312 */ 7313 nexus=XVisualDirectoryImage(display,resource_info,windows,exception); 7314 break; 7315 } 7316 case QuitCommand: 7317 { 7318 /* 7319 exit program. 7320 */ 7321 if (resource_info->confirm_exit == MagickFalse) 7322 XClientMessage(display,windows->image.id,windows->im_protocols, 7323 windows->im_exit,CurrentTime); 7324 else 7325 { 7326 int 7327 status; 7328 7329 /* 7330 Confirm program exit. 7331 */ 7332 status=XConfirmWidget(display,windows,"Do you really want to exit", 7333 resource_info->client_name); 7334 if (status > 0) 7335 XClientMessage(display,windows->image.id,windows->im_protocols, 7336 windows->im_exit,CurrentTime); 7337 } 7338 break; 7339 } 7340 case CutCommand: 7341 { 7342 /* 7343 Cut image. 7344 */ 7345 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception); 7346 break; 7347 } 7348 case CopyCommand: 7349 { 7350 /* 7351 Copy image. 7352 */ 7353 (void) XCropImage(display,resource_info,windows,*image,CopyMode, 7354 exception); 7355 break; 7356 } 7357 case PasteCommand: 7358 { 7359 /* 7360 Paste image. 7361 */ 7362 status=XPasteImage(display,resource_info,windows,*image,exception); 7363 if (status == MagickFalse) 7364 { 7365 XNoticeWidget(display,windows,"Unable to paste X image", 7366 (*image)->filename); 7367 break; 7368 } 7369 break; 7370 } 7371 case HalfSizeCommand: 7372 { 7373 /* 7374 Half image size. 7375 */ 7376 windows->image.window_changes.width=windows->image.ximage->width/2; 7377 windows->image.window_changes.height=windows->image.ximage->height/2; 7378 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7379 break; 7380 } 7381 case OriginalSizeCommand: 7382 { 7383 /* 7384 Original image size. 7385 */ 7386 windows->image.window_changes.width=(int) (*image)->columns; 7387 windows->image.window_changes.height=(int) (*image)->rows; 7388 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7389 break; 7390 } 7391 case DoubleSizeCommand: 7392 { 7393 /* 7394 Double the image size. 7395 */ 7396 windows->image.window_changes.width=windows->image.ximage->width << 1; 7397 windows->image.window_changes.height=windows->image.ximage->height << 1; 7398 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7399 break; 7400 } 7401 case ResizeCommand: 7402 { 7403 int 7404 status; 7405 7406 size_t 7407 height, 7408 width; 7409 7410 ssize_t 7411 x, 7412 y; 7413 7414 /* 7415 Resize image. 7416 */ 7417 width=(size_t) windows->image.ximage->width; 7418 height=(size_t) windows->image.ximage->height; 7419 x=0; 7420 y=0; 7421 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0", 7422 (double) width,(double) height); 7423 status=XDialogWidget(display,windows,"Resize", 7424 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7425 if (*geometry == '\0') 7426 break; 7427 if (status == 0) 7428 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent); 7429 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7430 windows->image.window_changes.width=(int) width; 7431 windows->image.window_changes.height=(int) height; 7432 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7433 break; 7434 } 7435 case ApplyCommand: 7436 { 7437 char 7438 image_geometry[MaxTextExtent]; 7439 7440 if ((windows->image.crop_geometry == (char *) NULL) && 7441 ((int) (*image)->columns == windows->image.ximage->width) && 7442 ((int) (*image)->rows == windows->image.ximage->height)) 7443 break; 7444 /* 7445 Apply size transforms to image. 7446 */ 7447 XSetCursorState(display,windows,MagickTrue); 7448 XCheckRefreshWindows(display,windows); 7449 /* 7450 Crop and/or scale displayed image. 7451 */ 7452 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 7453 windows->image.ximage->width,windows->image.ximage->height); 7454 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 7455 exception); 7456 if (windows->image.crop_geometry != (char *) NULL) 7457 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 7458 windows->image.crop_geometry); 7459 windows->image.x=0; 7460 windows->image.y=0; 7461 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7462 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7463 break; 7464 } 7465 case RefreshCommand: 7466 { 7467 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7468 break; 7469 } 7470 case RestoreCommand: 7471 { 7472 /* 7473 Restore Image window to its original size. 7474 */ 7475 if ((windows->image.width == (unsigned int) (*image)->columns) && 7476 (windows->image.height == (unsigned int) (*image)->rows) && 7477 (windows->image.crop_geometry == (char *) NULL)) 7478 { 7479 (void) XBell(display,0); 7480 break; 7481 } 7482 windows->image.window_changes.width=(int) (*image)->columns; 7483 windows->image.window_changes.height=(int) (*image)->rows; 7484 if (windows->image.crop_geometry != (char *) NULL) 7485 { 7486 windows->image.crop_geometry=(char *) 7487 RelinquishMagickMemory(windows->image.crop_geometry); 7488 windows->image.crop_geometry=(char *) NULL; 7489 windows->image.x=0; 7490 windows->image.y=0; 7491 } 7492 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7493 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7494 break; 7495 } 7496 case CropCommand: 7497 { 7498 /* 7499 Crop image. 7500 */ 7501 (void) XCropImage(display,resource_info,windows,*image,CropMode, 7502 exception); 7503 break; 7504 } 7505 case ChopCommand: 7506 { 7507 /* 7508 Chop image. 7509 */ 7510 status=XChopImage(display,resource_info,windows,image,exception); 7511 if (status == MagickFalse) 7512 { 7513 XNoticeWidget(display,windows,"Unable to cut X image", 7514 (*image)->filename); 7515 break; 7516 } 7517 break; 7518 } 7519 case FlopCommand: 7520 { 7521 Image 7522 *flop_image; 7523 7524 /* 7525 Flop image scanlines. 7526 */ 7527 XSetCursorState(display,windows,MagickTrue); 7528 XCheckRefreshWindows(display,windows); 7529 flop_image=FlopImage(*image,exception); 7530 if (flop_image != (Image *) NULL) 7531 { 7532 *image=DestroyImage(*image); 7533 *image=flop_image; 7534 } 7535 CatchException(exception); 7536 XSetCursorState(display,windows,MagickFalse); 7537 if (windows->image.crop_geometry != (char *) NULL) 7538 { 7539 /* 7540 Flop crop geometry. 7541 */ 7542 width=(unsigned int) (*image)->columns; 7543 height=(unsigned int) (*image)->rows; 7544 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7545 &width,&height); 7546 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7547 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7548 } 7549 if (windows->image.orphan != MagickFalse) 7550 break; 7551 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7552 break; 7553 } 7554 case FlipCommand: 7555 { 7556 Image 7557 *flip_image; 7558 7559 /* 7560 Flip image scanlines. 7561 */ 7562 XSetCursorState(display,windows,MagickTrue); 7563 XCheckRefreshWindows(display,windows); 7564 flip_image=FlipImage(*image,exception); 7565 if (flip_image != (Image *) NULL) 7566 { 7567 *image=DestroyImage(*image); 7568 *image=flip_image; 7569 } 7570 CatchException(exception); 7571 XSetCursorState(display,windows,MagickFalse); 7572 if (windows->image.crop_geometry != (char *) NULL) 7573 { 7574 /* 7575 Flip crop geometry. 7576 */ 7577 width=(unsigned int) (*image)->columns; 7578 height=(unsigned int) (*image)->rows; 7579 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7580 &width,&height); 7581 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7582 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7583 } 7584 if (windows->image.orphan != MagickFalse) 7585 break; 7586 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7587 break; 7588 } 7589 case RotateRightCommand: 7590 { 7591 /* 7592 Rotate image 90 degrees clockwise. 7593 */ 7594 status=XRotateImage(display,resource_info,windows,90.0,image,exception); 7595 if (status == MagickFalse) 7596 { 7597 XNoticeWidget(display,windows,"Unable to rotate X image", 7598 (*image)->filename); 7599 break; 7600 } 7601 break; 7602 } 7603 case RotateLeftCommand: 7604 { 7605 /* 7606 Rotate image 90 degrees counter-clockwise. 7607 */ 7608 status=XRotateImage(display,resource_info,windows,-90.0,image,exception); 7609 if (status == MagickFalse) 7610 { 7611 XNoticeWidget(display,windows,"Unable to rotate X image", 7612 (*image)->filename); 7613 break; 7614 } 7615 break; 7616 } 7617 case RotateCommand: 7618 { 7619 /* 7620 Rotate image. 7621 */ 7622 status=XRotateImage(display,resource_info,windows,0.0,image,exception); 7623 if (status == MagickFalse) 7624 { 7625 XNoticeWidget(display,windows,"Unable to rotate X image", 7626 (*image)->filename); 7627 break; 7628 } 7629 break; 7630 } 7631 case ShearCommand: 7632 { 7633 Image 7634 *shear_image; 7635 7636 static char 7637 geometry[MaxTextExtent] = "45.0x45.0"; 7638 7639 /* 7640 Query user for shear color and geometry. 7641 */ 7642 XColorBrowserWidget(display,windows,"Select",color); 7643 if (*color == '\0') 7644 break; 7645 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7646 geometry); 7647 if (*geometry == '\0') 7648 break; 7649 /* 7650 Shear image. 7651 */ 7652 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7653 exception); 7654 XSetCursorState(display,windows,MagickTrue); 7655 XCheckRefreshWindows(display,windows); 7656 (void) QueryColorCompliance(color,AllCompliance, 7657 &(*image)->background_color,exception); 7658 flags=ParseGeometry(geometry,&geometry_info); 7659 if ((flags & SigmaValue) == 0) 7660 geometry_info.sigma=geometry_info.rho; 7661 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7662 exception); 7663 if (shear_image != (Image *) NULL) 7664 { 7665 *image=DestroyImage(*image); 7666 *image=shear_image; 7667 } 7668 CatchException(exception); 7669 XSetCursorState(display,windows,MagickFalse); 7670 if (windows->image.orphan != MagickFalse) 7671 break; 7672 windows->image.window_changes.width=(int) (*image)->columns; 7673 windows->image.window_changes.height=(int) (*image)->rows; 7674 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7675 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7676 break; 7677 } 7678 case RollCommand: 7679 { 7680 Image 7681 *roll_image; 7682 7683 static char 7684 geometry[MaxTextExtent] = "+2+2"; 7685 7686 /* 7687 Query user for the roll geometry. 7688 */ 7689 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7690 geometry); 7691 if (*geometry == '\0') 7692 break; 7693 /* 7694 Roll image. 7695 */ 7696 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7697 exception); 7698 XSetCursorState(display,windows,MagickTrue); 7699 XCheckRefreshWindows(display,windows); 7700 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7701 exception); 7702 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7703 exception); 7704 if (roll_image != (Image *) NULL) 7705 { 7706 *image=DestroyImage(*image); 7707 *image=roll_image; 7708 } 7709 CatchException(exception); 7710 XSetCursorState(display,windows,MagickFalse); 7711 if (windows->image.orphan != MagickFalse) 7712 break; 7713 windows->image.window_changes.width=(int) (*image)->columns; 7714 windows->image.window_changes.height=(int) (*image)->rows; 7715 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7716 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7717 break; 7718 } 7719 case TrimCommand: 7720 { 7721 static char 7722 fuzz[MaxTextExtent]; 7723 7724 /* 7725 Query user for the fuzz factor. 7726 */ 7727 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0* 7728 (*image)->fuzz/(QuantumRange+1.0)); 7729 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7730 if (*fuzz == '\0') 7731 break; 7732 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0); 7733 /* 7734 Trim image. 7735 */ 7736 status=XTrimImage(display,resource_info,windows,*image,exception); 7737 if (status == MagickFalse) 7738 { 7739 XNoticeWidget(display,windows,"Unable to trim X image", 7740 (*image)->filename); 7741 break; 7742 } 7743 break; 7744 } 7745 case HueCommand: 7746 { 7747 static char 7748 hue_percent[MaxTextExtent] = "110"; 7749 7750 /* 7751 Query user for percent hue change. 7752 */ 7753 (void) XDialogWidget(display,windows,"Apply", 7754 "Enter percent change in image hue (0-200):",hue_percent); 7755 if (*hue_percent == '\0') 7756 break; 7757 /* 7758 Vary the image hue. 7759 */ 7760 XSetCursorState(display,windows,MagickTrue); 7761 XCheckRefreshWindows(display,windows); 7762 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent); 7763 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7764 MaxTextExtent); 7765 (void) ModulateImage(*image,modulate_factors,exception); 7766 XSetCursorState(display,windows,MagickFalse); 7767 if (windows->image.orphan != MagickFalse) 7768 break; 7769 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7770 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7771 break; 7772 } 7773 case SaturationCommand: 7774 { 7775 static char 7776 saturation_percent[MaxTextExtent] = "110"; 7777 7778 /* 7779 Query user for percent saturation change. 7780 */ 7781 (void) XDialogWidget(display,windows,"Apply", 7782 "Enter percent change in color saturation (0-200):",saturation_percent); 7783 if (*saturation_percent == '\0') 7784 break; 7785 /* 7786 Vary color saturation. 7787 */ 7788 XSetCursorState(display,windows,MagickTrue); 7789 XCheckRefreshWindows(display,windows); 7790 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent); 7791 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7792 MaxTextExtent); 7793 (void) ModulateImage(*image,modulate_factors,exception); 7794 XSetCursorState(display,windows,MagickFalse); 7795 if (windows->image.orphan != MagickFalse) 7796 break; 7797 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7798 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7799 break; 7800 } 7801 case BrightnessCommand: 7802 { 7803 static char 7804 brightness_percent[MaxTextExtent] = "110"; 7805 7806 /* 7807 Query user for percent brightness change. 7808 */ 7809 (void) XDialogWidget(display,windows,"Apply", 7810 "Enter percent change in color brightness (0-200):",brightness_percent); 7811 if (*brightness_percent == '\0') 7812 break; 7813 /* 7814 Vary the color brightness. 7815 */ 7816 XSetCursorState(display,windows,MagickTrue); 7817 XCheckRefreshWindows(display,windows); 7818 (void) CopyMagickString(modulate_factors,brightness_percent, 7819 MaxTextExtent); 7820 (void) ModulateImage(*image,modulate_factors,exception); 7821 XSetCursorState(display,windows,MagickFalse); 7822 if (windows->image.orphan != MagickFalse) 7823 break; 7824 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7825 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7826 break; 7827 } 7828 case GammaCommand: 7829 { 7830 static char 7831 factor[MaxTextExtent] = "1.6"; 7832 7833 /* 7834 Query user for gamma value. 7835 */ 7836 (void) XDialogWidget(display,windows,"Gamma", 7837 "Enter gamma value (e.g. 1.2):",factor); 7838 if (*factor == '\0') 7839 break; 7840 /* 7841 Gamma correct image. 7842 */ 7843 XSetCursorState(display,windows,MagickTrue); 7844 XCheckRefreshWindows(display,windows); 7845 (void) GammaImage(*image,atof(factor),exception); 7846 XSetCursorState(display,windows,MagickFalse); 7847 if (windows->image.orphan != MagickFalse) 7848 break; 7849 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7850 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7851 break; 7852 } 7853 case SpiffCommand: 7854 { 7855 /* 7856 Sharpen the image contrast. 7857 */ 7858 XSetCursorState(display,windows,MagickTrue); 7859 XCheckRefreshWindows(display,windows); 7860 (void) ContrastImage(*image,MagickTrue,exception); 7861 XSetCursorState(display,windows,MagickFalse); 7862 if (windows->image.orphan != MagickFalse) 7863 break; 7864 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7865 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7866 break; 7867 } 7868 case DullCommand: 7869 { 7870 /* 7871 Dull the image contrast. 7872 */ 7873 XSetCursorState(display,windows,MagickTrue); 7874 XCheckRefreshWindows(display,windows); 7875 (void) ContrastImage(*image,MagickFalse,exception); 7876 XSetCursorState(display,windows,MagickFalse); 7877 if (windows->image.orphan != MagickFalse) 7878 break; 7879 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7880 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7881 break; 7882 } 7883 case ContrastStretchCommand: 7884 { 7885 double 7886 black_point, 7887 white_point; 7888 7889 static char 7890 levels[MaxTextExtent] = "1%"; 7891 7892 /* 7893 Query user for gamma value. 7894 */ 7895 (void) XDialogWidget(display,windows,"Contrast Stretch", 7896 "Enter black and white points:",levels); 7897 if (*levels == '\0') 7898 break; 7899 /* 7900 Contrast stretch image. 7901 */ 7902 XSetCursorState(display,windows,MagickTrue); 7903 XCheckRefreshWindows(display,windows); 7904 flags=ParseGeometry(levels,&geometry_info); 7905 black_point=geometry_info.rho; 7906 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7907 if ((flags & PercentValue) != 0) 7908 { 7909 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7910 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7911 } 7912 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point; 7913 (void) ContrastStretchImage(*image,black_point,white_point, 7914 exception); 7915 XSetCursorState(display,windows,MagickFalse); 7916 if (windows->image.orphan != MagickFalse) 7917 break; 7918 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7919 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7920 break; 7921 } 7922 case SigmoidalContrastCommand: 7923 { 7924 GeometryInfo 7925 geometry_info; 7926 7927 MagickStatusType 7928 flags; 7929 7930 static char 7931 levels[MaxTextExtent] = "3x50%"; 7932 7933 /* 7934 Query user for gamma value. 7935 */ 7936 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7937 "Enter contrast and midpoint:",levels); 7938 if (*levels == '\0') 7939 break; 7940 /* 7941 Contrast stretch image. 7942 */ 7943 XSetCursorState(display,windows,MagickTrue); 7944 XCheckRefreshWindows(display,windows); 7945 flags=ParseGeometry(levels,&geometry_info); 7946 if ((flags & SigmaValue) == 0) 7947 geometry_info.sigma=1.0*QuantumRange/2.0; 7948 if ((flags & PercentValue) != 0) 7949 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0; 7950 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho, 7951 geometry_info.sigma,exception); 7952 XSetCursorState(display,windows,MagickFalse); 7953 if (windows->image.orphan != MagickFalse) 7954 break; 7955 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7956 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7957 break; 7958 } 7959 case NormalizeCommand: 7960 { 7961 /* 7962 Perform histogram normalization on the image. 7963 */ 7964 XSetCursorState(display,windows,MagickTrue); 7965 XCheckRefreshWindows(display,windows); 7966 (void) NormalizeImage(*image,exception); 7967 XSetCursorState(display,windows,MagickFalse); 7968 if (windows->image.orphan != MagickFalse) 7969 break; 7970 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7971 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7972 break; 7973 } 7974 case EqualizeCommand: 7975 { 7976 /* 7977 Perform histogram equalization on the image. 7978 */ 7979 XSetCursorState(display,windows,MagickTrue); 7980 XCheckRefreshWindows(display,windows); 7981 (void) EqualizeImage(*image,exception); 7982 XSetCursorState(display,windows,MagickFalse); 7983 if (windows->image.orphan != MagickFalse) 7984 break; 7985 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7986 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7987 break; 7988 } 7989 case NegateCommand: 7990 { 7991 /* 7992 Negate colors in image. 7993 */ 7994 XSetCursorState(display,windows,MagickTrue); 7995 XCheckRefreshWindows(display,windows); 7996 (void) NegateImage(*image,MagickFalse,exception); 7997 XSetCursorState(display,windows,MagickFalse); 7998 if (windows->image.orphan != MagickFalse) 7999 break; 8000 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8001 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8002 break; 8003 } 8004 case GrayscaleCommand: 8005 { 8006 /* 8007 Convert image to grayscale. 8008 */ 8009 XSetCursorState(display,windows,MagickTrue); 8010 XCheckRefreshWindows(display,windows); 8011 (void) SetImageType(*image,(*image)->matte == MagickFalse ? 8012 GrayscaleType : GrayscaleMatteType,exception); 8013 XSetCursorState(display,windows,MagickFalse); 8014 if (windows->image.orphan != MagickFalse) 8015 break; 8016 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8017 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8018 break; 8019 } 8020 case MapCommand: 8021 { 8022 Image 8023 *affinity_image; 8024 8025 static char 8026 filename[MaxTextExtent] = "\0"; 8027 8028 /* 8029 Request image file name from user. 8030 */ 8031 XFileBrowserWidget(display,windows,"Map",filename); 8032 if (*filename == '\0') 8033 break; 8034 /* 8035 Map image. 8036 */ 8037 XSetCursorState(display,windows,MagickTrue); 8038 XCheckRefreshWindows(display,windows); 8039 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 8040 affinity_image=ReadImage(image_info,exception); 8041 if (affinity_image != (Image *) NULL) 8042 { 8043 (void) RemapImage(&quantize_info,*image,affinity_image,exception); 8044 affinity_image=DestroyImage(affinity_image); 8045 } 8046 CatchException(exception); 8047 XSetCursorState(display,windows,MagickFalse); 8048 if (windows->image.orphan != MagickFalse) 8049 break; 8050 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8051 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8052 break; 8053 } 8054 case QuantizeCommand: 8055 { 8056 int 8057 status; 8058 8059 static char 8060 colors[MaxTextExtent] = "256"; 8061 8062 /* 8063 Query user for maximum number of colors. 8064 */ 8065 status=XDialogWidget(display,windows,"Quantize", 8066 "Maximum number of colors:",colors); 8067 if (*colors == '\0') 8068 break; 8069 /* 8070 Color reduce the image. 8071 */ 8072 XSetCursorState(display,windows,MagickTrue); 8073 XCheckRefreshWindows(display,windows); 8074 quantize_info.number_colors=StringToUnsignedLong(colors); 8075 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse; 8076 (void) QuantizeImage(&quantize_info,*image,exception); 8077 XSetCursorState(display,windows,MagickFalse); 8078 if (windows->image.orphan != MagickFalse) 8079 break; 8080 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8081 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8082 break; 8083 } 8084 case DespeckleCommand: 8085 { 8086 Image 8087 *despeckle_image; 8088 8089 /* 8090 Despeckle image. 8091 */ 8092 XSetCursorState(display,windows,MagickTrue); 8093 XCheckRefreshWindows(display,windows); 8094 despeckle_image=DespeckleImage(*image,exception); 8095 if (despeckle_image != (Image *) NULL) 8096 { 8097 *image=DestroyImage(*image); 8098 *image=despeckle_image; 8099 } 8100 CatchException(exception); 8101 XSetCursorState(display,windows,MagickFalse); 8102 if (windows->image.orphan != MagickFalse) 8103 break; 8104 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8105 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8106 break; 8107 } 8108 case EmbossCommand: 8109 { 8110 Image 8111 *emboss_image; 8112 8113 static char 8114 radius[MaxTextExtent] = "0.0x1.0"; 8115 8116 /* 8117 Query user for emboss radius. 8118 */ 8119 (void) XDialogWidget(display,windows,"Emboss", 8120 "Enter the emboss radius and standard deviation:",radius); 8121 if (*radius == '\0') 8122 break; 8123 /* 8124 Reduce noise in the image. 8125 */ 8126 XSetCursorState(display,windows,MagickTrue); 8127 XCheckRefreshWindows(display,windows); 8128 flags=ParseGeometry(radius,&geometry_info); 8129 if ((flags & SigmaValue) == 0) 8130 geometry_info.sigma=1.0; 8131 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma, 8132 exception); 8133 if (emboss_image != (Image *) NULL) 8134 { 8135 *image=DestroyImage(*image); 8136 *image=emboss_image; 8137 } 8138 CatchException(exception); 8139 XSetCursorState(display,windows,MagickFalse); 8140 if (windows->image.orphan != MagickFalse) 8141 break; 8142 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8143 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8144 break; 8145 } 8146 case ReduceNoiseCommand: 8147 { 8148 Image 8149 *noise_image; 8150 8151 static char 8152 radius[MaxTextExtent] = "0"; 8153 8154 /* 8155 Query user for noise radius. 8156 */ 8157 (void) XDialogWidget(display,windows,"Reduce Noise", 8158 "Enter the noise radius:",radius); 8159 if (*radius == '\0') 8160 break; 8161 /* 8162 Reduce noise in the image. 8163 */ 8164 XSetCursorState(display,windows,MagickTrue); 8165 XCheckRefreshWindows(display,windows); 8166 flags=ParseGeometry(radius,&geometry_info); 8167 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t) 8168 geometry_info.rho,(size_t) geometry_info.rho,exception); 8169 if (noise_image != (Image *) NULL) 8170 { 8171 *image=DestroyImage(*image); 8172 *image=noise_image; 8173 } 8174 CatchException(exception); 8175 XSetCursorState(display,windows,MagickFalse); 8176 if (windows->image.orphan != MagickFalse) 8177 break; 8178 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8179 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8180 break; 8181 } 8182 case AddNoiseCommand: 8183 { 8184 char 8185 **noises; 8186 8187 Image 8188 *noise_image; 8189 8190 static char 8191 noise_type[MaxTextExtent] = "Gaussian"; 8192 8193 /* 8194 Add noise to the image. 8195 */ 8196 noises=GetCommandOptions(MagickNoiseOptions); 8197 if (noises == (char **) NULL) 8198 break; 8199 XListBrowserWidget(display,windows,&windows->widget, 8200 (const char **) noises,"Add Noise", 8201 "Select a type of noise to add to your image:",noise_type); 8202 noises=DestroyStringList(noises); 8203 if (*noise_type == '\0') 8204 break; 8205 XSetCursorState(display,windows,MagickTrue); 8206 XCheckRefreshWindows(display,windows); 8207 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption( 8208 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception); 8209 if (noise_image != (Image *) NULL) 8210 { 8211 *image=DestroyImage(*image); 8212 *image=noise_image; 8213 } 8214 CatchException(exception); 8215 XSetCursorState(display,windows,MagickFalse); 8216 if (windows->image.orphan != MagickFalse) 8217 break; 8218 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8219 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8220 break; 8221 } 8222 case SharpenCommand: 8223 { 8224 Image 8225 *sharp_image; 8226 8227 static char 8228 radius[MaxTextExtent] = "0.0x1.0"; 8229 8230 /* 8231 Query user for sharpen radius. 8232 */ 8233 (void) XDialogWidget(display,windows,"Sharpen", 8234 "Enter the sharpen radius and standard deviation:",radius); 8235 if (*radius == '\0') 8236 break; 8237 /* 8238 Sharpen image scanlines. 8239 */ 8240 XSetCursorState(display,windows,MagickTrue); 8241 XCheckRefreshWindows(display,windows); 8242 flags=ParseGeometry(radius,&geometry_info); 8243 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma, 8244 geometry_info.xi,exception); 8245 if (sharp_image != (Image *) NULL) 8246 { 8247 *image=DestroyImage(*image); 8248 *image=sharp_image; 8249 } 8250 CatchException(exception); 8251 XSetCursorState(display,windows,MagickFalse); 8252 if (windows->image.orphan != MagickFalse) 8253 break; 8254 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8255 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8256 break; 8257 } 8258 case BlurCommand: 8259 { 8260 Image 8261 *blur_image; 8262 8263 static char 8264 radius[MaxTextExtent] = "0.0x1.0"; 8265 8266 /* 8267 Query user for blur radius. 8268 */ 8269 (void) XDialogWidget(display,windows,"Blur", 8270 "Enter the blur radius and standard deviation:",radius); 8271 if (*radius == '\0') 8272 break; 8273 /* 8274 Blur an image. 8275 */ 8276 XSetCursorState(display,windows,MagickTrue); 8277 XCheckRefreshWindows(display,windows); 8278 flags=ParseGeometry(radius,&geometry_info); 8279 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma, 8280 geometry_info.xi,exception); 8281 if (blur_image != (Image *) NULL) 8282 { 8283 *image=DestroyImage(*image); 8284 *image=blur_image; 8285 } 8286 CatchException(exception); 8287 XSetCursorState(display,windows,MagickFalse); 8288 if (windows->image.orphan != MagickFalse) 8289 break; 8290 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8291 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8292 break; 8293 } 8294 case ThresholdCommand: 8295 { 8296 double 8297 threshold; 8298 8299 static char 8300 factor[MaxTextExtent] = "128"; 8301 8302 /* 8303 Query user for threshold value. 8304 */ 8305 (void) XDialogWidget(display,windows,"Threshold", 8306 "Enter threshold value:",factor); 8307 if (*factor == '\0') 8308 break; 8309 /* 8310 Gamma correct image. 8311 */ 8312 XSetCursorState(display,windows,MagickTrue); 8313 XCheckRefreshWindows(display,windows); 8314 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8315 (void) BilevelImage(*image,threshold,exception); 8316 XSetCursorState(display,windows,MagickFalse); 8317 if (windows->image.orphan != MagickFalse) 8318 break; 8319 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8320 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8321 break; 8322 } 8323 case EdgeDetectCommand: 8324 { 8325 Image 8326 *edge_image; 8327 8328 static char 8329 radius[MaxTextExtent] = "0"; 8330 8331 /* 8332 Query user for edge factor. 8333 */ 8334 (void) XDialogWidget(display,windows,"Detect Edges", 8335 "Enter the edge detect radius:",radius); 8336 if (*radius == '\0') 8337 break; 8338 /* 8339 Detect edge in image. 8340 */ 8341 XSetCursorState(display,windows,MagickTrue); 8342 XCheckRefreshWindows(display,windows); 8343 flags=ParseGeometry(radius,&geometry_info); 8344 edge_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8345 exception); 8346 if (edge_image != (Image *) NULL) 8347 { 8348 *image=DestroyImage(*image); 8349 *image=edge_image; 8350 } 8351 CatchException(exception); 8352 XSetCursorState(display,windows,MagickFalse); 8353 if (windows->image.orphan != MagickFalse) 8354 break; 8355 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8356 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8357 break; 8358 } 8359 case SpreadCommand: 8360 { 8361 Image 8362 *spread_image; 8363 8364 static char 8365 amount[MaxTextExtent] = "2"; 8366 8367 /* 8368 Query user for spread amount. 8369 */ 8370 (void) XDialogWidget(display,windows,"Spread", 8371 "Enter the displacement amount:",amount); 8372 if (*amount == '\0') 8373 break; 8374 /* 8375 Displace image pixels by a random amount. 8376 */ 8377 XSetCursorState(display,windows,MagickTrue); 8378 XCheckRefreshWindows(display,windows); 8379 flags=ParseGeometry(amount,&geometry_info); 8380 spread_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8381 exception); 8382 if (spread_image != (Image *) NULL) 8383 { 8384 *image=DestroyImage(*image); 8385 *image=spread_image; 8386 } 8387 CatchException(exception); 8388 XSetCursorState(display,windows,MagickFalse); 8389 if (windows->image.orphan != MagickFalse) 8390 break; 8391 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8392 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8393 break; 8394 } 8395 case ShadeCommand: 8396 { 8397 Image 8398 *shade_image; 8399 8400 int 8401 status; 8402 8403 static char 8404 geometry[MaxTextExtent] = "30x30"; 8405 8406 /* 8407 Query user for the shade geometry. 8408 */ 8409 status=XDialogWidget(display,windows,"Shade", 8410 "Enter the azimuth and elevation of the light source:",geometry); 8411 if (*geometry == '\0') 8412 break; 8413 /* 8414 Shade image pixels. 8415 */ 8416 XSetCursorState(display,windows,MagickTrue); 8417 XCheckRefreshWindows(display,windows); 8418 flags=ParseGeometry(geometry,&geometry_info); 8419 if ((flags & SigmaValue) == 0) 8420 geometry_info.sigma=1.0; 8421 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue, 8422 geometry_info.rho,geometry_info.sigma,exception); 8423 if (shade_image != (Image *) NULL) 8424 { 8425 *image=DestroyImage(*image); 8426 *image=shade_image; 8427 } 8428 CatchException(exception); 8429 XSetCursorState(display,windows,MagickFalse); 8430 if (windows->image.orphan != MagickFalse) 8431 break; 8432 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8433 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8434 break; 8435 } 8436 case RaiseCommand: 8437 { 8438 static char 8439 bevel_width[MaxTextExtent] = "10"; 8440 8441 /* 8442 Query user for bevel width. 8443 */ 8444 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8445 if (*bevel_width == '\0') 8446 break; 8447 /* 8448 Raise an image. 8449 */ 8450 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8451 exception); 8452 XSetCursorState(display,windows,MagickTrue); 8453 XCheckRefreshWindows(display,windows); 8454 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8455 exception); 8456 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception); 8457 XSetCursorState(display,windows,MagickFalse); 8458 if (windows->image.orphan != MagickFalse) 8459 break; 8460 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8461 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8462 break; 8463 } 8464 case SegmentCommand: 8465 { 8466 static char 8467 threshold[MaxTextExtent] = "1.0x1.5"; 8468 8469 /* 8470 Query user for smoothing threshold. 8471 */ 8472 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8473 threshold); 8474 if (*threshold == '\0') 8475 break; 8476 /* 8477 Segment an image. 8478 */ 8479 XSetCursorState(display,windows,MagickTrue); 8480 XCheckRefreshWindows(display,windows); 8481 flags=ParseGeometry(threshold,&geometry_info); 8482 if ((flags & SigmaValue) == 0) 8483 geometry_info.sigma=1.0; 8484 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho, 8485 geometry_info.sigma,exception); 8486 XSetCursorState(display,windows,MagickFalse); 8487 if (windows->image.orphan != MagickFalse) 8488 break; 8489 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8490 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8491 break; 8492 } 8493 case SepiaToneCommand: 8494 { 8495 double 8496 threshold; 8497 8498 Image 8499 *sepia_image; 8500 8501 static char 8502 factor[MaxTextExtent] = "80%"; 8503 8504 /* 8505 Query user for sepia-tone factor. 8506 */ 8507 (void) XDialogWidget(display,windows,"Sepia Tone", 8508 "Enter the sepia tone factor (0 - 99.9%):",factor); 8509 if (*factor == '\0') 8510 break; 8511 /* 8512 Sepia tone image pixels. 8513 */ 8514 XSetCursorState(display,windows,MagickTrue); 8515 XCheckRefreshWindows(display,windows); 8516 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8517 sepia_image=SepiaToneImage(*image,threshold,exception); 8518 if (sepia_image != (Image *) NULL) 8519 { 8520 *image=DestroyImage(*image); 8521 *image=sepia_image; 8522 } 8523 CatchException(exception); 8524 XSetCursorState(display,windows,MagickFalse); 8525 if (windows->image.orphan != MagickFalse) 8526 break; 8527 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8528 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8529 break; 8530 } 8531 case SolarizeCommand: 8532 { 8533 double 8534 threshold; 8535 8536 static char 8537 factor[MaxTextExtent] = "60%"; 8538 8539 /* 8540 Query user for solarize factor. 8541 */ 8542 (void) XDialogWidget(display,windows,"Solarize", 8543 "Enter the solarize factor (0 - 99.9%):",factor); 8544 if (*factor == '\0') 8545 break; 8546 /* 8547 Solarize image pixels. 8548 */ 8549 XSetCursorState(display,windows,MagickTrue); 8550 XCheckRefreshWindows(display,windows); 8551 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8552 (void) SolarizeImage(*image,threshold,exception); 8553 XSetCursorState(display,windows,MagickFalse); 8554 if (windows->image.orphan != MagickFalse) 8555 break; 8556 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8557 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8558 break; 8559 } 8560 case SwirlCommand: 8561 { 8562 Image 8563 *swirl_image; 8564 8565 static char 8566 degrees[MaxTextExtent] = "60"; 8567 8568 /* 8569 Query user for swirl angle. 8570 */ 8571 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8572 degrees); 8573 if (*degrees == '\0') 8574 break; 8575 /* 8576 Swirl image pixels about the center. 8577 */ 8578 XSetCursorState(display,windows,MagickTrue); 8579 XCheckRefreshWindows(display,windows); 8580 flags=ParseGeometry(degrees,&geometry_info); 8581 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate, 8582 exception); 8583 if (swirl_image != (Image *) NULL) 8584 { 8585 *image=DestroyImage(*image); 8586 *image=swirl_image; 8587 } 8588 CatchException(exception); 8589 XSetCursorState(display,windows,MagickFalse); 8590 if (windows->image.orphan != MagickFalse) 8591 break; 8592 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8593 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8594 break; 8595 } 8596 case ImplodeCommand: 8597 { 8598 Image 8599 *implode_image; 8600 8601 static char 8602 factor[MaxTextExtent] = "0.3"; 8603 8604 /* 8605 Query user for implode factor. 8606 */ 8607 (void) XDialogWidget(display,windows,"Implode", 8608 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8609 if (*factor == '\0') 8610 break; 8611 /* 8612 Implode image pixels about the center. 8613 */ 8614 XSetCursorState(display,windows,MagickTrue); 8615 XCheckRefreshWindows(display,windows); 8616 flags=ParseGeometry(factor,&geometry_info); 8617 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate, 8618 exception); 8619 if (implode_image != (Image *) NULL) 8620 { 8621 *image=DestroyImage(*image); 8622 *image=implode_image; 8623 } 8624 CatchException(exception); 8625 XSetCursorState(display,windows,MagickFalse); 8626 if (windows->image.orphan != MagickFalse) 8627 break; 8628 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8629 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8630 break; 8631 } 8632 case VignetteCommand: 8633 { 8634 Image 8635 *vignette_image; 8636 8637 static char 8638 geometry[MaxTextExtent] = "0x20"; 8639 8640 /* 8641 Query user for the vignette geometry. 8642 */ 8643 (void) XDialogWidget(display,windows,"Vignette", 8644 "Enter the radius, sigma, and x and y offsets:",geometry); 8645 if (*geometry == '\0') 8646 break; 8647 /* 8648 Soften the edges of the image in vignette style 8649 */ 8650 XSetCursorState(display,windows,MagickTrue); 8651 XCheckRefreshWindows(display,windows); 8652 flags=ParseGeometry(geometry,&geometry_info); 8653 if ((flags & SigmaValue) == 0) 8654 geometry_info.sigma=1.0; 8655 if ((flags & XiValue) == 0) 8656 geometry_info.xi=0.1*(*image)->columns; 8657 if ((flags & PsiValue) == 0) 8658 geometry_info.psi=0.1*(*image)->rows; 8659 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma, 8660 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi- 8661 0.5),exception); 8662 if (vignette_image != (Image *) NULL) 8663 { 8664 *image=DestroyImage(*image); 8665 *image=vignette_image; 8666 } 8667 CatchException(exception); 8668 XSetCursorState(display,windows,MagickFalse); 8669 if (windows->image.orphan != MagickFalse) 8670 break; 8671 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8672 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8673 break; 8674 } 8675 case WaveCommand: 8676 { 8677 Image 8678 *wave_image; 8679 8680 static char 8681 geometry[MaxTextExtent] = "25x150"; 8682 8683 /* 8684 Query user for the wave geometry. 8685 */ 8686 (void) XDialogWidget(display,windows,"Wave", 8687 "Enter the amplitude and length of the wave:",geometry); 8688 if (*geometry == '\0') 8689 break; 8690 /* 8691 Alter an image along a sine wave. 8692 */ 8693 XSetCursorState(display,windows,MagickTrue); 8694 XCheckRefreshWindows(display,windows); 8695 flags=ParseGeometry(geometry,&geometry_info); 8696 if ((flags & SigmaValue) == 0) 8697 geometry_info.sigma=1.0; 8698 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8699 (*image)->interpolate,exception); 8700 if (wave_image != (Image *) NULL) 8701 { 8702 *image=DestroyImage(*image); 8703 *image=wave_image; 8704 } 8705 CatchException(exception); 8706 XSetCursorState(display,windows,MagickFalse); 8707 if (windows->image.orphan != MagickFalse) 8708 break; 8709 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8710 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8711 break; 8712 } 8713 case OilPaintCommand: 8714 { 8715 Image 8716 *paint_image; 8717 8718 static char 8719 radius[MaxTextExtent] = "0"; 8720 8721 /* 8722 Query user for circular neighborhood radius. 8723 */ 8724 (void) XDialogWidget(display,windows,"Oil Paint", 8725 "Enter the mask radius:",radius); 8726 if (*radius == '\0') 8727 break; 8728 /* 8729 OilPaint image scanlines. 8730 */ 8731 XSetCursorState(display,windows,MagickTrue); 8732 XCheckRefreshWindows(display,windows); 8733 flags=ParseGeometry(radius,&geometry_info); 8734 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma, 8735 exception); 8736 if (paint_image != (Image *) NULL) 8737 { 8738 *image=DestroyImage(*image); 8739 *image=paint_image; 8740 } 8741 CatchException(exception); 8742 XSetCursorState(display,windows,MagickFalse); 8743 if (windows->image.orphan != MagickFalse) 8744 break; 8745 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8746 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8747 break; 8748 } 8749 case CharcoalDrawCommand: 8750 { 8751 Image 8752 *charcoal_image; 8753 8754 static char 8755 radius[MaxTextExtent] = "0x1"; 8756 8757 /* 8758 Query user for charcoal radius. 8759 */ 8760 (void) XDialogWidget(display,windows,"Charcoal Draw", 8761 "Enter the charcoal radius and sigma:",radius); 8762 if (*radius == '\0') 8763 break; 8764 /* 8765 Charcoal the image. 8766 */ 8767 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8768 exception); 8769 XSetCursorState(display,windows,MagickTrue); 8770 XCheckRefreshWindows(display,windows); 8771 flags=ParseGeometry(radius,&geometry_info); 8772 if ((flags & SigmaValue) == 0) 8773 geometry_info.sigma=geometry_info.rho; 8774 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8775 geometry_info.xi,exception); 8776 if (charcoal_image != (Image *) NULL) 8777 { 8778 *image=DestroyImage(*image); 8779 *image=charcoal_image; 8780 } 8781 CatchException(exception); 8782 XSetCursorState(display,windows,MagickFalse); 8783 if (windows->image.orphan != MagickFalse) 8784 break; 8785 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8786 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8787 break; 8788 } 8789 case AnnotateCommand: 8790 { 8791 /* 8792 Annotate the image with text. 8793 */ 8794 status=XAnnotateEditImage(display,resource_info,windows,*image,exception); 8795 if (status == MagickFalse) 8796 { 8797 XNoticeWidget(display,windows,"Unable to annotate X image", 8798 (*image)->filename); 8799 break; 8800 } 8801 break; 8802 } 8803 case DrawCommand: 8804 { 8805 /* 8806 Draw image. 8807 */ 8808 status=XDrawEditImage(display,resource_info,windows,image,exception); 8809 if (status == MagickFalse) 8810 { 8811 XNoticeWidget(display,windows,"Unable to draw on the X image", 8812 (*image)->filename); 8813 break; 8814 } 8815 break; 8816 } 8817 case ColorCommand: 8818 { 8819 /* 8820 Color edit. 8821 */ 8822 status=XColorEditImage(display,resource_info,windows,image,exception); 8823 if (status == MagickFalse) 8824 { 8825 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8826 (*image)->filename); 8827 break; 8828 } 8829 break; 8830 } 8831 case MatteCommand: 8832 { 8833 /* 8834 Matte edit. 8835 */ 8836 status=XMatteEditImage(display,resource_info,windows,image,exception); 8837 if (status == MagickFalse) 8838 { 8839 XNoticeWidget(display,windows,"Unable to matte edit X image", 8840 (*image)->filename); 8841 break; 8842 } 8843 break; 8844 } 8845 case CompositeCommand: 8846 { 8847 /* 8848 Composite image. 8849 */ 8850 status=XCompositeImage(display,resource_info,windows,*image, 8851 exception); 8852 if (status == MagickFalse) 8853 { 8854 XNoticeWidget(display,windows,"Unable to composite X image", 8855 (*image)->filename); 8856 break; 8857 } 8858 break; 8859 } 8860 case AddBorderCommand: 8861 { 8862 Image 8863 *border_image; 8864 8865 static char 8866 geometry[MaxTextExtent] = "6x6"; 8867 8868 /* 8869 Query user for border color and geometry. 8870 */ 8871 XColorBrowserWidget(display,windows,"Select",color); 8872 if (*color == '\0') 8873 break; 8874 (void) XDialogWidget(display,windows,"Add Border", 8875 "Enter border geometry:",geometry); 8876 if (*geometry == '\0') 8877 break; 8878 /* 8879 Add a border to the image. 8880 */ 8881 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8882 exception); 8883 XSetCursorState(display,windows,MagickTrue); 8884 XCheckRefreshWindows(display,windows); 8885 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color, 8886 exception); 8887 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8888 exception); 8889 border_image=BorderImage(*image,&page_geometry,(*image)->compose, 8890 exception); 8891 if (border_image != (Image *) NULL) 8892 { 8893 *image=DestroyImage(*image); 8894 *image=border_image; 8895 } 8896 CatchException(exception); 8897 XSetCursorState(display,windows,MagickFalse); 8898 if (windows->image.orphan != MagickFalse) 8899 break; 8900 windows->image.window_changes.width=(int) (*image)->columns; 8901 windows->image.window_changes.height=(int) (*image)->rows; 8902 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8903 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8904 break; 8905 } 8906 case AddFrameCommand: 8907 { 8908 FrameInfo 8909 frame_info; 8910 8911 Image 8912 *frame_image; 8913 8914 static char 8915 geometry[MaxTextExtent] = "6x6"; 8916 8917 /* 8918 Query user for frame color and geometry. 8919 */ 8920 XColorBrowserWidget(display,windows,"Select",color); 8921 if (*color == '\0') 8922 break; 8923 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8924 geometry); 8925 if (*geometry == '\0') 8926 break; 8927 /* 8928 Surround image with an ornamental border. 8929 */ 8930 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8931 exception); 8932 XSetCursorState(display,windows,MagickTrue); 8933 XCheckRefreshWindows(display,windows); 8934 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color, 8935 exception); 8936 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8937 exception); 8938 frame_info.width=page_geometry.width; 8939 frame_info.height=page_geometry.height; 8940 frame_info.outer_bevel=page_geometry.x; 8941 frame_info.inner_bevel=page_geometry.y; 8942 frame_info.x=(ssize_t) frame_info.width; 8943 frame_info.y=(ssize_t) frame_info.height; 8944 frame_info.width=(*image)->columns+2*frame_info.width; 8945 frame_info.height=(*image)->rows+2*frame_info.height; 8946 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception); 8947 if (frame_image != (Image *) NULL) 8948 { 8949 *image=DestroyImage(*image); 8950 *image=frame_image; 8951 } 8952 CatchException(exception); 8953 XSetCursorState(display,windows,MagickFalse); 8954 if (windows->image.orphan != MagickFalse) 8955 break; 8956 windows->image.window_changes.width=(int) (*image)->columns; 8957 windows->image.window_changes.height=(int) (*image)->rows; 8958 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8959 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8960 break; 8961 } 8962 case CommentCommand: 8963 { 8964 const char 8965 *value; 8966 8967 FILE 8968 *file; 8969 8970 int 8971 unique_file; 8972 8973 /* 8974 Edit image comment. 8975 */ 8976 unique_file=AcquireUniqueFileResource(image_info->filename); 8977 if (unique_file == -1) 8978 XNoticeWidget(display,windows,"Unable to edit image comment", 8979 image_info->filename); 8980 value=GetImageProperty(*image,"comment",exception); 8981 if (value == (char *) NULL) 8982 unique_file=close(unique_file)-1; 8983 else 8984 { 8985 register const char 8986 *p; 8987 8988 file=fdopen(unique_file,"w"); 8989 if (file == (FILE *) NULL) 8990 { 8991 XNoticeWidget(display,windows,"Unable to edit image comment", 8992 image_info->filename); 8993 break; 8994 } 8995 for (p=value; *p != '\0'; p++) 8996 (void) fputc((int) *p,file); 8997 (void) fputc('\n',file); 8998 (void) fclose(file); 8999 } 9000 XSetCursorState(display,windows,MagickTrue); 9001 XCheckRefreshWindows(display,windows); 9002 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 9003 exception); 9004 if (status == MagickFalse) 9005 XNoticeWidget(display,windows,"Unable to edit image comment", 9006 (char *) NULL); 9007 else 9008 { 9009 char 9010 *comment; 9011 9012 comment=FileToString(image_info->filename,~0UL,exception); 9013 if (comment != (char *) NULL) 9014 { 9015 (void) SetImageProperty(*image,"comment",comment,exception); 9016 (*image)->taint=MagickTrue; 9017 } 9018 } 9019 (void) RelinquishUniqueFileResource(image_info->filename); 9020 XSetCursorState(display,windows,MagickFalse); 9021 break; 9022 } 9023 case LaunchCommand: 9024 { 9025 /* 9026 Launch program. 9027 */ 9028 XSetCursorState(display,windows,MagickTrue); 9029 XCheckRefreshWindows(display,windows); 9030 (void) AcquireUniqueFilename(filename); 9031 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s", 9032 filename); 9033 status=WriteImage(image_info,*image,exception); 9034 if (status == MagickFalse) 9035 XNoticeWidget(display,windows,"Unable to launch image editor", 9036 (char *) NULL); 9037 else 9038 { 9039 nexus=ReadImage(resource_info->image_info,exception); 9040 CatchException(exception); 9041 XClientMessage(display,windows->image.id,windows->im_protocols, 9042 windows->im_next_image,CurrentTime); 9043 } 9044 (void) RelinquishUniqueFileResource(filename); 9045 XSetCursorState(display,windows,MagickFalse); 9046 break; 9047 } 9048 case RegionofInterestCommand: 9049 { 9050 /* 9051 Apply an image processing technique to a region of interest. 9052 */ 9053 (void) XROIImage(display,resource_info,windows,image,exception); 9054 break; 9055 } 9056 case InfoCommand: 9057 break; 9058 case ZoomCommand: 9059 { 9060 /* 9061 Zoom image. 9062 */ 9063 if (windows->magnify.mapped != MagickFalse) 9064 (void) XRaiseWindow(display,windows->magnify.id); 9065 else 9066 { 9067 /* 9068 Make magnify image. 9069 */ 9070 XSetCursorState(display,windows,MagickTrue); 9071 (void) XMapRaised(display,windows->magnify.id); 9072 XSetCursorState(display,windows,MagickFalse); 9073 } 9074 break; 9075 } 9076 case ShowPreviewCommand: 9077 { 9078 char 9079 **previews; 9080 9081 Image 9082 *preview_image; 9083 9084 static char 9085 preview_type[MaxTextExtent] = "Gamma"; 9086 9087 /* 9088 Select preview type from menu. 9089 */ 9090 previews=GetCommandOptions(MagickPreviewOptions); 9091 if (previews == (char **) NULL) 9092 break; 9093 XListBrowserWidget(display,windows,&windows->widget, 9094 (const char **) previews,"Preview", 9095 "Select an enhancement, effect, or F/X:",preview_type); 9096 previews=DestroyStringList(previews); 9097 if (*preview_type == '\0') 9098 break; 9099 /* 9100 Show image preview. 9101 */ 9102 XSetCursorState(display,windows,MagickTrue); 9103 XCheckRefreshWindows(display,windows); 9104 image_info->preview_type=(PreviewType) 9105 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type); 9106 image_info->group=(ssize_t) windows->image.id; 9107 (void) DeleteImageProperty(*image,"label"); 9108 (void) SetImageProperty(*image,"label","Preview",exception); 9109 (void) AcquireUniqueFilename(filename); 9110 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s", 9111 filename); 9112 status=WriteImage(image_info,*image,exception); 9113 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9114 preview_image=ReadImage(image_info,exception); 9115 (void) RelinquishUniqueFileResource(filename); 9116 if (preview_image == (Image *) NULL) 9117 break; 9118 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s", 9119 filename); 9120 status=WriteImage(image_info,preview_image,exception); 9121 preview_image=DestroyImage(preview_image); 9122 if (status == MagickFalse) 9123 XNoticeWidget(display,windows,"Unable to show image preview", 9124 (*image)->filename); 9125 XDelay(display,1500); 9126 XSetCursorState(display,windows,MagickFalse); 9127 break; 9128 } 9129 case ShowHistogramCommand: 9130 { 9131 Image 9132 *histogram_image; 9133 9134 /* 9135 Show image histogram. 9136 */ 9137 XSetCursorState(display,windows,MagickTrue); 9138 XCheckRefreshWindows(display,windows); 9139 image_info->group=(ssize_t) windows->image.id; 9140 (void) DeleteImageProperty(*image,"label"); 9141 (void) SetImageProperty(*image,"label","Histogram",exception); 9142 (void) AcquireUniqueFilename(filename); 9143 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s", 9144 filename); 9145 status=WriteImage(image_info,*image,exception); 9146 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9147 histogram_image=ReadImage(image_info,exception); 9148 (void) RelinquishUniqueFileResource(filename); 9149 if (histogram_image == (Image *) NULL) 9150 break; 9151 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent, 9152 "show:%s",filename); 9153 status=WriteImage(image_info,histogram_image,exception); 9154 histogram_image=DestroyImage(histogram_image); 9155 if (status == MagickFalse) 9156 XNoticeWidget(display,windows,"Unable to show histogram", 9157 (*image)->filename); 9158 XDelay(display,1500); 9159 XSetCursorState(display,windows,MagickFalse); 9160 break; 9161 } 9162 case ShowMatteCommand: 9163 { 9164 Image 9165 *matte_image; 9166 9167 if ((*image)->matte == MagickFalse) 9168 { 9169 XNoticeWidget(display,windows, 9170 "Image does not have any matte information",(*image)->filename); 9171 break; 9172 } 9173 /* 9174 Show image matte. 9175 */ 9176 XSetCursorState(display,windows,MagickTrue); 9177 XCheckRefreshWindows(display,windows); 9178 image_info->group=(ssize_t) windows->image.id; 9179 (void) DeleteImageProperty(*image,"label"); 9180 (void) SetImageProperty(*image,"label","Matte",exception); 9181 (void) AcquireUniqueFilename(filename); 9182 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s", 9183 filename); 9184 status=WriteImage(image_info,*image,exception); 9185 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9186 matte_image=ReadImage(image_info,exception); 9187 (void) RelinquishUniqueFileResource(filename); 9188 if (matte_image == (Image *) NULL) 9189 break; 9190 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s", 9191 filename); 9192 status=WriteImage(image_info,matte_image,exception); 9193 matte_image=DestroyImage(matte_image); 9194 if (status == MagickFalse) 9195 XNoticeWidget(display,windows,"Unable to show matte", 9196 (*image)->filename); 9197 XDelay(display,1500); 9198 XSetCursorState(display,windows,MagickFalse); 9199 break; 9200 } 9201 case BackgroundCommand: 9202 { 9203 /* 9204 Background image. 9205 */ 9206 status=XBackgroundImage(display,resource_info,windows,image,exception); 9207 if (status == MagickFalse) 9208 break; 9209 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9210 if (nexus != (Image *) NULL) 9211 XClientMessage(display,windows->image.id,windows->im_protocols, 9212 windows->im_next_image,CurrentTime); 9213 break; 9214 } 9215 case SlideShowCommand: 9216 { 9217 static char 9218 delay[MaxTextExtent] = "5"; 9219 9220 /* 9221 Display next image after pausing. 9222 */ 9223 (void) XDialogWidget(display,windows,"Slide Show", 9224 "Pause how many 1/100ths of a second between images:",delay); 9225 if (*delay == '\0') 9226 break; 9227 resource_info->delay=StringToUnsignedLong(delay); 9228 XClientMessage(display,windows->image.id,windows->im_protocols, 9229 windows->im_next_image,CurrentTime); 9230 break; 9231 } 9232 case PreferencesCommand: 9233 { 9234 /* 9235 Set user preferences. 9236 */ 9237 status=XPreferencesWidget(display,resource_info,windows); 9238 if (status == MagickFalse) 9239 break; 9240 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9241 if (nexus != (Image *) NULL) 9242 XClientMessage(display,windows->image.id,windows->im_protocols, 9243 windows->im_next_image,CurrentTime); 9244 break; 9245 } 9246 case HelpCommand: 9247 { 9248 /* 9249 User requested help. 9250 */ 9251 XTextViewWidget(display,resource_info,windows,MagickFalse, 9252 "Help Viewer - Display",DisplayHelp); 9253 break; 9254 } 9255 case BrowseDocumentationCommand: 9256 { 9257 Atom 9258 mozilla_atom; 9259 9260 Window 9261 mozilla_window, 9262 root_window; 9263 9264 /* 9265 Browse the ImageMagick documentation. 9266 */ 9267 root_window=XRootWindow(display,XDefaultScreen(display)); 9268 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); 9269 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); 9270 if (mozilla_window != (Window) NULL) 9271 { 9272 char 9273 command[MaxTextExtent], 9274 *url; 9275 9276 /* 9277 Display documentation using Netscape remote control. 9278 */ 9279 url=GetMagickHomeURL(); 9280 (void) FormatLocaleString(command,MaxTextExtent, 9281 "openurl(%s,new-tab)",url); 9282 url=DestroyString(url); 9283 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); 9284 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING, 9285 8,PropModeReplace,(unsigned char *) command,(int) strlen(command)); 9286 XSetCursorState(display,windows,MagickFalse); 9287 break; 9288 } 9289 XSetCursorState(display,windows,MagickTrue); 9290 XCheckRefreshWindows(display,windows); 9291 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL, 9292 exception); 9293 if (status == MagickFalse) 9294 XNoticeWidget(display,windows,"Unable to browse documentation", 9295 (char *) NULL); 9296 XDelay(display,1500); 9297 XSetCursorState(display,windows,MagickFalse); 9298 break; 9299 } 9300 case VersionCommand: 9301 { 9302 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), 9303 GetMagickCopyright()); 9304 break; 9305 } 9306 case SaveToUndoBufferCommand: 9307 break; 9308 default: 9309 { 9310 (void) XBell(display,0); 9311 break; 9312 } 9313 } 9314 image_info=DestroyImageInfo(image_info); 9315 return(nexus); 9316} 9317 9318/* 9319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9320% % 9321% % 9322% % 9323+ X M a g n i f y I m a g e % 9324% % 9325% % 9326% % 9327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9328% 9329% XMagnifyImage() magnifies portions of the image as indicated by the pointer. 9330% The magnified portion is displayed in a separate window. 9331% 9332% The format of the XMagnifyImage method is: 9333% 9334% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9335% ExceptionInfo *exception) 9336% 9337% A description of each parameter follows: 9338% 9339% o display: Specifies a connection to an X server; returned from 9340% XOpenDisplay. 9341% 9342% o windows: Specifies a pointer to a XWindows structure. 9343% 9344% o event: Specifies a pointer to a XEvent structure. If it is NULL, 9345% the entire image is refreshed. 9346% 9347% o exception: return any errors or warnings in this structure. 9348% 9349*/ 9350static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9351 ExceptionInfo *exception) 9352{ 9353 char 9354 text[MaxTextExtent]; 9355 9356 register int 9357 x, 9358 y; 9359 9360 size_t 9361 state; 9362 9363 /* 9364 Update magnified image until the mouse button is released. 9365 */ 9366 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor); 9367 state=DefaultState; 9368 x=event->xbutton.x; 9369 y=event->xbutton.y; 9370 windows->magnify.x=(int) windows->image.x+x; 9371 windows->magnify.y=(int) windows->image.y+y; 9372 do 9373 { 9374 /* 9375 Map and unmap Info widget as text cursor crosses its boundaries. 9376 */ 9377 if (windows->info.mapped != MagickFalse) 9378 { 9379 if ((x < (int) (windows->info.x+windows->info.width)) && 9380 (y < (int) (windows->info.y+windows->info.height))) 9381 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 9382 } 9383 else 9384 if ((x > (int) (windows->info.x+windows->info.width)) || 9385 (y > (int) (windows->info.y+windows->info.height))) 9386 (void) XMapWindow(display,windows->info.id); 9387 if (windows->info.mapped != MagickFalse) 9388 { 9389 /* 9390 Display pointer position. 9391 */ 9392 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9393 windows->magnify.x,windows->magnify.y); 9394 XInfoWidget(display,windows,text); 9395 } 9396 /* 9397 Wait for next event. 9398 */ 9399 XScreenEvent(display,windows,event,exception); 9400 switch (event->type) 9401 { 9402 case ButtonPress: 9403 break; 9404 case ButtonRelease: 9405 { 9406 /* 9407 User has finished magnifying image. 9408 */ 9409 x=event->xbutton.x; 9410 y=event->xbutton.y; 9411 state|=ExitState; 9412 break; 9413 } 9414 case Expose: 9415 break; 9416 case MotionNotify: 9417 { 9418 x=event->xmotion.x; 9419 y=event->xmotion.y; 9420 break; 9421 } 9422 default: 9423 break; 9424 } 9425 /* 9426 Check boundary conditions. 9427 */ 9428 if (x < 0) 9429 x=0; 9430 else 9431 if (x >= (int) windows->image.width) 9432 x=(int) windows->image.width-1; 9433 if (y < 0) 9434 y=0; 9435 else 9436 if (y >= (int) windows->image.height) 9437 y=(int) windows->image.height-1; 9438 } while ((state & ExitState) == 0); 9439 /* 9440 Display magnified image. 9441 */ 9442 XSetCursorState(display,windows,MagickFalse); 9443} 9444 9445/* 9446%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9447% % 9448% % 9449% % 9450+ X M a g n i f y W i n d o w C o m m a n d % 9451% % 9452% % 9453% % 9454%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9455% 9456% XMagnifyWindowCommand() moves the image within an Magnify window by one 9457% pixel as specified by the key symbol. 9458% 9459% The format of the XMagnifyWindowCommand method is: 9460% 9461% void XMagnifyWindowCommand(Display *display,XWindows *windows, 9462% const MagickStatusType state,const KeySym key_symbol, 9463% ExceptionInfo *exception) 9464% 9465% A description of each parameter follows: 9466% 9467% o display: Specifies a connection to an X server; returned from 9468% XOpenDisplay. 9469% 9470% o windows: Specifies a pointer to a XWindows structure. 9471% 9472% o state: key mask. 9473% 9474% o key_symbol: Specifies a KeySym which indicates which side of the image 9475% to trim. 9476% 9477% o exception: return any errors or warnings in this structure. 9478% 9479*/ 9480static void XMagnifyWindowCommand(Display *display,XWindows *windows, 9481 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception) 9482{ 9483 unsigned int 9484 quantum; 9485 9486 /* 9487 User specified a magnify factor or position. 9488 */ 9489 quantum=1; 9490 if ((state & Mod1Mask) != 0) 9491 quantum=10; 9492 switch ((int) key_symbol) 9493 { 9494 case QuitCommand: 9495 { 9496 (void) XWithdrawWindow(display,windows->magnify.id, 9497 windows->magnify.screen); 9498 break; 9499 } 9500 case XK_Home: 9501 case XK_KP_Home: 9502 { 9503 windows->magnify.x=(int) windows->image.width/2; 9504 windows->magnify.y=(int) windows->image.height/2; 9505 break; 9506 } 9507 case XK_Left: 9508 case XK_KP_Left: 9509 { 9510 if (windows->magnify.x > 0) 9511 windows->magnify.x-=quantum; 9512 break; 9513 } 9514 case XK_Up: 9515 case XK_KP_Up: 9516 { 9517 if (windows->magnify.y > 0) 9518 windows->magnify.y-=quantum; 9519 break; 9520 } 9521 case XK_Right: 9522 case XK_KP_Right: 9523 { 9524 if (windows->magnify.x < (int) (windows->image.ximage->width-1)) 9525 windows->magnify.x+=quantum; 9526 break; 9527 } 9528 case XK_Down: 9529 case XK_KP_Down: 9530 { 9531 if (windows->magnify.y < (int) (windows->image.ximage->height-1)) 9532 windows->magnify.y+=quantum; 9533 break; 9534 } 9535 case XK_0: 9536 case XK_1: 9537 case XK_2: 9538 case XK_3: 9539 case XK_4: 9540 case XK_5: 9541 case XK_6: 9542 case XK_7: 9543 case XK_8: 9544 case XK_9: 9545 { 9546 windows->magnify.data=(key_symbol-XK_0); 9547 break; 9548 } 9549 case XK_KP_0: 9550 case XK_KP_1: 9551 case XK_KP_2: 9552 case XK_KP_3: 9553 case XK_KP_4: 9554 case XK_KP_5: 9555 case XK_KP_6: 9556 case XK_KP_7: 9557 case XK_KP_8: 9558 case XK_KP_9: 9559 { 9560 windows->magnify.data=(key_symbol-XK_KP_0); 9561 break; 9562 } 9563 default: 9564 break; 9565 } 9566 XMakeMagnifyImage(display,windows,exception); 9567} 9568 9569/* 9570%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9571% % 9572% % 9573% % 9574+ X M a k e P a n I m a g e % 9575% % 9576% % 9577% % 9578%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9579% 9580% XMakePanImage() creates a thumbnail of the image and displays it in the Pan 9581% icon window. 9582% 9583% The format of the XMakePanImage method is: 9584% 9585% void XMakePanImage(Display *display,XResourceInfo *resource_info, 9586% XWindows *windows,Image *image,ExceptionInfo *exception) 9587% 9588% A description of each parameter follows: 9589% 9590% o display: Specifies a connection to an X server; returned from 9591% XOpenDisplay. 9592% 9593% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9594% 9595% o windows: Specifies a pointer to a XWindows structure. 9596% 9597% o image: the image. 9598% 9599% o exception: return any errors or warnings in this structure. 9600% 9601*/ 9602static void XMakePanImage(Display *display,XResourceInfo *resource_info, 9603 XWindows *windows,Image *image,ExceptionInfo *exception) 9604{ 9605 MagickStatusType 9606 status; 9607 9608 /* 9609 Create and display image for panning icon. 9610 */ 9611 XSetCursorState(display,windows,MagickTrue); 9612 XCheckRefreshWindows(display,windows); 9613 windows->pan.x=(int) windows->image.x; 9614 windows->pan.y=(int) windows->image.y; 9615 status=XMakeImage(display,resource_info,&windows->pan,image, 9616 windows->pan.width,windows->pan.height,exception); 9617 if (status == MagickFalse) 9618 ThrowXWindowFatalException(ResourceLimitError, 9619 "MemoryAllocationFailed",image->filename); 9620 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 9621 windows->pan.pixmap); 9622 (void) XClearWindow(display,windows->pan.id); 9623 XDrawPanRectangle(display,windows); 9624 XSetCursorState(display,windows,MagickFalse); 9625} 9626 9627/* 9628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9629% % 9630% % 9631% % 9632+ X M a t t a E d i t I m a g e % 9633% % 9634% % 9635% % 9636%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9637% 9638% XMatteEditImage() allows the user to interactively change the Matte channel 9639% of an image. If the image is PseudoClass it is promoted to DirectClass 9640% before the matte information is stored. 9641% 9642% The format of the XMatteEditImage method is: 9643% 9644% MagickBooleanType XMatteEditImage(Display *display, 9645% XResourceInfo *resource_info,XWindows *windows,Image **image, 9646% ExceptionInfo *exception) 9647% 9648% A description of each parameter follows: 9649% 9650% o display: Specifies a connection to an X server; returned from 9651% XOpenDisplay. 9652% 9653% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9654% 9655% o windows: Specifies a pointer to a XWindows structure. 9656% 9657% o image: the image; returned from ReadImage. 9658% 9659% o exception: return any errors or warnings in this structure. 9660% 9661*/ 9662static MagickBooleanType XMatteEditImage(Display *display, 9663 XResourceInfo *resource_info,XWindows *windows,Image **image, 9664 ExceptionInfo *exception) 9665{ 9666 static char 9667 matte[MaxTextExtent] = "0"; 9668 9669 static const char 9670 *MatteEditMenu[] = 9671 { 9672 "Method", 9673 "Border Color", 9674 "Fuzz", 9675 "Matte Value", 9676 "Undo", 9677 "Help", 9678 "Dismiss", 9679 (char *) NULL 9680 }; 9681 9682 static const ModeType 9683 MatteEditCommands[] = 9684 { 9685 MatteEditMethod, 9686 MatteEditBorderCommand, 9687 MatteEditFuzzCommand, 9688 MatteEditValueCommand, 9689 MatteEditUndoCommand, 9690 MatteEditHelpCommand, 9691 MatteEditDismissCommand 9692 }; 9693 9694 static PaintMethod 9695 method = PointMethod; 9696 9697 static XColor 9698 border_color = { 0, 0, 0, 0, 0, 0 }; 9699 9700 char 9701 command[MaxTextExtent], 9702 text[MaxTextExtent]; 9703 9704 Cursor 9705 cursor; 9706 9707 int 9708 entry, 9709 id, 9710 x, 9711 x_offset, 9712 y, 9713 y_offset; 9714 9715 register int 9716 i; 9717 9718 register Quantum 9719 *q; 9720 9721 unsigned int 9722 height, 9723 width; 9724 9725 size_t 9726 state; 9727 9728 XEvent 9729 event; 9730 9731 /* 9732 Map Command widget. 9733 */ 9734 (void) CloneString(&windows->command.name,"Matte Edit"); 9735 windows->command.data=4; 9736 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL); 9737 (void) XMapRaised(display,windows->command.id); 9738 XClientMessage(display,windows->image.id,windows->im_protocols, 9739 windows->im_update_widget,CurrentTime); 9740 /* 9741 Make cursor. 9742 */ 9743 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 9744 resource_info->background_color,resource_info->foreground_color); 9745 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9746 /* 9747 Track pointer until button 1 is pressed. 9748 */ 9749 XQueryPosition(display,windows->image.id,&x,&y); 9750 (void) XSelectInput(display,windows->image.id, 9751 windows->image.attributes.event_mask | PointerMotionMask); 9752 state=DefaultState; 9753 do 9754 { 9755 if (windows->info.mapped != MagickFalse) 9756 { 9757 /* 9758 Display pointer position. 9759 */ 9760 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9761 x+windows->image.x,y+windows->image.y); 9762 XInfoWidget(display,windows,text); 9763 } 9764 /* 9765 Wait for next event. 9766 */ 9767 XScreenEvent(display,windows,&event,exception); 9768 if (event.xany.window == windows->command.id) 9769 { 9770 /* 9771 Select a command from the Command widget. 9772 */ 9773 id=XCommandWidget(display,windows,MatteEditMenu,&event); 9774 if (id < 0) 9775 { 9776 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9777 continue; 9778 } 9779 switch (MatteEditCommands[id]) 9780 { 9781 case MatteEditMethod: 9782 { 9783 char 9784 **methods; 9785 9786 /* 9787 Select a method from the pop-up menu. 9788 */ 9789 methods=GetCommandOptions(MagickMethodOptions); 9790 if (methods == (char **) NULL) 9791 break; 9792 entry=XMenuWidget(display,windows,MatteEditMenu[id], 9793 (const char **) methods,command); 9794 if (entry >= 0) 9795 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 9796 MagickFalse,methods[entry]); 9797 methods=DestroyStringList(methods); 9798 break; 9799 } 9800 case MatteEditBorderCommand: 9801 { 9802 const char 9803 *ColorMenu[MaxNumberPens]; 9804 9805 int 9806 pen_number; 9807 9808 /* 9809 Initialize menu selections. 9810 */ 9811 for (i=0; i < (int) (MaxNumberPens-2); i++) 9812 ColorMenu[i]=resource_info->pen_colors[i]; 9813 ColorMenu[MaxNumberPens-2]="Browser..."; 9814 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 9815 /* 9816 Select a pen color from the pop-up menu. 9817 */ 9818 pen_number=XMenuWidget(display,windows,MatteEditMenu[id], 9819 (const char **) ColorMenu,command); 9820 if (pen_number < 0) 9821 break; 9822 if (pen_number == (MaxNumberPens-2)) 9823 { 9824 static char 9825 color_name[MaxTextExtent] = "gray"; 9826 9827 /* 9828 Select a pen color from a dialog. 9829 */ 9830 resource_info->pen_colors[pen_number]=color_name; 9831 XColorBrowserWidget(display,windows,"Select",color_name); 9832 if (*color_name == '\0') 9833 break; 9834 } 9835 /* 9836 Set border color. 9837 */ 9838 (void) XParseColor(display,windows->map_info->colormap, 9839 resource_info->pen_colors[pen_number],&border_color); 9840 break; 9841 } 9842 case MatteEditFuzzCommand: 9843 { 9844 static char 9845 fuzz[MaxTextExtent]; 9846 9847 static const char 9848 *FuzzMenu[] = 9849 { 9850 "0%", 9851 "2%", 9852 "5%", 9853 "10%", 9854 "15%", 9855 "Dialog...", 9856 (char *) NULL, 9857 }; 9858 9859 /* 9860 Select a command from the pop-up menu. 9861 */ 9862 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu, 9863 command); 9864 if (entry < 0) 9865 break; 9866 if (entry != 5) 9867 { 9868 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 9869 QuantumRange+1.0); 9870 break; 9871 } 9872 (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 9873 (void) XDialogWidget(display,windows,"Ok", 9874 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 9875 if (*fuzz == '\0') 9876 break; 9877 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 9878 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 9879 1.0); 9880 break; 9881 } 9882 case MatteEditValueCommand: 9883 { 9884 static char 9885 message[MaxTextExtent]; 9886 9887 static const char 9888 *MatteMenu[] = 9889 { 9890 "Opaque", 9891 "Transparent", 9892 "Dialog...", 9893 (char *) NULL, 9894 }; 9895 9896 /* 9897 Select a command from the pop-up menu. 9898 */ 9899 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu, 9900 command); 9901 if (entry < 0) 9902 break; 9903 if (entry != 2) 9904 { 9905 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9906 OpaqueAlpha); 9907 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9908 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9909 (Quantum) TransparentAlpha); 9910 break; 9911 } 9912 (void) FormatLocaleString(message,MaxTextExtent, 9913 "Enter matte value (0 - " QuantumFormat "):",(Quantum) 9914 QuantumRange); 9915 (void) XDialogWidget(display,windows,"Matte",message,matte); 9916 if (*matte == '\0') 9917 break; 9918 break; 9919 } 9920 case MatteEditUndoCommand: 9921 { 9922 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 9923 image,exception); 9924 break; 9925 } 9926 case MatteEditHelpCommand: 9927 { 9928 XTextViewWidget(display,resource_info,windows,MagickFalse, 9929 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9930 break; 9931 } 9932 case MatteEditDismissCommand: 9933 { 9934 /* 9935 Prematurely exit. 9936 */ 9937 state|=EscapeState; 9938 state|=ExitState; 9939 break; 9940 } 9941 default: 9942 break; 9943 } 9944 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9945 continue; 9946 } 9947 switch (event.type) 9948 { 9949 case ButtonPress: 9950 { 9951 if (event.xbutton.button != Button1) 9952 break; 9953 if ((event.xbutton.window != windows->image.id) && 9954 (event.xbutton.window != windows->magnify.id)) 9955 break; 9956 /* 9957 Update matte data. 9958 */ 9959 x=event.xbutton.x; 9960 y=event.xbutton.y; 9961 (void) XMagickCommand(display,resource_info,windows, 9962 SaveToUndoBufferCommand,image,exception); 9963 state|=UpdateConfigurationState; 9964 break; 9965 } 9966 case ButtonRelease: 9967 { 9968 if (event.xbutton.button != Button1) 9969 break; 9970 if ((event.xbutton.window != windows->image.id) && 9971 (event.xbutton.window != windows->magnify.id)) 9972 break; 9973 /* 9974 Update colormap information. 9975 */ 9976 x=event.xbutton.x; 9977 y=event.xbutton.y; 9978 XConfigureImageColormap(display,resource_info,windows,*image,exception); 9979 (void) XConfigureImage(display,resource_info,windows,*image,exception); 9980 XInfoWidget(display,windows,text); 9981 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9982 state&=(~UpdateConfigurationState); 9983 break; 9984 } 9985 case Expose: 9986 break; 9987 case KeyPress: 9988 { 9989 char 9990 command[MaxTextExtent]; 9991 9992 KeySym 9993 key_symbol; 9994 9995 if (event.xkey.window == windows->magnify.id) 9996 { 9997 Window 9998 window; 9999 10000 window=windows->magnify.id; 10001 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 10002 } 10003 if (event.xkey.window != windows->image.id) 10004 break; 10005 /* 10006 Respond to a user key press. 10007 */ 10008 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 10009 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10010 switch ((int) key_symbol) 10011 { 10012 case XK_Escape: 10013 case XK_F20: 10014 { 10015 /* 10016 Prematurely exit. 10017 */ 10018 state|=ExitState; 10019 break; 10020 } 10021 case XK_F1: 10022 case XK_Help: 10023 { 10024 XTextViewWidget(display,resource_info,windows,MagickFalse, 10025 "Help Viewer - Matte Edit",ImageMatteEditHelp); 10026 break; 10027 } 10028 default: 10029 { 10030 (void) XBell(display,0); 10031 break; 10032 } 10033 } 10034 break; 10035 } 10036 case MotionNotify: 10037 { 10038 /* 10039 Map and unmap Info widget as cursor crosses its boundaries. 10040 */ 10041 x=event.xmotion.x; 10042 y=event.xmotion.y; 10043 if (windows->info.mapped != MagickFalse) 10044 { 10045 if ((x < (int) (windows->info.x+windows->info.width)) && 10046 (y < (int) (windows->info.y+windows->info.height))) 10047 (void) XWithdrawWindow(display,windows->info.id, 10048 windows->info.screen); 10049 } 10050 else 10051 if ((x > (int) (windows->info.x+windows->info.width)) || 10052 (y > (int) (windows->info.y+windows->info.height))) 10053 (void) XMapWindow(display,windows->info.id); 10054 break; 10055 } 10056 default: 10057 break; 10058 } 10059 if (event.xany.window == windows->magnify.id) 10060 { 10061 x=windows->magnify.x-windows->image.x; 10062 y=windows->magnify.y-windows->image.y; 10063 } 10064 x_offset=x; 10065 y_offset=y; 10066 if ((state & UpdateConfigurationState) != 0) 10067 { 10068 CacheView 10069 *image_view; 10070 10071 int 10072 x, 10073 y; 10074 10075 /* 10076 Matte edit is relative to image configuration. 10077 */ 10078 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 10079 MagickTrue); 10080 XPutPixel(windows->image.ximage,x_offset,y_offset, 10081 windows->pixel_info->background_color.pixel); 10082 width=(unsigned int) (*image)->columns; 10083 height=(unsigned int) (*image)->rows; 10084 x=0; 10085 y=0; 10086 if (windows->image.crop_geometry != (char *) NULL) 10087 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width, 10088 &height); 10089 x_offset=(int) (width*(windows->image.x+x_offset)/ 10090 windows->image.ximage->width+x); 10091 y_offset=(int) (height*(windows->image.y+y_offset)/ 10092 windows->image.ximage->height+y); 10093 if ((x_offset < 0) || (y_offset < 0)) 10094 continue; 10095 if ((x_offset >= (int) (*image)->columns) || 10096 (y_offset >= (int) (*image)->rows)) 10097 continue; 10098 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10099 return(MagickFalse); 10100 (*image)->matte=MagickTrue; 10101 image_view=AcquireCacheView(*image); 10102 switch (method) 10103 { 10104 case PointMethod: 10105 default: 10106 { 10107 /* 10108 Update matte information using point algorithm. 10109 */ 10110 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset, 10111 (ssize_t) y_offset,1,1,exception); 10112 if (q == (Quantum *) NULL) 10113 break; 10114 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10115 (void) SyncCacheViewAuthenticPixels(image_view,exception); 10116 break; 10117 } 10118 case ReplaceMethod: 10119 { 10120 PixelInfo 10121 pixel, 10122 target; 10123 10124 Quantum 10125 virtual_pixel[CompositePixelChannel]; 10126 10127 /* 10128 Update matte information using replace algorithm. 10129 */ 10130 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 10131 (ssize_t) y_offset,virtual_pixel,exception); 10132 target.red=virtual_pixel[RedPixelChannel]; 10133 target.green=virtual_pixel[GreenPixelChannel]; 10134 target.blue=virtual_pixel[BluePixelChannel]; 10135 target.alpha=virtual_pixel[AlphaPixelChannel]; 10136 for (y=0; y < (int) (*image)->rows; y++) 10137 { 10138 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10139 (*image)->columns,1,exception); 10140 if (q == (Quantum *) NULL) 10141 break; 10142 for (x=0; x < (int) (*image)->columns; x++) 10143 { 10144 GetPixelInfoPixel(*image,q,&pixel); 10145 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 10146 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10147 q+=GetPixelChannels(*image); 10148 } 10149 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10150 break; 10151 } 10152 break; 10153 } 10154 case FloodfillMethod: 10155 case FillToBorderMethod: 10156 { 10157 ChannelType 10158 channel_mask; 10159 10160 DrawInfo 10161 *draw_info; 10162 10163 PixelInfo 10164 target; 10165 10166 /* 10167 Update matte information using floodfill algorithm. 10168 */ 10169 (void) GetOneVirtualMagickPixel(*image, 10170 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 10171 y_offset,&target,exception); 10172 if (method == FillToBorderMethod) 10173 { 10174 target.red=(MagickRealType) ScaleShortToQuantum( 10175 border_color.red); 10176 target.green=(MagickRealType) ScaleShortToQuantum( 10177 border_color.green); 10178 target.blue=(MagickRealType) ScaleShortToQuantum( 10179 border_color.blue); 10180 } 10181 draw_info=CloneDrawInfo(resource_info->image_info, 10182 (DrawInfo *) NULL); 10183 draw_info->fill.alpha=ClampToQuantum(StringToDouble(matte, 10184 (char **) NULL)); 10185 channel_mask=SetPixelChannelMask(*image,AlphaChannel); 10186 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 10187 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 10188 MagickFalse : MagickTrue,exception); 10189 (void) SetPixelChannelMap(*image,channel_mask); 10190 draw_info=DestroyDrawInfo(draw_info); 10191 break; 10192 } 10193 case ResetMethod: 10194 { 10195 /* 10196 Update matte information using reset algorithm. 10197 */ 10198 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10199 return(MagickFalse); 10200 for (y=0; y < (int) (*image)->rows; y++) 10201 { 10202 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10203 (*image)->columns,1,exception); 10204 if (q == (Quantum *) NULL) 10205 break; 10206 for (x=0; x < (int) (*image)->columns; x++) 10207 { 10208 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10209 q+=GetPixelChannels(*image); 10210 } 10211 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10212 break; 10213 } 10214 if (StringToLong(matte) == (long) OpaqueAlpha) 10215 (*image)->matte=MagickFalse; 10216 break; 10217 } 10218 } 10219 image_view=DestroyCacheView(image_view); 10220 state&=(~UpdateConfigurationState); 10221 } 10222 } while ((state & ExitState) == 0); 10223 (void) XSelectInput(display,windows->image.id, 10224 windows->image.attributes.event_mask); 10225 XSetCursorState(display,windows,MagickFalse); 10226 (void) XFreeCursor(display,cursor); 10227 return(MagickTrue); 10228} 10229 10230/* 10231%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10232% % 10233% % 10234% % 10235+ X O p e n I m a g e % 10236% % 10237% % 10238% % 10239%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10240% 10241% XOpenImage() loads an image from a file. 10242% 10243% The format of the XOpenImage method is: 10244% 10245% Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10246% XWindows *windows,const unsigned int command) 10247% 10248% A description of each parameter follows: 10249% 10250% o display: Specifies a connection to an X server; returned from 10251% XOpenDisplay. 10252% 10253% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10254% 10255% o windows: Specifies a pointer to a XWindows structure. 10256% 10257% o command: A value other than zero indicates that the file is selected 10258% from the command line argument list. 10259% 10260*/ 10261static Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10262 XWindows *windows,const MagickBooleanType command) 10263{ 10264 const MagickInfo 10265 *magick_info; 10266 10267 ExceptionInfo 10268 *exception; 10269 10270 Image 10271 *nexus; 10272 10273 ImageInfo 10274 *image_info; 10275 10276 static char 10277 filename[MaxTextExtent] = "\0"; 10278 10279 /* 10280 Request file name from user. 10281 */ 10282 if (command == MagickFalse) 10283 XFileBrowserWidget(display,windows,"Open",filename); 10284 else 10285 { 10286 char 10287 **filelist, 10288 **files; 10289 10290 int 10291 count, 10292 status; 10293 10294 register int 10295 i, 10296 j; 10297 10298 /* 10299 Select next image from the command line. 10300 */ 10301 status=XGetCommand(display,windows->image.id,&files,&count); 10302 if (status == 0) 10303 { 10304 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","..."); 10305 return((Image *) NULL); 10306 } 10307 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10308 if (filelist == (char **) NULL) 10309 { 10310 ThrowXWindowFatalException(ResourceLimitError, 10311 "MemoryAllocationFailed","..."); 10312 (void) XFreeStringList(files); 10313 return((Image *) NULL); 10314 } 10315 j=0; 10316 for (i=1; i < count; i++) 10317 if (*files[i] != '-') 10318 filelist[j++]=files[i]; 10319 filelist[j]=(char *) NULL; 10320 XListBrowserWidget(display,windows,&windows->widget, 10321 (const char **) filelist,"Load","Select Image to Load:",filename); 10322 filelist=(char **) RelinquishMagickMemory(filelist); 10323 (void) XFreeStringList(files); 10324 } 10325 if (*filename == '\0') 10326 return((Image *) NULL); 10327 image_info=CloneImageInfo(resource_info->image_info); 10328 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL, 10329 (void *) NULL); 10330 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10331 exception=AcquireExceptionInfo(); 10332 (void) SetImageInfo(image_info,0,exception); 10333 if (LocaleCompare(image_info->magick,"X") == 0) 10334 { 10335 char 10336 seconds[MaxTextExtent]; 10337 10338 /* 10339 User may want to delay the X server screen grab. 10340 */ 10341 (void) CopyMagickString(seconds,"0",MaxTextExtent); 10342 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:", 10343 seconds); 10344 if (*seconds == '\0') 10345 return((Image *) NULL); 10346 XDelay(display,(size_t) (1000*StringToLong(seconds))); 10347 } 10348 magick_info=GetMagickInfo(image_info->magick,exception); 10349 if ((magick_info != (const MagickInfo *) NULL) && 10350 (magick_info->raw != MagickFalse)) 10351 { 10352 char 10353 geometry[MaxTextExtent]; 10354 10355 /* 10356 Request image size from the user. 10357 */ 10358 (void) CopyMagickString(geometry,"512x512",MaxTextExtent); 10359 if (image_info->size != (char *) NULL) 10360 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent); 10361 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:", 10362 geometry); 10363 (void) CloneString(&image_info->size,geometry); 10364 } 10365 /* 10366 Load the image. 10367 */ 10368 XSetCursorState(display,windows,MagickTrue); 10369 XCheckRefreshWindows(display,windows); 10370 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10371 nexus=ReadImage(image_info,exception); 10372 CatchException(exception); 10373 XSetCursorState(display,windows,MagickFalse); 10374 if (nexus != (Image *) NULL) 10375 XClientMessage(display,windows->image.id,windows->im_protocols, 10376 windows->im_next_image,CurrentTime); 10377 else 10378 { 10379 char 10380 *text, 10381 **textlist; 10382 10383 /* 10384 Unknown image format. 10385 */ 10386 text=FileToString(filename,~0,exception); 10387 if (text == (char *) NULL) 10388 return((Image *) NULL); 10389 textlist=StringToList(text); 10390 if (textlist != (char **) NULL) 10391 { 10392 char 10393 title[MaxTextExtent]; 10394 10395 register int 10396 i; 10397 10398 (void) FormatLocaleString(title,MaxTextExtent, 10399 "Unknown format: %s",filename); 10400 XTextViewWidget(display,resource_info,windows,MagickTrue,title, 10401 (const char **) textlist); 10402 for (i=0; textlist[i] != (char *) NULL; i++) 10403 textlist[i]=DestroyString(textlist[i]); 10404 textlist=(char **) RelinquishMagickMemory(textlist); 10405 } 10406 text=DestroyString(text); 10407 } 10408 exception=DestroyExceptionInfo(exception); 10409 image_info=DestroyImageInfo(image_info); 10410 return(nexus); 10411} 10412 10413/* 10414%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10415% % 10416% % 10417% % 10418+ X P a n I m a g e % 10419% % 10420% % 10421% % 10422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10423% 10424% XPanImage() pans the image until the mouse button is released. 10425% 10426% The format of the XPanImage method is: 10427% 10428% void XPanImage(Display *display,XWindows *windows,XEvent *event, 10429% ExceptionInfo *exception) 10430% 10431% A description of each parameter follows: 10432% 10433% o display: Specifies a connection to an X server; returned from 10434% XOpenDisplay. 10435% 10436% o windows: Specifies a pointer to a XWindows structure. 10437% 10438% o event: Specifies a pointer to a XEvent structure. If it is NULL, 10439% the entire image is refreshed. 10440% 10441% o exception: return any errors or warnings in this structure. 10442% 10443*/ 10444static void XPanImage(Display *display,XWindows *windows,XEvent *event, 10445 ExceptionInfo *exception) 10446{ 10447 char 10448 text[MaxTextExtent]; 10449 10450 Cursor 10451 cursor; 10452 10453 MagickRealType 10454 x_factor, 10455 y_factor; 10456 10457 RectangleInfo 10458 pan_info; 10459 10460 size_t 10461 state; 10462 10463 /* 10464 Define cursor. 10465 */ 10466 if ((windows->image.ximage->width > (int) windows->image.width) && 10467 (windows->image.ximage->height > (int) windows->image.height)) 10468 cursor=XCreateFontCursor(display,XC_fleur); 10469 else 10470 if (windows->image.ximage->width > (int) windows->image.width) 10471 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow); 10472 else 10473 if (windows->image.ximage->height > (int) windows->image.height) 10474 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow); 10475 else 10476 cursor=XCreateFontCursor(display,XC_arrow); 10477 (void) XCheckDefineCursor(display,windows->pan.id,cursor); 10478 /* 10479 Pan image as pointer moves until the mouse button is released. 10480 */ 10481 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width; 10482 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height; 10483 pan_info.width=windows->pan.width*windows->image.width/ 10484 windows->image.ximage->width; 10485 pan_info.height=windows->pan.height*windows->image.height/ 10486 windows->image.ximage->height; 10487 pan_info.x=0; 10488 pan_info.y=0; 10489 state=UpdateConfigurationState; 10490 do 10491 { 10492 switch (event->type) 10493 { 10494 case ButtonPress: 10495 { 10496 /* 10497 User choose an initial pan location. 10498 */ 10499 pan_info.x=(ssize_t) event->xbutton.x; 10500 pan_info.y=(ssize_t) event->xbutton.y; 10501 state|=UpdateConfigurationState; 10502 break; 10503 } 10504 case ButtonRelease: 10505 { 10506 /* 10507 User has finished panning the image. 10508 */ 10509 pan_info.x=(ssize_t) event->xbutton.x; 10510 pan_info.y=(ssize_t) event->xbutton.y; 10511 state|=UpdateConfigurationState | ExitState; 10512 break; 10513 } 10514 case MotionNotify: 10515 { 10516 pan_info.x=(ssize_t) event->xmotion.x; 10517 pan_info.y=(ssize_t) event->xmotion.y; 10518 state|=UpdateConfigurationState; 10519 } 10520 default: 10521 break; 10522 } 10523 if ((state & UpdateConfigurationState) != 0) 10524 { 10525 /* 10526 Check boundary conditions. 10527 */ 10528 if (pan_info.x < (ssize_t) (pan_info.width/2)) 10529 pan_info.x=0; 10530 else 10531 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2))); 10532 if (pan_info.x < 0) 10533 pan_info.x=0; 10534 else 10535 if ((int) (pan_info.x+windows->image.width) > 10536 windows->image.ximage->width) 10537 pan_info.x=(ssize_t) 10538 (windows->image.ximage->width-windows->image.width); 10539 if (pan_info.y < (ssize_t) (pan_info.height/2)) 10540 pan_info.y=0; 10541 else 10542 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2))); 10543 if (pan_info.y < 0) 10544 pan_info.y=0; 10545 else 10546 if ((int) (pan_info.y+windows->image.height) > 10547 windows->image.ximage->height) 10548 pan_info.y=(ssize_t) 10549 (windows->image.ximage->height-windows->image.height); 10550 if ((windows->image.x != (int) pan_info.x) || 10551 (windows->image.y != (int) pan_info.y)) 10552 { 10553 /* 10554 Display image pan offset. 10555 */ 10556 windows->image.x=(int) pan_info.x; 10557 windows->image.y=(int) pan_info.y; 10558 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 10559 windows->image.width,windows->image.height,windows->image.x, 10560 windows->image.y); 10561 XInfoWidget(display,windows,text); 10562 /* 10563 Refresh Image window. 10564 */ 10565 XDrawPanRectangle(display,windows); 10566 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 10567 } 10568 state&=(~UpdateConfigurationState); 10569 } 10570 /* 10571 Wait for next event. 10572 */ 10573 if ((state & ExitState) == 0) 10574 XScreenEvent(display,windows,event,exception); 10575 } while ((state & ExitState) == 0); 10576 /* 10577 Restore cursor. 10578 */ 10579 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor); 10580 (void) XFreeCursor(display,cursor); 10581 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 10582} 10583 10584/* 10585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10586% % 10587% % 10588% % 10589+ X P a s t e I m a g e % 10590% % 10591% % 10592% % 10593%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10594% 10595% XPasteImage() pastes an image previously saved with XCropImage in the X 10596% window image at a location the user chooses with the pointer. 10597% 10598% The format of the XPasteImage method is: 10599% 10600% MagickBooleanType XPasteImage(Display *display, 10601% XResourceInfo *resource_info,XWindows *windows,Image *image, 10602% ExceptionInfo *exception) 10603% 10604% A description of each parameter follows: 10605% 10606% o display: Specifies a connection to an X server; returned from 10607% XOpenDisplay. 10608% 10609% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10610% 10611% o windows: Specifies a pointer to a XWindows structure. 10612% 10613% o image: the image; returned from ReadImage. 10614% 10615% o exception: return any errors or warnings in this structure. 10616% 10617*/ 10618static MagickBooleanType XPasteImage(Display *display, 10619 XResourceInfo *resource_info,XWindows *windows,Image *image, 10620 ExceptionInfo *exception) 10621{ 10622 static const char 10623 *PasteMenu[] = 10624 { 10625 "Operator", 10626 "Help", 10627 "Dismiss", 10628 (char *) NULL 10629 }; 10630 10631 static const ModeType 10632 PasteCommands[] = 10633 { 10634 PasteOperatorsCommand, 10635 PasteHelpCommand, 10636 PasteDismissCommand 10637 }; 10638 10639 static CompositeOperator 10640 compose = CopyCompositeOp; 10641 10642 char 10643 text[MaxTextExtent]; 10644 10645 Cursor 10646 cursor; 10647 10648 Image 10649 *paste_image; 10650 10651 int 10652 entry, 10653 id, 10654 x, 10655 y; 10656 10657 MagickRealType 10658 scale_factor; 10659 10660 RectangleInfo 10661 highlight_info, 10662 paste_info; 10663 10664 unsigned int 10665 height, 10666 width; 10667 10668 size_t 10669 state; 10670 10671 XEvent 10672 event; 10673 10674 /* 10675 Copy image. 10676 */ 10677 if (resource_info->copy_image == (Image *) NULL) 10678 return(MagickFalse); 10679 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception); 10680 /* 10681 Map Command widget. 10682 */ 10683 (void) CloneString(&windows->command.name,"Paste"); 10684 windows->command.data=1; 10685 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL); 10686 (void) XMapRaised(display,windows->command.id); 10687 XClientMessage(display,windows->image.id,windows->im_protocols, 10688 windows->im_update_widget,CurrentTime); 10689 /* 10690 Track pointer until button 1 is pressed. 10691 */ 10692 XSetCursorState(display,windows,MagickFalse); 10693 XQueryPosition(display,windows->image.id,&x,&y); 10694 (void) XSelectInput(display,windows->image.id, 10695 windows->image.attributes.event_mask | PointerMotionMask); 10696 paste_info.x=(ssize_t) windows->image.x+x; 10697 paste_info.y=(ssize_t) windows->image.y+y; 10698 paste_info.width=0; 10699 paste_info.height=0; 10700 cursor=XCreateFontCursor(display,XC_ul_angle); 10701 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 10702 state=DefaultState; 10703 do 10704 { 10705 if (windows->info.mapped != MagickFalse) 10706 { 10707 /* 10708 Display pointer position. 10709 */ 10710 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 10711 (long) paste_info.x,(long) paste_info.y); 10712 XInfoWidget(display,windows,text); 10713 } 10714 highlight_info=paste_info; 10715 highlight_info.x=paste_info.x-windows->image.x; 10716 highlight_info.y=paste_info.y-windows->image.y; 10717 XHighlightRectangle(display,windows->image.id, 10718 windows->image.highlight_context,&highlight_info); 10719 /* 10720 Wait for next event. 10721 */ 10722 XScreenEvent(display,windows,&event,exception); 10723 XHighlightRectangle(display,windows->image.id, 10724 windows->image.highlight_context,&highlight_info); 10725 if (event.xany.window == windows->command.id) 10726 { 10727 /* 10728 Select a command from the Command widget. 10729 */ 10730 id=XCommandWidget(display,windows,PasteMenu,&event); 10731 if (id < 0) 10732 continue; 10733 switch (PasteCommands[id]) 10734 { 10735 case PasteOperatorsCommand: 10736 { 10737 char 10738 command[MaxTextExtent], 10739 **operators; 10740 10741 /* 10742 Select a command from the pop-up menu. 10743 */ 10744 operators=GetCommandOptions(MagickComposeOptions); 10745 if (operators == (char **) NULL) 10746 break; 10747 entry=XMenuWidget(display,windows,PasteMenu[id], 10748 (const char **) operators,command); 10749 if (entry >= 0) 10750 compose=(CompositeOperator) ParseCommandOption( 10751 MagickComposeOptions,MagickFalse,operators[entry]); 10752 operators=DestroyStringList(operators); 10753 break; 10754 } 10755 case PasteHelpCommand: 10756 { 10757 XTextViewWidget(display,resource_info,windows,MagickFalse, 10758 "Help Viewer - Image Composite",ImagePasteHelp); 10759 break; 10760 } 10761 case PasteDismissCommand: 10762 { 10763 /* 10764 Prematurely exit. 10765 */ 10766 state|=EscapeState; 10767 state|=ExitState; 10768 break; 10769 } 10770 default: 10771 break; 10772 } 10773 continue; 10774 } 10775 switch (event.type) 10776 { 10777 case ButtonPress: 10778 { 10779 if (image->debug != MagickFalse) 10780 (void) LogMagickEvent(X11Event,GetMagickModule(), 10781 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 10782 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10783 if (event.xbutton.button != Button1) 10784 break; 10785 if (event.xbutton.window != windows->image.id) 10786 break; 10787 /* 10788 Paste rectangle is relative to image configuration. 10789 */ 10790 width=(unsigned int) image->columns; 10791 height=(unsigned int) image->rows; 10792 x=0; 10793 y=0; 10794 if (windows->image.crop_geometry != (char *) NULL) 10795 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 10796 &width,&height); 10797 scale_factor=(MagickRealType) windows->image.ximage->width/width; 10798 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5); 10799 scale_factor=(MagickRealType) windows->image.ximage->height/height; 10800 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5); 10801 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10802 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10803 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10804 break; 10805 } 10806 case ButtonRelease: 10807 { 10808 if (image->debug != MagickFalse) 10809 (void) LogMagickEvent(X11Event,GetMagickModule(), 10810 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 10811 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10812 if (event.xbutton.button != Button1) 10813 break; 10814 if (event.xbutton.window != windows->image.id) 10815 break; 10816 if ((paste_info.width != 0) && (paste_info.height != 0)) 10817 { 10818 /* 10819 User has selected the location of the paste image. 10820 */ 10821 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10822 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10823 state|=ExitState; 10824 } 10825 break; 10826 } 10827 case Expose: 10828 break; 10829 case KeyPress: 10830 { 10831 char 10832 command[MaxTextExtent]; 10833 10834 KeySym 10835 key_symbol; 10836 10837 int 10838 length; 10839 10840 if (event.xkey.window != windows->image.id) 10841 break; 10842 /* 10843 Respond to a user key press. 10844 */ 10845 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 10846 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10847 *(command+length)='\0'; 10848 if (image->debug != MagickFalse) 10849 (void) LogMagickEvent(X11Event,GetMagickModule(), 10850 "Key press: 0x%lx (%s)",(long) key_symbol,command); 10851 switch ((int) key_symbol) 10852 { 10853 case XK_Escape: 10854 case XK_F20: 10855 { 10856 /* 10857 Prematurely exit. 10858 */ 10859 paste_image=DestroyImage(paste_image); 10860 state|=EscapeState; 10861 state|=ExitState; 10862 break; 10863 } 10864 case XK_F1: 10865 case XK_Help: 10866 { 10867 (void) XSetFunction(display,windows->image.highlight_context, 10868 GXcopy); 10869 XTextViewWidget(display,resource_info,windows,MagickFalse, 10870 "Help Viewer - Image Composite",ImagePasteHelp); 10871 (void) XSetFunction(display,windows->image.highlight_context, 10872 GXinvert); 10873 break; 10874 } 10875 default: 10876 { 10877 (void) XBell(display,0); 10878 break; 10879 } 10880 } 10881 break; 10882 } 10883 case MotionNotify: 10884 { 10885 /* 10886 Map and unmap Info widget as text cursor crosses its boundaries. 10887 */ 10888 x=event.xmotion.x; 10889 y=event.xmotion.y; 10890 if (windows->info.mapped != MagickFalse) 10891 { 10892 if ((x < (int) (windows->info.x+windows->info.width)) && 10893 (y < (int) (windows->info.y+windows->info.height))) 10894 (void) XWithdrawWindow(display,windows->info.id, 10895 windows->info.screen); 10896 } 10897 else 10898 if ((x > (int) (windows->info.x+windows->info.width)) || 10899 (y > (int) (windows->info.y+windows->info.height))) 10900 (void) XMapWindow(display,windows->info.id); 10901 paste_info.x=(ssize_t) windows->image.x+x; 10902 paste_info.y=(ssize_t) windows->image.y+y; 10903 break; 10904 } 10905 default: 10906 { 10907 if (image->debug != MagickFalse) 10908 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 10909 event.type); 10910 break; 10911 } 10912 } 10913 } while ((state & ExitState) == 0); 10914 (void) XSelectInput(display,windows->image.id, 10915 windows->image.attributes.event_mask); 10916 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 10917 XSetCursorState(display,windows,MagickFalse); 10918 (void) XFreeCursor(display,cursor); 10919 if ((state & EscapeState) != 0) 10920 return(MagickTrue); 10921 /* 10922 Image pasting is relative to image configuration. 10923 */ 10924 XSetCursorState(display,windows,MagickTrue); 10925 XCheckRefreshWindows(display,windows); 10926 width=(unsigned int) image->columns; 10927 height=(unsigned int) image->rows; 10928 x=0; 10929 y=0; 10930 if (windows->image.crop_geometry != (char *) NULL) 10931 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 10932 scale_factor=(MagickRealType) width/windows->image.ximage->width; 10933 paste_info.x+=x; 10934 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5); 10935 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5); 10936 scale_factor=(MagickRealType) height/windows->image.ximage->height; 10937 paste_info.y+=y; 10938 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5); 10939 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5); 10940 /* 10941 Paste image with X Image window. 10942 */ 10943 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y, 10944 exception); 10945 paste_image=DestroyImage(paste_image); 10946 XSetCursorState(display,windows,MagickFalse); 10947 /* 10948 Update image colormap. 10949 */ 10950 XConfigureImageColormap(display,resource_info,windows,image,exception); 10951 (void) XConfigureImage(display,resource_info,windows,image,exception); 10952 return(MagickTrue); 10953} 10954 10955/* 10956%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10957% % 10958% % 10959% % 10960+ X P r i n t I m a g e % 10961% % 10962% % 10963% % 10964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10965% 10966% XPrintImage() prints an image to a Postscript printer. 10967% 10968% The format of the XPrintImage method is: 10969% 10970% MagickBooleanType XPrintImage(Display *display, 10971% XResourceInfo *resource_info,XWindows *windows,Image *image, 10972% ExceptionInfo *exception) 10973% 10974% A description of each parameter follows: 10975% 10976% o display: Specifies a connection to an X server; returned from 10977% XOpenDisplay. 10978% 10979% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10980% 10981% o windows: Specifies a pointer to a XWindows structure. 10982% 10983% o image: the image. 10984% 10985% o exception: return any errors or warnings in this structure. 10986% 10987*/ 10988static MagickBooleanType XPrintImage(Display *display, 10989 XResourceInfo *resource_info,XWindows *windows,Image *image, 10990 ExceptionInfo *exception) 10991{ 10992 char 10993 filename[MaxTextExtent], 10994 geometry[MaxTextExtent]; 10995 10996 Image 10997 *print_image; 10998 10999 ImageInfo 11000 *image_info; 11001 11002 MagickStatusType 11003 status; 11004 11005 /* 11006 Request Postscript page geometry from user. 11007 */ 11008 image_info=CloneImageInfo(resource_info->image_info); 11009 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter"); 11010 if (image_info->page != (char *) NULL) 11011 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 11012 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 11013 "Select Postscript Page Geometry:",geometry); 11014 if (*geometry == '\0') 11015 return(MagickTrue); 11016 image_info->page=GetPageGeometry(geometry); 11017 /* 11018 Apply image transforms. 11019 */ 11020 XSetCursorState(display,windows,MagickTrue); 11021 XCheckRefreshWindows(display,windows); 11022 print_image=CloneImage(image,0,0,MagickTrue,exception); 11023 if (print_image == (Image *) NULL) 11024 return(MagickFalse); 11025 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 11026 windows->image.ximage->width,windows->image.ximage->height); 11027 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry, 11028 exception); 11029 /* 11030 Print image. 11031 */ 11032 (void) AcquireUniqueFilename(filename); 11033 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s", 11034 filename); 11035 status=WriteImage(image_info,print_image,exception); 11036 (void) RelinquishUniqueFileResource(filename); 11037 print_image=DestroyImage(print_image); 11038 image_info=DestroyImageInfo(image_info); 11039 XSetCursorState(display,windows,MagickFalse); 11040 return(status != 0 ? MagickTrue : MagickFalse); 11041} 11042 11043/* 11044%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11045% % 11046% % 11047% % 11048+ X R O I I m a g e % 11049% % 11050% % 11051% % 11052%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11053% 11054% XROIImage() applies an image processing technique to a region of interest. 11055% 11056% The format of the XROIImage method is: 11057% 11058% MagickBooleanType XROIImage(Display *display, 11059% XResourceInfo *resource_info,XWindows *windows,Image **image, 11060% ExceptionInfo *exception) 11061% 11062% A description of each parameter follows: 11063% 11064% o display: Specifies a connection to an X server; returned from 11065% XOpenDisplay. 11066% 11067% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11068% 11069% o windows: Specifies a pointer to a XWindows structure. 11070% 11071% o image: the image; returned from ReadImage. 11072% 11073% o exception: return any errors or warnings in this structure. 11074% 11075*/ 11076static MagickBooleanType XROIImage(Display *display, 11077 XResourceInfo *resource_info,XWindows *windows,Image **image, 11078 ExceptionInfo *exception) 11079{ 11080#define ApplyMenus 7 11081 11082 static const char 11083 *ROIMenu[] = 11084 { 11085 "Help", 11086 "Dismiss", 11087 (char *) NULL 11088 }, 11089 *ApplyMenu[] = 11090 { 11091 "File", 11092 "Edit", 11093 "Transform", 11094 "Enhance", 11095 "Effects", 11096 "F/X", 11097 "Miscellany", 11098 "Help", 11099 "Dismiss", 11100 (char *) NULL 11101 }, 11102 *FileMenu[] = 11103 { 11104 "Save...", 11105 "Print...", 11106 (char *) NULL 11107 }, 11108 *EditMenu[] = 11109 { 11110 "Undo", 11111 "Redo", 11112 (char *) NULL 11113 }, 11114 *TransformMenu[] = 11115 { 11116 "Flop", 11117 "Flip", 11118 "Rotate Right", 11119 "Rotate Left", 11120 (char *) NULL 11121 }, 11122 *EnhanceMenu[] = 11123 { 11124 "Hue...", 11125 "Saturation...", 11126 "Brightness...", 11127 "Gamma...", 11128 "Spiff", 11129 "Dull", 11130 "Contrast Stretch...", 11131 "Sigmoidal Contrast...", 11132 "Normalize", 11133 "Equalize", 11134 "Negate", 11135 "Grayscale", 11136 "Map...", 11137 "Quantize...", 11138 (char *) NULL 11139 }, 11140 *EffectsMenu[] = 11141 { 11142 "Despeckle", 11143 "Emboss", 11144 "Reduce Noise", 11145 "Add Noise", 11146 "Sharpen...", 11147 "Blur...", 11148 "Threshold...", 11149 "Edge Detect...", 11150 "Spread...", 11151 "Shade...", 11152 "Raise...", 11153 "Segment...", 11154 (char *) NULL 11155 }, 11156 *FXMenu[] = 11157 { 11158 "Solarize...", 11159 "Sepia Tone...", 11160 "Swirl...", 11161 "Implode...", 11162 "Vignette...", 11163 "Wave...", 11164 "Oil Paint...", 11165 "Charcoal Draw...", 11166 (char *) NULL 11167 }, 11168 *MiscellanyMenu[] = 11169 { 11170 "Image Info", 11171 "Zoom Image", 11172 "Show Preview...", 11173 "Show Histogram", 11174 "Show Matte", 11175 (char *) NULL 11176 }; 11177 11178 static const char 11179 **Menus[ApplyMenus] = 11180 { 11181 FileMenu, 11182 EditMenu, 11183 TransformMenu, 11184 EnhanceMenu, 11185 EffectsMenu, 11186 FXMenu, 11187 MiscellanyMenu 11188 }; 11189 11190 static const CommandType 11191 ApplyCommands[] = 11192 { 11193 NullCommand, 11194 NullCommand, 11195 NullCommand, 11196 NullCommand, 11197 NullCommand, 11198 NullCommand, 11199 NullCommand, 11200 HelpCommand, 11201 QuitCommand 11202 }, 11203 FileCommands[] = 11204 { 11205 SaveCommand, 11206 PrintCommand 11207 }, 11208 EditCommands[] = 11209 { 11210 UndoCommand, 11211 RedoCommand 11212 }, 11213 TransformCommands[] = 11214 { 11215 FlopCommand, 11216 FlipCommand, 11217 RotateRightCommand, 11218 RotateLeftCommand 11219 }, 11220 EnhanceCommands[] = 11221 { 11222 HueCommand, 11223 SaturationCommand, 11224 BrightnessCommand, 11225 GammaCommand, 11226 SpiffCommand, 11227 DullCommand, 11228 ContrastStretchCommand, 11229 SigmoidalContrastCommand, 11230 NormalizeCommand, 11231 EqualizeCommand, 11232 NegateCommand, 11233 GrayscaleCommand, 11234 MapCommand, 11235 QuantizeCommand 11236 }, 11237 EffectsCommands[] = 11238 { 11239 DespeckleCommand, 11240 EmbossCommand, 11241 ReduceNoiseCommand, 11242 AddNoiseCommand, 11243 SharpenCommand, 11244 BlurCommand, 11245 EdgeDetectCommand, 11246 SpreadCommand, 11247 ShadeCommand, 11248 RaiseCommand, 11249 SegmentCommand 11250 }, 11251 FXCommands[] = 11252 { 11253 SolarizeCommand, 11254 SepiaToneCommand, 11255 SwirlCommand, 11256 ImplodeCommand, 11257 VignetteCommand, 11258 WaveCommand, 11259 OilPaintCommand, 11260 CharcoalDrawCommand 11261 }, 11262 MiscellanyCommands[] = 11263 { 11264 InfoCommand, 11265 ZoomCommand, 11266 ShowPreviewCommand, 11267 ShowHistogramCommand, 11268 ShowMatteCommand 11269 }, 11270 ROICommands[] = 11271 { 11272 ROIHelpCommand, 11273 ROIDismissCommand 11274 }; 11275 11276 static const CommandType 11277 *Commands[ApplyMenus] = 11278 { 11279 FileCommands, 11280 EditCommands, 11281 TransformCommands, 11282 EnhanceCommands, 11283 EffectsCommands, 11284 FXCommands, 11285 MiscellanyCommands 11286 }; 11287 11288 char 11289 command[MaxTextExtent], 11290 text[MaxTextExtent]; 11291 11292 CommandType 11293 command_type; 11294 11295 Cursor 11296 cursor; 11297 11298 Image 11299 *roi_image; 11300 11301 int 11302 entry, 11303 id, 11304 x, 11305 y; 11306 11307 MagickRealType 11308 scale_factor; 11309 11310 MagickProgressMonitor 11311 progress_monitor; 11312 11313 RectangleInfo 11314 crop_info, 11315 highlight_info, 11316 roi_info; 11317 11318 unsigned int 11319 height, 11320 width; 11321 11322 size_t 11323 state; 11324 11325 XEvent 11326 event; 11327 11328 /* 11329 Map Command widget. 11330 */ 11331 (void) CloneString(&windows->command.name,"ROI"); 11332 windows->command.data=0; 11333 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL); 11334 (void) XMapRaised(display,windows->command.id); 11335 XClientMessage(display,windows->image.id,windows->im_protocols, 11336 windows->im_update_widget,CurrentTime); 11337 /* 11338 Track pointer until button 1 is pressed. 11339 */ 11340 XQueryPosition(display,windows->image.id,&x,&y); 11341 (void) XSelectInput(display,windows->image.id, 11342 windows->image.attributes.event_mask | PointerMotionMask); 11343 roi_info.x=(ssize_t) windows->image.x+x; 11344 roi_info.y=(ssize_t) windows->image.y+y; 11345 roi_info.width=0; 11346 roi_info.height=0; 11347 cursor=XCreateFontCursor(display,XC_fleur); 11348 state=DefaultState; 11349 do 11350 { 11351 if (windows->info.mapped != MagickFalse) 11352 { 11353 /* 11354 Display pointer position. 11355 */ 11356 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 11357 (long) roi_info.x,(long) roi_info.y); 11358 XInfoWidget(display,windows,text); 11359 } 11360 /* 11361 Wait for next event. 11362 */ 11363 XScreenEvent(display,windows,&event,exception); 11364 if (event.xany.window == windows->command.id) 11365 { 11366 /* 11367 Select a command from the Command widget. 11368 */ 11369 id=XCommandWidget(display,windows,ROIMenu,&event); 11370 if (id < 0) 11371 continue; 11372 switch (ROICommands[id]) 11373 { 11374 case ROIHelpCommand: 11375 { 11376 XTextViewWidget(display,resource_info,windows,MagickFalse, 11377 "Help Viewer - Region of Interest",ImageROIHelp); 11378 break; 11379 } 11380 case ROIDismissCommand: 11381 { 11382 /* 11383 Prematurely exit. 11384 */ 11385 state|=EscapeState; 11386 state|=ExitState; 11387 break; 11388 } 11389 default: 11390 break; 11391 } 11392 continue; 11393 } 11394 switch (event.type) 11395 { 11396 case ButtonPress: 11397 { 11398 if (event.xbutton.button != Button1) 11399 break; 11400 if (event.xbutton.window != windows->image.id) 11401 break; 11402 /* 11403 Note first corner of region of interest rectangle-- exit loop. 11404 */ 11405 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11406 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11407 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11408 state|=ExitState; 11409 break; 11410 } 11411 case ButtonRelease: 11412 break; 11413 case Expose: 11414 break; 11415 case KeyPress: 11416 { 11417 KeySym 11418 key_symbol; 11419 11420 if (event.xkey.window != windows->image.id) 11421 break; 11422 /* 11423 Respond to a user key press. 11424 */ 11425 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11426 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11427 switch ((int) key_symbol) 11428 { 11429 case XK_Escape: 11430 case XK_F20: 11431 { 11432 /* 11433 Prematurely exit. 11434 */ 11435 state|=EscapeState; 11436 state|=ExitState; 11437 break; 11438 } 11439 case XK_F1: 11440 case XK_Help: 11441 { 11442 XTextViewWidget(display,resource_info,windows,MagickFalse, 11443 "Help Viewer - Region of Interest",ImageROIHelp); 11444 break; 11445 } 11446 default: 11447 { 11448 (void) XBell(display,0); 11449 break; 11450 } 11451 } 11452 break; 11453 } 11454 case MotionNotify: 11455 { 11456 /* 11457 Map and unmap Info widget as text cursor crosses its boundaries. 11458 */ 11459 x=event.xmotion.x; 11460 y=event.xmotion.y; 11461 if (windows->info.mapped != MagickFalse) 11462 { 11463 if ((x < (int) (windows->info.x+windows->info.width)) && 11464 (y < (int) (windows->info.y+windows->info.height))) 11465 (void) XWithdrawWindow(display,windows->info.id, 11466 windows->info.screen); 11467 } 11468 else 11469 if ((x > (int) (windows->info.x+windows->info.width)) || 11470 (y > (int) (windows->info.y+windows->info.height))) 11471 (void) XMapWindow(display,windows->info.id); 11472 roi_info.x=(ssize_t) windows->image.x+x; 11473 roi_info.y=(ssize_t) windows->image.y+y; 11474 break; 11475 } 11476 default: 11477 break; 11478 } 11479 } while ((state & ExitState) == 0); 11480 (void) XSelectInput(display,windows->image.id, 11481 windows->image.attributes.event_mask); 11482 if ((state & EscapeState) != 0) 11483 { 11484 /* 11485 User want to exit without region of interest. 11486 */ 11487 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11488 (void) XFreeCursor(display,cursor); 11489 return(MagickTrue); 11490 } 11491 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11492 do 11493 { 11494 /* 11495 Size rectangle as pointer moves until the mouse button is released. 11496 */ 11497 x=(int) roi_info.x; 11498 y=(int) roi_info.y; 11499 roi_info.width=0; 11500 roi_info.height=0; 11501 state=DefaultState; 11502 do 11503 { 11504 highlight_info=roi_info; 11505 highlight_info.x=roi_info.x-windows->image.x; 11506 highlight_info.y=roi_info.y-windows->image.y; 11507 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11508 { 11509 /* 11510 Display info and draw region of interest rectangle. 11511 */ 11512 if (windows->info.mapped == MagickFalse) 11513 (void) XMapWindow(display,windows->info.id); 11514 (void) FormatLocaleString(text,MaxTextExtent, 11515 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11516 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11517 XInfoWidget(display,windows,text); 11518 XHighlightRectangle(display,windows->image.id, 11519 windows->image.highlight_context,&highlight_info); 11520 } 11521 else 11522 if (windows->info.mapped != MagickFalse) 11523 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11524 /* 11525 Wait for next event. 11526 */ 11527 XScreenEvent(display,windows,&event,exception); 11528 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11529 XHighlightRectangle(display,windows->image.id, 11530 windows->image.highlight_context,&highlight_info); 11531 switch (event.type) 11532 { 11533 case ButtonPress: 11534 { 11535 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11536 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11537 break; 11538 } 11539 case ButtonRelease: 11540 { 11541 /* 11542 User has committed to region of interest rectangle. 11543 */ 11544 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11545 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11546 XSetCursorState(display,windows,MagickFalse); 11547 state|=ExitState; 11548 if (LocaleCompare(windows->command.name,"Apply") == 0) 11549 break; 11550 (void) CloneString(&windows->command.name,"Apply"); 11551 windows->command.data=ApplyMenus; 11552 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL); 11553 break; 11554 } 11555 case Expose: 11556 break; 11557 case MotionNotify: 11558 { 11559 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11560 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11561 } 11562 default: 11563 break; 11564 } 11565 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) || 11566 ((state & ExitState) != 0)) 11567 { 11568 /* 11569 Check boundary conditions. 11570 */ 11571 if (roi_info.x < 0) 11572 roi_info.x=0; 11573 else 11574 if (roi_info.x > (ssize_t) windows->image.ximage->width) 11575 roi_info.x=(ssize_t) windows->image.ximage->width; 11576 if ((int) roi_info.x < x) 11577 roi_info.width=(unsigned int) (x-roi_info.x); 11578 else 11579 { 11580 roi_info.width=(unsigned int) (roi_info.x-x); 11581 roi_info.x=(ssize_t) x; 11582 } 11583 if (roi_info.y < 0) 11584 roi_info.y=0; 11585 else 11586 if (roi_info.y > (ssize_t) windows->image.ximage->height) 11587 roi_info.y=(ssize_t) windows->image.ximage->height; 11588 if ((int) roi_info.y < y) 11589 roi_info.height=(unsigned int) (y-roi_info.y); 11590 else 11591 { 11592 roi_info.height=(unsigned int) (roi_info.y-y); 11593 roi_info.y=(ssize_t) y; 11594 } 11595 } 11596 } while ((state & ExitState) == 0); 11597 /* 11598 Wait for user to grab a corner of the rectangle or press return. 11599 */ 11600 state=DefaultState; 11601 command_type=NullCommand; 11602 (void) XMapWindow(display,windows->info.id); 11603 do 11604 { 11605 if (windows->info.mapped != MagickFalse) 11606 { 11607 /* 11608 Display pointer position. 11609 */ 11610 (void) FormatLocaleString(text,MaxTextExtent, 11611 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11612 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11613 XInfoWidget(display,windows,text); 11614 } 11615 highlight_info=roi_info; 11616 highlight_info.x=roi_info.x-windows->image.x; 11617 highlight_info.y=roi_info.y-windows->image.y; 11618 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11619 { 11620 state|=EscapeState; 11621 state|=ExitState; 11622 break; 11623 } 11624 if ((state & UpdateRegionState) != 0) 11625 { 11626 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11627 switch (command_type) 11628 { 11629 case UndoCommand: 11630 case RedoCommand: 11631 { 11632 (void) XMagickCommand(display,resource_info,windows,command_type, 11633 image,exception); 11634 break; 11635 } 11636 default: 11637 { 11638 /* 11639 Region of interest is relative to image configuration. 11640 */ 11641 progress_monitor=SetImageProgressMonitor(*image, 11642 (MagickProgressMonitor) NULL,(*image)->client_data); 11643 crop_info=roi_info; 11644 width=(unsigned int) (*image)->columns; 11645 height=(unsigned int) (*image)->rows; 11646 x=0; 11647 y=0; 11648 if (windows->image.crop_geometry != (char *) NULL) 11649 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11650 &width,&height); 11651 scale_factor=(MagickRealType) width/windows->image.ximage->width; 11652 crop_info.x+=x; 11653 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11654 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11655 scale_factor=(MagickRealType) 11656 height/windows->image.ximage->height; 11657 crop_info.y+=y; 11658 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11659 crop_info.height=(unsigned int) 11660 (scale_factor*crop_info.height+0.5); 11661 roi_image=CropImage(*image,&crop_info,exception); 11662 (void) SetImageProgressMonitor(*image,progress_monitor, 11663 (*image)->client_data); 11664 if (roi_image == (Image *) NULL) 11665 continue; 11666 /* 11667 Apply image processing technique to the region of interest. 11668 */ 11669 windows->image.orphan=MagickTrue; 11670 (void) XMagickCommand(display,resource_info,windows,command_type, 11671 &roi_image,exception); 11672 progress_monitor=SetImageProgressMonitor(*image, 11673 (MagickProgressMonitor) NULL,(*image)->client_data); 11674 (void) XMagickCommand(display,resource_info,windows, 11675 SaveToUndoBufferCommand,image,exception); 11676 windows->image.orphan=MagickFalse; 11677 (void) CompositeImage(*image,CopyCompositeOp,roi_image, 11678 crop_info.x,crop_info.y,exception); 11679 roi_image=DestroyImage(roi_image); 11680 (void) SetImageProgressMonitor(*image,progress_monitor, 11681 (*image)->client_data); 11682 break; 11683 } 11684 } 11685 if (command_type != InfoCommand) 11686 { 11687 XConfigureImageColormap(display,resource_info,windows,*image, 11688 exception); 11689 (void) XConfigureImage(display,resource_info,windows,*image, 11690 exception); 11691 } 11692 XCheckRefreshWindows(display,windows); 11693 XInfoWidget(display,windows,text); 11694 (void) XSetFunction(display,windows->image.highlight_context, 11695 GXinvert); 11696 state&=(~UpdateRegionState); 11697 } 11698 XHighlightRectangle(display,windows->image.id, 11699 windows->image.highlight_context,&highlight_info); 11700 XScreenEvent(display,windows,&event,exception); 11701 if (event.xany.window == windows->command.id) 11702 { 11703 /* 11704 Select a command from the Command widget. 11705 */ 11706 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11707 command_type=NullCommand; 11708 id=XCommandWidget(display,windows,ApplyMenu,&event); 11709 if (id >= 0) 11710 { 11711 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent); 11712 command_type=ApplyCommands[id]; 11713 if (id < ApplyMenus) 11714 { 11715 /* 11716 Select a command from a pop-up menu. 11717 */ 11718 entry=XMenuWidget(display,windows,ApplyMenu[id], 11719 (const char **) Menus[id],command); 11720 if (entry >= 0) 11721 { 11722 (void) CopyMagickString(command,Menus[id][entry], 11723 MaxTextExtent); 11724 command_type=Commands[id][entry]; 11725 } 11726 } 11727 } 11728 (void) XSetFunction(display,windows->image.highlight_context, 11729 GXinvert); 11730 XHighlightRectangle(display,windows->image.id, 11731 windows->image.highlight_context,&highlight_info); 11732 if (command_type == HelpCommand) 11733 { 11734 (void) XSetFunction(display,windows->image.highlight_context, 11735 GXcopy); 11736 XTextViewWidget(display,resource_info,windows,MagickFalse, 11737 "Help Viewer - Region of Interest",ImageROIHelp); 11738 (void) XSetFunction(display,windows->image.highlight_context, 11739 GXinvert); 11740 continue; 11741 } 11742 if (command_type == QuitCommand) 11743 { 11744 /* 11745 exit. 11746 */ 11747 state|=EscapeState; 11748 state|=ExitState; 11749 continue; 11750 } 11751 if (command_type != NullCommand) 11752 state|=UpdateRegionState; 11753 continue; 11754 } 11755 XHighlightRectangle(display,windows->image.id, 11756 windows->image.highlight_context,&highlight_info); 11757 switch (event.type) 11758 { 11759 case ButtonPress: 11760 { 11761 x=windows->image.x; 11762 y=windows->image.y; 11763 if (event.xbutton.button != Button1) 11764 break; 11765 if (event.xbutton.window != windows->image.id) 11766 break; 11767 x=windows->image.x+event.xbutton.x; 11768 y=windows->image.y+event.xbutton.y; 11769 if ((x < (int) (roi_info.x+RoiDelta)) && 11770 (x > (int) (roi_info.x-RoiDelta)) && 11771 (y < (int) (roi_info.y+RoiDelta)) && 11772 (y > (int) (roi_info.y-RoiDelta))) 11773 { 11774 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11775 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11776 state|=UpdateConfigurationState; 11777 break; 11778 } 11779 if ((x < (int) (roi_info.x+RoiDelta)) && 11780 (x > (int) (roi_info.x-RoiDelta)) && 11781 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11782 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11783 { 11784 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11785 state|=UpdateConfigurationState; 11786 break; 11787 } 11788 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11789 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11790 (y < (int) (roi_info.y+RoiDelta)) && 11791 (y > (int) (roi_info.y-RoiDelta))) 11792 { 11793 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11794 state|=UpdateConfigurationState; 11795 break; 11796 } 11797 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11798 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11799 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11800 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11801 { 11802 state|=UpdateConfigurationState; 11803 break; 11804 } 11805 } 11806 case ButtonRelease: 11807 { 11808 if (event.xbutton.window == windows->pan.id) 11809 if ((highlight_info.x != crop_info.x-windows->image.x) || 11810 (highlight_info.y != crop_info.y-windows->image.y)) 11811 XHighlightRectangle(display,windows->image.id, 11812 windows->image.highlight_context,&highlight_info); 11813 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11814 event.xbutton.time); 11815 break; 11816 } 11817 case Expose: 11818 { 11819 if (event.xexpose.window == windows->image.id) 11820 if (event.xexpose.count == 0) 11821 { 11822 event.xexpose.x=(int) highlight_info.x; 11823 event.xexpose.y=(int) highlight_info.y; 11824 event.xexpose.width=(int) highlight_info.width; 11825 event.xexpose.height=(int) highlight_info.height; 11826 XRefreshWindow(display,&windows->image,&event); 11827 } 11828 if (event.xexpose.window == windows->info.id) 11829 if (event.xexpose.count == 0) 11830 XInfoWidget(display,windows,text); 11831 break; 11832 } 11833 case KeyPress: 11834 { 11835 KeySym 11836 key_symbol; 11837 11838 if (event.xkey.window != windows->image.id) 11839 break; 11840 /* 11841 Respond to a user key press. 11842 */ 11843 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11844 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11845 switch ((int) key_symbol) 11846 { 11847 case XK_Shift_L: 11848 case XK_Shift_R: 11849 break; 11850 case XK_Escape: 11851 case XK_F20: 11852 state|=EscapeState; 11853 case XK_Return: 11854 { 11855 state|=ExitState; 11856 break; 11857 } 11858 case XK_Home: 11859 case XK_KP_Home: 11860 { 11861 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11862 roi_info.y=(ssize_t) (windows->image.height/2L- 11863 roi_info.height/2L); 11864 break; 11865 } 11866 case XK_Left: 11867 case XK_KP_Left: 11868 { 11869 roi_info.x--; 11870 break; 11871 } 11872 case XK_Up: 11873 case XK_KP_Up: 11874 case XK_Next: 11875 { 11876 roi_info.y--; 11877 break; 11878 } 11879 case XK_Right: 11880 case XK_KP_Right: 11881 { 11882 roi_info.x++; 11883 break; 11884 } 11885 case XK_Prior: 11886 case XK_Down: 11887 case XK_KP_Down: 11888 { 11889 roi_info.y++; 11890 break; 11891 } 11892 case XK_F1: 11893 case XK_Help: 11894 { 11895 (void) XSetFunction(display,windows->image.highlight_context, 11896 GXcopy); 11897 XTextViewWidget(display,resource_info,windows,MagickFalse, 11898 "Help Viewer - Region of Interest",ImageROIHelp); 11899 (void) XSetFunction(display,windows->image.highlight_context, 11900 GXinvert); 11901 break; 11902 } 11903 default: 11904 { 11905 command_type=XImageWindowCommand(display,resource_info,windows, 11906 event.xkey.state,key_symbol,image,exception); 11907 if (command_type != NullCommand) 11908 state|=UpdateRegionState; 11909 break; 11910 } 11911 } 11912 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11913 event.xkey.time); 11914 break; 11915 } 11916 case KeyRelease: 11917 break; 11918 case MotionNotify: 11919 { 11920 if (event.xbutton.window != windows->image.id) 11921 break; 11922 /* 11923 Map and unmap Info widget as text cursor crosses its boundaries. 11924 */ 11925 x=event.xmotion.x; 11926 y=event.xmotion.y; 11927 if (windows->info.mapped != MagickFalse) 11928 { 11929 if ((x < (int) (windows->info.x+windows->info.width)) && 11930 (y < (int) (windows->info.y+windows->info.height))) 11931 (void) XWithdrawWindow(display,windows->info.id, 11932 windows->info.screen); 11933 } 11934 else 11935 if ((x > (int) (windows->info.x+windows->info.width)) || 11936 (y > (int) (windows->info.y+windows->info.height))) 11937 (void) XMapWindow(display,windows->info.id); 11938 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11939 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11940 break; 11941 } 11942 case SelectionRequest: 11943 { 11944 XSelectionEvent 11945 notify; 11946 11947 XSelectionRequestEvent 11948 *request; 11949 11950 /* 11951 Set primary selection. 11952 */ 11953 (void) FormatLocaleString(text,MaxTextExtent, 11954 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11955 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11956 request=(&(event.xselectionrequest)); 11957 (void) XChangeProperty(request->display,request->requestor, 11958 request->property,request->target,8,PropModeReplace, 11959 (unsigned char *) text,(int) strlen(text)); 11960 notify.type=SelectionNotify; 11961 notify.display=request->display; 11962 notify.requestor=request->requestor; 11963 notify.selection=request->selection; 11964 notify.target=request->target; 11965 notify.time=request->time; 11966 if (request->property == None) 11967 notify.property=request->target; 11968 else 11969 notify.property=request->property; 11970 (void) XSendEvent(request->display,request->requestor,False,0, 11971 (XEvent *) ¬ify); 11972 } 11973 default: 11974 break; 11975 } 11976 if ((state & UpdateConfigurationState) != 0) 11977 { 11978 (void) XPutBackEvent(display,&event); 11979 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11980 break; 11981 } 11982 } while ((state & ExitState) == 0); 11983 } while ((state & ExitState) == 0); 11984 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11985 XSetCursorState(display,windows,MagickFalse); 11986 if ((state & EscapeState) != 0) 11987 return(MagickTrue); 11988 return(MagickTrue); 11989} 11990 11991/* 11992%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11993% % 11994% % 11995% % 11996+ X R o t a t e I m a g e % 11997% % 11998% % 11999% % 12000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12001% 12002% XRotateImage() rotates the X image. If the degrees parameter if zero, the 12003% rotation angle is computed from the slope of a line drawn by the user. 12004% 12005% The format of the XRotateImage method is: 12006% 12007% MagickBooleanType XRotateImage(Display *display, 12008% XResourceInfo *resource_info,XWindows *windows,double degrees, 12009% Image **image,ExceptionInfo *exception) 12010% 12011% A description of each parameter follows: 12012% 12013% o display: Specifies a connection to an X server; returned from 12014% XOpenDisplay. 12015% 12016% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12017% 12018% o windows: Specifies a pointer to a XWindows structure. 12019% 12020% o degrees: Specifies the number of degrees to rotate the image. 12021% 12022% o image: the image. 12023% 12024% o exception: return any errors or warnings in this structure. 12025% 12026*/ 12027static MagickBooleanType XRotateImage(Display *display, 12028 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image, 12029 ExceptionInfo *exception) 12030{ 12031 static const char 12032 *RotateMenu[] = 12033 { 12034 "Pixel Color", 12035 "Direction", 12036 "Help", 12037 "Dismiss", 12038 (char *) NULL 12039 }; 12040 12041 static ModeType 12042 direction = HorizontalRotateCommand; 12043 12044 static const ModeType 12045 DirectionCommands[] = 12046 { 12047 HorizontalRotateCommand, 12048 VerticalRotateCommand 12049 }, 12050 RotateCommands[] = 12051 { 12052 RotateColorCommand, 12053 RotateDirectionCommand, 12054 RotateHelpCommand, 12055 RotateDismissCommand 12056 }; 12057 12058 static unsigned int 12059 pen_id = 0; 12060 12061 char 12062 command[MaxTextExtent], 12063 text[MaxTextExtent]; 12064 12065 Image 12066 *rotate_image; 12067 12068 int 12069 id, 12070 x, 12071 y; 12072 12073 MagickRealType 12074 normalized_degrees; 12075 12076 register int 12077 i; 12078 12079 unsigned int 12080 height, 12081 rotations, 12082 width; 12083 12084 if (degrees == 0.0) 12085 { 12086 unsigned int 12087 distance; 12088 12089 size_t 12090 state; 12091 12092 XEvent 12093 event; 12094 12095 XSegment 12096 rotate_info; 12097 12098 /* 12099 Map Command widget. 12100 */ 12101 (void) CloneString(&windows->command.name,"Rotate"); 12102 windows->command.data=2; 12103 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 12104 (void) XMapRaised(display,windows->command.id); 12105 XClientMessage(display,windows->image.id,windows->im_protocols, 12106 windows->im_update_widget,CurrentTime); 12107 /* 12108 Wait for first button press. 12109 */ 12110 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12111 XQueryPosition(display,windows->image.id,&x,&y); 12112 rotate_info.x1=x; 12113 rotate_info.y1=y; 12114 rotate_info.x2=x; 12115 rotate_info.y2=y; 12116 state=DefaultState; 12117 do 12118 { 12119 XHighlightLine(display,windows->image.id, 12120 windows->image.highlight_context,&rotate_info); 12121 /* 12122 Wait for next event. 12123 */ 12124 XScreenEvent(display,windows,&event,exception); 12125 XHighlightLine(display,windows->image.id, 12126 windows->image.highlight_context,&rotate_info); 12127 if (event.xany.window == windows->command.id) 12128 { 12129 /* 12130 Select a command from the Command widget. 12131 */ 12132 id=XCommandWidget(display,windows,RotateMenu,&event); 12133 if (id < 0) 12134 continue; 12135 (void) XSetFunction(display,windows->image.highlight_context, 12136 GXcopy); 12137 switch (RotateCommands[id]) 12138 { 12139 case RotateColorCommand: 12140 { 12141 const char 12142 *ColorMenu[MaxNumberPens]; 12143 12144 int 12145 pen_number; 12146 12147 XColor 12148 color; 12149 12150 /* 12151 Initialize menu selections. 12152 */ 12153 for (i=0; i < (int) (MaxNumberPens-2); i++) 12154 ColorMenu[i]=resource_info->pen_colors[i]; 12155 ColorMenu[MaxNumberPens-2]="Browser..."; 12156 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12157 /* 12158 Select a pen color from the pop-up menu. 12159 */ 12160 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12161 (const char **) ColorMenu,command); 12162 if (pen_number < 0) 12163 break; 12164 if (pen_number == (MaxNumberPens-2)) 12165 { 12166 static char 12167 color_name[MaxTextExtent] = "gray"; 12168 12169 /* 12170 Select a pen color from a dialog. 12171 */ 12172 resource_info->pen_colors[pen_number]=color_name; 12173 XColorBrowserWidget(display,windows,"Select",color_name); 12174 if (*color_name == '\0') 12175 break; 12176 } 12177 /* 12178 Set pen color. 12179 */ 12180 (void) XParseColor(display,windows->map_info->colormap, 12181 resource_info->pen_colors[pen_number],&color); 12182 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12183 (unsigned int) MaxColors,&color); 12184 windows->pixel_info->pen_colors[pen_number]=color; 12185 pen_id=(unsigned int) pen_number; 12186 break; 12187 } 12188 case RotateDirectionCommand: 12189 { 12190 static const char 12191 *Directions[] = 12192 { 12193 "horizontal", 12194 "vertical", 12195 (char *) NULL, 12196 }; 12197 12198 /* 12199 Select a command from the pop-up menu. 12200 */ 12201 id=XMenuWidget(display,windows,RotateMenu[id], 12202 Directions,command); 12203 if (id >= 0) 12204 direction=DirectionCommands[id]; 12205 break; 12206 } 12207 case RotateHelpCommand: 12208 { 12209 XTextViewWidget(display,resource_info,windows,MagickFalse, 12210 "Help Viewer - Image Rotation",ImageRotateHelp); 12211 break; 12212 } 12213 case RotateDismissCommand: 12214 { 12215 /* 12216 Prematurely exit. 12217 */ 12218 state|=EscapeState; 12219 state|=ExitState; 12220 break; 12221 } 12222 default: 12223 break; 12224 } 12225 (void) XSetFunction(display,windows->image.highlight_context, 12226 GXinvert); 12227 continue; 12228 } 12229 switch (event.type) 12230 { 12231 case ButtonPress: 12232 { 12233 if (event.xbutton.button != Button1) 12234 break; 12235 if (event.xbutton.window != windows->image.id) 12236 break; 12237 /* 12238 exit loop. 12239 */ 12240 (void) XSetFunction(display,windows->image.highlight_context, 12241 GXcopy); 12242 rotate_info.x1=event.xbutton.x; 12243 rotate_info.y1=event.xbutton.y; 12244 state|=ExitState; 12245 break; 12246 } 12247 case ButtonRelease: 12248 break; 12249 case Expose: 12250 break; 12251 case KeyPress: 12252 { 12253 char 12254 command[MaxTextExtent]; 12255 12256 KeySym 12257 key_symbol; 12258 12259 if (event.xkey.window != windows->image.id) 12260 break; 12261 /* 12262 Respond to a user key press. 12263 */ 12264 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12265 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12266 switch ((int) key_symbol) 12267 { 12268 case XK_Escape: 12269 case XK_F20: 12270 { 12271 /* 12272 Prematurely exit. 12273 */ 12274 state|=EscapeState; 12275 state|=ExitState; 12276 break; 12277 } 12278 case XK_F1: 12279 case XK_Help: 12280 { 12281 (void) XSetFunction(display,windows->image.highlight_context, 12282 GXcopy); 12283 XTextViewWidget(display,resource_info,windows,MagickFalse, 12284 "Help Viewer - Image Rotation",ImageRotateHelp); 12285 (void) XSetFunction(display,windows->image.highlight_context, 12286 GXinvert); 12287 break; 12288 } 12289 default: 12290 { 12291 (void) XBell(display,0); 12292 break; 12293 } 12294 } 12295 break; 12296 } 12297 case MotionNotify: 12298 { 12299 rotate_info.x1=event.xmotion.x; 12300 rotate_info.y1=event.xmotion.y; 12301 } 12302 } 12303 rotate_info.x2=rotate_info.x1; 12304 rotate_info.y2=rotate_info.y1; 12305 if (direction == HorizontalRotateCommand) 12306 rotate_info.x2+=32; 12307 else 12308 rotate_info.y2-=32; 12309 } while ((state & ExitState) == 0); 12310 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12311 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12312 if ((state & EscapeState) != 0) 12313 return(MagickTrue); 12314 /* 12315 Draw line as pointer moves until the mouse button is released. 12316 */ 12317 distance=0; 12318 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12319 state=DefaultState; 12320 do 12321 { 12322 if (distance > 9) 12323 { 12324 /* 12325 Display info and draw rotation line. 12326 */ 12327 if (windows->info.mapped == MagickFalse) 12328 (void) XMapWindow(display,windows->info.id); 12329 (void) FormatLocaleString(text,MaxTextExtent," %g", 12330 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12331 XInfoWidget(display,windows,text); 12332 XHighlightLine(display,windows->image.id, 12333 windows->image.highlight_context,&rotate_info); 12334 } 12335 else 12336 if (windows->info.mapped != MagickFalse) 12337 (void) XWithdrawWindow(display,windows->info.id, 12338 windows->info.screen); 12339 /* 12340 Wait for next event. 12341 */ 12342 XScreenEvent(display,windows,&event,exception); 12343 if (distance > 9) 12344 XHighlightLine(display,windows->image.id, 12345 windows->image.highlight_context,&rotate_info); 12346 switch (event.type) 12347 { 12348 case ButtonPress: 12349 break; 12350 case ButtonRelease: 12351 { 12352 /* 12353 User has committed to rotation line. 12354 */ 12355 rotate_info.x2=event.xbutton.x; 12356 rotate_info.y2=event.xbutton.y; 12357 state|=ExitState; 12358 break; 12359 } 12360 case Expose: 12361 break; 12362 case MotionNotify: 12363 { 12364 rotate_info.x2=event.xmotion.x; 12365 rotate_info.y2=event.xmotion.y; 12366 } 12367 default: 12368 break; 12369 } 12370 /* 12371 Check boundary conditions. 12372 */ 12373 if (rotate_info.x2 < 0) 12374 rotate_info.x2=0; 12375 else 12376 if (rotate_info.x2 > (int) windows->image.width) 12377 rotate_info.x2=(short) windows->image.width; 12378 if (rotate_info.y2 < 0) 12379 rotate_info.y2=0; 12380 else 12381 if (rotate_info.y2 > (int) windows->image.height) 12382 rotate_info.y2=(short) windows->image.height; 12383 /* 12384 Compute rotation angle from the slope of the line. 12385 */ 12386 degrees=0.0; 12387 distance=(unsigned int) 12388 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12389 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12390 if (distance > 9) 12391 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12392 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12393 } while ((state & ExitState) == 0); 12394 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12395 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12396 if (distance <= 9) 12397 return(MagickTrue); 12398 } 12399 if (direction == VerticalRotateCommand) 12400 degrees-=90.0; 12401 if (degrees == 0.0) 12402 return(MagickTrue); 12403 /* 12404 Rotate image. 12405 */ 12406 normalized_degrees=degrees; 12407 while (normalized_degrees < -45.0) 12408 normalized_degrees+=360.0; 12409 for (rotations=0; normalized_degrees > 45.0; rotations++) 12410 normalized_degrees-=90.0; 12411 if (normalized_degrees != 0.0) 12412 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 12413 exception); 12414 XSetCursorState(display,windows,MagickTrue); 12415 XCheckRefreshWindows(display,windows); 12416 (*image)->background_color.red=ScaleShortToQuantum( 12417 windows->pixel_info->pen_colors[pen_id].red); 12418 (*image)->background_color.green=ScaleShortToQuantum( 12419 windows->pixel_info->pen_colors[pen_id].green); 12420 (*image)->background_color.blue=ScaleShortToQuantum( 12421 windows->pixel_info->pen_colors[pen_id].blue); 12422 rotate_image=RotateImage(*image,degrees,exception); 12423 XSetCursorState(display,windows,MagickFalse); 12424 if (rotate_image == (Image *) NULL) 12425 return(MagickFalse); 12426 *image=DestroyImage(*image); 12427 *image=rotate_image; 12428 if (windows->image.crop_geometry != (char *) NULL) 12429 { 12430 /* 12431 Rotate crop geometry. 12432 */ 12433 width=(unsigned int) (*image)->columns; 12434 height=(unsigned int) (*image)->rows; 12435 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12436 switch (rotations % 4) 12437 { 12438 default: 12439 case 0: 12440 break; 12441 case 1: 12442 { 12443 /* 12444 Rotate 90 degrees. 12445 */ 12446 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12447 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12448 (int) height-y,x); 12449 break; 12450 } 12451 case 2: 12452 { 12453 /* 12454 Rotate 180 degrees. 12455 */ 12456 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12457 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12458 break; 12459 } 12460 case 3: 12461 { 12462 /* 12463 Rotate 270 degrees. 12464 */ 12465 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12466 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12467 break; 12468 } 12469 } 12470 } 12471 if (windows->image.orphan != MagickFalse) 12472 return(MagickTrue); 12473 if (normalized_degrees != 0.0) 12474 { 12475 /* 12476 Update image colormap. 12477 */ 12478 windows->image.window_changes.width=(int) (*image)->columns; 12479 windows->image.window_changes.height=(int) (*image)->rows; 12480 if (windows->image.crop_geometry != (char *) NULL) 12481 { 12482 /* 12483 Obtain dimensions of image from crop geometry. 12484 */ 12485 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12486 &width,&height); 12487 windows->image.window_changes.width=(int) width; 12488 windows->image.window_changes.height=(int) height; 12489 } 12490 XConfigureImageColormap(display,resource_info,windows,*image,exception); 12491 } 12492 else 12493 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12494 { 12495 windows->image.window_changes.width=windows->image.ximage->height; 12496 windows->image.window_changes.height=windows->image.ximage->width; 12497 } 12498 /* 12499 Update image configuration. 12500 */ 12501 (void) XConfigureImage(display,resource_info,windows,*image,exception); 12502 return(MagickTrue); 12503} 12504 12505/* 12506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12507% % 12508% % 12509% % 12510+ X S a v e I m a g e % 12511% % 12512% % 12513% % 12514%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12515% 12516% XSaveImage() saves an image to a file. 12517% 12518% The format of the XSaveImage method is: 12519% 12520% MagickBooleanType XSaveImage(Display *display, 12521% XResourceInfo *resource_info,XWindows *windows,Image *image, 12522% ExceptionInfo *exception) 12523% 12524% A description of each parameter follows: 12525% 12526% o display: Specifies a connection to an X server; returned from 12527% XOpenDisplay. 12528% 12529% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12530% 12531% o windows: Specifies a pointer to a XWindows structure. 12532% 12533% o image: the image. 12534% 12535% o exception: return any errors or warnings in this structure. 12536% 12537*/ 12538static MagickBooleanType XSaveImage(Display *display, 12539 XResourceInfo *resource_info,XWindows *windows,Image *image, 12540 ExceptionInfo *exception) 12541{ 12542 char 12543 filename[MaxTextExtent], 12544 geometry[MaxTextExtent]; 12545 12546 Image 12547 *save_image; 12548 12549 ImageInfo 12550 *image_info; 12551 12552 MagickStatusType 12553 status; 12554 12555 /* 12556 Request file name from user. 12557 */ 12558 if (resource_info->write_filename != (char *) NULL) 12559 (void) CopyMagickString(filename,resource_info->write_filename, 12560 MaxTextExtent); 12561 else 12562 { 12563 char 12564 path[MaxTextExtent]; 12565 12566 int 12567 status; 12568 12569 GetPathComponent(image->filename,HeadPath,path); 12570 GetPathComponent(image->filename,TailPath,filename); 12571 if (*path != '\0') 12572 { 12573 status=chdir(path); 12574 if (status == -1) 12575 (void) ThrowMagickException(exception,GetMagickModule(), 12576 FileOpenError,"UnableToOpenFile","%s",path); 12577 } 12578 } 12579 XFileBrowserWidget(display,windows,"Save",filename); 12580 if (*filename == '\0') 12581 return(MagickTrue); 12582 if (IsPathAccessible(filename) != MagickFalse) 12583 { 12584 int 12585 status; 12586 12587 /* 12588 File exists-- seek user's permission before overwriting. 12589 */ 12590 status=XConfirmWidget(display,windows,"Overwrite",filename); 12591 if (status <= 0) 12592 return(MagickTrue); 12593 } 12594 image_info=CloneImageInfo(resource_info->image_info); 12595 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 12596 (void) SetImageInfo(image_info,1,exception); 12597 if ((LocaleCompare(image_info->magick,"JPEG") == 0) || 12598 (LocaleCompare(image_info->magick,"JPG") == 0)) 12599 { 12600 char 12601 quality[MaxTextExtent]; 12602 12603 int 12604 status; 12605 12606 /* 12607 Request JPEG quality from user. 12608 */ 12609 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double) 12610 image->quality); 12611 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", 12612 quality); 12613 if (*quality == '\0') 12614 return(MagickTrue); 12615 image->quality=StringToUnsignedLong(quality); 12616 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace; 12617 } 12618 if ((LocaleCompare(image_info->magick,"EPS") == 0) || 12619 (LocaleCompare(image_info->magick,"PDF") == 0) || 12620 (LocaleCompare(image_info->magick,"PS") == 0) || 12621 (LocaleCompare(image_info->magick,"PS2") == 0)) 12622 { 12623 char 12624 geometry[MaxTextExtent]; 12625 12626 /* 12627 Request page geometry from user. 12628 */ 12629 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12630 if (LocaleCompare(image_info->magick,"PDF") == 0) 12631 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12632 if (image_info->page != (char *) NULL) 12633 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 12634 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 12635 "Select page geometry:",geometry); 12636 if (*geometry != '\0') 12637 image_info->page=GetPageGeometry(geometry); 12638 } 12639 /* 12640 Apply image transforms. 12641 */ 12642 XSetCursorState(display,windows,MagickTrue); 12643 XCheckRefreshWindows(display,windows); 12644 save_image=CloneImage(image,0,0,MagickTrue,exception); 12645 if (save_image == (Image *) NULL) 12646 return(MagickFalse); 12647 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 12648 windows->image.ximage->width,windows->image.ximage->height); 12649 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry, 12650 exception); 12651 /* 12652 Write image. 12653 */ 12654 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent); 12655 status=WriteImage(image_info,save_image,exception); 12656 if (status != MagickFalse) 12657 image->taint=MagickFalse; 12658 save_image=DestroyImage(save_image); 12659 image_info=DestroyImageInfo(image_info); 12660 XSetCursorState(display,windows,MagickFalse); 12661 return(status != 0 ? MagickTrue : MagickFalse); 12662} 12663 12664/* 12665%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12666% % 12667% % 12668% % 12669+ X S c r e e n E v e n t % 12670% % 12671% % 12672% % 12673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12674% 12675% XScreenEvent() handles global events associated with the Pan and Magnify 12676% windows. 12677% 12678% The format of the XScreenEvent function is: 12679% 12680% void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12681% ExceptionInfo *exception) 12682% 12683% A description of each parameter follows: 12684% 12685% o display: Specifies a pointer to the Display structure; returned from 12686% XOpenDisplay. 12687% 12688% o windows: Specifies a pointer to a XWindows structure. 12689% 12690% o event: Specifies a pointer to a X11 XEvent structure. 12691% 12692% o exception: return any errors or warnings in this structure. 12693% 12694*/ 12695 12696#if defined(__cplusplus) || defined(c_plusplus) 12697extern "C" { 12698#endif 12699 12700static int XPredicate(Display *magick_unused(display),XEvent *event,char *data) 12701{ 12702 register XWindows 12703 *windows; 12704 12705 windows=(XWindows *) data; 12706 if ((event->type == ClientMessage) && 12707 (event->xclient.window == windows->image.id)) 12708 return(MagickFalse); 12709 return(MagickTrue); 12710} 12711 12712#if defined(__cplusplus) || defined(c_plusplus) 12713} 12714#endif 12715 12716static void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12717 ExceptionInfo *exception) 12718{ 12719 register int 12720 x, 12721 y; 12722 12723 (void) XIfEvent(display,event,XPredicate,(char *) windows); 12724 if (event->xany.window == windows->command.id) 12725 return; 12726 switch (event->type) 12727 { 12728 case ButtonPress: 12729 case ButtonRelease: 12730 { 12731 if ((event->xbutton.button == Button3) && 12732 (event->xbutton.state & Mod1Mask)) 12733 { 12734 /* 12735 Convert Alt-Button3 to Button2. 12736 */ 12737 event->xbutton.button=Button2; 12738 event->xbutton.state&=(~Mod1Mask); 12739 } 12740 if (event->xbutton.window == windows->backdrop.id) 12741 { 12742 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent, 12743 event->xbutton.time); 12744 break; 12745 } 12746 if (event->xbutton.window == windows->pan.id) 12747 { 12748 XPanImage(display,windows,event,exception); 12749 break; 12750 } 12751 if (event->xbutton.window == windows->image.id) 12752 if (event->xbutton.button == Button2) 12753 { 12754 /* 12755 Update magnified image. 12756 */ 12757 x=event->xbutton.x; 12758 y=event->xbutton.y; 12759 if (x < 0) 12760 x=0; 12761 else 12762 if (x >= (int) windows->image.width) 12763 x=(int) (windows->image.width-1); 12764 windows->magnify.x=(int) windows->image.x+x; 12765 if (y < 0) 12766 y=0; 12767 else 12768 if (y >= (int) windows->image.height) 12769 y=(int) (windows->image.height-1); 12770 windows->magnify.y=windows->image.y+y; 12771 if (windows->magnify.mapped == MagickFalse) 12772 (void) XMapRaised(display,windows->magnify.id); 12773 XMakeMagnifyImage(display,windows,exception); 12774 if (event->type == ButtonRelease) 12775 (void) XWithdrawWindow(display,windows->info.id, 12776 windows->info.screen); 12777 break; 12778 } 12779 break; 12780 } 12781 case ClientMessage: 12782 { 12783 /* 12784 If client window delete message, exit. 12785 */ 12786 if (event->xclient.message_type != windows->wm_protocols) 12787 break; 12788 if (*event->xclient.data.l != (long) windows->wm_delete_window) 12789 break; 12790 if (event->xclient.window == windows->magnify.id) 12791 { 12792 (void) XWithdrawWindow(display,windows->magnify.id, 12793 windows->magnify.screen); 12794 break; 12795 } 12796 break; 12797 } 12798 case ConfigureNotify: 12799 { 12800 if (event->xconfigure.window == windows->magnify.id) 12801 { 12802 unsigned int 12803 magnify; 12804 12805 /* 12806 Magnify window has a new configuration. 12807 */ 12808 windows->magnify.width=(unsigned int) event->xconfigure.width; 12809 windows->magnify.height=(unsigned int) event->xconfigure.height; 12810 if (windows->magnify.mapped == MagickFalse) 12811 break; 12812 magnify=1; 12813 while ((int) magnify <= event->xconfigure.width) 12814 magnify<<=1; 12815 while ((int) magnify <= event->xconfigure.height) 12816 magnify<<=1; 12817 magnify>>=1; 12818 if (((int) magnify != event->xconfigure.width) || 12819 ((int) magnify != event->xconfigure.height)) 12820 { 12821 XWindowChanges 12822 window_changes; 12823 12824 window_changes.width=(int) magnify; 12825 window_changes.height=(int) magnify; 12826 (void) XReconfigureWMWindow(display,windows->magnify.id, 12827 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 12828 &window_changes); 12829 break; 12830 } 12831 XMakeMagnifyImage(display,windows,exception); 12832 break; 12833 } 12834 break; 12835 } 12836 case Expose: 12837 { 12838 if (event->xexpose.window == windows->image.id) 12839 { 12840 XRefreshWindow(display,&windows->image,event); 12841 break; 12842 } 12843 if (event->xexpose.window == windows->pan.id) 12844 if (event->xexpose.count == 0) 12845 { 12846 XDrawPanRectangle(display,windows); 12847 break; 12848 } 12849 if (event->xexpose.window == windows->magnify.id) 12850 if (event->xexpose.count == 0) 12851 { 12852 XMakeMagnifyImage(display,windows,exception); 12853 break; 12854 } 12855 break; 12856 } 12857 case KeyPress: 12858 { 12859 char 12860 command[MaxTextExtent]; 12861 12862 KeySym 12863 key_symbol; 12864 12865 if (event->xkey.window != windows->magnify.id) 12866 break; 12867 /* 12868 Respond to a user key press. 12869 */ 12870 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int) 12871 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12872 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol, 12873 exception); 12874 break; 12875 } 12876 case MapNotify: 12877 { 12878 if (event->xmap.window == windows->magnify.id) 12879 { 12880 windows->magnify.mapped=MagickTrue; 12881 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12882 break; 12883 } 12884 if (event->xmap.window == windows->info.id) 12885 { 12886 windows->info.mapped=MagickTrue; 12887 break; 12888 } 12889 break; 12890 } 12891 case MotionNotify: 12892 { 12893 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; 12894 if (event->xmotion.window == windows->image.id) 12895 if (windows->magnify.mapped != MagickFalse) 12896 { 12897 /* 12898 Update magnified image. 12899 */ 12900 x=event->xmotion.x; 12901 y=event->xmotion.y; 12902 if (x < 0) 12903 x=0; 12904 else 12905 if (x >= (int) windows->image.width) 12906 x=(int) (windows->image.width-1); 12907 windows->magnify.x=(int) windows->image.x+x; 12908 if (y < 0) 12909 y=0; 12910 else 12911 if (y >= (int) windows->image.height) 12912 y=(int) (windows->image.height-1); 12913 windows->magnify.y=windows->image.y+y; 12914 XMakeMagnifyImage(display,windows,exception); 12915 } 12916 break; 12917 } 12918 case UnmapNotify: 12919 { 12920 if (event->xunmap.window == windows->magnify.id) 12921 { 12922 windows->magnify.mapped=MagickFalse; 12923 break; 12924 } 12925 if (event->xunmap.window == windows->info.id) 12926 { 12927 windows->info.mapped=MagickFalse; 12928 break; 12929 } 12930 break; 12931 } 12932 default: 12933 break; 12934 } 12935} 12936 12937/* 12938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12939% % 12940% % 12941% % 12942+ X S e t C r o p G e o m e t r y % 12943% % 12944% % 12945% % 12946%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12947% 12948% XSetCropGeometry() accepts a cropping geometry relative to the Image window 12949% and translates it to a cropping geometry relative to the image. 12950% 12951% The format of the XSetCropGeometry method is: 12952% 12953% void XSetCropGeometry(Display *display,XWindows *windows, 12954% RectangleInfo *crop_info,Image *image) 12955% 12956% A description of each parameter follows: 12957% 12958% o display: Specifies a connection to an X server; returned from 12959% XOpenDisplay. 12960% 12961% o windows: Specifies a pointer to a XWindows structure. 12962% 12963% o crop_info: A pointer to a RectangleInfo that defines a region of the 12964% Image window to crop. 12965% 12966% o image: the image. 12967% 12968*/ 12969static void XSetCropGeometry(Display *display,XWindows *windows, 12970 RectangleInfo *crop_info,Image *image) 12971{ 12972 char 12973 text[MaxTextExtent]; 12974 12975 int 12976 x, 12977 y; 12978 12979 MagickRealType 12980 scale_factor; 12981 12982 unsigned int 12983 height, 12984 width; 12985 12986 if (windows->info.mapped != MagickFalse) 12987 { 12988 /* 12989 Display info on cropping rectangle. 12990 */ 12991 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g", 12992 (double) crop_info->width,(double) crop_info->height,(double) 12993 crop_info->x,(double) crop_info->y); 12994 XInfoWidget(display,windows,text); 12995 } 12996 /* 12997 Cropping geometry is relative to any previous crop geometry. 12998 */ 12999 x=0; 13000 y=0; 13001 width=(unsigned int) image->columns; 13002 height=(unsigned int) image->rows; 13003 if (windows->image.crop_geometry != (char *) NULL) 13004 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13005 else 13006 windows->image.crop_geometry=AcquireString((char *) NULL); 13007 /* 13008 Define the crop geometry string from the cropping rectangle. 13009 */ 13010 scale_factor=(MagickRealType) width/windows->image.ximage->width; 13011 if (crop_info->x > 0) 13012 x+=(int) (scale_factor*crop_info->x+0.5); 13013 width=(unsigned int) (scale_factor*crop_info->width+0.5); 13014 if (width == 0) 13015 width=1; 13016 scale_factor=(MagickRealType) height/windows->image.ximage->height; 13017 if (crop_info->y > 0) 13018 y+=(int) (scale_factor*crop_info->y+0.5); 13019 height=(unsigned int) (scale_factor*crop_info->height+0.5); 13020 if (height == 0) 13021 height=1; 13022 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 13023 "%ux%u%+d%+d",width,height,x,y); 13024} 13025 13026/* 13027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13028% % 13029% % 13030% % 13031+ X T i l e I m a g e % 13032% % 13033% % 13034% % 13035%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13036% 13037% XTileImage() loads or deletes a selected tile from a visual image directory. 13038% The load or delete command is chosen from a menu. 13039% 13040% The format of the XTileImage method is: 13041% 13042% Image *XTileImage(Display *display,XResourceInfo *resource_info, 13043% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13044% 13045% A description of each parameter follows: 13046% 13047% o tile_image: XTileImage reads or deletes the tile image 13048% and returns it. A null image is returned if an error occurs. 13049% 13050% o display: Specifies a connection to an X server; returned from 13051% XOpenDisplay. 13052% 13053% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13054% 13055% o windows: Specifies a pointer to a XWindows structure. 13056% 13057% o image: the image; returned from ReadImage. 13058% 13059% o event: Specifies a pointer to a XEvent structure. If it is NULL, 13060% the entire image is refreshed. 13061% 13062% o exception: return any errors or warnings in this structure. 13063% 13064*/ 13065static Image *XTileImage(Display *display,XResourceInfo *resource_info, 13066 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13067{ 13068 static const char 13069 *VerbMenu[] = 13070 { 13071 "Load", 13072 "Next", 13073 "Former", 13074 "Delete", 13075 "Update", 13076 (char *) NULL, 13077 }; 13078 13079 static const ModeType 13080 TileCommands[] = 13081 { 13082 TileLoadCommand, 13083 TileNextCommand, 13084 TileFormerCommand, 13085 TileDeleteCommand, 13086 TileUpdateCommand 13087 }; 13088 13089 char 13090 command[MaxTextExtent], 13091 filename[MaxTextExtent]; 13092 13093 Image 13094 *tile_image; 13095 13096 int 13097 id, 13098 status, 13099 tile, 13100 x, 13101 y; 13102 13103 MagickRealType 13104 scale_factor; 13105 13106 register char 13107 *p, 13108 *q; 13109 13110 register int 13111 i; 13112 13113 unsigned int 13114 height, 13115 width; 13116 13117 /* 13118 Tile image is relative to montage image configuration. 13119 */ 13120 x=0; 13121 y=0; 13122 width=(unsigned int) image->columns; 13123 height=(unsigned int) image->rows; 13124 if (windows->image.crop_geometry != (char *) NULL) 13125 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13126 scale_factor=(MagickRealType) width/windows->image.ximage->width; 13127 event->xbutton.x+=windows->image.x; 13128 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5); 13129 scale_factor=(MagickRealType) height/windows->image.ximage->height; 13130 event->xbutton.y+=windows->image.y; 13131 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5); 13132 /* 13133 Determine size and location of each tile in the visual image directory. 13134 */ 13135 width=(unsigned int) image->columns; 13136 height=(unsigned int) image->rows; 13137 x=0; 13138 y=0; 13139 (void) XParseGeometry(image->montage,&x,&y,&width,&height); 13140 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+ 13141 (event->xbutton.x-x)/width; 13142 if (tile < 0) 13143 { 13144 /* 13145 Button press is outside any tile. 13146 */ 13147 (void) XBell(display,0); 13148 return((Image *) NULL); 13149 } 13150 /* 13151 Determine file name from the tile directory. 13152 */ 13153 p=image->directory; 13154 for (i=tile; (i != 0) && (*p != '\0'); ) 13155 { 13156 if (*p == '\n') 13157 i--; 13158 p++; 13159 } 13160 if (*p == '\0') 13161 { 13162 /* 13163 Button press is outside any tile. 13164 */ 13165 (void) XBell(display,0); 13166 return((Image *) NULL); 13167 } 13168 /* 13169 Select a command from the pop-up menu. 13170 */ 13171 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command); 13172 if (id < 0) 13173 return((Image *) NULL); 13174 q=p; 13175 while ((*q != '\n') && (*q != '\0')) 13176 q++; 13177 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13178 /* 13179 Perform command for the selected tile. 13180 */ 13181 XSetCursorState(display,windows,MagickTrue); 13182 XCheckRefreshWindows(display,windows); 13183 tile_image=NewImageList(); 13184 switch (TileCommands[id]) 13185 { 13186 case TileLoadCommand: 13187 { 13188 /* 13189 Load tile image. 13190 */ 13191 XCheckRefreshWindows(display,windows); 13192 (void) CopyMagickString(resource_info->image_info->magick,"MIFF", 13193 MaxTextExtent); 13194 (void) CopyMagickString(resource_info->image_info->filename,filename, 13195 MaxTextExtent); 13196 tile_image=ReadImage(resource_info->image_info,exception); 13197 CatchException(exception); 13198 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13199 break; 13200 } 13201 case TileNextCommand: 13202 { 13203 /* 13204 Display next image. 13205 */ 13206 XClientMessage(display,windows->image.id,windows->im_protocols, 13207 windows->im_next_image,CurrentTime); 13208 break; 13209 } 13210 case TileFormerCommand: 13211 { 13212 /* 13213 Display former image. 13214 */ 13215 XClientMessage(display,windows->image.id,windows->im_protocols, 13216 windows->im_former_image,CurrentTime); 13217 break; 13218 } 13219 case TileDeleteCommand: 13220 { 13221 /* 13222 Delete tile image. 13223 */ 13224 if (IsPathAccessible(filename) == MagickFalse) 13225 { 13226 XNoticeWidget(display,windows,"Image file does not exist:",filename); 13227 break; 13228 } 13229 status=XConfirmWidget(display,windows,"Really delete tile",filename); 13230 if (status <= 0) 13231 break; 13232 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse; 13233 if (status != MagickFalse) 13234 { 13235 XNoticeWidget(display,windows,"Unable to delete image file:", 13236 filename); 13237 break; 13238 } 13239 } 13240 case TileUpdateCommand: 13241 { 13242 int 13243 x_offset, 13244 y_offset; 13245 13246 PixelInfo 13247 pixel; 13248 13249 Quantum 13250 virtual_pixel[CompositePixelChannel]; 13251 13252 register int 13253 j; 13254 13255 register Quantum 13256 *s; 13257 13258 /* 13259 Ensure all the images exist. 13260 */ 13261 tile=0; 13262 GetPixelInfo(image,&pixel); 13263 for (p=image->directory; *p != '\0'; p++) 13264 { 13265 CacheView 13266 *image_view; 13267 13268 q=p; 13269 while ((*q != '\n') && (*q != '\0')) 13270 q++; 13271 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13272 p=q; 13273 if (IsPathAccessible(filename) != MagickFalse) 13274 { 13275 tile++; 13276 continue; 13277 } 13278 /* 13279 Overwrite tile with background color. 13280 */ 13281 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x); 13282 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y); 13283 image_view=AcquireCacheView(image); 13284 (void) GetOneCacheViewVirtualPixel(image_view,0,0,virtual_pixel, 13285 exception); 13286 pixel.red=virtual_pixel[RedPixelChannel]; 13287 pixel.green=virtual_pixel[GreenPixelChannel]; 13288 pixel.blue=virtual_pixel[BluePixelChannel]; 13289 pixel.alpha=virtual_pixel[AlphaPixelChannel]; 13290 for (i=0; i < (int) height; i++) 13291 { 13292 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t) 13293 y_offset+i,width,1,exception); 13294 if (s == (Quantum *) NULL) 13295 break; 13296 for (j=0; j < (int) width; j++) 13297 { 13298 SetPixelInfoPixel(image,&pixel,s); 13299 s+=GetPixelChannels(image); 13300 } 13301 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 13302 break; 13303 } 13304 image_view=DestroyCacheView(image_view); 13305 tile++; 13306 } 13307 windows->image.window_changes.width=(int) image->columns; 13308 windows->image.window_changes.height=(int) image->rows; 13309 XConfigureImageColormap(display,resource_info,windows,image,exception); 13310 (void) XConfigureImage(display,resource_info,windows,image,exception); 13311 break; 13312 } 13313 default: 13314 break; 13315 } 13316 XSetCursorState(display,windows,MagickFalse); 13317 return(tile_image); 13318} 13319 13320/* 13321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13322% % 13323% % 13324% % 13325+ X T r a n s l a t e I m a g e % 13326% % 13327% % 13328% % 13329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13330% 13331% XTranslateImage() translates the image within an Image window by one pixel 13332% as specified by the key symbol. If the image has a `montage string the 13333% translation is respect to the width and height contained within the string. 13334% 13335% The format of the XTranslateImage method is: 13336% 13337% void XTranslateImage(Display *display,XWindows *windows, 13338% Image *image,const KeySym key_symbol) 13339% 13340% A description of each parameter follows: 13341% 13342% o display: Specifies a connection to an X server; returned from 13343% XOpenDisplay. 13344% 13345% o windows: Specifies a pointer to a XWindows structure. 13346% 13347% o image: the image. 13348% 13349% o key_symbol: Specifies a KeySym which indicates which side of the image 13350% to trim. 13351% 13352*/ 13353static void XTranslateImage(Display *display,XWindows *windows, 13354 Image *image,const KeySym key_symbol) 13355{ 13356 char 13357 text[MaxTextExtent]; 13358 13359 int 13360 x, 13361 y; 13362 13363 unsigned int 13364 x_offset, 13365 y_offset; 13366 13367 /* 13368 User specified a pan position offset. 13369 */ 13370 x_offset=windows->image.width; 13371 y_offset=windows->image.height; 13372 if (image->montage != (char *) NULL) 13373 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset); 13374 switch ((int) key_symbol) 13375 { 13376 case XK_Home: 13377 case XK_KP_Home: 13378 { 13379 windows->image.x=(int) windows->image.width/2; 13380 windows->image.y=(int) windows->image.height/2; 13381 break; 13382 } 13383 case XK_Left: 13384 case XK_KP_Left: 13385 { 13386 windows->image.x-=x_offset; 13387 break; 13388 } 13389 case XK_Next: 13390 case XK_Up: 13391 case XK_KP_Up: 13392 { 13393 windows->image.y-=y_offset; 13394 break; 13395 } 13396 case XK_Right: 13397 case XK_KP_Right: 13398 { 13399 windows->image.x+=x_offset; 13400 break; 13401 } 13402 case XK_Prior: 13403 case XK_Down: 13404 case XK_KP_Down: 13405 { 13406 windows->image.y+=y_offset; 13407 break; 13408 } 13409 default: 13410 return; 13411 } 13412 /* 13413 Check boundary conditions. 13414 */ 13415 if (windows->image.x < 0) 13416 windows->image.x=0; 13417 else 13418 if ((int) (windows->image.x+windows->image.width) > 13419 windows->image.ximage->width) 13420 windows->image.x=(int) windows->image.ximage->width-windows->image.width; 13421 if (windows->image.y < 0) 13422 windows->image.y=0; 13423 else 13424 if ((int) (windows->image.y+windows->image.height) > 13425 windows->image.ximage->height) 13426 windows->image.y=(int) windows->image.ximage->height-windows->image.height; 13427 /* 13428 Refresh Image window. 13429 */ 13430 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 13431 windows->image.width,windows->image.height,windows->image.x, 13432 windows->image.y); 13433 XInfoWidget(display,windows,text); 13434 XCheckRefreshWindows(display,windows); 13435 XDrawPanRectangle(display,windows); 13436 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 13437 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13438} 13439 13440/* 13441%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13442% % 13443% % 13444% % 13445+ X T r i m I m a g e % 13446% % 13447% % 13448% % 13449%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13450% 13451% XTrimImage() trims the edges from the Image window. 13452% 13453% The format of the XTrimImage method is: 13454% 13455% MagickBooleanType XTrimImage(Display *display, 13456% XResourceInfo *resource_info,XWindows *windows,Image *image, 13457% ExceptionInfo *exception) 13458% 13459% A description of each parameter follows: 13460% 13461% o display: Specifies a connection to an X server; returned from 13462% XOpenDisplay. 13463% 13464% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13465% 13466% o windows: Specifies a pointer to a XWindows structure. 13467% 13468% o image: the image. 13469% 13470% o exception: return any errors or warnings in this structure. 13471% 13472*/ 13473static MagickBooleanType XTrimImage(Display *display, 13474 XResourceInfo *resource_info,XWindows *windows,Image *image, 13475 ExceptionInfo *exception) 13476{ 13477 RectangleInfo 13478 trim_info; 13479 13480 register int 13481 x, 13482 y; 13483 13484 size_t 13485 background, 13486 pixel; 13487 13488 /* 13489 Trim edges from image. 13490 */ 13491 XSetCursorState(display,windows,MagickTrue); 13492 XCheckRefreshWindows(display,windows); 13493 /* 13494 Crop the left edge. 13495 */ 13496 background=XGetPixel(windows->image.ximage,0,0); 13497 trim_info.width=(size_t) windows->image.ximage->width; 13498 for (x=0; x < windows->image.ximage->width; x++) 13499 { 13500 for (y=0; y < windows->image.ximage->height; y++) 13501 { 13502 pixel=XGetPixel(windows->image.ximage,x,y); 13503 if (pixel != background) 13504 break; 13505 } 13506 if (y < windows->image.ximage->height) 13507 break; 13508 } 13509 trim_info.x=(ssize_t) x; 13510 if (trim_info.x == (ssize_t) windows->image.ximage->width) 13511 { 13512 XSetCursorState(display,windows,MagickFalse); 13513 return(MagickFalse); 13514 } 13515 /* 13516 Crop the right edge. 13517 */ 13518 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0); 13519 for (x=windows->image.ximage->width-1; x != 0; x--) 13520 { 13521 for (y=0; y < windows->image.ximage->height; y++) 13522 { 13523 pixel=XGetPixel(windows->image.ximage,x,y); 13524 if (pixel != background) 13525 break; 13526 } 13527 if (y < windows->image.ximage->height) 13528 break; 13529 } 13530 trim_info.width=(size_t) (x-trim_info.x+1); 13531 /* 13532 Crop the top edge. 13533 */ 13534 background=XGetPixel(windows->image.ximage,0,0); 13535 trim_info.height=(size_t) windows->image.ximage->height; 13536 for (y=0; y < windows->image.ximage->height; y++) 13537 { 13538 for (x=0; x < windows->image.ximage->width; x++) 13539 { 13540 pixel=XGetPixel(windows->image.ximage,x,y); 13541 if (pixel != background) 13542 break; 13543 } 13544 if (x < windows->image.ximage->width) 13545 break; 13546 } 13547 trim_info.y=(ssize_t) y; 13548 /* 13549 Crop the bottom edge. 13550 */ 13551 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1); 13552 for (y=windows->image.ximage->height-1; y != 0; y--) 13553 { 13554 for (x=0; x < windows->image.ximage->width; x++) 13555 { 13556 pixel=XGetPixel(windows->image.ximage,x,y); 13557 if (pixel != background) 13558 break; 13559 } 13560 if (x < windows->image.ximage->width) 13561 break; 13562 } 13563 trim_info.height=(size_t) y-trim_info.y+1; 13564 if (((unsigned int) trim_info.width != windows->image.width) || 13565 ((unsigned int) trim_info.height != windows->image.height)) 13566 { 13567 /* 13568 Reconfigure Image window as defined by the trimming rectangle. 13569 */ 13570 XSetCropGeometry(display,windows,&trim_info,image); 13571 windows->image.window_changes.width=(int) trim_info.width; 13572 windows->image.window_changes.height=(int) trim_info.height; 13573 (void) XConfigureImage(display,resource_info,windows,image,exception); 13574 } 13575 XSetCursorState(display,windows,MagickFalse); 13576 return(MagickTrue); 13577} 13578 13579/* 13580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13581% % 13582% % 13583% % 13584+ X V i s u a l D i r e c t o r y I m a g e % 13585% % 13586% % 13587% % 13588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13589% 13590% XVisualDirectoryImage() creates a Visual Image Directory. 13591% 13592% The format of the XVisualDirectoryImage method is: 13593% 13594% Image *XVisualDirectoryImage(Display *display, 13595% XResourceInfo *resource_info,XWindows *windows, 13596% ExceptionInfo *exception) 13597% 13598% A description of each parameter follows: 13599% 13600% o display: Specifies a connection to an X server; returned from 13601% XOpenDisplay. 13602% 13603% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13604% 13605% o windows: Specifies a pointer to a XWindows structure. 13606% 13607% o exception: return any errors or warnings in this structure. 13608% 13609*/ 13610static Image *XVisualDirectoryImage(Display *display, 13611 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception) 13612{ 13613#define TileImageTag "Scale/Image" 13614#define XClientName "montage" 13615 13616 char 13617 **filelist; 13618 13619 Image 13620 *images, 13621 *montage_image, 13622 *next_image, 13623 *thumbnail_image; 13624 13625 ImageInfo 13626 *read_info; 13627 13628 int 13629 number_files; 13630 13631 MagickBooleanType 13632 backdrop; 13633 13634 MagickStatusType 13635 status; 13636 13637 MontageInfo 13638 *montage_info; 13639 13640 RectangleInfo 13641 geometry; 13642 13643 register int 13644 i; 13645 13646 static char 13647 filename[MaxTextExtent] = "\0", 13648 filenames[MaxTextExtent] = "*"; 13649 13650 XResourceInfo 13651 background_resources; 13652 13653 /* 13654 Request file name from user. 13655 */ 13656 XFileBrowserWidget(display,windows,"Directory",filenames); 13657 if (*filenames == '\0') 13658 return((Image *) NULL); 13659 /* 13660 Expand the filenames. 13661 */ 13662 filelist=(char **) AcquireMagickMemory(sizeof(*filelist)); 13663 if (filelist == (char **) NULL) 13664 { 13665 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13666 filenames); 13667 return((Image *) NULL); 13668 } 13669 number_files=1; 13670 filelist[0]=filenames; 13671 status=ExpandFilenames(&number_files,&filelist); 13672 if ((status == MagickFalse) || (number_files == 0)) 13673 { 13674 if (number_files == 0) 13675 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames) 13676 else 13677 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13678 filenames); 13679 return((Image *) NULL); 13680 } 13681 /* 13682 Set image background resources. 13683 */ 13684 background_resources=(*resource_info); 13685 background_resources.window_id=AcquireString(""); 13686 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent, 13687 "0x%lx",windows->image.id); 13688 background_resources.backdrop=MagickTrue; 13689 /* 13690 Read each image and convert them to a tile. 13691 */ 13692 backdrop=(windows->visual_info->klass == TrueColor) || 13693 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse; 13694 read_info=CloneImageInfo(resource_info->image_info); 13695 (void) SetImageOption(read_info,"jpeg:size","120x120"); 13696 (void) CloneString(&read_info->size,DefaultTileGeometry); 13697 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 13698 (void *) NULL); 13699 images=NewImageList(); 13700 XSetCursorState(display,windows,MagickTrue); 13701 XCheckRefreshWindows(display,windows); 13702 for (i=0; i < (int) number_files; i++) 13703 { 13704 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent); 13705 filelist[i]=DestroyString(filelist[i]); 13706 *read_info->magick='\0'; 13707 next_image=ReadImage(read_info,exception); 13708 CatchException(exception); 13709 if (next_image != (Image *) NULL) 13710 { 13711 (void) DeleteImageProperty(next_image,"label"); 13712 (void) SetImageProperty(next_image,"label",InterpretImageProperties( 13713 read_info,next_image,DefaultTileLabel,exception),exception); 13714 (void) ParseRegionGeometry(next_image,read_info->size,&geometry, 13715 exception); 13716 thumbnail_image=ThumbnailImage(next_image,geometry.width, 13717 geometry.height,exception); 13718 if (thumbnail_image != (Image *) NULL) 13719 { 13720 next_image=DestroyImage(next_image); 13721 next_image=thumbnail_image; 13722 } 13723 if (backdrop) 13724 { 13725 (void) XDisplayBackgroundImage(display,&background_resources, 13726 next_image,exception); 13727 XSetCursorState(display,windows,MagickTrue); 13728 } 13729 AppendImageToList(&images,next_image); 13730 if (images->progress_monitor != (MagickProgressMonitor) NULL) 13731 { 13732 MagickBooleanType 13733 proceed; 13734 13735 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i, 13736 (MagickSizeType) number_files); 13737 if (proceed == MagickFalse) 13738 break; 13739 } 13740 } 13741 } 13742 filelist=(char **) RelinquishMagickMemory(filelist); 13743 if (images == (Image *) NULL) 13744 { 13745 read_info=DestroyImageInfo(read_info); 13746 XSetCursorState(display,windows,MagickFalse); 13747 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames); 13748 return((Image *) NULL); 13749 } 13750 /* 13751 Create the Visual Image Directory. 13752 */ 13753 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL); 13754 montage_info->pointsize=10; 13755 if (resource_info->font != (char *) NULL) 13756 (void) CloneString(&montage_info->font,resource_info->font); 13757 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent); 13758 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList( 13759 images),exception); 13760 images=DestroyImageList(images); 13761 montage_info=DestroyMontageInfo(montage_info); 13762 read_info=DestroyImageInfo(read_info); 13763 XSetCursorState(display,windows,MagickFalse); 13764 if (montage_image == (Image *) NULL) 13765 return(montage_image); 13766 XClientMessage(display,windows->image.id,windows->im_protocols, 13767 windows->im_next_image,CurrentTime); 13768 return(montage_image); 13769} 13770 13771/* 13772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13773% % 13774% % 13775% % 13776% X D i s p l a y B a c k g r o u n d I m a g e % 13777% % 13778% % 13779% % 13780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13781% 13782% XDisplayBackgroundImage() displays an image in the background of a window. 13783% 13784% The format of the XDisplayBackgroundImage method is: 13785% 13786% MagickBooleanType XDisplayBackgroundImage(Display *display, 13787% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13788% 13789% A description of each parameter follows: 13790% 13791% o display: Specifies a connection to an X server; returned from 13792% XOpenDisplay. 13793% 13794% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13795% 13796% o image: the image. 13797% 13798% o exception: return any errors or warnings in this structure. 13799% 13800*/ 13801MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display, 13802 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13803{ 13804 char 13805 geometry[MaxTextExtent], 13806 visual_type[MaxTextExtent]; 13807 13808 int 13809 height, 13810 status, 13811 width; 13812 13813 RectangleInfo 13814 geometry_info; 13815 13816 static XPixelInfo 13817 pixel; 13818 13819 static XStandardColormap 13820 *map_info; 13821 13822 static XVisualInfo 13823 *visual_info = (XVisualInfo *) NULL; 13824 13825 static XWindowInfo 13826 window_info; 13827 13828 size_t 13829 delay; 13830 13831 Window 13832 root_window; 13833 13834 XGCValues 13835 context_values; 13836 13837 XResourceInfo 13838 resources; 13839 13840 XWindowAttributes 13841 window_attributes; 13842 13843 /* 13844 Determine target window. 13845 */ 13846 assert(image != (Image *) NULL); 13847 assert(image->signature == MagickSignature); 13848 if (image->debug != MagickFalse) 13849 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 13850 resources=(*resource_info); 13851 window_info.id=(Window) NULL; 13852 root_window=XRootWindow(display,XDefaultScreen(display)); 13853 if (LocaleCompare(resources.window_id,"root") == 0) 13854 window_info.id=root_window; 13855 else 13856 { 13857 if (isdigit((unsigned char) *resources.window_id) != 0) 13858 window_info.id=XWindowByID(display,root_window, 13859 (Window) strtol((char *) resources.window_id,(char **) NULL,0)); 13860 if (window_info.id == (Window) NULL) 13861 window_info.id=XWindowByName(display,root_window,resources.window_id); 13862 } 13863 if (window_info.id == (Window) NULL) 13864 { 13865 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists", 13866 resources.window_id); 13867 return(MagickFalse); 13868 } 13869 /* 13870 Determine window visual id. 13871 */ 13872 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); 13873 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); 13874 (void) CopyMagickString(visual_type,"default",MaxTextExtent); 13875 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13876 if (status != 0) 13877 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx", 13878 XVisualIDFromVisual(window_attributes.visual)); 13879 if (visual_info == (XVisualInfo *) NULL) 13880 { 13881 /* 13882 Allocate standard colormap. 13883 */ 13884 map_info=XAllocStandardColormap(); 13885 if (map_info == (XStandardColormap *) NULL) 13886 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", 13887 image->filename); 13888 map_info->colormap=(Colormap) NULL; 13889 pixel.pixels=(unsigned long *) NULL; 13890 /* 13891 Initialize visual info. 13892 */ 13893 resources.map_type=(char *) NULL; 13894 resources.visual_type=visual_type; 13895 visual_info=XBestVisualInfo(display,map_info,&resources); 13896 if (visual_info == (XVisualInfo *) NULL) 13897 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", 13898 resources.visual_type); 13899 /* 13900 Initialize window info. 13901 */ 13902 window_info.ximage=(XImage *) NULL; 13903 window_info.matte_image=(XImage *) NULL; 13904 window_info.pixmap=(Pixmap) NULL; 13905 window_info.matte_pixmap=(Pixmap) NULL; 13906 } 13907 /* 13908 Free previous root colors. 13909 */ 13910 if (window_info.id == root_window) 13911 (void) XDestroyWindowColors(display,root_window); 13912 /* 13913 Initialize Standard Colormap. 13914 */ 13915 resources.colormap=SharedColormap; 13916 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel, 13917 exception); 13918 /* 13919 Graphic context superclass. 13920 */ 13921 context_values.background=pixel.background_color.pixel; 13922 context_values.foreground=pixel.foreground_color.pixel; 13923 pixel.annotate_context=XCreateGC(display,window_info.id, 13924 (size_t) (GCBackground | GCForeground),&context_values); 13925 if (pixel.annotate_context == (GC) NULL) 13926 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 13927 image->filename); 13928 /* 13929 Initialize Image window attributes. 13930 */ 13931 window_info.name=AcquireString("\0"); 13932 window_info.icon_name=AcquireString("\0"); 13933 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, 13934 &resources,&window_info); 13935 /* 13936 Create the X image. 13937 */ 13938 window_info.width=(unsigned int) image->columns; 13939 window_info.height=(unsigned int) image->rows; 13940 if ((image->columns != window_info.width) || 13941 (image->rows != window_info.height)) 13942 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13943 image->filename); 13944 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>", 13945 window_attributes.width,window_attributes.height); 13946 geometry_info.width=window_info.width; 13947 geometry_info.height=window_info.height; 13948 geometry_info.x=(ssize_t) window_info.x; 13949 geometry_info.y=(ssize_t) window_info.y; 13950 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 13951 &geometry_info.width,&geometry_info.height); 13952 window_info.width=(unsigned int) geometry_info.width; 13953 window_info.height=(unsigned int) geometry_info.height; 13954 window_info.x=(int) geometry_info.x; 13955 window_info.y=(int) geometry_info.y; 13956 status=XMakeImage(display,&resources,&window_info,image,window_info.width, 13957 window_info.height,exception); 13958 if (status == MagickFalse) 13959 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13960 image->filename); 13961 window_info.x=0; 13962 window_info.y=0; 13963 if (image->debug != MagickFalse) 13964 { 13965 (void) LogMagickEvent(X11Event,GetMagickModule(), 13966 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene, 13967 (double) image->columns,(double) image->rows); 13968 if (image->colors != 0) 13969 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 13970 image->colors); 13971 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick); 13972 } 13973 /* 13974 Adjust image dimensions as specified by backdrop or geometry options. 13975 */ 13976 width=(int) window_info.width; 13977 height=(int) window_info.height; 13978 if (resources.backdrop != MagickFalse) 13979 { 13980 /* 13981 Center image on window. 13982 */ 13983 window_info.x=(window_attributes.width/2)- 13984 (window_info.ximage->width/2); 13985 window_info.y=(window_attributes.height/2)- 13986 (window_info.ximage->height/2); 13987 width=window_attributes.width; 13988 height=window_attributes.height; 13989 } 13990 if ((resources.image_geometry != (char *) NULL) && 13991 (*resources.image_geometry != '\0')) 13992 { 13993 char 13994 default_geometry[MaxTextExtent]; 13995 13996 int 13997 flags, 13998 gravity; 13999 14000 XSizeHints 14001 *size_hints; 14002 14003 /* 14004 User specified geometry. 14005 */ 14006 size_hints=XAllocSizeHints(); 14007 if (size_hints == (XSizeHints *) NULL) 14008 ThrowXWindowFatalException(ResourceLimitFatalError, 14009 "MemoryAllocationFailed",image->filename); 14010 size_hints->flags=0L; 14011 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d", 14012 width,height); 14013 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, 14014 default_geometry,window_info.border_width,size_hints,&window_info.x, 14015 &window_info.y,&width,&height,&gravity); 14016 if (flags & (XValue | YValue)) 14017 { 14018 width=window_attributes.width; 14019 height=window_attributes.height; 14020 } 14021 (void) XFree((void *) size_hints); 14022 } 14023 /* 14024 Create the X pixmap. 14025 */ 14026 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, 14027 (unsigned int) height,window_info.depth); 14028 if (window_info.pixmap == (Pixmap) NULL) 14029 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", 14030 image->filename); 14031 /* 14032 Display pixmap on the window. 14033 */ 14034 if (((unsigned int) width > window_info.width) || 14035 ((unsigned int) height > window_info.height)) 14036 (void) XFillRectangle(display,window_info.pixmap, 14037 window_info.annotate_context,0,0,(unsigned int) width, 14038 (unsigned int) height); 14039 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, 14040 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int) 14041 window_info.width,(unsigned int) window_info.height); 14042 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); 14043 (void) XClearWindow(display,window_info.id); 14044 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); 14045 XDelay(display,delay == 0UL ? 10UL : delay); 14046 (void) XSync(display,MagickFalse); 14047 return(window_info.id == root_window ? MagickTrue : MagickFalse); 14048} 14049 14050/* 14051%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14052% % 14053% % 14054% % 14055+ X D i s p l a y I m a g e % 14056% % 14057% % 14058% % 14059%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14060% 14061% XDisplayImage() displays an image via X11. A new image is created and 14062% returned if the user interactively transforms the displayed image. 14063% 14064% The format of the XDisplayImage method is: 14065% 14066% Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14067% char **argv,int argc,Image **image,size_t *state, 14068% ExceptionInfo *exception) 14069% 14070% A description of each parameter follows: 14071% 14072% o nexus: Method XDisplayImage returns an image when the 14073% user chooses 'Open Image' from the command menu or picks a tile 14074% from the image directory. Otherwise a null image is returned. 14075% 14076% o display: Specifies a connection to an X server; returned from 14077% XOpenDisplay. 14078% 14079% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 14080% 14081% o argv: Specifies the application's argument list. 14082% 14083% o argc: Specifies the number of arguments. 14084% 14085% o image: Specifies an address to an address of an Image structure; 14086% 14087% o exception: return any errors or warnings in this structure. 14088% 14089*/ 14090MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14091 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception) 14092{ 14093#define MagnifySize 256 /* must be a power of 2 */ 14094#define MagickMenus 10 14095#define MagickTitle "Commands" 14096 14097 static const char 14098 *CommandMenu[] = 14099 { 14100 "File", 14101 "Edit", 14102 "View", 14103 "Transform", 14104 "Enhance", 14105 "Effects", 14106 "F/X", 14107 "Image Edit", 14108 "Miscellany", 14109 "Help", 14110 (char *) NULL 14111 }, 14112 *FileMenu[] = 14113 { 14114 "Open...", 14115 "Next", 14116 "Former", 14117 "Select...", 14118 "Save...", 14119 "Print...", 14120 "Delete...", 14121 "New...", 14122 "Visual Directory...", 14123 "Quit", 14124 (char *) NULL 14125 }, 14126 *EditMenu[] = 14127 { 14128 "Undo", 14129 "Redo", 14130 "Cut", 14131 "Copy", 14132 "Paste", 14133 (char *) NULL 14134 }, 14135 *ViewMenu[] = 14136 { 14137 "Half Size", 14138 "Original Size", 14139 "Double Size", 14140 "Resize...", 14141 "Apply", 14142 "Refresh", 14143 "Restore", 14144 (char *) NULL 14145 }, 14146 *TransformMenu[] = 14147 { 14148 "Crop", 14149 "Chop", 14150 "Flop", 14151 "Flip", 14152 "Rotate Right", 14153 "Rotate Left", 14154 "Rotate...", 14155 "Shear...", 14156 "Roll...", 14157 "Trim Edges", 14158 (char *) NULL 14159 }, 14160 *EnhanceMenu[] = 14161 { 14162 "Hue...", 14163 "Saturation...", 14164 "Brightness...", 14165 "Gamma...", 14166 "Spiff", 14167 "Dull", 14168 "Contrast Stretch...", 14169 "Sigmoidal Contrast...", 14170 "Normalize", 14171 "Equalize", 14172 "Negate", 14173 "Grayscale", 14174 "Map...", 14175 "Quantize...", 14176 (char *) NULL 14177 }, 14178 *EffectsMenu[] = 14179 { 14180 "Despeckle", 14181 "Emboss", 14182 "Reduce Noise", 14183 "Add Noise...", 14184 "Sharpen...", 14185 "Blur...", 14186 "Threshold...", 14187 "Edge Detect...", 14188 "Spread...", 14189 "Shade...", 14190 "Raise...", 14191 "Segment...", 14192 (char *) NULL 14193 }, 14194 *FXMenu[] = 14195 { 14196 "Solarize...", 14197 "Sepia Tone...", 14198 "Swirl...", 14199 "Implode...", 14200 "Vignette...", 14201 "Wave...", 14202 "Oil Paint...", 14203 "Charcoal Draw...", 14204 (char *) NULL 14205 }, 14206 *ImageEditMenu[] = 14207 { 14208 "Annotate...", 14209 "Draw...", 14210 "Color...", 14211 "Matte...", 14212 "Composite...", 14213 "Add Border...", 14214 "Add Frame...", 14215 "Comment...", 14216 "Launch...", 14217 "Region of Interest...", 14218 (char *) NULL 14219 }, 14220 *MiscellanyMenu[] = 14221 { 14222 "Image Info", 14223 "Zoom Image", 14224 "Show Preview...", 14225 "Show Histogram", 14226 "Show Matte", 14227 "Background...", 14228 "Slide Show...", 14229 "Preferences...", 14230 (char *) NULL 14231 }, 14232 *HelpMenu[] = 14233 { 14234 "Overview", 14235 "Browse Documentation", 14236 "About Display", 14237 (char *) NULL 14238 }, 14239 *ShortCutsMenu[] = 14240 { 14241 "Next", 14242 "Former", 14243 "Open...", 14244 "Save...", 14245 "Print...", 14246 "Undo", 14247 "Restore", 14248 "Image Info", 14249 "Quit", 14250 (char *) NULL 14251 }, 14252 *VirtualMenu[] = 14253 { 14254 "Image Info", 14255 "Print", 14256 "Next", 14257 "Quit", 14258 (char *) NULL 14259 }; 14260 14261 static const char 14262 **Menus[MagickMenus] = 14263 { 14264 FileMenu, 14265 EditMenu, 14266 ViewMenu, 14267 TransformMenu, 14268 EnhanceMenu, 14269 EffectsMenu, 14270 FXMenu, 14271 ImageEditMenu, 14272 MiscellanyMenu, 14273 HelpMenu 14274 }; 14275 14276 static CommandType 14277 CommandMenus[] = 14278 { 14279 NullCommand, 14280 NullCommand, 14281 NullCommand, 14282 NullCommand, 14283 NullCommand, 14284 NullCommand, 14285 NullCommand, 14286 NullCommand, 14287 NullCommand, 14288 NullCommand, 14289 }, 14290 FileCommands[] = 14291 { 14292 OpenCommand, 14293 NextCommand, 14294 FormerCommand, 14295 SelectCommand, 14296 SaveCommand, 14297 PrintCommand, 14298 DeleteCommand, 14299 NewCommand, 14300 VisualDirectoryCommand, 14301 QuitCommand 14302 }, 14303 EditCommands[] = 14304 { 14305 UndoCommand, 14306 RedoCommand, 14307 CutCommand, 14308 CopyCommand, 14309 PasteCommand 14310 }, 14311 ViewCommands[] = 14312 { 14313 HalfSizeCommand, 14314 OriginalSizeCommand, 14315 DoubleSizeCommand, 14316 ResizeCommand, 14317 ApplyCommand, 14318 RefreshCommand, 14319 RestoreCommand 14320 }, 14321 TransformCommands[] = 14322 { 14323 CropCommand, 14324 ChopCommand, 14325 FlopCommand, 14326 FlipCommand, 14327 RotateRightCommand, 14328 RotateLeftCommand, 14329 RotateCommand, 14330 ShearCommand, 14331 RollCommand, 14332 TrimCommand 14333 }, 14334 EnhanceCommands[] = 14335 { 14336 HueCommand, 14337 SaturationCommand, 14338 BrightnessCommand, 14339 GammaCommand, 14340 SpiffCommand, 14341 DullCommand, 14342 ContrastStretchCommand, 14343 SigmoidalContrastCommand, 14344 NormalizeCommand, 14345 EqualizeCommand, 14346 NegateCommand, 14347 GrayscaleCommand, 14348 MapCommand, 14349 QuantizeCommand 14350 }, 14351 EffectsCommands[] = 14352 { 14353 DespeckleCommand, 14354 EmbossCommand, 14355 ReduceNoiseCommand, 14356 AddNoiseCommand, 14357 SharpenCommand, 14358 BlurCommand, 14359 ThresholdCommand, 14360 EdgeDetectCommand, 14361 SpreadCommand, 14362 ShadeCommand, 14363 RaiseCommand, 14364 SegmentCommand 14365 }, 14366 FXCommands[] = 14367 { 14368 SolarizeCommand, 14369 SepiaToneCommand, 14370 SwirlCommand, 14371 ImplodeCommand, 14372 VignetteCommand, 14373 WaveCommand, 14374 OilPaintCommand, 14375 CharcoalDrawCommand 14376 }, 14377 ImageEditCommands[] = 14378 { 14379 AnnotateCommand, 14380 DrawCommand, 14381 ColorCommand, 14382 MatteCommand, 14383 CompositeCommand, 14384 AddBorderCommand, 14385 AddFrameCommand, 14386 CommentCommand, 14387 LaunchCommand, 14388 RegionofInterestCommand 14389 }, 14390 MiscellanyCommands[] = 14391 { 14392 InfoCommand, 14393 ZoomCommand, 14394 ShowPreviewCommand, 14395 ShowHistogramCommand, 14396 ShowMatteCommand, 14397 BackgroundCommand, 14398 SlideShowCommand, 14399 PreferencesCommand 14400 }, 14401 HelpCommands[] = 14402 { 14403 HelpCommand, 14404 BrowseDocumentationCommand, 14405 VersionCommand 14406 }, 14407 ShortCutsCommands[] = 14408 { 14409 NextCommand, 14410 FormerCommand, 14411 OpenCommand, 14412 SaveCommand, 14413 PrintCommand, 14414 UndoCommand, 14415 RestoreCommand, 14416 InfoCommand, 14417 QuitCommand 14418 }, 14419 VirtualCommands[] = 14420 { 14421 InfoCommand, 14422 PrintCommand, 14423 NextCommand, 14424 QuitCommand 14425 }; 14426 14427 static CommandType 14428 *Commands[MagickMenus] = 14429 { 14430 FileCommands, 14431 EditCommands, 14432 ViewCommands, 14433 TransformCommands, 14434 EnhanceCommands, 14435 EffectsCommands, 14436 FXCommands, 14437 ImageEditCommands, 14438 MiscellanyCommands, 14439 HelpCommands 14440 }; 14441 14442 char 14443 command[MaxTextExtent], 14444 *directory, 14445 geometry[MaxTextExtent], 14446 resource_name[MaxTextExtent]; 14447 14448 CommandType 14449 command_type; 14450 14451 Image 14452 *display_image, 14453 *nexus; 14454 14455 int 14456 entry, 14457 id; 14458 14459 KeySym 14460 key_symbol; 14461 14462 MagickStatusType 14463 context_mask, 14464 status; 14465 14466 RectangleInfo 14467 geometry_info; 14468 14469 register int 14470 i; 14471 14472 static char 14473 working_directory[MaxTextExtent]; 14474 14475 static XPoint 14476 vid_info; 14477 14478 static XWindowInfo 14479 *magick_windows[MaxXWindows]; 14480 14481 static unsigned int 14482 number_windows; 14483 14484 struct stat 14485 attributes; 14486 14487 time_t 14488 timer, 14489 timestamp, 14490 update_time; 14491 14492 unsigned int 14493 height, 14494 width; 14495 14496 size_t 14497 delay; 14498 14499 WarningHandler 14500 warning_handler; 14501 14502 Window 14503 root_window; 14504 14505 XClassHint 14506 *class_hints; 14507 14508 XEvent 14509 event; 14510 14511 XFontStruct 14512 *font_info; 14513 14514 XGCValues 14515 context_values; 14516 14517 XPixelInfo 14518 *icon_pixel, 14519 *pixel; 14520 14521 XResourceInfo 14522 *icon_resources; 14523 14524 XStandardColormap 14525 *icon_map, 14526 *map_info; 14527 14528 XVisualInfo 14529 *icon_visual, 14530 *visual_info; 14531 14532 XWindowChanges 14533 window_changes; 14534 14535 XWindows 14536 *windows; 14537 14538 XWMHints 14539 *manager_hints; 14540 14541 assert(image != (Image **) NULL); 14542 assert((*image)->signature == MagickSignature); 14543 if ((*image)->debug != MagickFalse) 14544 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 14545 display_image=(*image); 14546 warning_handler=(WarningHandler) NULL; 14547 windows=XSetWindows((XWindows *) ~0); 14548 if (windows != (XWindows *) NULL) 14549 { 14550 int 14551 status; 14552 14553 status=chdir(working_directory); 14554 if (status == -1) 14555 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 14556 "UnableToOpenFile","%s",working_directory); 14557 warning_handler=resource_info->display_warnings ? 14558 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14559 warning_handler=resource_info->display_warnings ? 14560 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14561 } 14562 else 14563 { 14564 /* 14565 Allocate windows structure. 14566 */ 14567 resource_info->colors=display_image->colors; 14568 windows=XSetWindows(XInitializeWindows(display,resource_info)); 14569 if (windows == (XWindows *) NULL) 14570 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow", 14571 (*image)->filename); 14572 /* 14573 Initialize window id's. 14574 */ 14575 number_windows=0; 14576 magick_windows[number_windows++]=(&windows->icon); 14577 magick_windows[number_windows++]=(&windows->backdrop); 14578 magick_windows[number_windows++]=(&windows->image); 14579 magick_windows[number_windows++]=(&windows->info); 14580 magick_windows[number_windows++]=(&windows->command); 14581 magick_windows[number_windows++]=(&windows->widget); 14582 magick_windows[number_windows++]=(&windows->popup); 14583 magick_windows[number_windows++]=(&windows->magnify); 14584 magick_windows[number_windows++]=(&windows->pan); 14585 for (i=0; i < (int) number_windows; i++) 14586 magick_windows[i]->id=(Window) NULL; 14587 vid_info.x=0; 14588 vid_info.y=0; 14589 } 14590 /* 14591 Initialize font info. 14592 */ 14593 if (windows->font_info != (XFontStruct *) NULL) 14594 (void) XFreeFont(display,windows->font_info); 14595 windows->font_info=XBestFont(display,resource_info,MagickFalse); 14596 if (windows->font_info == (XFontStruct *) NULL) 14597 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", 14598 resource_info->font); 14599 /* 14600 Initialize Standard Colormap. 14601 */ 14602 map_info=windows->map_info; 14603 icon_map=windows->icon_map; 14604 visual_info=windows->visual_info; 14605 icon_visual=windows->icon_visual; 14606 pixel=windows->pixel_info; 14607 icon_pixel=windows->icon_pixel; 14608 font_info=windows->font_info; 14609 icon_resources=windows->icon_resources; 14610 class_hints=windows->class_hints; 14611 manager_hints=windows->manager_hints; 14612 root_window=XRootWindow(display,visual_info->screen); 14613 nexus=NewImageList(); 14614 if (display_image->debug != MagickFalse) 14615 { 14616 (void) LogMagickEvent(X11Event,GetMagickModule(), 14617 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename, 14618 (double) display_image->scene,(double) display_image->columns, 14619 (double) display_image->rows); 14620 if (display_image->colors != 0) 14621 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 14622 display_image->colors); 14623 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", 14624 display_image->magick); 14625 } 14626 XMakeStandardColormap(display,visual_info,resource_info,display_image, 14627 map_info,pixel,exception); 14628 display_image->taint=MagickFalse; 14629 /* 14630 Initialize graphic context. 14631 */ 14632 windows->context.id=(Window) NULL; 14633 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14634 resource_info,&windows->context); 14635 (void) CloneString(&class_hints->res_name,resource_info->client_name); 14636 (void) CloneString(&class_hints->res_class,resource_info->client_name); 14637 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]); 14638 manager_hints->flags=InputHint | StateHint; 14639 manager_hints->input=MagickFalse; 14640 manager_hints->initial_state=WithdrawnState; 14641 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14642 &windows->context); 14643 if (display_image->debug != MagickFalse) 14644 (void) LogMagickEvent(X11Event,GetMagickModule(), 14645 "Window id: 0x%lx (context)",windows->context.id); 14646 context_values.background=pixel->background_color.pixel; 14647 context_values.font=font_info->fid; 14648 context_values.foreground=pixel->foreground_color.pixel; 14649 context_values.graphics_exposures=MagickFalse; 14650 context_mask=(MagickStatusType) 14651 (GCBackground | GCFont | GCForeground | GCGraphicsExposures); 14652 if (pixel->annotate_context != (GC) NULL) 14653 (void) XFreeGC(display,pixel->annotate_context); 14654 pixel->annotate_context=XCreateGC(display,windows->context.id, 14655 context_mask,&context_values); 14656 if (pixel->annotate_context == (GC) NULL) 14657 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14658 display_image->filename); 14659 context_values.background=pixel->depth_color.pixel; 14660 if (pixel->widget_context != (GC) NULL) 14661 (void) XFreeGC(display,pixel->widget_context); 14662 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask, 14663 &context_values); 14664 if (pixel->widget_context == (GC) NULL) 14665 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14666 display_image->filename); 14667 context_values.background=pixel->foreground_color.pixel; 14668 context_values.foreground=pixel->background_color.pixel; 14669 context_values.plane_mask=context_values.background ^ 14670 context_values.foreground; 14671 if (pixel->highlight_context != (GC) NULL) 14672 (void) XFreeGC(display,pixel->highlight_context); 14673 pixel->highlight_context=XCreateGC(display,windows->context.id, 14674 (size_t) (context_mask | GCPlaneMask),&context_values); 14675 if (pixel->highlight_context == (GC) NULL) 14676 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14677 display_image->filename); 14678 (void) XDestroyWindow(display,windows->context.id); 14679 /* 14680 Initialize icon window. 14681 */ 14682 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, 14683 icon_resources,&windows->icon); 14684 windows->icon.geometry=resource_info->icon_geometry; 14685 XBestIconSize(display,&windows->icon,display_image); 14686 windows->icon.attributes.colormap=XDefaultColormap(display, 14687 icon_visual->screen); 14688 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; 14689 manager_hints->flags=InputHint | StateHint; 14690 manager_hints->input=MagickFalse; 14691 manager_hints->initial_state=IconicState; 14692 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14693 &windows->icon); 14694 if (display_image->debug != MagickFalse) 14695 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", 14696 windows->icon.id); 14697 /* 14698 Initialize graphic context for icon window. 14699 */ 14700 if (icon_pixel->annotate_context != (GC) NULL) 14701 (void) XFreeGC(display,icon_pixel->annotate_context); 14702 context_values.background=icon_pixel->background_color.pixel; 14703 context_values.foreground=icon_pixel->foreground_color.pixel; 14704 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, 14705 (size_t) (GCBackground | GCForeground),&context_values); 14706 if (icon_pixel->annotate_context == (GC) NULL) 14707 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14708 display_image->filename); 14709 windows->icon.annotate_context=icon_pixel->annotate_context; 14710 /* 14711 Initialize Image window. 14712 */ 14713 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14714 &windows->image); 14715 windows->image.shape=MagickTrue; /* non-rectangular shape hint */ 14716 if (resource_info->use_shared_memory == MagickFalse) 14717 windows->image.shared_memory=MagickFalse; 14718 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState)) 14719 { 14720 char 14721 *title; 14722 14723 title=InterpretImageProperties(resource_info->image_info,display_image, 14724 resource_info->title,exception); 14725 (void) CopyMagickString(windows->image.name,title,MaxTextExtent); 14726 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent); 14727 title=DestroyString(title); 14728 } 14729 else 14730 { 14731 char 14732 filename[MaxTextExtent]; 14733 14734 /* 14735 Window name is the base of the filename. 14736 */ 14737 GetPathComponent(display_image->magick_filename,TailPath,filename); 14738 if (display_image->scene == 0) 14739 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14740 "%s: %s",MagickPackageName,filename); 14741 else 14742 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14743 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename, 14744 (double) display_image->scene,(double) GetImageListLength( 14745 display_image)); 14746 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent); 14747 } 14748 if (resource_info->immutable) 14749 windows->image.immutable=MagickTrue; 14750 windows->image.use_pixmap=resource_info->use_pixmap; 14751 windows->image.geometry=resource_info->image_geometry; 14752 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 14753 XDisplayWidth(display,visual_info->screen), 14754 XDisplayHeight(display,visual_info->screen)); 14755 geometry_info.width=display_image->columns; 14756 geometry_info.height=display_image->rows; 14757 geometry_info.x=0; 14758 geometry_info.y=0; 14759 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 14760 &geometry_info.width,&geometry_info.height); 14761 windows->image.width=(unsigned int) geometry_info.width; 14762 windows->image.height=(unsigned int) geometry_info.height; 14763 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14764 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14765 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14766 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; 14767 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14768 resource_info,&windows->backdrop); 14769 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) 14770 { 14771 /* 14772 Initialize backdrop window. 14773 */ 14774 windows->backdrop.x=0; 14775 windows->backdrop.y=0; 14776 (void) CloneString(&windows->backdrop.name,"Backdrop"); 14777 windows->backdrop.flags=(size_t) (USSize | USPosition); 14778 windows->backdrop.width=(unsigned int) 14779 XDisplayWidth(display,visual_info->screen); 14780 windows->backdrop.height=(unsigned int) 14781 XDisplayHeight(display,visual_info->screen); 14782 windows->backdrop.border_width=0; 14783 windows->backdrop.immutable=MagickTrue; 14784 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | 14785 ButtonReleaseMask; 14786 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | 14787 StructureNotifyMask; 14788 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14789 manager_hints->icon_window=windows->icon.id; 14790 manager_hints->input=MagickTrue; 14791 manager_hints->initial_state=resource_info->iconic ? IconicState : 14792 NormalState; 14793 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14794 &windows->backdrop); 14795 if (display_image->debug != MagickFalse) 14796 (void) LogMagickEvent(X11Event,GetMagickModule(), 14797 "Window id: 0x%lx (backdrop)",windows->backdrop.id); 14798 (void) XMapWindow(display,windows->backdrop.id); 14799 (void) XClearWindow(display,windows->backdrop.id); 14800 if (windows->image.id != (Window) NULL) 14801 { 14802 (void) XDestroyWindow(display,windows->image.id); 14803 windows->image.id=(Window) NULL; 14804 } 14805 /* 14806 Position image in the center the backdrop. 14807 */ 14808 windows->image.flags|=USPosition; 14809 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- 14810 (windows->image.width/2); 14811 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- 14812 (windows->image.height/2); 14813 } 14814 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14815 manager_hints->icon_window=windows->icon.id; 14816 manager_hints->input=MagickTrue; 14817 manager_hints->initial_state=resource_info->iconic ? IconicState : 14818 NormalState; 14819 if (windows->group_leader.id != (Window) NULL) 14820 { 14821 /* 14822 Follow the leader. 14823 */ 14824 manager_hints->flags|=WindowGroupHint; 14825 manager_hints->window_group=windows->group_leader.id; 14826 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); 14827 if (display_image->debug != MagickFalse) 14828 (void) LogMagickEvent(X11Event,GetMagickModule(), 14829 "Window id: 0x%lx (group leader)",windows->group_leader.id); 14830 } 14831 XMakeWindow(display, 14832 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), 14833 argv,argc,class_hints,manager_hints,&windows->image); 14834 (void) XChangeProperty(display,windows->image.id,windows->im_protocols, 14835 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); 14836 if (windows->group_leader.id != (Window) NULL) 14837 (void) XSetTransientForHint(display,windows->image.id, 14838 windows->group_leader.id); 14839 if (display_image->debug != MagickFalse) 14840 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", 14841 windows->image.id); 14842 /* 14843 Initialize Info widget. 14844 */ 14845 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14846 &windows->info); 14847 (void) CloneString(&windows->info.name,"Info"); 14848 (void) CloneString(&windows->info.icon_name,"Info"); 14849 windows->info.border_width=1; 14850 windows->info.x=2; 14851 windows->info.y=2; 14852 windows->info.flags|=PPosition; 14853 windows->info.attributes.win_gravity=UnmapGravity; 14854 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | 14855 StructureNotifyMask; 14856 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14857 manager_hints->input=MagickFalse; 14858 manager_hints->initial_state=NormalState; 14859 manager_hints->window_group=windows->image.id; 14860 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, 14861 &windows->info); 14862 windows->info.highlight_stipple=XCreateBitmapFromData(display, 14863 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14864 windows->info.shadow_stipple=XCreateBitmapFromData(display, 14865 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14866 (void) XSetTransientForHint(display,windows->info.id,windows->image.id); 14867 if (windows->image.mapped != MagickFalse) 14868 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14869 if (display_image->debug != MagickFalse) 14870 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", 14871 windows->info.id); 14872 /* 14873 Initialize Command widget. 14874 */ 14875 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14876 resource_info,&windows->command); 14877 windows->command.data=MagickMenus; 14878 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); 14879 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command", 14880 resource_info->client_name); 14881 windows->command.geometry=XGetResourceClass(resource_info->resource_database, 14882 resource_name,"geometry",(char *) NULL); 14883 (void) CloneString(&windows->command.name,MagickTitle); 14884 windows->command.border_width=0; 14885 windows->command.flags|=PPosition; 14886 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14887 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | 14888 OwnerGrabButtonMask | StructureNotifyMask; 14889 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14890 manager_hints->input=MagickTrue; 14891 manager_hints->initial_state=NormalState; 14892 manager_hints->window_group=windows->image.id; 14893 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14894 &windows->command); 14895 windows->command.highlight_stipple=XCreateBitmapFromData(display, 14896 windows->command.id,(char *) HighlightBitmap,HighlightWidth, 14897 HighlightHeight); 14898 windows->command.shadow_stipple=XCreateBitmapFromData(display, 14899 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14900 (void) XSetTransientForHint(display,windows->command.id,windows->image.id); 14901 if (windows->command.mapped != MagickFalse) 14902 (void) XMapRaised(display,windows->command.id); 14903 if (display_image->debug != MagickFalse) 14904 (void) LogMagickEvent(X11Event,GetMagickModule(), 14905 "Window id: 0x%lx (command)",windows->command.id); 14906 /* 14907 Initialize Widget window. 14908 */ 14909 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14910 resource_info,&windows->widget); 14911 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget", 14912 resource_info->client_name); 14913 windows->widget.geometry=XGetResourceClass(resource_info->resource_database, 14914 resource_name,"geometry",(char *) NULL); 14915 windows->widget.border_width=0; 14916 windows->widget.flags|=PPosition; 14917 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14918 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14919 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14920 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->widget); 14927 windows->widget.highlight_stipple=XCreateBitmapFromData(display, 14928 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14929 windows->widget.shadow_stipple=XCreateBitmapFromData(display, 14930 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14931 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); 14932 if (display_image->debug != MagickFalse) 14933 (void) LogMagickEvent(X11Event,GetMagickModule(), 14934 "Window id: 0x%lx (widget)",windows->widget.id); 14935 /* 14936 Initialize popup window. 14937 */ 14938 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14939 resource_info,&windows->popup); 14940 windows->popup.border_width=0; 14941 windows->popup.flags|=PPosition; 14942 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14943 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14944 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask; 14945 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14946 manager_hints->input=MagickTrue; 14947 manager_hints->initial_state=NormalState; 14948 manager_hints->window_group=windows->image.id; 14949 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14950 &windows->popup); 14951 windows->popup.highlight_stipple=XCreateBitmapFromData(display, 14952 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14953 windows->popup.shadow_stipple=XCreateBitmapFromData(display, 14954 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14955 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); 14956 if (display_image->debug != MagickFalse) 14957 (void) LogMagickEvent(X11Event,GetMagickModule(), 14958 "Window id: 0x%lx (pop up)",windows->popup.id); 14959 /* 14960 Initialize Magnify window and cursor. 14961 */ 14962 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14963 resource_info,&windows->magnify); 14964 if (resource_info->use_shared_memory == MagickFalse) 14965 windows->magnify.shared_memory=MagickFalse; 14966 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify", 14967 resource_info->client_name); 14968 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database, 14969 resource_name,"geometry",(char *) NULL); 14970 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX", 14971 resource_info->magnify); 14972 if (windows->magnify.cursor != (Cursor) NULL) 14973 (void) XFreeCursor(display,windows->magnify.cursor); 14974 windows->magnify.cursor=XMakeCursor(display,windows->image.id, 14975 map_info->colormap,resource_info->background_color, 14976 resource_info->foreground_color); 14977 if (windows->magnify.cursor == (Cursor) NULL) 14978 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor", 14979 display_image->filename); 14980 windows->magnify.width=MagnifySize; 14981 windows->magnify.height=MagnifySize; 14982 windows->magnify.flags|=PPosition; 14983 windows->magnify.min_width=MagnifySize; 14984 windows->magnify.min_height=MagnifySize; 14985 windows->magnify.width_inc=MagnifySize; 14986 windows->magnify.height_inc=MagnifySize; 14987 windows->magnify.data=resource_info->magnify; 14988 windows->magnify.attributes.cursor=windows->magnify.cursor; 14989 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask | 14990 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask | 14991 StructureNotifyMask; 14992 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14993 manager_hints->input=MagickTrue; 14994 manager_hints->initial_state=NormalState; 14995 manager_hints->window_group=windows->image.id; 14996 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14997 &windows->magnify); 14998 if (display_image->debug != MagickFalse) 14999 (void) LogMagickEvent(X11Event,GetMagickModule(), 15000 "Window id: 0x%lx (magnify)",windows->magnify.id); 15001 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id); 15002 /* 15003 Initialize panning window. 15004 */ 15005 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 15006 resource_info,&windows->pan); 15007 (void) CloneString(&windows->pan.name,"Pan Icon"); 15008 windows->pan.width=windows->icon.width; 15009 windows->pan.height=windows->icon.height; 15010 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan", 15011 resource_info->client_name); 15012 windows->pan.geometry=XGetResourceClass(resource_info->resource_database, 15013 resource_name,"geometry",(char *) NULL); 15014 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 15015 &windows->pan.width,&windows->pan.height); 15016 windows->pan.flags|=PPosition; 15017 windows->pan.immutable=MagickTrue; 15018 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 15019 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask | 15020 StructureNotifyMask; 15021 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 15022 manager_hints->input=MagickFalse; 15023 manager_hints->initial_state=NormalState; 15024 manager_hints->window_group=windows->image.id; 15025 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 15026 &windows->pan); 15027 if (display_image->debug != MagickFalse) 15028 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)", 15029 windows->pan.id); 15030 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id); 15031 if (windows->info.mapped != MagickFalse) 15032 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15033 if ((windows->image.mapped == MagickFalse) || 15034 (windows->backdrop.id != (Window) NULL)) 15035 (void) XMapWindow(display,windows->image.id); 15036 /* 15037 Set our progress monitor and warning handlers. 15038 */ 15039 if (warning_handler == (WarningHandler) NULL) 15040 { 15041 warning_handler=resource_info->display_warnings ? 15042 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 15043 warning_handler=resource_info->display_warnings ? 15044 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 15045 } 15046 /* 15047 Initialize Image and Magnify X images. 15048 */ 15049 windows->image.x=0; 15050 windows->image.y=0; 15051 windows->magnify.shape=MagickFalse; 15052 width=(unsigned int) display_image->columns; 15053 height=(unsigned int) display_image->rows; 15054 if ((display_image->columns != width) || (display_image->rows != height)) 15055 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15056 display_image->filename); 15057 status=XMakeImage(display,resource_info,&windows->image,display_image, 15058 width,height,exception); 15059 if (status == MagickFalse) 15060 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15061 display_image->filename); 15062 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL, 15063 windows->magnify.width,windows->magnify.height,exception); 15064 if (status == MagickFalse) 15065 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15066 display_image->filename); 15067 if (windows->magnify.mapped != MagickFalse) 15068 (void) XMapRaised(display,windows->magnify.id); 15069 if (windows->pan.mapped != MagickFalse) 15070 (void) XMapRaised(display,windows->pan.id); 15071 windows->image.window_changes.width=(int) display_image->columns; 15072 windows->image.window_changes.height=(int) display_image->rows; 15073 (void) XConfigureImage(display,resource_info,windows,display_image,exception); 15074 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15075 (void) XSync(display,MagickFalse); 15076 /* 15077 Respond to events. 15078 */ 15079 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L); 15080 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15081 update_time=0; 15082 if (resource_info->update != MagickFalse) 15083 { 15084 MagickBooleanType 15085 status; 15086 15087 /* 15088 Determine when file data was last modified. 15089 */ 15090 status=GetPathAttributes(display_image->filename,&attributes); 15091 if (status != MagickFalse) 15092 update_time=attributes.st_mtime; 15093 } 15094 *state&=(~FormerImageState); 15095 *state&=(~MontageImageState); 15096 *state&=(~NextImageState); 15097 do 15098 { 15099 /* 15100 Handle a window event. 15101 */ 15102 if (windows->image.mapped != MagickFalse) 15103 if ((display_image->delay != 0) || (resource_info->update != 0)) 15104 { 15105 if (timer < time((time_t *) NULL)) 15106 { 15107 if (resource_info->update == MagickFalse) 15108 *state|=NextImageState | ExitState; 15109 else 15110 { 15111 MagickBooleanType 15112 status; 15113 15114 /* 15115 Determine if image file was modified. 15116 */ 15117 status=GetPathAttributes(display_image->filename,&attributes); 15118 if (status != MagickFalse) 15119 if (update_time != attributes.st_mtime) 15120 { 15121 /* 15122 Redisplay image. 15123 */ 15124 (void) FormatLocaleString( 15125 resource_info->image_info->filename,MaxTextExtent, 15126 "%s:%s",display_image->magick, 15127 display_image->filename); 15128 nexus=ReadImage(resource_info->image_info,exception); 15129 if (nexus != (Image *) NULL) 15130 { 15131 nexus=DestroyImage(nexus); 15132 *state|=NextImageState | ExitState; 15133 } 15134 } 15135 delay=display_image->delay/MagickMax( 15136 display_image->ticks_per_second,1L); 15137 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15138 } 15139 } 15140 if (XEventsQueued(display,QueuedAfterFlush) == 0) 15141 { 15142 /* 15143 Do not block if delay > 0. 15144 */ 15145 XDelay(display,SuspendTime << 2); 15146 continue; 15147 } 15148 } 15149 timestamp=time((time_t *) NULL); 15150 (void) XNextEvent(display,&event); 15151 if (windows->image.stasis == MagickFalse) 15152 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15153 MagickTrue : MagickFalse; 15154 if (windows->magnify.stasis == MagickFalse) 15155 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15156 MagickTrue : MagickFalse; 15157 if (event.xany.window == windows->command.id) 15158 { 15159 /* 15160 Select a command from the Command widget. 15161 */ 15162 id=XCommandWidget(display,windows,CommandMenu,&event); 15163 if (id < 0) 15164 continue; 15165 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent); 15166 command_type=CommandMenus[id]; 15167 if (id < MagickMenus) 15168 { 15169 /* 15170 Select a command from a pop-up menu. 15171 */ 15172 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15173 command); 15174 if (entry < 0) 15175 continue; 15176 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent); 15177 command_type=Commands[id][entry]; 15178 } 15179 if (command_type != NullCommand) 15180 nexus=XMagickCommand(display,resource_info,windows,command_type, 15181 &display_image,exception); 15182 continue; 15183 } 15184 switch (event.type) 15185 { 15186 case ButtonPress: 15187 { 15188 if (display_image->debug != MagickFalse) 15189 (void) LogMagickEvent(X11Event,GetMagickModule(), 15190 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15191 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15192 if ((event.xbutton.button == Button3) && 15193 (event.xbutton.state & Mod1Mask)) 15194 { 15195 /* 15196 Convert Alt-Button3 to Button2. 15197 */ 15198 event.xbutton.button=Button2; 15199 event.xbutton.state&=(~Mod1Mask); 15200 } 15201 if (event.xbutton.window == windows->backdrop.id) 15202 { 15203 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15204 event.xbutton.time); 15205 break; 15206 } 15207 if (event.xbutton.window == windows->image.id) 15208 { 15209 switch (event.xbutton.button) 15210 { 15211 case Button1: 15212 { 15213 if (resource_info->immutable) 15214 { 15215 /* 15216 Select a command from the Virtual menu. 15217 */ 15218 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15219 command); 15220 if (entry >= 0) 15221 nexus=XMagickCommand(display,resource_info,windows, 15222 VirtualCommands[entry],&display_image,exception); 15223 break; 15224 } 15225 /* 15226 Map/unmap Command widget. 15227 */ 15228 if (windows->command.mapped != MagickFalse) 15229 (void) XWithdrawWindow(display,windows->command.id, 15230 windows->command.screen); 15231 else 15232 { 15233 (void) XCommandWidget(display,windows,CommandMenu, 15234 (XEvent *) NULL); 15235 (void) XMapRaised(display,windows->command.id); 15236 } 15237 break; 15238 } 15239 case Button2: 15240 { 15241 /* 15242 User pressed the image magnify button. 15243 */ 15244 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15245 &display_image,exception); 15246 XMagnifyImage(display,windows,&event,exception); 15247 break; 15248 } 15249 case Button3: 15250 { 15251 if (resource_info->immutable) 15252 { 15253 /* 15254 Select a command from the Virtual menu. 15255 */ 15256 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15257 command); 15258 if (entry >= 0) 15259 nexus=XMagickCommand(display,resource_info,windows, 15260 VirtualCommands[entry],&display_image,exception); 15261 break; 15262 } 15263 if (display_image->montage != (char *) NULL) 15264 { 15265 /* 15266 Open or delete a tile from a visual image directory. 15267 */ 15268 nexus=XTileImage(display,resource_info,windows, 15269 display_image,&event,exception); 15270 if (nexus != (Image *) NULL) 15271 *state|=MontageImageState | NextImageState | ExitState; 15272 vid_info.x=(short int) windows->image.x; 15273 vid_info.y=(short int) windows->image.y; 15274 break; 15275 } 15276 /* 15277 Select a command from the Short Cuts menu. 15278 */ 15279 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15280 command); 15281 if (entry >= 0) 15282 nexus=XMagickCommand(display,resource_info,windows, 15283 ShortCutsCommands[entry],&display_image,exception); 15284 break; 15285 } 15286 case Button4: 15287 { 15288 /* 15289 Wheel up. 15290 */ 15291 XTranslateImage(display,windows,*image,XK_Up); 15292 break; 15293 } 15294 case Button5: 15295 { 15296 /* 15297 Wheel down. 15298 */ 15299 XTranslateImage(display,windows,*image,XK_Down); 15300 break; 15301 } 15302 default: 15303 break; 15304 } 15305 break; 15306 } 15307 if (event.xbutton.window == windows->magnify.id) 15308 { 15309 int 15310 factor; 15311 15312 static const char 15313 *MagnifyMenu[] = 15314 { 15315 "2", 15316 "4", 15317 "5", 15318 "6", 15319 "7", 15320 "8", 15321 "9", 15322 "3", 15323 (char *) NULL, 15324 }; 15325 15326 static KeySym 15327 MagnifyCommands[] = 15328 { 15329 XK_2, 15330 XK_4, 15331 XK_5, 15332 XK_6, 15333 XK_7, 15334 XK_8, 15335 XK_9, 15336 XK_3 15337 }; 15338 15339 /* 15340 Select a magnify factor from the pop-up menu. 15341 */ 15342 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15343 if (factor >= 0) 15344 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor], 15345 exception); 15346 break; 15347 } 15348 if (event.xbutton.window == windows->pan.id) 15349 { 15350 switch (event.xbutton.button) 15351 { 15352 case Button4: 15353 { 15354 /* 15355 Wheel up. 15356 */ 15357 XTranslateImage(display,windows,*image,XK_Up); 15358 break; 15359 } 15360 case Button5: 15361 { 15362 /* 15363 Wheel down. 15364 */ 15365 XTranslateImage(display,windows,*image,XK_Down); 15366 break; 15367 } 15368 default: 15369 { 15370 XPanImage(display,windows,&event,exception); 15371 break; 15372 } 15373 } 15374 break; 15375 } 15376 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15377 1L); 15378 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15379 break; 15380 } 15381 case ButtonRelease: 15382 { 15383 if (display_image->debug != MagickFalse) 15384 (void) LogMagickEvent(X11Event,GetMagickModule(), 15385 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15386 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15387 break; 15388 } 15389 case ClientMessage: 15390 { 15391 if (display_image->debug != MagickFalse) 15392 (void) LogMagickEvent(X11Event,GetMagickModule(), 15393 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15394 event.xclient.message_type,event.xclient.format,(unsigned long) 15395 event.xclient.data.l[0]); 15396 if (event.xclient.message_type == windows->im_protocols) 15397 { 15398 if (*event.xclient.data.l == (long) windows->im_update_widget) 15399 { 15400 (void) CloneString(&windows->command.name,MagickTitle); 15401 windows->command.data=MagickMenus; 15402 (void) XCommandWidget(display,windows,CommandMenu, 15403 (XEvent *) NULL); 15404 break; 15405 } 15406 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15407 { 15408 /* 15409 Update graphic context and window colormap. 15410 */ 15411 for (i=0; i < (int) number_windows; i++) 15412 { 15413 if (magick_windows[i]->id == windows->icon.id) 15414 continue; 15415 context_values.background=pixel->background_color.pixel; 15416 context_values.foreground=pixel->foreground_color.pixel; 15417 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15418 context_mask,&context_values); 15419 (void) XChangeGC(display,magick_windows[i]->widget_context, 15420 context_mask,&context_values); 15421 context_values.background=pixel->foreground_color.pixel; 15422 context_values.foreground=pixel->background_color.pixel; 15423 context_values.plane_mask=context_values.background ^ 15424 context_values.foreground; 15425 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15426 (size_t) (context_mask | GCPlaneMask), 15427 &context_values); 15428 magick_windows[i]->attributes.background_pixel= 15429 pixel->background_color.pixel; 15430 magick_windows[i]->attributes.border_pixel= 15431 pixel->border_color.pixel; 15432 magick_windows[i]->attributes.colormap=map_info->colormap; 15433 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15434 (unsigned long) magick_windows[i]->mask, 15435 &magick_windows[i]->attributes); 15436 } 15437 if (windows->pan.mapped != MagickFalse) 15438 { 15439 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15440 windows->pan.pixmap); 15441 (void) XClearWindow(display,windows->pan.id); 15442 XDrawPanRectangle(display,windows); 15443 } 15444 if (windows->backdrop.id != (Window) NULL) 15445 (void) XInstallColormap(display,map_info->colormap); 15446 break; 15447 } 15448 if (*event.xclient.data.l == (long) windows->im_former_image) 15449 { 15450 *state|=FormerImageState | ExitState; 15451 break; 15452 } 15453 if (*event.xclient.data.l == (long) windows->im_next_image) 15454 { 15455 *state|=NextImageState | ExitState; 15456 break; 15457 } 15458 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15459 { 15460 *state|=RetainColorsState; 15461 break; 15462 } 15463 if (*event.xclient.data.l == (long) windows->im_exit) 15464 { 15465 *state|=ExitState; 15466 break; 15467 } 15468 break; 15469 } 15470 if (event.xclient.message_type == windows->dnd_protocols) 15471 { 15472 Atom 15473 selection, 15474 type; 15475 15476 int 15477 format, 15478 status; 15479 15480 unsigned char 15481 *data; 15482 15483 unsigned long 15484 after, 15485 length; 15486 15487 /* 15488 Display image named by the Drag-and-Drop selection. 15489 */ 15490 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15491 break; 15492 selection=XInternAtom(display,"DndSelection",MagickFalse); 15493 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15494 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15495 &length,&after,&data); 15496 if ((status != Success) || (length == 0)) 15497 break; 15498 if (*event.xclient.data.l == 2) 15499 { 15500 /* 15501 Offix DND. 15502 */ 15503 (void) CopyMagickString(resource_info->image_info->filename, 15504 (char *) data,MaxTextExtent); 15505 } 15506 else 15507 { 15508 /* 15509 XDND. 15510 */ 15511 if (strncmp((char *) data, "file:", 5) != 0) 15512 { 15513 (void) XFree((void *) data); 15514 break; 15515 } 15516 (void) CopyMagickString(resource_info->image_info->filename, 15517 ((char *) data)+5,MaxTextExtent); 15518 } 15519 nexus=ReadImage(resource_info->image_info,exception); 15520 CatchException(exception); 15521 if (nexus != (Image *) NULL) 15522 *state|=NextImageState | ExitState; 15523 (void) XFree((void *) data); 15524 break; 15525 } 15526 /* 15527 If client window delete message, exit. 15528 */ 15529 if (event.xclient.message_type != windows->wm_protocols) 15530 break; 15531 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15532 break; 15533 (void) XWithdrawWindow(display,event.xclient.window, 15534 visual_info->screen); 15535 if (event.xclient.window == windows->image.id) 15536 { 15537 *state|=ExitState; 15538 break; 15539 } 15540 if (event.xclient.window == windows->pan.id) 15541 { 15542 /* 15543 Restore original image size when pan window is deleted. 15544 */ 15545 windows->image.window_changes.width=windows->image.ximage->width; 15546 windows->image.window_changes.height=windows->image.ximage->height; 15547 (void) XConfigureImage(display,resource_info,windows, 15548 display_image,exception); 15549 } 15550 break; 15551 } 15552 case ConfigureNotify: 15553 { 15554 if (display_image->debug != MagickFalse) 15555 (void) LogMagickEvent(X11Event,GetMagickModule(), 15556 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15557 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15558 event.xconfigure.y,event.xconfigure.send_event); 15559 if (event.xconfigure.window == windows->image.id) 15560 { 15561 /* 15562 Image window has a new configuration. 15563 */ 15564 if (event.xconfigure.send_event != 0) 15565 { 15566 XWindowChanges 15567 window_changes; 15568 15569 /* 15570 Position the transient windows relative of the Image window. 15571 */ 15572 if (windows->command.geometry == (char *) NULL) 15573 if (windows->command.mapped == MagickFalse) 15574 { 15575 windows->command.x=event.xconfigure.x- 15576 windows->command.width-25; 15577 windows->command.y=event.xconfigure.y; 15578 XConstrainWindowPosition(display,&windows->command); 15579 window_changes.x=windows->command.x; 15580 window_changes.y=windows->command.y; 15581 (void) XReconfigureWMWindow(display,windows->command.id, 15582 windows->command.screen,(unsigned int) (CWX | CWY), 15583 &window_changes); 15584 } 15585 if (windows->widget.geometry == (char *) NULL) 15586 if (windows->widget.mapped == MagickFalse) 15587 { 15588 windows->widget.x=event.xconfigure.x+ 15589 event.xconfigure.width/10; 15590 windows->widget.y=event.xconfigure.y+ 15591 event.xconfigure.height/10; 15592 XConstrainWindowPosition(display,&windows->widget); 15593 window_changes.x=windows->widget.x; 15594 window_changes.y=windows->widget.y; 15595 (void) XReconfigureWMWindow(display,windows->widget.id, 15596 windows->widget.screen,(unsigned int) (CWX | CWY), 15597 &window_changes); 15598 } 15599 if (windows->magnify.geometry == (char *) NULL) 15600 if (windows->magnify.mapped == MagickFalse) 15601 { 15602 windows->magnify.x=event.xconfigure.x+ 15603 event.xconfigure.width+25; 15604 windows->magnify.y=event.xconfigure.y; 15605 XConstrainWindowPosition(display,&windows->magnify); 15606 window_changes.x=windows->magnify.x; 15607 window_changes.y=windows->magnify.y; 15608 (void) XReconfigureWMWindow(display,windows->magnify.id, 15609 windows->magnify.screen,(unsigned int) (CWX | CWY), 15610 &window_changes); 15611 } 15612 if (windows->pan.geometry == (char *) NULL) 15613 if (windows->pan.mapped == MagickFalse) 15614 { 15615 windows->pan.x=event.xconfigure.x+ 15616 event.xconfigure.width+25; 15617 windows->pan.y=event.xconfigure.y+ 15618 windows->magnify.height+50; 15619 XConstrainWindowPosition(display,&windows->pan); 15620 window_changes.x=windows->pan.x; 15621 window_changes.y=windows->pan.y; 15622 (void) XReconfigureWMWindow(display,windows->pan.id, 15623 windows->pan.screen,(unsigned int) (CWX | CWY), 15624 &window_changes); 15625 } 15626 } 15627 if ((event.xconfigure.width == (int) windows->image.width) && 15628 (event.xconfigure.height == (int) windows->image.height)) 15629 break; 15630 windows->image.width=(unsigned int) event.xconfigure.width; 15631 windows->image.height=(unsigned int) event.xconfigure.height; 15632 windows->image.x=0; 15633 windows->image.y=0; 15634 if (display_image->montage != (char *) NULL) 15635 { 15636 windows->image.x=vid_info.x; 15637 windows->image.y=vid_info.y; 15638 } 15639 if ((windows->image.mapped != MagickFalse) && 15640 (windows->image.stasis != MagickFalse)) 15641 { 15642 /* 15643 Update image window configuration. 15644 */ 15645 windows->image.window_changes.width=event.xconfigure.width; 15646 windows->image.window_changes.height=event.xconfigure.height; 15647 (void) XConfigureImage(display,resource_info,windows, 15648 display_image,exception); 15649 } 15650 /* 15651 Update pan window configuration. 15652 */ 15653 if ((event.xconfigure.width < windows->image.ximage->width) || 15654 (event.xconfigure.height < windows->image.ximage->height)) 15655 { 15656 (void) XMapRaised(display,windows->pan.id); 15657 XDrawPanRectangle(display,windows); 15658 } 15659 else 15660 if (windows->pan.mapped != MagickFalse) 15661 (void) XWithdrawWindow(display,windows->pan.id, 15662 windows->pan.screen); 15663 break; 15664 } 15665 if (event.xconfigure.window == windows->magnify.id) 15666 { 15667 unsigned int 15668 magnify; 15669 15670 /* 15671 Magnify window has a new configuration. 15672 */ 15673 windows->magnify.width=(unsigned int) event.xconfigure.width; 15674 windows->magnify.height=(unsigned int) event.xconfigure.height; 15675 if (windows->magnify.mapped == MagickFalse) 15676 break; 15677 magnify=1; 15678 while ((int) magnify <= event.xconfigure.width) 15679 magnify<<=1; 15680 while ((int) magnify <= event.xconfigure.height) 15681 magnify<<=1; 15682 magnify>>=1; 15683 if (((int) magnify != event.xconfigure.width) || 15684 ((int) magnify != event.xconfigure.height)) 15685 { 15686 window_changes.width=(int) magnify; 15687 window_changes.height=(int) magnify; 15688 (void) XReconfigureWMWindow(display,windows->magnify.id, 15689 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15690 &window_changes); 15691 break; 15692 } 15693 if ((windows->magnify.mapped != MagickFalse) && 15694 (windows->magnify.stasis != MagickFalse)) 15695 { 15696 status=XMakeImage(display,resource_info,&windows->magnify, 15697 display_image,windows->magnify.width,windows->magnify.height, 15698 exception); 15699 XMakeMagnifyImage(display,windows,exception); 15700 } 15701 break; 15702 } 15703 if ((windows->magnify.mapped != MagickFalse) && 15704 (event.xconfigure.window == windows->pan.id)) 15705 { 15706 /* 15707 Pan icon window has a new configuration. 15708 */ 15709 if (event.xconfigure.send_event != 0) 15710 { 15711 windows->pan.x=event.xconfigure.x; 15712 windows->pan.y=event.xconfigure.y; 15713 } 15714 windows->pan.width=(unsigned int) event.xconfigure.width; 15715 windows->pan.height=(unsigned int) event.xconfigure.height; 15716 break; 15717 } 15718 if (event.xconfigure.window == windows->icon.id) 15719 { 15720 /* 15721 Icon window has a new configuration. 15722 */ 15723 windows->icon.width=(unsigned int) event.xconfigure.width; 15724 windows->icon.height=(unsigned int) event.xconfigure.height; 15725 break; 15726 } 15727 break; 15728 } 15729 case DestroyNotify: 15730 { 15731 /* 15732 Group leader has exited. 15733 */ 15734 if (display_image->debug != MagickFalse) 15735 (void) LogMagickEvent(X11Event,GetMagickModule(), 15736 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15737 if (event.xdestroywindow.window == windows->group_leader.id) 15738 { 15739 *state|=ExitState; 15740 break; 15741 } 15742 break; 15743 } 15744 case EnterNotify: 15745 { 15746 /* 15747 Selectively install colormap. 15748 */ 15749 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15750 if (event.xcrossing.mode != NotifyUngrab) 15751 XInstallColormap(display,map_info->colormap); 15752 break; 15753 } 15754 case Expose: 15755 { 15756 if (display_image->debug != MagickFalse) 15757 (void) LogMagickEvent(X11Event,GetMagickModule(), 15758 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15759 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15760 event.xexpose.y); 15761 /* 15762 Refresh windows that are now exposed. 15763 */ 15764 if ((event.xexpose.window == windows->image.id) && 15765 (windows->image.mapped != MagickFalse)) 15766 { 15767 XRefreshWindow(display,&windows->image,&event); 15768 delay=display_image->delay/MagickMax( 15769 display_image->ticks_per_second,1L); 15770 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15771 break; 15772 } 15773 if ((event.xexpose.window == windows->magnify.id) && 15774 (windows->magnify.mapped != MagickFalse)) 15775 { 15776 XMakeMagnifyImage(display,windows,exception); 15777 break; 15778 } 15779 if (event.xexpose.window == windows->pan.id) 15780 { 15781 XDrawPanRectangle(display,windows); 15782 break; 15783 } 15784 if (event.xexpose.window == windows->icon.id) 15785 { 15786 XRefreshWindow(display,&windows->icon,&event); 15787 break; 15788 } 15789 break; 15790 } 15791 case KeyPress: 15792 { 15793 int 15794 length; 15795 15796 /* 15797 Respond to a user key press. 15798 */ 15799 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15800 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15801 *(command+length)='\0'; 15802 if (display_image->debug != MagickFalse) 15803 (void) LogMagickEvent(X11Event,GetMagickModule(), 15804 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15805 key_symbol,command); 15806 if (event.xkey.window == windows->image.id) 15807 { 15808 command_type=XImageWindowCommand(display,resource_info,windows, 15809 event.xkey.state,key_symbol,&display_image,exception); 15810 if (command_type != NullCommand) 15811 nexus=XMagickCommand(display,resource_info,windows,command_type, 15812 &display_image,exception); 15813 } 15814 if (event.xkey.window == windows->magnify.id) 15815 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol, 15816 exception); 15817 if (event.xkey.window == windows->pan.id) 15818 { 15819 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15820 (void) XWithdrawWindow(display,windows->pan.id, 15821 windows->pan.screen); 15822 else 15823 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15824 XTextViewWidget(display,resource_info,windows,MagickFalse, 15825 "Help Viewer - Image Pan",ImagePanHelp); 15826 else 15827 XTranslateImage(display,windows,*image,key_symbol); 15828 } 15829 delay=display_image->delay/MagickMax( 15830 display_image->ticks_per_second,1L); 15831 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15832 break; 15833 } 15834 case KeyRelease: 15835 { 15836 /* 15837 Respond to a user key release. 15838 */ 15839 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15840 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15841 if (display_image->debug != MagickFalse) 15842 (void) LogMagickEvent(X11Event,GetMagickModule(), 15843 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15844 break; 15845 } 15846 case LeaveNotify: 15847 { 15848 /* 15849 Selectively uninstall colormap. 15850 */ 15851 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15852 if (event.xcrossing.mode != NotifyUngrab) 15853 XUninstallColormap(display,map_info->colormap); 15854 break; 15855 } 15856 case MapNotify: 15857 { 15858 if (display_image->debug != MagickFalse) 15859 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15860 event.xmap.window); 15861 if (event.xmap.window == windows->backdrop.id) 15862 { 15863 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15864 CurrentTime); 15865 windows->backdrop.mapped=MagickTrue; 15866 break; 15867 } 15868 if (event.xmap.window == windows->image.id) 15869 { 15870 if (windows->backdrop.id != (Window) NULL) 15871 (void) XInstallColormap(display,map_info->colormap); 15872 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15873 { 15874 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15875 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15876 } 15877 if (((int) windows->image.width < windows->image.ximage->width) || 15878 ((int) windows->image.height < windows->image.ximage->height)) 15879 (void) XMapRaised(display,windows->pan.id); 15880 windows->image.mapped=MagickTrue; 15881 break; 15882 } 15883 if (event.xmap.window == windows->magnify.id) 15884 { 15885 XMakeMagnifyImage(display,windows,exception); 15886 windows->magnify.mapped=MagickTrue; 15887 (void) XWithdrawWindow(display,windows->info.id, 15888 windows->info.screen); 15889 break; 15890 } 15891 if (event.xmap.window == windows->pan.id) 15892 { 15893 XMakePanImage(display,resource_info,windows,display_image, 15894 exception); 15895 windows->pan.mapped=MagickTrue; 15896 break; 15897 } 15898 if (event.xmap.window == windows->info.id) 15899 { 15900 windows->info.mapped=MagickTrue; 15901 break; 15902 } 15903 if (event.xmap.window == windows->icon.id) 15904 { 15905 MagickBooleanType 15906 taint; 15907 15908 /* 15909 Create an icon image. 15910 */ 15911 taint=display_image->taint; 15912 XMakeStandardColormap(display,icon_visual,icon_resources, 15913 display_image,icon_map,icon_pixel,exception); 15914 (void) XMakeImage(display,icon_resources,&windows->icon, 15915 display_image,windows->icon.width,windows->icon.height, 15916 exception); 15917 display_image->taint=taint; 15918 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15919 windows->icon.pixmap); 15920 (void) XClearWindow(display,windows->icon.id); 15921 (void) XWithdrawWindow(display,windows->info.id, 15922 windows->info.screen); 15923 windows->icon.mapped=MagickTrue; 15924 break; 15925 } 15926 if (event.xmap.window == windows->command.id) 15927 { 15928 windows->command.mapped=MagickTrue; 15929 break; 15930 } 15931 if (event.xmap.window == windows->popup.id) 15932 { 15933 windows->popup.mapped=MagickTrue; 15934 break; 15935 } 15936 if (event.xmap.window == windows->widget.id) 15937 { 15938 windows->widget.mapped=MagickTrue; 15939 break; 15940 } 15941 break; 15942 } 15943 case MappingNotify: 15944 { 15945 (void) XRefreshKeyboardMapping(&event.xmapping); 15946 break; 15947 } 15948 case NoExpose: 15949 break; 15950 case PropertyNotify: 15951 { 15952 Atom 15953 type; 15954 15955 int 15956 format, 15957 status; 15958 15959 unsigned char 15960 *data; 15961 15962 unsigned long 15963 after, 15964 length; 15965 15966 if (display_image->debug != MagickFalse) 15967 (void) LogMagickEvent(X11Event,GetMagickModule(), 15968 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15969 event.xproperty.atom,event.xproperty.state); 15970 if (event.xproperty.atom != windows->im_remote_command) 15971 break; 15972 /* 15973 Display image named by the remote command protocol. 15974 */ 15975 status=XGetWindowProperty(display,event.xproperty.window, 15976 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom) 15977 AnyPropertyType,&type,&format,&length,&after,&data); 15978 if ((status != Success) || (length == 0)) 15979 break; 15980 if (LocaleCompare((char *) data,"-quit") == 0) 15981 { 15982 XClientMessage(display,windows->image.id,windows->im_protocols, 15983 windows->im_exit,CurrentTime); 15984 (void) XFree((void *) data); 15985 break; 15986 } 15987 (void) CopyMagickString(resource_info->image_info->filename, 15988 (char *) data,MaxTextExtent); 15989 (void) XFree((void *) data); 15990 nexus=ReadImage(resource_info->image_info,exception); 15991 CatchException(exception); 15992 if (nexus != (Image *) NULL) 15993 *state|=NextImageState | ExitState; 15994 break; 15995 } 15996 case ReparentNotify: 15997 { 15998 if (display_image->debug != MagickFalse) 15999 (void) LogMagickEvent(X11Event,GetMagickModule(), 16000 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 16001 event.xreparent.window); 16002 break; 16003 } 16004 case UnmapNotify: 16005 { 16006 if (display_image->debug != MagickFalse) 16007 (void) LogMagickEvent(X11Event,GetMagickModule(), 16008 "Unmap Notify: 0x%lx",event.xunmap.window); 16009 if (event.xunmap.window == windows->backdrop.id) 16010 { 16011 windows->backdrop.mapped=MagickFalse; 16012 break; 16013 } 16014 if (event.xunmap.window == windows->image.id) 16015 { 16016 windows->image.mapped=MagickFalse; 16017 break; 16018 } 16019 if (event.xunmap.window == windows->magnify.id) 16020 { 16021 windows->magnify.mapped=MagickFalse; 16022 break; 16023 } 16024 if (event.xunmap.window == windows->pan.id) 16025 { 16026 windows->pan.mapped=MagickFalse; 16027 break; 16028 } 16029 if (event.xunmap.window == windows->info.id) 16030 { 16031 windows->info.mapped=MagickFalse; 16032 break; 16033 } 16034 if (event.xunmap.window == windows->icon.id) 16035 { 16036 if (map_info->colormap == icon_map->colormap) 16037 XConfigureImageColormap(display,resource_info,windows, 16038 display_image,exception); 16039 (void) XFreeStandardColormap(display,icon_visual,icon_map, 16040 icon_pixel); 16041 windows->icon.mapped=MagickFalse; 16042 break; 16043 } 16044 if (event.xunmap.window == windows->command.id) 16045 { 16046 windows->command.mapped=MagickFalse; 16047 break; 16048 } 16049 if (event.xunmap.window == windows->popup.id) 16050 { 16051 if (windows->backdrop.id != (Window) NULL) 16052 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16053 CurrentTime); 16054 windows->popup.mapped=MagickFalse; 16055 break; 16056 } 16057 if (event.xunmap.window == windows->widget.id) 16058 { 16059 if (windows->backdrop.id != (Window) NULL) 16060 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16061 CurrentTime); 16062 windows->widget.mapped=MagickFalse; 16063 break; 16064 } 16065 break; 16066 } 16067 default: 16068 { 16069 if (display_image->debug != MagickFalse) 16070 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 16071 event.type); 16072 break; 16073 } 16074 } 16075 } while (!(*state & ExitState)); 16076 if ((*state & ExitState) == 0) 16077 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 16078 &display_image,exception); 16079 else 16080 if (resource_info->confirm_edit != MagickFalse) 16081 { 16082 /* 16083 Query user if image has changed. 16084 */ 16085 if ((resource_info->immutable == MagickFalse) && 16086 (display_image->taint != MagickFalse)) 16087 { 16088 int 16089 status; 16090 16091 status=XConfirmWidget(display,windows,"Your image changed.", 16092 "Do you want to save it"); 16093 if (status == 0) 16094 *state&=(~ExitState); 16095 else 16096 if (status > 0) 16097 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 16098 &display_image,exception); 16099 } 16100 } 16101 if ((windows->visual_info->klass == GrayScale) || 16102 (windows->visual_info->klass == PseudoColor) || 16103 (windows->visual_info->klass == DirectColor)) 16104 { 16105 /* 16106 Withdraw pan and Magnify window. 16107 */ 16108 if (windows->info.mapped != MagickFalse) 16109 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 16110 if (windows->magnify.mapped != MagickFalse) 16111 (void) XWithdrawWindow(display,windows->magnify.id, 16112 windows->magnify.screen); 16113 if (windows->command.mapped != MagickFalse) 16114 (void) XWithdrawWindow(display,windows->command.id, 16115 windows->command.screen); 16116 } 16117 if (windows->pan.mapped != MagickFalse) 16118 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 16119 if (resource_info->backdrop == MagickFalse) 16120 if (windows->backdrop.mapped) 16121 { 16122 (void) XWithdrawWindow(display,windows->backdrop.id, 16123 windows->backdrop.screen); 16124 (void) XDestroyWindow(display,windows->backdrop.id); 16125 windows->backdrop.id=(Window) NULL; 16126 (void) XWithdrawWindow(display,windows->image.id, 16127 windows->image.screen); 16128 (void) XDestroyWindow(display,windows->image.id); 16129 windows->image.id=(Window) NULL; 16130 } 16131 XSetCursorState(display,windows,MagickTrue); 16132 XCheckRefreshWindows(display,windows); 16133 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 16134 *state&=(~ExitState); 16135 if (*state & ExitState) 16136 { 16137 /* 16138 Free Standard Colormap. 16139 */ 16140 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 16141 if (resource_info->map_type == (char *) NULL) 16142 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 16143 /* 16144 Free X resources. 16145 */ 16146 if (resource_info->copy_image != (Image *) NULL) 16147 { 16148 resource_info->copy_image=DestroyImage(resource_info->copy_image); 16149 resource_info->copy_image=NewImageList(); 16150 } 16151 DestroyXResources(); 16152 } 16153 (void) XSync(display,MagickFalse); 16154 /* 16155 Restore our progress monitor and warning handlers. 16156 */ 16157 (void) SetErrorHandler(warning_handler); 16158 (void) SetWarningHandler(warning_handler); 16159 /* 16160 Change to home directory. 16161 */ 16162 directory=getcwd(working_directory,MaxTextExtent); 16163 (void) directory; 16164 { 16165 int 16166 status; 16167 16168 status=chdir(resource_info->home_directory); 16169 if (status == -1) 16170 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 16171 "UnableToOpenFile","%s",resource_info->home_directory); 16172 } 16173 *image=display_image; 16174 return(nexus); 16175} 16176#else 16177 16178/* 16179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16180% % 16181% % 16182% % 16183+ D i s p l a y I m a g e s % 16184% % 16185% % 16186% % 16187%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16188% 16189% DisplayImages() displays an image sequence to any X window screen. It 16190% returns a value other than 0 if successful. Check the exception member 16191% of image to determine the reason for any failure. 16192% 16193% The format of the DisplayImages method is: 16194% 16195% MagickBooleanType DisplayImages(const ImageInfo *image_info, 16196% Image *images,ExceptionInfo *exception) 16197% 16198% A description of each parameter follows: 16199% 16200% o image_info: the image info. 16201% 16202% o image: the image. 16203% 16204% o exception: return any errors or warnings in this structure. 16205% 16206*/ 16207MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16208 Image *image,ExceptionInfo *exception) 16209{ 16210 assert(image_info != (const ImageInfo *) NULL); 16211 assert(image_info->signature == MagickSignature); 16212 assert(image != (Image *) NULL); 16213 assert(image->signature == MagickSignature); 16214 if (image->debug != MagickFalse) 16215 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16216 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16217 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image->filename); 16218 return(MagickFalse); 16219} 16220 16221/* 16222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16223% % 16224% % 16225% % 16226+ R e m o t e D i s p l a y C o m m a n d % 16227% % 16228% % 16229% % 16230%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16231% 16232% RemoteDisplayCommand() encourages a remote display program to display the 16233% specified image filename. 16234% 16235% The format of the RemoteDisplayCommand method is: 16236% 16237% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16238% const char *window,const char *filename,ExceptionInfo *exception) 16239% 16240% A description of each parameter follows: 16241% 16242% o image_info: the image info. 16243% 16244% o window: Specifies the name or id of an X window. 16245% 16246% o filename: the name of the image filename to display. 16247% 16248% o exception: return any errors or warnings in this structure. 16249% 16250*/ 16251MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16252 const char *window,const char *filename,ExceptionInfo *exception) 16253{ 16254 assert(image_info != (const ImageInfo *) NULL); 16255 assert(image_info->signature == MagickSignature); 16256 assert(filename != (char *) NULL); 16257 (void) window; 16258 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16259 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16260 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename); 16261 return(MagickFalse); 16262} 16263#endif 16264