display.c revision 4d246fc57cf90dc0ac7addcd8192d5c013fce640
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% Cristy % 17% July 1992 % 18% % 19% % 20% Copyright 1999-2014 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/attribute.h" 45#include "MagickCore/blob.h" 46#include "MagickCore/cache.h" 47#include "MagickCore/cache-private.h" 48#include "MagickCore/channel.h" 49#include "MagickCore/client.h" 50#include "MagickCore/color.h" 51#include "MagickCore/colorspace.h" 52#include "MagickCore/composite.h" 53#include "MagickCore/constitute.h" 54#include "MagickCore/decorate.h" 55#include "MagickCore/delegate.h" 56#include "MagickCore/display.h" 57#include "MagickCore/display-private.h" 58#include "MagickCore/distort.h" 59#include "MagickCore/draw.h" 60#include "MagickCore/effect.h" 61#include "MagickCore/enhance.h" 62#include "MagickCore/exception.h" 63#include "MagickCore/exception-private.h" 64#include "MagickCore/fx.h" 65#include "MagickCore/geometry.h" 66#include "MagickCore/image.h" 67#include "MagickCore/image-private.h" 68#include "MagickCore/list.h" 69#include "MagickCore/log.h" 70#include "MagickCore/magick.h" 71#include "MagickCore/memory_.h" 72#include "MagickCore/monitor.h" 73#include "MagickCore/monitor-private.h" 74#include "MagickCore/montage.h" 75#include "MagickCore/option.h" 76#include "MagickCore/paint.h" 77#include "MagickCore/pixel.h" 78#include "MagickCore/pixel-accessor.h" 79#include "MagickCore/PreRvIcccm.h" 80#include "MagickCore/property.h" 81#include "MagickCore/quantum.h" 82#include "MagickCore/quantum-private.h" 83#include "MagickCore/resize.h" 84#include "MagickCore/resource_.h" 85#include "MagickCore/shear.h" 86#include "MagickCore/segment.h" 87#include "MagickCore/statistic.h" 88#include "MagickCore/string_.h" 89#include "MagickCore/string-private.h" 90#include "MagickCore/transform.h" 91#include "MagickCore/threshold.h" 92#include "MagickCore/utility.h" 93#include "MagickCore/utility-private.h" 94#include "MagickCore/version.h" 95#include "MagickCore/widget.h" 96#include "MagickCore/widget-private.h" 97#include "MagickCore/xwindow.h" 98#include "MagickCore/xwindow-private.h" 99 100#if defined(MAGICKCORE_X11_DELEGATE) 101/* 102 Define declarations. 103*/ 104#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L) 105 106/* 107 Constant declarations. 108*/ 109static const unsigned char 110 HighlightBitmap[8] = 111 { 112 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 113 }, 114 OpaqueBitmap[8] = 115 { 116 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 117 }, 118 ShadowBitmap[8] = 119 { 120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 121 }; 122 123static const char 124 *PageSizes[] = 125 { 126 "Letter", 127 "Tabloid", 128 "Ledger", 129 "Legal", 130 "Statement", 131 "Executive", 132 "A3", 133 "A4", 134 "A5", 135 "B4", 136 "B5", 137 "Folio", 138 "Quarto", 139 "10x14", 140 (char *) NULL 141 }; 142 143/* 144 Help widget declarations. 145*/ 146static const char 147 *ImageAnnotateHelp[] = 148 { 149 "In annotate mode, the Command widget has these options:", 150 "", 151 " Font Name", 152 " fixed", 153 " variable", 154 " 5x8", 155 " 6x10", 156 " 7x13bold", 157 " 8x13bold", 158 " 9x15bold", 159 " 10x20", 160 " 12x24", 161 " Browser...", 162 " Font Color", 163 " black", 164 " blue", 165 " cyan", 166 " green", 167 " gray", 168 " red", 169 " magenta", 170 " yellow", 171 " white", 172 " transparent", 173 " Browser...", 174 " Font Color", 175 " black", 176 " blue", 177 " cyan", 178 " green", 179 " gray", 180 " red", 181 " magenta", 182 " yellow", 183 " white", 184 " transparent", 185 " Browser...", 186 " Rotate Text", 187 " -90", 188 " -45", 189 " -30", 190 " 0", 191 " 30", 192 " 45", 193 " 90", 194 " 180", 195 " Dialog...", 196 " Help", 197 " Dismiss", 198 "", 199 "Choose a font name from the Font Name sub-menu. Additional", 200 "font names can be specified with the font browser. You can", 201 "change the menu names by setting the X resources font1", 202 "through font9.", 203 "", 204 "Choose a font color from the Font Color sub-menu.", 205 "Additional font colors can be specified with the color", 206 "browser. You can change the menu colors by setting the X", 207 "resources pen1 through pen9.", 208 "", 209 "If you select the color browser and press Grab, you can", 210 "choose the font color by moving the pointer to the desired", 211 "color on the screen and press any button.", 212 "", 213 "If you choose to rotate the text, choose Rotate Text from the", 214 "menu and select an angle. Typically you will only want to", 215 "rotate one line of text at a time. Depending on the angle you", 216 "choose, subsequent lines may end up overwriting each other.", 217 "", 218 "Choosing a font and its color is optional. The default font", 219 "is fixed and the default color is black. However, you must", 220 "choose a location to begin entering text and press button 1.", 221 "An underscore character will appear at the location of the", 222 "pointer. The cursor changes to a pencil to indicate you are", 223 "in text mode. To exit immediately, press Dismiss.", 224 "", 225 "In text mode, any key presses will display the character at", 226 "the location of the underscore and advance the underscore", 227 "cursor. Enter your text and once completed press Apply to", 228 "finish your image annotation. To correct errors press BACK", 229 "SPACE. To delete an entire line of text, press DELETE. Any", 230 "text that exceeds the boundaries of the image window is", 231 "automagically continued onto the next line.", 232 "", 233 "The actual color you request for the font is saved in the", 234 "image. However, the color that appears in your image window", 235 "may be different. For example, on a monochrome screen the", 236 "text will appear black or white even if you choose the color", 237 "red as the font color. However, the image saved to a file", 238 "with -write is written with red lettering. To assure the", 239 "correct color text in the final image, any PseudoClass image", 240 "is promoted to DirectClass (see miff(5)). To force a", 241 "PseudoClass image to remain PseudoClass, use -colors.", 242 (char *) NULL, 243 }, 244 *ImageChopHelp[] = 245 { 246 "In chop mode, the Command widget has these options:", 247 "", 248 " Direction", 249 " horizontal", 250 " vertical", 251 " Help", 252 " Dismiss", 253 "", 254 "If the you choose the horizontal direction (this the", 255 "default), the area of the image between the two horizontal", 256 "endpoints of the chop line is removed. Otherwise, the area", 257 "of the image between the two vertical endpoints of the chop", 258 "line is removed.", 259 "", 260 "Select a location within the image window to begin your chop,", 261 "press and hold any button. Next, move the pointer to", 262 "another location in the image. As you move a line will", 263 "connect the initial location and the pointer. When you", 264 "release the button, the area within the image to chop is", 265 "determined by which direction you choose from the Command", 266 "widget.", 267 "", 268 "To cancel the image chopping, move the pointer back to the", 269 "starting point of the line and release the button.", 270 (char *) NULL, 271 }, 272 *ImageColorEditHelp[] = 273 { 274 "In color edit mode, the Command widget has these options:", 275 "", 276 " Method", 277 " point", 278 " replace", 279 " floodfill", 280 " filltoborder", 281 " reset", 282 " Pixel Color", 283 " black", 284 " blue", 285 " cyan", 286 " green", 287 " gray", 288 " red", 289 " magenta", 290 " yellow", 291 " white", 292 " Browser...", 293 " Border Color", 294 " black", 295 " blue", 296 " cyan", 297 " green", 298 " gray", 299 " red", 300 " magenta", 301 " yellow", 302 " white", 303 " Browser...", 304 " Fuzz", 305 " 0%", 306 " 2%", 307 " 5%", 308 " 10%", 309 " 15%", 310 " Dialog...", 311 " Undo", 312 " Help", 313 " Dismiss", 314 "", 315 "Choose a color editing method from the Method sub-menu", 316 "of the Command widget. The point method recolors any pixel", 317 "selected with the pointer until the button is released. The", 318 "replace method recolors any pixel that matches the color of", 319 "the pixel you select with a button press. Floodfill recolors", 320 "any pixel that matches the color of the pixel you select with", 321 "a button press and is a neighbor. Whereas filltoborder recolors", 322 "any neighbor pixel that is not the border color. Finally reset", 323 "changes the entire image to the designated color.", 324 "", 325 "Next, choose a pixel color from the Pixel Color sub-menu.", 326 "Additional pixel colors can be specified with the color", 327 "browser. You can change the menu colors by setting the X", 328 "resources pen1 through pen9.", 329 "", 330 "Now press button 1 to select a pixel within the image window", 331 "to change its color. Additional pixels may be recolored as", 332 "prescribed by the method you choose.", 333 "", 334 "If the Magnify widget is mapped, it can be helpful in positioning", 335 "your pointer within the image (refer to button 2).", 336 "", 337 "The actual color you request for the pixels is saved in the", 338 "image. However, the color that appears in your image window", 339 "may be different. For example, on a monochrome screen the", 340 "pixel will appear black or white even if you choose the", 341 "color red as the pixel color. However, the image saved to a", 342 "file with -write is written with red pixels. To assure the", 343 "correct color text in the final image, any PseudoClass image", 344 "is promoted to DirectClass (see miff(5)). To force a", 345 "PseudoClass image to remain PseudoClass, use -colors.", 346 (char *) NULL, 347 }, 348 *ImageCompositeHelp[] = 349 { 350 "First a widget window is displayed requesting you to enter an", 351 "image name. Press Composite, Grab or type a file name.", 352 "Press Cancel if you choose not to create a composite image.", 353 "When you choose Grab, move the pointer to the desired window", 354 "and press any button.", 355 "", 356 "If the Composite image does not have any matte information,", 357 "you are informed and the file browser is displayed again.", 358 "Enter the name of a mask image. The image is typically", 359 "grayscale and the same size as the composite image. If the", 360 "image is not grayscale, it is converted to grayscale and the", 361 "resulting intensities are used as matte information.", 362 "", 363 "A small window appears showing the location of the cursor in", 364 "the image window. You are now in composite mode. To exit", 365 "immediately, press Dismiss. In composite mode, the Command", 366 "widget has these options:", 367 "", 368 " Operators", 369 " Over", 370 " In", 371 " Out", 372 " Atop", 373 " Xor", 374 " Plus", 375 " Minus", 376 " Add", 377 " Subtract", 378 " Difference", 379 " Multiply", 380 " Bumpmap", 381 " Copy", 382 " CopyRed", 383 " CopyGreen", 384 " CopyBlue", 385 " CopyOpacity", 386 " Clear", 387 " Dissolve", 388 " Displace", 389 " Help", 390 " Dismiss", 391 "", 392 "Choose a composite operation from the Operators sub-menu of", 393 "the Command widget. How each operator behaves is described", 394 "below. Image window is the image currently displayed on", 395 "your X server and image is the image obtained with the File", 396 "Browser widget.", 397 "", 398 "Over The result is the union of the two image shapes,", 399 " with image obscuring image window in the region of", 400 " overlap.", 401 "", 402 "In The result is simply image cut by the shape of", 403 " image window. None of the image data of image", 404 " window is in the result.", 405 "", 406 "Out The resulting image is image with the shape of", 407 " image window cut out.", 408 "", 409 "Atop The result is the same shape as image image window,", 410 " with image obscuring image window where the image", 411 " shapes overlap. Note this differs from over", 412 " because the portion of image outside image window's", 413 " shape does not appear in the result.", 414 "", 415 "Xor The result is the image data from both image and", 416 " image window that is outside the overlap region.", 417 " The overlap region is blank.", 418 "", 419 "Plus The result is just the sum of the image data.", 420 " Output values are cropped to QuantumRange (no overflow).", 421 "", 422 "Minus The result of image - image window, with underflow", 423 " cropped to zero.", 424 "", 425 "Add The result of image + image window, with overflow", 426 " wrapping around (mod 256).", 427 "", 428 "Subtract The result of image - image window, with underflow", 429 " wrapping around (mod 256). The add and subtract", 430 " operators can be used to perform reversible", 431 " transformations.", 432 "", 433 "Difference", 434 " The result of abs(image - image window). This", 435 " useful for comparing two very similar images.", 436 "", 437 "Multiply", 438 " The result of image * image window. This", 439 " useful for the creation of drop-shadows.", 440 "", 441 "Bumpmap The result of surface normals from image * image", 442 " window.", 443 "", 444 "Copy The resulting image is image window replaced with", 445 " image. Here the matte information is ignored.", 446 "", 447 "CopyRed The red layer of the image window is replace with", 448 " the red layer of the image. The other layers are", 449 " untouched.", 450 "", 451 "CopyGreen", 452 " The green layer of the image window is replace with", 453 " the green layer of the image. The other layers are", 454 " untouched.", 455 "", 456 "CopyBlue The blue layer of the image window is replace with", 457 " the blue layer of the image. The other layers are", 458 " untouched.", 459 "", 460 "CopyOpacity", 461 " The matte layer of the image window is replace with", 462 " the matte layer of the image. The other layers are", 463 " untouched.", 464 "", 465 "The image compositor requires a matte, or alpha channel in", 466 "the image for some operations. This extra channel usually", 467 "defines a mask which represents a sort of a cookie-cutter", 468 "for the image. This the case when matte is opaque (full", 469 "coverage) for pixels inside the shape, zero outside, and", 470 "between 0 and QuantumRange on the boundary. If image does not", 471 "have a matte channel, it is initialized with 0 for any pixel", 472 "matching in color to pixel location (0,0), otherwise QuantumRange.", 473 "", 474 "If you choose Dissolve, the composite operator becomes Over. The", 475 "image matte channel percent transparency is initialized to factor.", 476 "The image window is initialized to (100-factor). Where factor is the", 477 "value you specify in the Dialog widget.", 478 "", 479 "Displace shifts the image pixels as defined by a displacement", 480 "map. With this option, image is used as a displacement map.", 481 "Black, within the displacement map, is a maximum positive", 482 "displacement. White is a maximum negative displacement and", 483 "middle gray is neutral. The displacement is scaled to determine", 484 "the pixel shift. By default, the displacement applies in both the", 485 "horizontal and vertical directions. However, if you specify a mask,", 486 "image is the horizontal X displacement and mask the vertical Y", 487 "displacement.", 488 "", 489 "Note that matte information for image window is not retained", 490 "for colormapped X server visuals (e.g. StaticColor,", 491 "StaticColor, GrayScale, PseudoColor). Correct compositing", 492 "behavior may require a TrueColor or DirectColor visual or a", 493 "Standard Colormap.", 494 "", 495 "Choosing a composite operator is optional. The default", 496 "operator is replace. However, you must choose a location to", 497 "composite your image and press button 1. Press and hold the", 498 "button before releasing and an outline of the image will", 499 "appear to help you identify your location.", 500 "", 501 "The actual colors of the composite image is saved. However,", 502 "the color that appears in image window may be different.", 503 "For example, on a monochrome screen image window will appear", 504 "black or white even though your composited image may have", 505 "many colors. If the image is saved to a file it is written", 506 "with the correct colors. To assure the correct colors are", 507 "saved in the final image, any PseudoClass image is promoted", 508 "to DirectClass (see miff(5)). To force a PseudoClass image", 509 "to remain PseudoClass, use -colors.", 510 (char *) NULL, 511 }, 512 *ImageCutHelp[] = 513 { 514 "In cut mode, the Command widget has these options:", 515 "", 516 " Help", 517 " Dismiss", 518 "", 519 "To define a cut region, press button 1 and drag. The", 520 "cut region is defined by a highlighted rectangle that", 521 "expands or contracts as it follows the pointer. Once you", 522 "are satisfied with the cut region, release the button.", 523 "You are now in rectify mode. In rectify mode, the Command", 524 "widget has these options:", 525 "", 526 " Cut", 527 " Help", 528 " Dismiss", 529 "", 530 "You can make adjustments by moving the pointer to one of the", 531 "cut rectangle corners, pressing a button, and dragging.", 532 "Finally, press Cut to commit your copy region. To", 533 "exit without cutting the image, press Dismiss.", 534 (char *) NULL, 535 }, 536 *ImageCopyHelp[] = 537 { 538 "In copy mode, the Command widget has these options:", 539 "", 540 " Help", 541 " Dismiss", 542 "", 543 "To define a copy region, press button 1 and drag. The", 544 "copy region is defined by a highlighted rectangle that", 545 "expands or contracts as it follows the pointer. Once you", 546 "are satisfied with the copy region, release the button.", 547 "You are now in rectify mode. In rectify mode, the Command", 548 "widget has these options:", 549 "", 550 " Copy", 551 " Help", 552 " Dismiss", 553 "", 554 "You can make adjustments by moving the pointer to one of the", 555 "copy rectangle corners, pressing a button, and dragging.", 556 "Finally, press Copy to commit your copy region. To", 557 "exit without copying the image, press Dismiss.", 558 (char *) NULL, 559 }, 560 *ImageCropHelp[] = 561 { 562 "In crop mode, the Command widget has these options:", 563 "", 564 " Help", 565 " Dismiss", 566 "", 567 "To define a cropping region, press button 1 and drag. The", 568 "cropping region is defined by a highlighted rectangle that", 569 "expands or contracts as it follows the pointer. Once you", 570 "are satisfied with the cropping region, release the button.", 571 "You are now in rectify mode. In rectify mode, the Command", 572 "widget has these options:", 573 "", 574 " Crop", 575 " Help", 576 " Dismiss", 577 "", 578 "You can make adjustments by moving the pointer to one of the", 579 "cropping rectangle corners, pressing a button, and dragging.", 580 "Finally, press Crop to commit your cropping region. To", 581 "exit without cropping the image, press Dismiss.", 582 (char *) NULL, 583 }, 584 *ImageDrawHelp[] = 585 { 586 "The cursor changes to a crosshair to indicate you are in", 587 "draw mode. To exit immediately, press Dismiss. In draw mode,", 588 "the Command widget has these options:", 589 "", 590 " Element", 591 " point", 592 " line", 593 " rectangle", 594 " fill rectangle", 595 " circle", 596 " fill circle", 597 " ellipse", 598 " fill ellipse", 599 " polygon", 600 " fill polygon", 601 " Color", 602 " black", 603 " blue", 604 " cyan", 605 " green", 606 " gray", 607 " red", 608 " magenta", 609 " yellow", 610 " white", 611 " transparent", 612 " Browser...", 613 " Stipple", 614 " Brick", 615 " Diagonal", 616 " Scales", 617 " Vertical", 618 " Wavy", 619 " Translucent", 620 " Opaque", 621 " Open...", 622 " Width", 623 " 1", 624 " 2", 625 " 4", 626 " 8", 627 " 16", 628 " Dialog...", 629 " Undo", 630 " Help", 631 " Dismiss", 632 "", 633 "Choose a drawing primitive from the Element sub-menu.", 634 "", 635 "Choose a color from the Color sub-menu. Additional", 636 "colors can be specified with the color browser.", 637 "", 638 "If you choose the color browser and press Grab, you can", 639 "select the color by moving the pointer to the desired", 640 "color on the screen and press any button. The transparent", 641 "color updates the image matte channel and is useful for", 642 "image compositing.", 643 "", 644 "Choose a stipple, if appropriate, from the Stipple sub-menu.", 645 "Additional stipples can be specified with the file browser.", 646 "Stipples obtained from the file browser must be on disk in the", 647 "X11 bitmap format.", 648 "", 649 "Choose a width, if appropriate, from the Width sub-menu. To", 650 "choose a specific width select the Dialog widget.", 651 "", 652 "Choose a point in the Image window and press button 1 and", 653 "hold. Next, move the pointer to another location in the", 654 "image. As you move, a line connects the initial location and", 655 "the pointer. When you release the button, the image is", 656 "updated with the primitive you just drew. For polygons, the", 657 "image is updated when you press and release the button without", 658 "moving the pointer.", 659 "", 660 "To cancel image drawing, move the pointer back to the", 661 "starting point of the line and release the button.", 662 (char *) NULL, 663 }, 664 *DisplayHelp[] = 665 { 666 "BUTTONS", 667 " The effects of each button press is described below. Three", 668 " buttons are required. If you have a two button mouse,", 669 " button 1 and 3 are returned. Press ALT and button 3 to", 670 " simulate button 2.", 671 "", 672 " 1 Press this button to map or unmap the Command widget.", 673 "", 674 " 2 Press and drag to define a region of the image to", 675 " magnify.", 676 "", 677 " 3 Press and drag to choose from a select set of commands.", 678 " This button behaves differently if the image being", 679 " displayed is a visual image directory. Here, choose a", 680 " particular tile of the directory and press this button and", 681 " drag to select a command from a pop-up menu. Choose from", 682 " these menu items:", 683 "", 684 " Open", 685 " Next", 686 " Former", 687 " Delete", 688 " Update", 689 "", 690 " If you choose Open, the image represented by the tile is", 691 " displayed. To return to the visual image directory, choose", 692 " Next from the Command widget. Next and Former moves to the", 693 " next or former image respectively. Choose Delete to delete", 694 " a particular image tile. Finally, choose Update to", 695 " synchronize all the image tiles with their respective", 696 " images.", 697 "", 698 "COMMAND WIDGET", 699 " The Command widget lists a number of sub-menus and commands.", 700 " They are", 701 "", 702 " File", 703 " Open...", 704 " Next", 705 " Former", 706 " Select...", 707 " Save...", 708 " Print...", 709 " Delete...", 710 " New...", 711 " Visual Directory...", 712 " Quit", 713 " Edit", 714 " Undo", 715 " Redo", 716 " Cut", 717 " Copy", 718 " Paste", 719 " View", 720 " Half Size", 721 " Original Size", 722 " Double Size", 723 " Resize...", 724 " Apply", 725 " Refresh", 726 " Restore", 727 " Transform", 728 " Crop", 729 " Chop", 730 " Flop", 731 " Flip", 732 " Rotate Right", 733 " Rotate Left", 734 " Rotate...", 735 " Shear...", 736 " Roll...", 737 " Trim Edges", 738 " Enhance", 739 " Brightness...", 740 " Saturation...", 741 " Hue...", 742 " Gamma...", 743 " Sharpen...", 744 " Dull", 745 " Contrast Stretch...", 746 " Sigmoidal Contrast...", 747 " Normalize", 748 " Equalize", 749 " Negate", 750 " Grayscale", 751 " Map...", 752 " Quantize...", 753 " Effects", 754 " Despeckle", 755 " Emboss", 756 " Reduce Noise", 757 " Add Noise", 758 " Sharpen...", 759 " Blur...", 760 " Threshold...", 761 " Edge Detect...", 762 " Spread...", 763 " Shade...", 764 " Painting...", 765 " Segment...", 766 " F/X", 767 " Solarize...", 768 " Sepia Tone...", 769 " Swirl...", 770 " Implode...", 771 " Vignette...", 772 " Wave...", 773 " Oil Painting...", 774 " Charcoal Drawing...", 775 " Image Edit", 776 " Annotate...", 777 " Draw...", 778 " Color...", 779 " Matte...", 780 " Composite...", 781 " Add Border...", 782 " Add Frame...", 783 " Comment...", 784 " Launch...", 785 " Region of Interest...", 786 " Miscellany", 787 " Image Info", 788 " Zoom Image", 789 " Show Preview...", 790 " Show Histogram", 791 " Show Matte", 792 " Background...", 793 " Slide Show", 794 " Preferences...", 795 " Help", 796 " Overview", 797 " Browse Documentation", 798 " About Display", 799 "", 800 " Menu items with a indented triangle have a sub-menu. They", 801 " are represented above as the indented items. To access a", 802 " sub-menu item, move the pointer to the appropriate menu and", 803 " press a button and drag. When you find the desired sub-menu", 804 " item, release the button and the command is executed. Move", 805 " the pointer away from the sub-menu if you decide not to", 806 " execute a particular command.", 807 "", 808 "KEYBOARD ACCELERATORS", 809 " Accelerators are one or two key presses that effect a", 810 " particular command. The keyboard accelerators that", 811 " display(1) understands is:", 812 "", 813 " Ctl+O Press to open an image from a file.", 814 "", 815 " space Press to display the next image.", 816 "", 817 " If the image is a multi-paged document such as a Postscript", 818 " document, you can skip ahead several pages by preceding", 819 " this command with a number. For example to display the", 820 " third page beyond the current page, press 3<space>.", 821 "", 822 " backspace Press to display the former image.", 823 "", 824 " If the image is a multi-paged document such as a Postscript", 825 " document, you can skip behind several pages by preceding", 826 " this command with a number. For example to display the", 827 " third page preceding the current page, press 3<backspace>.", 828 "", 829 " Ctl+S Press to write the image to a file.", 830 "", 831 " Ctl+P Press to print the image to a Postscript printer.", 832 "", 833 " Ctl+D Press to delete an image file.", 834 "", 835 " Ctl+N Press to create a blank canvas.", 836 "", 837 " Ctl+Q Press to discard all images and exit program.", 838 "", 839 " Ctl+Z Press to undo last image transformation.", 840 "", 841 " Ctl+R Press to redo last image transformation.", 842 "", 843 " Ctl+X Press to cut a region of the image.", 844 "", 845 " Ctl+C Press to copy a region of the image.", 846 "", 847 " Ctl+V Press to paste a region to the image.", 848 "", 849 " < Press to half the image size.", 850 "", 851 " - Press to return to the original image size.", 852 "", 853 " > Press to double the image size.", 854 "", 855 " % Press to resize the image to a width and height you", 856 " specify.", 857 "", 858 "Cmd-A Press to make any image transformations permanent." 859 "", 860 " By default, any image size transformations are applied", 861 " to the original image to create the image displayed on", 862 " the X server. However, the transformations are not", 863 " permanent (i.e. the original image does not change", 864 " size only the X image does). For example, if you", 865 " press > the X image will appear to double in size,", 866 " but the original image will in fact remain the same size.", 867 " To force the original image to double in size, press >", 868 " followed by Cmd-A.", 869 "", 870 " @ Press to refresh the image window.", 871 "", 872 " C Press to cut out a rectangular region of the image.", 873 "", 874 " [ Press to chop the image.", 875 "", 876 " H Press to flop image in the horizontal direction.", 877 "", 878 " V Press to flip image in the vertical direction.", 879 "", 880 " / Press to rotate the image 90 degrees clockwise.", 881 "", 882 " \\ Press to rotate the image 90 degrees counter-clockwise.", 883 "", 884 " * Press to rotate the image the number of degrees you", 885 " specify.", 886 "", 887 " S Press to shear the image the number of degrees you", 888 " specify.", 889 "", 890 " R Press to roll the image.", 891 "", 892 " T Press to trim the image edges.", 893 "", 894 " Shft-H Press to vary the image hue.", 895 "", 896 " Shft-S Press to vary the color saturation.", 897 "", 898 " Shft-L Press to vary the color brightness.", 899 "", 900 " Shft-G Press to gamma correct the image.", 901 "", 902 " Shft-C Press to sharpen the image contrast.", 903 "", 904 " Shft-Z Press to dull the image contrast.", 905 "", 906 " = Press to perform histogram equalization on the image.", 907 "", 908 " Shft-N Press to perform histogram normalization on the image.", 909 "", 910 " Shft-~ Press to negate the colors of the image.", 911 "", 912 " . Press to convert the image colors to gray.", 913 "", 914 " Shft-# Press to set the maximum number of unique colors in the", 915 " image.", 916 "", 917 " F2 Press to reduce the speckles in an image.", 918 "", 919 " F3 Press to eliminate peak noise from an image.", 920 "", 921 " F4 Press to add noise to an image.", 922 "", 923 " F5 Press to sharpen an image.", 924 "", 925 " F6 Press to delete an image file.", 926 "", 927 " F7 Press to threshold the image.", 928 "", 929 " F8 Press to detect edges within an image.", 930 "", 931 " F9 Press to emboss an image.", 932 "", 933 " F10 Press to displace pixels by a random amount.", 934 "", 935 " F11 Press to negate all pixels above the threshold level.", 936 "", 937 " F12 Press to shade the image using a distant light source.", 938 "", 939 " F13 Press to lighten or darken image edges to create a 3-D effect.", 940 "", 941 " F14 Press to segment the image by color.", 942 "", 943 " Meta-S Press to swirl image pixels about the center.", 944 "", 945 " Meta-I Press to implode image pixels about the center.", 946 "", 947 " Meta-W Press to alter an image along a sine wave.", 948 "", 949 " Meta-P Press to simulate an oil painting.", 950 "", 951 " Meta-C Press to simulate a charcoal drawing.", 952 "", 953 " Alt-A Press to annotate the image with text.", 954 "", 955 " Alt-D Press to draw on an image.", 956 "", 957 " Alt-P Press to edit an image pixel color.", 958 "", 959 " Alt-M Press to edit the image matte information.", 960 "", 961 " Alt-V Press to composite the image with another.", 962 "", 963 " Alt-B Press to add a border to the image.", 964 "", 965 " Alt-F Press to add an ornamental border to the image.", 966 "", 967 " Alt-Shft-!", 968 " Press to add an image comment.", 969 "", 970 " Ctl-A Press to apply image processing techniques to a region", 971 " of interest.", 972 "", 973 " Shft-? Press to display information about the image.", 974 "", 975 " Shft-+ Press to map the zoom image window.", 976 "", 977 " Shft-P Press to preview an image enhancement, effect, or f/x.", 978 "", 979 " F1 Press to display helpful information about display(1).", 980 "", 981 " Find Press to browse documentation about ImageMagick.", 982 "", 983 " 1-9 Press to change the level of magnification.", 984 "", 985 " Use the arrow keys to move the image one pixel up, down,", 986 " left, or right within the magnify window. Be sure to first", 987 " map the magnify window by pressing button 2.", 988 "", 989 " Press ALT and one of the arrow keys to trim off one pixel", 990 " from any side of the image.", 991 (char *) NULL, 992 }, 993 *ImageMatteEditHelp[] = 994 { 995 "Matte information within an image is useful for some", 996 "operations such as image compositing (See IMAGE", 997 "COMPOSITING). This extra channel usually defines a mask", 998 "which represents a sort of a cookie-cutter for the image.", 999 "This the case when matte is opaque (full coverage) for", 1000 "pixels inside the shape, zero outside, and between 0 and", 1001 "QuantumRange on the boundary.", 1002 "", 1003 "A small window appears showing the location of the cursor in", 1004 "the image window. You are now in matte edit mode. To exit", 1005 "immediately, press Dismiss. In matte edit mode, the Command", 1006 "widget has these options:", 1007 "", 1008 " Method", 1009 " point", 1010 " replace", 1011 " floodfill", 1012 " filltoborder", 1013 " reset", 1014 " Border Color", 1015 " black", 1016 " blue", 1017 " cyan", 1018 " green", 1019 " gray", 1020 " red", 1021 " magenta", 1022 " yellow", 1023 " white", 1024 " Browser...", 1025 " Fuzz", 1026 " 0%", 1027 " 2%", 1028 " 5%", 1029 " 10%", 1030 " 15%", 1031 " Dialog...", 1032 " Matte", 1033 " Opaque", 1034 " Transparent", 1035 " Dialog...", 1036 " Undo", 1037 " Help", 1038 " Dismiss", 1039 "", 1040 "Choose a matte editing method from the Method sub-menu of", 1041 "the Command widget. The point method changes the matte value", 1042 "of any pixel selected with the pointer until the button is", 1043 "is released. The replace method changes the matte value of", 1044 "any pixel that matches the color of the pixel you select with", 1045 "a button press. Floodfill changes the matte value of any pixel", 1046 "that matches the color of the pixel you select with a button", 1047 "press and is a neighbor. Whereas filltoborder changes the matte", 1048 "value any neighbor pixel that is not the border color. Finally", 1049 "reset changes the entire image to the designated matte value.", 1050 "", 1051 "Choose Matte Value and pick Opaque or Transarent. For other values", 1052 "select the Dialog entry. Here a dialog appears requesting a matte", 1053 "value. The value you select is assigned as the opacity value of the", 1054 "selected pixel or pixels.", 1055 "", 1056 "Now, press any button to select a pixel within the image", 1057 "window to change its matte value.", 1058 "", 1059 "If the Magnify widget is mapped, it can be helpful in positioning", 1060 "your pointer within the image (refer to button 2).", 1061 "", 1062 "Matte information is only valid in a DirectClass image.", 1063 "Therefore, any PseudoClass image is promoted to DirectClass", 1064 "(see miff(5)). Note that matte information for PseudoClass", 1065 "is not retained for colormapped X server visuals (e.g.", 1066 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you", 1067 "immediately save your image to a file (refer to Write).", 1068 "Correct matte editing behavior may require a TrueColor or", 1069 "DirectColor visual or a Standard Colormap.", 1070 (char *) NULL, 1071 }, 1072 *ImagePanHelp[] = 1073 { 1074 "When an image exceeds the width or height of the X server", 1075 "screen, display maps a small panning icon. The rectangle", 1076 "within the panning icon shows the area that is currently", 1077 "displayed in the image window. To pan about the image,", 1078 "press any button and drag the pointer within the panning", 1079 "icon. The pan rectangle moves with the pointer and the", 1080 "image window is updated to reflect the location of the", 1081 "rectangle within the panning icon. When you have selected", 1082 "the area of the image you wish to view, release the button.", 1083 "", 1084 "Use the arrow keys to pan the image one pixel up, down,", 1085 "left, or right within the image window.", 1086 "", 1087 "The panning icon is withdrawn if the image becomes smaller", 1088 "than the dimensions of the X server screen.", 1089 (char *) NULL, 1090 }, 1091 *ImagePasteHelp[] = 1092 { 1093 "A small window appears showing the location of the cursor in", 1094 "the image window. You are now in paste mode. To exit", 1095 "immediately, press Dismiss. In paste mode, the Command", 1096 "widget has these options:", 1097 "", 1098 " Operators", 1099 " over", 1100 " in", 1101 " out", 1102 " atop", 1103 " xor", 1104 " plus", 1105 " minus", 1106 " add", 1107 " subtract", 1108 " difference", 1109 " replace", 1110 " Help", 1111 " Dismiss", 1112 "", 1113 "Choose a composite operation from the Operators sub-menu of", 1114 "the Command widget. How each operator behaves is described", 1115 "below. Image window is the image currently displayed on", 1116 "your X server and image is the image obtained with the File", 1117 "Browser widget.", 1118 "", 1119 "Over The result is the union of the two image shapes,", 1120 " with image obscuring image window in the region of", 1121 " overlap.", 1122 "", 1123 "In The result is simply image cut by the shape of", 1124 " image window. None of the image data of image", 1125 " window is in the result.", 1126 "", 1127 "Out The resulting image is image with the shape of", 1128 " image window cut out.", 1129 "", 1130 "Atop The result is the same shape as image image window,", 1131 " with image obscuring image window where the image", 1132 " shapes overlap. Note this differs from over", 1133 " because the portion of image outside image window's", 1134 " shape does not appear in the result.", 1135 "", 1136 "Xor The result is the image data from both image and", 1137 " image window that is outside the overlap region.", 1138 " The overlap region is blank.", 1139 "", 1140 "Plus The result is just the sum of the image data.", 1141 " Output values are cropped to QuantumRange (no overflow).", 1142 " This operation is independent of the matte", 1143 " channels.", 1144 "", 1145 "Minus The result of image - image window, with underflow", 1146 " cropped to zero.", 1147 "", 1148 "Add The result of image + image window, with overflow", 1149 " wrapping around (mod 256).", 1150 "", 1151 "Subtract The result of image - image window, with underflow", 1152 " wrapping around (mod 256). The add and subtract", 1153 " operators can be used to perform reversible", 1154 " transformations.", 1155 "", 1156 "Difference", 1157 " The result of abs(image - image window). This", 1158 " useful for comparing two very similar images.", 1159 "", 1160 "Copy The resulting image is image window replaced with", 1161 " image. Here the matte information is ignored.", 1162 "", 1163 "CopyRed The red layer of the image window is replace with", 1164 " the red layer of the image. The other layers are", 1165 " untouched.", 1166 "", 1167 "CopyGreen", 1168 " The green layer of the image window is replace with", 1169 " the green layer of the image. The other layers are", 1170 " untouched.", 1171 "", 1172 "CopyBlue The blue layer of the image window is replace with", 1173 " the blue layer of the image. The other layers are", 1174 " untouched.", 1175 "", 1176 "CopyOpacity", 1177 " The matte layer of the image window is replace with", 1178 " the matte layer of the image. The other layers are", 1179 " untouched.", 1180 "", 1181 "The image compositor requires a matte, or alpha channel in", 1182 "the image for some operations. This extra channel usually", 1183 "defines a mask which represents a sort of a cookie-cutter", 1184 "for the image. This the case when matte is opaque (full", 1185 "coverage) for pixels inside the shape, zero outside, and", 1186 "between 0 and QuantumRange on the boundary. If image does not", 1187 "have a matte channel, it is initialized with 0 for any pixel", 1188 "matching in color to pixel location (0,0), otherwise QuantumRange.", 1189 "", 1190 "Note that matte information for image window is not retained", 1191 "for colormapped X server visuals (e.g. StaticColor,", 1192 "StaticColor, GrayScale, PseudoColor). Correct compositing", 1193 "behavior may require a TrueColor or DirectColor visual or a", 1194 "Standard Colormap.", 1195 "", 1196 "Choosing a composite operator is optional. The default", 1197 "operator is replace. However, you must choose a location to", 1198 "paste your image and press button 1. Press and hold the", 1199 "button before releasing and an outline of the image will", 1200 "appear to help you identify your location.", 1201 "", 1202 "The actual colors of the pasted image is saved. However,", 1203 "the color that appears in image window may be different.", 1204 "For example, on a monochrome screen image window will appear", 1205 "black or white even though your pasted image may have", 1206 "many colors. If the image is saved to a file it is written", 1207 "with the correct colors. To assure the correct colors are", 1208 "saved in the final image, any PseudoClass image is promoted", 1209 "to DirectClass (see miff(5)). To force a PseudoClass image", 1210 "to remain PseudoClass, use -colors.", 1211 (char *) NULL, 1212 }, 1213 *ImageROIHelp[] = 1214 { 1215 "In region of interest mode, the Command widget has these", 1216 "options:", 1217 "", 1218 " Help", 1219 " Dismiss", 1220 "", 1221 "To define a region of interest, press button 1 and drag.", 1222 "The region of interest is defined by a highlighted rectangle", 1223 "that expands or contracts as it follows the pointer. Once", 1224 "you are satisfied with the region of interest, release the", 1225 "button. You are now in apply mode. In apply mode the", 1226 "Command widget has these options:", 1227 "", 1228 " File", 1229 " Save...", 1230 " Print...", 1231 " Edit", 1232 " Undo", 1233 " Redo", 1234 " Transform", 1235 " Flop", 1236 " Flip", 1237 " Rotate Right", 1238 " Rotate Left", 1239 " Enhance", 1240 " Hue...", 1241 " Saturation...", 1242 " Brightness...", 1243 " Gamma...", 1244 " Spiff", 1245 " Dull", 1246 " Contrast Stretch", 1247 " Sigmoidal Contrast...", 1248 " Normalize", 1249 " Equalize", 1250 " Negate", 1251 " Grayscale", 1252 " Map...", 1253 " Quantize...", 1254 " Effects", 1255 " Despeckle", 1256 " Emboss", 1257 " Reduce Noise", 1258 " Sharpen...", 1259 " Blur...", 1260 " Threshold...", 1261 " Edge Detect...", 1262 " Spread...", 1263 " Shade...", 1264 " Raise...", 1265 " Segment...", 1266 " F/X", 1267 " Solarize...", 1268 " Sepia Tone...", 1269 " Swirl...", 1270 " Implode...", 1271 " Vignette...", 1272 " Wave...", 1273 " Oil Painting...", 1274 " Charcoal Drawing...", 1275 " Miscellany", 1276 " Image Info", 1277 " Zoom Image", 1278 " Show Preview...", 1279 " Show Histogram", 1280 " Show Matte", 1281 " Help", 1282 " Dismiss", 1283 "", 1284 "You can make adjustments to the region of interest by moving", 1285 "the pointer to one of the rectangle corners, pressing a", 1286 "button, and dragging. Finally, choose an image processing", 1287 "technique from the Command widget. You can choose more than", 1288 "one image processing technique to apply to an area.", 1289 "Alternatively, you can move the region of interest before", 1290 "applying another image processing technique. To exit, press", 1291 "Dismiss.", 1292 (char *) NULL, 1293 }, 1294 *ImageRotateHelp[] = 1295 { 1296 "In rotate mode, the Command widget has these options:", 1297 "", 1298 " Pixel Color", 1299 " black", 1300 " blue", 1301 " cyan", 1302 " green", 1303 " gray", 1304 " red", 1305 " magenta", 1306 " yellow", 1307 " white", 1308 " Browser...", 1309 " Direction", 1310 " horizontal", 1311 " vertical", 1312 " Help", 1313 " Dismiss", 1314 "", 1315 "Choose a background color from the Pixel Color sub-menu.", 1316 "Additional background colors can be specified with the color", 1317 "browser. You can change the menu colors by setting the X", 1318 "resources pen1 through pen9.", 1319 "", 1320 "If you choose the color browser and press Grab, you can", 1321 "select the background color by moving the pointer to the", 1322 "desired color on the screen and press any button.", 1323 "", 1324 "Choose a point in the image window and press this button and", 1325 "hold. Next, move the pointer to another location in the", 1326 "image. As you move a line connects the initial location and", 1327 "the pointer. When you release the button, the degree of", 1328 "image rotation is determined by the slope of the line you", 1329 "just drew. The slope is relative to the direction you", 1330 "choose from the Direction sub-menu of the Command widget.", 1331 "", 1332 "To cancel the image rotation, move the pointer back to the", 1333 "starting point of the line and release the button.", 1334 (char *) NULL, 1335 }; 1336 1337/* 1338 Enumeration declarations. 1339*/ 1340typedef enum 1341{ 1342 CopyMode, 1343 CropMode, 1344 CutMode 1345} ClipboardMode; 1346 1347typedef enum 1348{ 1349 OpenCommand, 1350 NextCommand, 1351 FormerCommand, 1352 SelectCommand, 1353 SaveCommand, 1354 PrintCommand, 1355 DeleteCommand, 1356 NewCommand, 1357 VisualDirectoryCommand, 1358 QuitCommand, 1359 UndoCommand, 1360 RedoCommand, 1361 CutCommand, 1362 CopyCommand, 1363 PasteCommand, 1364 HalfSizeCommand, 1365 OriginalSizeCommand, 1366 DoubleSizeCommand, 1367 ResizeCommand, 1368 ApplyCommand, 1369 RefreshCommand, 1370 RestoreCommand, 1371 CropCommand, 1372 ChopCommand, 1373 FlopCommand, 1374 FlipCommand, 1375 RotateRightCommand, 1376 RotateLeftCommand, 1377 RotateCommand, 1378 ShearCommand, 1379 RollCommand, 1380 TrimCommand, 1381 HueCommand, 1382 SaturationCommand, 1383 BrightnessCommand, 1384 GammaCommand, 1385 SpiffCommand, 1386 DullCommand, 1387 ContrastStretchCommand, 1388 SigmoidalContrastCommand, 1389 NormalizeCommand, 1390 EqualizeCommand, 1391 NegateCommand, 1392 GrayscaleCommand, 1393 MapCommand, 1394 QuantizeCommand, 1395 DespeckleCommand, 1396 EmbossCommand, 1397 ReduceNoiseCommand, 1398 AddNoiseCommand, 1399 SharpenCommand, 1400 BlurCommand, 1401 ThresholdCommand, 1402 EdgeDetectCommand, 1403 SpreadCommand, 1404 ShadeCommand, 1405 RaiseCommand, 1406 SegmentCommand, 1407 SolarizeCommand, 1408 SepiaToneCommand, 1409 SwirlCommand, 1410 ImplodeCommand, 1411 VignetteCommand, 1412 WaveCommand, 1413 OilPaintCommand, 1414 CharcoalDrawCommand, 1415 AnnotateCommand, 1416 DrawCommand, 1417 ColorCommand, 1418 MatteCommand, 1419 CompositeCommand, 1420 AddBorderCommand, 1421 AddFrameCommand, 1422 CommentCommand, 1423 LaunchCommand, 1424 RegionofInterestCommand, 1425 ROIHelpCommand, 1426 ROIDismissCommand, 1427 InfoCommand, 1428 ZoomCommand, 1429 ShowPreviewCommand, 1430 ShowHistogramCommand, 1431 ShowMatteCommand, 1432 BackgroundCommand, 1433 SlideShowCommand, 1434 PreferencesCommand, 1435 HelpCommand, 1436 BrowseDocumentationCommand, 1437 VersionCommand, 1438 SaveToUndoBufferCommand, 1439 FreeBuffersCommand, 1440 NullCommand 1441} CommandType; 1442 1443typedef enum 1444{ 1445 AnnotateNameCommand, 1446 AnnotateFontColorCommand, 1447 AnnotateBackgroundColorCommand, 1448 AnnotateRotateCommand, 1449 AnnotateHelpCommand, 1450 AnnotateDismissCommand, 1451 TextHelpCommand, 1452 TextApplyCommand, 1453 ChopDirectionCommand, 1454 ChopHelpCommand, 1455 ChopDismissCommand, 1456 HorizontalChopCommand, 1457 VerticalChopCommand, 1458 ColorEditMethodCommand, 1459 ColorEditColorCommand, 1460 ColorEditBorderCommand, 1461 ColorEditFuzzCommand, 1462 ColorEditUndoCommand, 1463 ColorEditHelpCommand, 1464 ColorEditDismissCommand, 1465 CompositeOperatorsCommand, 1466 CompositeDissolveCommand, 1467 CompositeDisplaceCommand, 1468 CompositeHelpCommand, 1469 CompositeDismissCommand, 1470 CropHelpCommand, 1471 CropDismissCommand, 1472 RectifyCopyCommand, 1473 RectifyHelpCommand, 1474 RectifyDismissCommand, 1475 DrawElementCommand, 1476 DrawColorCommand, 1477 DrawStippleCommand, 1478 DrawWidthCommand, 1479 DrawUndoCommand, 1480 DrawHelpCommand, 1481 DrawDismissCommand, 1482 MatteEditMethod, 1483 MatteEditBorderCommand, 1484 MatteEditFuzzCommand, 1485 MatteEditValueCommand, 1486 MatteEditUndoCommand, 1487 MatteEditHelpCommand, 1488 MatteEditDismissCommand, 1489 PasteOperatorsCommand, 1490 PasteHelpCommand, 1491 PasteDismissCommand, 1492 RotateColorCommand, 1493 RotateDirectionCommand, 1494 RotateCropCommand, 1495 RotateSharpenCommand, 1496 RotateHelpCommand, 1497 RotateDismissCommand, 1498 HorizontalRotateCommand, 1499 VerticalRotateCommand, 1500 TileLoadCommand, 1501 TileNextCommand, 1502 TileFormerCommand, 1503 TileDeleteCommand, 1504 TileUpdateCommand 1505} ModeType; 1506 1507/* 1508 Stipples. 1509*/ 1510#define BricksWidth 20 1511#define BricksHeight 20 1512#define DiagonalWidth 16 1513#define DiagonalHeight 16 1514#define HighlightWidth 8 1515#define HighlightHeight 8 1516#define OpaqueWidth 8 1517#define OpaqueHeight 8 1518#define ScalesWidth 16 1519#define ScalesHeight 16 1520#define ShadowWidth 8 1521#define ShadowHeight 8 1522#define VerticalWidth 16 1523#define VerticalHeight 16 1524#define WavyWidth 16 1525#define WavyHeight 16 1526 1527/* 1528 Constant declaration. 1529*/ 1530static const int 1531 RoiDelta = 8; 1532 1533static const unsigned char 1534 BricksBitmap[] = 1535 { 1536 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 1537 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 1538 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 1539 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 1540 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01 1541 }, 1542 DiagonalBitmap[] = 1543 { 1544 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 1545 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 1546 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22 1547 }, 1548 ScalesBitmap[] = 1549 { 1550 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80, 1551 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 1552 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e 1553 }, 1554 VerticalBitmap[] = 1555 { 1556 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1557 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1558 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 1559 }, 1560 WavyBitmap[] = 1561 { 1562 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff, 1563 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf, 1564 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f 1565 }; 1566 1567/* 1568 Function prototypes. 1569*/ 1570static CommandType 1571 XImageWindowCommand(Display *,XResourceInfo *,XWindows *, 1572 const MagickStatusType,KeySym,Image **,ExceptionInfo *); 1573 1574static Image 1575 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType, 1576 Image **,ExceptionInfo *), 1577 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType), 1578 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *, 1579 ExceptionInfo *), 1580 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *, 1581 ExceptionInfo *); 1582 1583static MagickBooleanType 1584 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *, 1585 ExceptionInfo *), 1586 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **, 1587 ExceptionInfo *), 1588 XChopImage(Display *,XResourceInfo *,XWindows *,Image **, 1589 ExceptionInfo *), 1590 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode, 1591 ExceptionInfo *), 1592 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1593 ExceptionInfo *), 1594 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *, 1595 ExceptionInfo *), 1596 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1597 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1598 ExceptionInfo *), 1599 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1600 ExceptionInfo *), 1601 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1602 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1603 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **, 1604 ExceptionInfo *), 1605 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *), 1606 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1607 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *); 1608 1609static void 1610 XDrawPanRectangle(Display *,XWindows *), 1611 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **, 1612 ExceptionInfo *), 1613 XMagnifyImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1614 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1615 XPanImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1616 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType, 1617 const KeySym,ExceptionInfo *), 1618 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *), 1619 XScreenEvent(Display *,XWindows *,XEvent *,ExceptionInfo *), 1620 XTranslateImage(Display *,XWindows *,Image *,const KeySym); 1621 1622/* 1623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1624% % 1625% % 1626% % 1627% D i s p l a y I m a g e s % 1628% % 1629% % 1630% % 1631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1632% 1633% DisplayImages() displays an image sequence to any X window screen. It 1634% returns a value other than 0 if successful. Check the exception member 1635% of image to determine the reason for any failure. 1636% 1637% The format of the DisplayImages method is: 1638% 1639% MagickBooleanType DisplayImages(const ImageInfo *image_info, 1640% Image *images,ExceptionInfo *exception) 1641% 1642% A description of each parameter follows: 1643% 1644% o image_info: the image info. 1645% 1646% o image: the image. 1647% 1648% o exception: return any errors or warnings in this structure. 1649% 1650*/ 1651MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 1652 Image *images,ExceptionInfo *exception) 1653{ 1654 char 1655 *argv[1]; 1656 1657 Display 1658 *display; 1659 1660 Image 1661 *image; 1662 1663 register ssize_t 1664 i; 1665 1666 size_t 1667 state; 1668 1669 XrmDatabase 1670 resource_database; 1671 1672 XResourceInfo 1673 resource_info; 1674 1675 assert(image_info != (const ImageInfo *) NULL); 1676 assert(image_info->signature == MagickSignature); 1677 assert(images != (Image *) NULL); 1678 assert(images->signature == MagickSignature); 1679 if (IfMagickTrue(images->debug) ) 1680 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 1681 display=XOpenDisplay(image_info->server_name); 1682 if (display == (Display *) NULL) 1683 { 1684 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1685 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1686 return(MagickFalse); 1687 } 1688 if (exception->severity != UndefinedException) 1689 CatchException(exception); 1690 (void) XSetErrorHandler(XError); 1691 resource_database=XGetResourceDatabase(display,GetClientName()); 1692 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info)); 1693 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info); 1694 if (image_info->page != (char *) NULL) 1695 resource_info.image_geometry=AcquireString(image_info->page); 1696 resource_info.immutable=MagickTrue; 1697 argv[0]=AcquireString(GetClientName()); 1698 state=DefaultState; 1699 for (i=0; (state & ExitState) == 0; i++) 1700 { 1701 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations)) 1702 break; 1703 image=GetImageFromList(images,i % GetImageListLength(images)); 1704 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception); 1705 } 1706 (void) SetErrorHandler((ErrorHandler) NULL); 1707 (void) SetWarningHandler((WarningHandler) NULL); 1708 argv[0]=DestroyString(argv[0]); 1709 (void) XCloseDisplay(display); 1710 XDestroyResourceInfo(&resource_info); 1711 if (exception->severity != UndefinedException) 1712 return(MagickFalse); 1713 return(MagickTrue); 1714} 1715 1716/* 1717%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1718% % 1719% % 1720% % 1721% R e m o t e D i s p l a y C o m m a n d % 1722% % 1723% % 1724% % 1725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1726% 1727% RemoteDisplayCommand() encourages a remote display program to display the 1728% specified image filename. 1729% 1730% The format of the RemoteDisplayCommand method is: 1731% 1732% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1733% const char *window,const char *filename,ExceptionInfo *exception) 1734% 1735% A description of each parameter follows: 1736% 1737% o image_info: the image info. 1738% 1739% o window: Specifies the name or id of an X window. 1740% 1741% o filename: the name of the image filename to display. 1742% 1743% o exception: return any errors or warnings in this structure. 1744% 1745*/ 1746MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1747 const char *window,const char *filename,ExceptionInfo *exception) 1748{ 1749 Display 1750 *display; 1751 1752 MagickStatusType 1753 status; 1754 1755 assert(image_info != (const ImageInfo *) NULL); 1756 assert(image_info->signature == MagickSignature); 1757 assert(filename != (char *) NULL); 1758 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 1759 display=XOpenDisplay(image_info->server_name); 1760 if (display == (Display *) NULL) 1761 { 1762 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1763 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1764 return(MagickFalse); 1765 } 1766 (void) XSetErrorHandler(XError); 1767 status=XRemoteCommand(display,window,filename); 1768 (void) XCloseDisplay(display); 1769 return(IsMagickTrue(status)); 1770} 1771 1772/* 1773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1774% % 1775% % 1776% % 1777+ X A n n o t a t e E d i t I m a g e % 1778% % 1779% % 1780% % 1781%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1782% 1783% XAnnotateEditImage() annotates the image with text. 1784% 1785% The format of the XAnnotateEditImage method is: 1786% 1787% MagickBooleanType XAnnotateEditImage(Display *display, 1788% XResourceInfo *resource_info,XWindows *windows,Image *image, 1789% ExceptionInfo *exception) 1790% 1791% A description of each parameter follows: 1792% 1793% o display: Specifies a connection to an X server; returned from 1794% XOpenDisplay. 1795% 1796% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 1797% 1798% o windows: Specifies a pointer to a XWindows structure. 1799% 1800% o image: the image; returned from ReadImage. 1801% 1802*/ 1803 1804static inline ssize_t MagickMax(const ssize_t x,const ssize_t y) 1805{ 1806 if (x > y) 1807 return(x); 1808 return(y); 1809} 1810 1811static inline ssize_t MagickMin(const ssize_t x,const ssize_t y) 1812{ 1813 if (x < y) 1814 return(x); 1815 return(y); 1816} 1817 1818static MagickBooleanType XAnnotateEditImage(Display *display, 1819 XResourceInfo *resource_info,XWindows *windows,Image *image, 1820 ExceptionInfo *exception) 1821{ 1822 static const char 1823 *AnnotateMenu[] = 1824 { 1825 "Font Name", 1826 "Font Color", 1827 "Box Color", 1828 "Rotate Text", 1829 "Help", 1830 "Dismiss", 1831 (char *) NULL 1832 }, 1833 *TextMenu[] = 1834 { 1835 "Help", 1836 "Apply", 1837 (char *) NULL 1838 }; 1839 1840 static const ModeType 1841 AnnotateCommands[] = 1842 { 1843 AnnotateNameCommand, 1844 AnnotateFontColorCommand, 1845 AnnotateBackgroundColorCommand, 1846 AnnotateRotateCommand, 1847 AnnotateHelpCommand, 1848 AnnotateDismissCommand 1849 }, 1850 TextCommands[] = 1851 { 1852 TextHelpCommand, 1853 TextApplyCommand 1854 }; 1855 1856 static MagickBooleanType 1857 transparent_box = MagickTrue, 1858 transparent_pen = MagickFalse; 1859 1860 static double 1861 degrees = 0.0; 1862 1863 static unsigned int 1864 box_id = MaxNumberPens-2, 1865 font_id = 0, 1866 pen_id = 0; 1867 1868 char 1869 command[MaxTextExtent], 1870 text[MaxTextExtent]; 1871 1872 const char 1873 *ColorMenu[MaxNumberPens+1]; 1874 1875 Cursor 1876 cursor; 1877 1878 GC 1879 annotate_context; 1880 1881 int 1882 id, 1883 pen_number, 1884 status, 1885 x, 1886 y; 1887 1888 KeySym 1889 key_symbol; 1890 1891 register char 1892 *p; 1893 1894 register ssize_t 1895 i; 1896 1897 unsigned int 1898 height, 1899 width; 1900 1901 size_t 1902 state; 1903 1904 XAnnotateInfo 1905 *annotate_info, 1906 *previous_info; 1907 1908 XColor 1909 color; 1910 1911 XFontStruct 1912 *font_info; 1913 1914 XEvent 1915 event, 1916 text_event; 1917 1918 /* 1919 Map Command widget. 1920 */ 1921 (void) CloneString(&windows->command.name,"Annotate"); 1922 windows->command.data=4; 1923 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL); 1924 (void) XMapRaised(display,windows->command.id); 1925 XClientMessage(display,windows->image.id,windows->im_protocols, 1926 windows->im_update_widget,CurrentTime); 1927 /* 1928 Track pointer until button 1 is pressed. 1929 */ 1930 XQueryPosition(display,windows->image.id,&x,&y); 1931 (void) XSelectInput(display,windows->image.id, 1932 windows->image.attributes.event_mask | PointerMotionMask); 1933 cursor=XCreateFontCursor(display,XC_left_side); 1934 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1935 state=DefaultState; 1936 do 1937 { 1938 if (IfMagickTrue(windows->info.mapped) ) 1939 { 1940 /* 1941 Display pointer position. 1942 */ 1943 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 1944 x+windows->image.x,y+windows->image.y); 1945 XInfoWidget(display,windows,text); 1946 } 1947 /* 1948 Wait for next event. 1949 */ 1950 XScreenEvent(display,windows,&event,exception); 1951 if (event.xany.window == windows->command.id) 1952 { 1953 /* 1954 Select a command from the Command widget. 1955 */ 1956 id=XCommandWidget(display,windows,AnnotateMenu,&event); 1957 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1958 if (id < 0) 1959 continue; 1960 switch (AnnotateCommands[id]) 1961 { 1962 case AnnotateNameCommand: 1963 { 1964 const char 1965 *FontMenu[MaxNumberFonts]; 1966 1967 int 1968 font_number; 1969 1970 /* 1971 Initialize menu selections. 1972 */ 1973 for (i=0; i < MaxNumberFonts; i++) 1974 FontMenu[i]=resource_info->font_name[i]; 1975 FontMenu[MaxNumberFonts-2]="Browser..."; 1976 FontMenu[MaxNumberFonts-1]=(const char *) NULL; 1977 /* 1978 Select a font name from the pop-up menu. 1979 */ 1980 font_number=XMenuWidget(display,windows,AnnotateMenu[id], 1981 (const char **) FontMenu,command); 1982 if (font_number < 0) 1983 break; 1984 if (font_number == (MaxNumberFonts-2)) 1985 { 1986 static char 1987 font_name[MaxTextExtent] = "fixed"; 1988 1989 /* 1990 Select a font name from a browser. 1991 */ 1992 resource_info->font_name[font_number]=font_name; 1993 XFontBrowserWidget(display,windows,"Select",font_name); 1994 if (*font_name == '\0') 1995 break; 1996 } 1997 /* 1998 Initialize font info. 1999 */ 2000 font_info=XLoadQueryFont(display,resource_info->font_name[ 2001 font_number]); 2002 if (font_info == (XFontStruct *) NULL) 2003 { 2004 XNoticeWidget(display,windows,"Unable to load font:", 2005 resource_info->font_name[font_number]); 2006 break; 2007 } 2008 font_id=(unsigned int) font_number; 2009 (void) XFreeFont(display,font_info); 2010 break; 2011 } 2012 case AnnotateFontColorCommand: 2013 { 2014 /* 2015 Initialize menu selections. 2016 */ 2017 for (i=0; i < (int) (MaxNumberPens-2); i++) 2018 ColorMenu[i]=resource_info->pen_colors[i]; 2019 ColorMenu[MaxNumberPens-2]="transparent"; 2020 ColorMenu[MaxNumberPens-1]="Browser..."; 2021 ColorMenu[MaxNumberPens]=(const char *) NULL; 2022 /* 2023 Select a pen color from the pop-up menu. 2024 */ 2025 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2026 (const char **) ColorMenu,command); 2027 if (pen_number < 0) 2028 break; 2029 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue : 2030 MagickFalse; 2031 if (IfMagickTrue(transparent_pen) ) 2032 break; 2033 if (pen_number == (MaxNumberPens-1)) 2034 { 2035 static char 2036 color_name[MaxTextExtent] = "gray"; 2037 2038 /* 2039 Select a pen color from a dialog. 2040 */ 2041 resource_info->pen_colors[pen_number]=color_name; 2042 XColorBrowserWidget(display,windows,"Select",color_name); 2043 if (*color_name == '\0') 2044 break; 2045 } 2046 /* 2047 Set pen color. 2048 */ 2049 (void) XParseColor(display,windows->map_info->colormap, 2050 resource_info->pen_colors[pen_number],&color); 2051 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2052 (unsigned int) MaxColors,&color); 2053 windows->pixel_info->pen_colors[pen_number]=color; 2054 pen_id=(unsigned int) pen_number; 2055 break; 2056 } 2057 case AnnotateBackgroundColorCommand: 2058 { 2059 /* 2060 Initialize menu selections. 2061 */ 2062 for (i=0; i < (int) (MaxNumberPens-2); i++) 2063 ColorMenu[i]=resource_info->pen_colors[i]; 2064 ColorMenu[MaxNumberPens-2]="transparent"; 2065 ColorMenu[MaxNumberPens-1]="Browser..."; 2066 ColorMenu[MaxNumberPens]=(const char *) NULL; 2067 /* 2068 Select a pen color from the pop-up menu. 2069 */ 2070 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2071 (const char **) ColorMenu,command); 2072 if (pen_number < 0) 2073 break; 2074 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue : 2075 MagickFalse; 2076 if (IfMagickTrue(transparent_box) ) 2077 break; 2078 if (pen_number == (MaxNumberPens-1)) 2079 { 2080 static char 2081 color_name[MaxTextExtent] = "gray"; 2082 2083 /* 2084 Select a pen color from a dialog. 2085 */ 2086 resource_info->pen_colors[pen_number]=color_name; 2087 XColorBrowserWidget(display,windows,"Select",color_name); 2088 if (*color_name == '\0') 2089 break; 2090 } 2091 /* 2092 Set pen color. 2093 */ 2094 (void) XParseColor(display,windows->map_info->colormap, 2095 resource_info->pen_colors[pen_number],&color); 2096 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2097 (unsigned int) MaxColors,&color); 2098 windows->pixel_info->pen_colors[pen_number]=color; 2099 box_id=(unsigned int) pen_number; 2100 break; 2101 } 2102 case AnnotateRotateCommand: 2103 { 2104 int 2105 entry; 2106 2107 static char 2108 angle[MaxTextExtent] = "30.0"; 2109 2110 static const char 2111 *RotateMenu[] = 2112 { 2113 "-90", 2114 "-45", 2115 "-30", 2116 "0", 2117 "30", 2118 "45", 2119 "90", 2120 "180", 2121 "Dialog...", 2122 (char *) NULL, 2123 }; 2124 2125 /* 2126 Select a command from the pop-up menu. 2127 */ 2128 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu, 2129 command); 2130 if (entry < 0) 2131 break; 2132 if (entry != 8) 2133 { 2134 degrees=StringToDouble(RotateMenu[entry],(char **) NULL); 2135 break; 2136 } 2137 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:", 2138 angle); 2139 if (*angle == '\0') 2140 break; 2141 degrees=StringToDouble(angle,(char **) NULL); 2142 break; 2143 } 2144 case AnnotateHelpCommand: 2145 { 2146 XTextViewWidget(display,resource_info,windows,MagickFalse, 2147 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2148 break; 2149 } 2150 case AnnotateDismissCommand: 2151 { 2152 /* 2153 Prematurely exit. 2154 */ 2155 state|=EscapeState; 2156 state|=ExitState; 2157 break; 2158 } 2159 default: 2160 break; 2161 } 2162 continue; 2163 } 2164 switch (event.type) 2165 { 2166 case ButtonPress: 2167 { 2168 if (event.xbutton.button != Button1) 2169 break; 2170 if (event.xbutton.window != windows->image.id) 2171 break; 2172 /* 2173 Change to text entering mode. 2174 */ 2175 x=event.xbutton.x; 2176 y=event.xbutton.y; 2177 state|=ExitState; 2178 break; 2179 } 2180 case ButtonRelease: 2181 break; 2182 case Expose: 2183 break; 2184 case KeyPress: 2185 { 2186 if (event.xkey.window != windows->image.id) 2187 break; 2188 /* 2189 Respond to a user key press. 2190 */ 2191 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2192 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2193 switch ((int) key_symbol) 2194 { 2195 case XK_Escape: 2196 case XK_F20: 2197 { 2198 /* 2199 Prematurely exit. 2200 */ 2201 state|=EscapeState; 2202 state|=ExitState; 2203 break; 2204 } 2205 case XK_F1: 2206 case XK_Help: 2207 { 2208 XTextViewWidget(display,resource_info,windows,MagickFalse, 2209 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2210 break; 2211 } 2212 default: 2213 { 2214 (void) XBell(display,0); 2215 break; 2216 } 2217 } 2218 break; 2219 } 2220 case MotionNotify: 2221 { 2222 /* 2223 Map and unmap Info widget as cursor crosses its boundaries. 2224 */ 2225 x=event.xmotion.x; 2226 y=event.xmotion.y; 2227 if (IfMagickTrue(windows->info.mapped) ) 2228 { 2229 if ((x < (int) (windows->info.x+windows->info.width)) && 2230 (y < (int) (windows->info.y+windows->info.height))) 2231 (void) XWithdrawWindow(display,windows->info.id, 2232 windows->info.screen); 2233 } 2234 else 2235 if ((x > (int) (windows->info.x+windows->info.width)) || 2236 (y > (int) (windows->info.y+windows->info.height))) 2237 (void) XMapWindow(display,windows->info.id); 2238 break; 2239 } 2240 default: 2241 break; 2242 } 2243 } while ((state & ExitState) == 0); 2244 (void) XSelectInput(display,windows->image.id, 2245 windows->image.attributes.event_mask); 2246 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 2247 if ((state & EscapeState) != 0) 2248 return(MagickTrue); 2249 /* 2250 Set font info and check boundary conditions. 2251 */ 2252 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]); 2253 if (font_info == (XFontStruct *) NULL) 2254 { 2255 XNoticeWidget(display,windows,"Unable to load font:", 2256 resource_info->font_name[font_id]); 2257 font_info=windows->font_info; 2258 } 2259 if ((x+font_info->max_bounds.width) >= (int) windows->image.width) 2260 x=(int) windows->image.width-font_info->max_bounds.width; 2261 if (y < (int) (font_info->ascent+font_info->descent)) 2262 y=(int) font_info->ascent+font_info->descent; 2263 if (((int) font_info->max_bounds.width > (int) windows->image.width) || 2264 ((font_info->ascent+font_info->descent) >= (int) windows->image.height)) 2265 return(MagickFalse); 2266 /* 2267 Initialize annotate structure. 2268 */ 2269 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info)); 2270 if (annotate_info == (XAnnotateInfo *) NULL) 2271 return(MagickFalse); 2272 XGetAnnotateInfo(annotate_info); 2273 annotate_info->x=x; 2274 annotate_info->y=y; 2275 if (IfMagickFalse(transparent_box) && IfMagickFalse(transparent_pen)) 2276 annotate_info->stencil=OpaqueStencil; 2277 else 2278 if (IfMagickFalse(transparent_box) ) 2279 annotate_info->stencil=BackgroundStencil; 2280 else 2281 annotate_info->stencil=ForegroundStencil; 2282 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent; 2283 annotate_info->degrees=degrees; 2284 annotate_info->font_info=font_info; 2285 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2286 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL, 2287 sizeof(*annotate_info->text)); 2288 if (annotate_info->text == (char *) NULL) 2289 return(MagickFalse); 2290 /* 2291 Create cursor and set graphic context. 2292 */ 2293 cursor=XCreateFontCursor(display,XC_pencil); 2294 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2295 annotate_context=windows->image.annotate_context; 2296 (void) XSetFont(display,annotate_context,font_info->fid); 2297 (void) XSetBackground(display,annotate_context, 2298 windows->pixel_info->pen_colors[box_id].pixel); 2299 (void) XSetForeground(display,annotate_context, 2300 windows->pixel_info->pen_colors[pen_id].pixel); 2301 /* 2302 Begin annotating the image with text. 2303 */ 2304 (void) CloneString(&windows->command.name,"Text"); 2305 windows->command.data=0; 2306 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL); 2307 state=DefaultState; 2308 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2309 text_event.xexpose.width=(int) font_info->max_bounds.width; 2310 text_event.xexpose.height=font_info->max_bounds.ascent+ 2311 font_info->max_bounds.descent; 2312 p=annotate_info->text; 2313 do 2314 { 2315 /* 2316 Display text cursor. 2317 */ 2318 *p='\0'; 2319 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2320 /* 2321 Wait for next event. 2322 */ 2323 XScreenEvent(display,windows,&event,exception); 2324 if (event.xany.window == windows->command.id) 2325 { 2326 /* 2327 Select a command from the Command widget. 2328 */ 2329 (void) XSetBackground(display,annotate_context, 2330 windows->pixel_info->background_color.pixel); 2331 (void) XSetForeground(display,annotate_context, 2332 windows->pixel_info->foreground_color.pixel); 2333 id=XCommandWidget(display,windows,AnnotateMenu,&event); 2334 (void) XSetBackground(display,annotate_context, 2335 windows->pixel_info->pen_colors[box_id].pixel); 2336 (void) XSetForeground(display,annotate_context, 2337 windows->pixel_info->pen_colors[pen_id].pixel); 2338 if (id < 0) 2339 continue; 2340 switch (TextCommands[id]) 2341 { 2342 case TextHelpCommand: 2343 { 2344 XTextViewWidget(display,resource_info,windows,MagickFalse, 2345 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2346 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2347 break; 2348 } 2349 case TextApplyCommand: 2350 { 2351 /* 2352 Finished annotating. 2353 */ 2354 annotate_info->width=(unsigned int) XTextWidth(font_info, 2355 annotate_info->text,(int) strlen(annotate_info->text)); 2356 XRefreshWindow(display,&windows->image,&text_event); 2357 state|=ExitState; 2358 break; 2359 } 2360 default: 2361 break; 2362 } 2363 continue; 2364 } 2365 /* 2366 Erase text cursor. 2367 */ 2368 text_event.xexpose.x=x; 2369 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2370 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y, 2371 (unsigned int) text_event.xexpose.width,(unsigned int) 2372 text_event.xexpose.height,MagickFalse); 2373 XRefreshWindow(display,&windows->image,&text_event); 2374 switch (event.type) 2375 { 2376 case ButtonPress: 2377 { 2378 if (event.xbutton.window != windows->image.id) 2379 break; 2380 if (event.xbutton.button == Button2) 2381 { 2382 /* 2383 Request primary selection. 2384 */ 2385 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, 2386 windows->image.id,CurrentTime); 2387 break; 2388 } 2389 break; 2390 } 2391 case Expose: 2392 { 2393 if (event.xexpose.count == 0) 2394 { 2395 XAnnotateInfo 2396 *text_info; 2397 2398 /* 2399 Refresh Image window. 2400 */ 2401 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 2402 text_info=annotate_info; 2403 while (text_info != (XAnnotateInfo *) NULL) 2404 { 2405 if (annotate_info->stencil == ForegroundStencil) 2406 (void) XDrawString(display,windows->image.id,annotate_context, 2407 text_info->x,text_info->y,text_info->text, 2408 (int) strlen(text_info->text)); 2409 else 2410 (void) XDrawImageString(display,windows->image.id, 2411 annotate_context,text_info->x,text_info->y,text_info->text, 2412 (int) strlen(text_info->text)); 2413 text_info=text_info->previous; 2414 } 2415 (void) XDrawString(display,windows->image.id,annotate_context, 2416 x,y,"_",1); 2417 } 2418 break; 2419 } 2420 case KeyPress: 2421 { 2422 int 2423 length; 2424 2425 if (event.xkey.window != windows->image.id) 2426 break; 2427 /* 2428 Respond to a user key press. 2429 */ 2430 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 2431 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2432 *(command+length)='\0'; 2433 if (((event.xkey.state & ControlMask) != 0) || 2434 ((event.xkey.state & Mod1Mask) != 0)) 2435 state|=ModifierState; 2436 if ((state & ModifierState) != 0) 2437 switch ((int) key_symbol) 2438 { 2439 case XK_u: 2440 case XK_U: 2441 { 2442 key_symbol=DeleteCommand; 2443 break; 2444 } 2445 default: 2446 break; 2447 } 2448 switch ((int) key_symbol) 2449 { 2450 case XK_BackSpace: 2451 { 2452 /* 2453 Erase one character. 2454 */ 2455 if (p == annotate_info->text) 2456 { 2457 if (annotate_info->previous == (XAnnotateInfo *) NULL) 2458 break; 2459 else 2460 { 2461 /* 2462 Go to end of the previous line of text. 2463 */ 2464 annotate_info=annotate_info->previous; 2465 p=annotate_info->text; 2466 x=annotate_info->x+annotate_info->width; 2467 y=annotate_info->y; 2468 if (annotate_info->width != 0) 2469 p+=strlen(annotate_info->text); 2470 break; 2471 } 2472 } 2473 p--; 2474 x-=XTextWidth(font_info,p,1); 2475 text_event.xexpose.x=x; 2476 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2477 XRefreshWindow(display,&windows->image,&text_event); 2478 break; 2479 } 2480 case XK_bracketleft: 2481 { 2482 key_symbol=XK_Escape; 2483 break; 2484 } 2485 case DeleteCommand: 2486 { 2487 /* 2488 Erase the entire line of text. 2489 */ 2490 while (p != annotate_info->text) 2491 { 2492 p--; 2493 x-=XTextWidth(font_info,p,1); 2494 text_event.xexpose.x=x; 2495 XRefreshWindow(display,&windows->image,&text_event); 2496 } 2497 break; 2498 } 2499 case XK_Escape: 2500 case XK_F20: 2501 { 2502 /* 2503 Finished annotating. 2504 */ 2505 annotate_info->width=(unsigned int) XTextWidth(font_info, 2506 annotate_info->text,(int) strlen(annotate_info->text)); 2507 XRefreshWindow(display,&windows->image,&text_event); 2508 state|=ExitState; 2509 break; 2510 } 2511 default: 2512 { 2513 /* 2514 Draw a single character on the Image window. 2515 */ 2516 if ((state & ModifierState) != 0) 2517 break; 2518 if (*command == '\0') 2519 break; 2520 *p=(*command); 2521 if (annotate_info->stencil == ForegroundStencil) 2522 (void) XDrawString(display,windows->image.id,annotate_context, 2523 x,y,p,1); 2524 else 2525 (void) XDrawImageString(display,windows->image.id, 2526 annotate_context,x,y,p,1); 2527 x+=XTextWidth(font_info,p,1); 2528 p++; 2529 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2530 break; 2531 } 2532 case XK_Return: 2533 case XK_KP_Enter: 2534 { 2535 /* 2536 Advance to the next line of text. 2537 */ 2538 *p='\0'; 2539 annotate_info->width=(unsigned int) XTextWidth(font_info, 2540 annotate_info->text,(int) strlen(annotate_info->text)); 2541 if (annotate_info->next != (XAnnotateInfo *) NULL) 2542 { 2543 /* 2544 Line of text already exists. 2545 */ 2546 annotate_info=annotate_info->next; 2547 x=annotate_info->x; 2548 y=annotate_info->y; 2549 p=annotate_info->text; 2550 break; 2551 } 2552 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2553 sizeof(*annotate_info->next)); 2554 if (annotate_info->next == (XAnnotateInfo *) NULL) 2555 return(MagickFalse); 2556 *annotate_info->next=(*annotate_info); 2557 annotate_info->next->previous=annotate_info; 2558 annotate_info=annotate_info->next; 2559 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2560 windows->image.width/MagickMax((ssize_t) 2561 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2562 if (annotate_info->text == (char *) NULL) 2563 return(MagickFalse); 2564 annotate_info->y+=annotate_info->height; 2565 if (annotate_info->y > (int) windows->image.height) 2566 annotate_info->y=(int) annotate_info->height; 2567 annotate_info->next=(XAnnotateInfo *) NULL; 2568 x=annotate_info->x; 2569 y=annotate_info->y; 2570 p=annotate_info->text; 2571 break; 2572 } 2573 } 2574 break; 2575 } 2576 case KeyRelease: 2577 { 2578 /* 2579 Respond to a user key release. 2580 */ 2581 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2582 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2583 state&=(~ModifierState); 2584 break; 2585 } 2586 case SelectionNotify: 2587 { 2588 Atom 2589 type; 2590 2591 int 2592 format; 2593 2594 unsigned char 2595 *data; 2596 2597 unsigned long 2598 after, 2599 length; 2600 2601 /* 2602 Obtain response from primary selection. 2603 */ 2604 if (event.xselection.property == (Atom) None) 2605 break; 2606 status=XGetWindowProperty(display,event.xselection.requestor, 2607 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING, 2608 &type,&format,&length,&after,&data); 2609 if ((status != Success) || (type != XA_STRING) || (format == 32) || 2610 (length == 0)) 2611 break; 2612 /* 2613 Annotate Image window with primary selection. 2614 */ 2615 for (i=0; i < (ssize_t) length; i++) 2616 { 2617 if ((char) data[i] != '\n') 2618 { 2619 /* 2620 Draw a single character on the Image window. 2621 */ 2622 *p=(char) data[i]; 2623 (void) XDrawString(display,windows->image.id,annotate_context, 2624 x,y,p,1); 2625 x+=XTextWidth(font_info,p,1); 2626 p++; 2627 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2628 continue; 2629 } 2630 /* 2631 Advance to the next line of text. 2632 */ 2633 *p='\0'; 2634 annotate_info->width=(unsigned int) XTextWidth(font_info, 2635 annotate_info->text,(int) strlen(annotate_info->text)); 2636 if (annotate_info->next != (XAnnotateInfo *) NULL) 2637 { 2638 /* 2639 Line of text already exists. 2640 */ 2641 annotate_info=annotate_info->next; 2642 x=annotate_info->x; 2643 y=annotate_info->y; 2644 p=annotate_info->text; 2645 continue; 2646 } 2647 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2648 sizeof(*annotate_info->next)); 2649 if (annotate_info->next == (XAnnotateInfo *) NULL) 2650 return(MagickFalse); 2651 *annotate_info->next=(*annotate_info); 2652 annotate_info->next->previous=annotate_info; 2653 annotate_info=annotate_info->next; 2654 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2655 windows->image.width/MagickMax((ssize_t) 2656 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2657 if (annotate_info->text == (char *) NULL) 2658 return(MagickFalse); 2659 annotate_info->y+=annotate_info->height; 2660 if (annotate_info->y > (int) windows->image.height) 2661 annotate_info->y=(int) annotate_info->height; 2662 annotate_info->next=(XAnnotateInfo *) NULL; 2663 x=annotate_info->x; 2664 y=annotate_info->y; 2665 p=annotate_info->text; 2666 } 2667 (void) XFree((void *) data); 2668 break; 2669 } 2670 default: 2671 break; 2672 } 2673 } while ((state & ExitState) == 0); 2674 (void) XFreeCursor(display,cursor); 2675 /* 2676 Annotation is relative to image configuration. 2677 */ 2678 width=(unsigned int) image->columns; 2679 height=(unsigned int) image->rows; 2680 x=0; 2681 y=0; 2682 if (windows->image.crop_geometry != (char *) NULL) 2683 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 2684 /* 2685 Initialize annotated image. 2686 */ 2687 XSetCursorState(display,windows,MagickTrue); 2688 XCheckRefreshWindows(display,windows); 2689 while (annotate_info != (XAnnotateInfo *) NULL) 2690 { 2691 if (annotate_info->width == 0) 2692 { 2693 /* 2694 No text on this line-- go to the next line of text. 2695 */ 2696 previous_info=annotate_info->previous; 2697 annotate_info->text=(char *) 2698 RelinquishMagickMemory(annotate_info->text); 2699 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2700 annotate_info=previous_info; 2701 continue; 2702 } 2703 /* 2704 Determine pixel index for box and pen color. 2705 */ 2706 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id]; 2707 if (windows->pixel_info->colors != 0) 2708 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2709 if (windows->pixel_info->pixels[i] == 2710 windows->pixel_info->pen_colors[box_id].pixel) 2711 { 2712 windows->pixel_info->box_index=(unsigned short) i; 2713 break; 2714 } 2715 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 2716 if (windows->pixel_info->colors != 0) 2717 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2718 if (windows->pixel_info->pixels[i] == 2719 windows->pixel_info->pen_colors[pen_id].pixel) 2720 { 2721 windows->pixel_info->pen_index=(unsigned short) i; 2722 break; 2723 } 2724 /* 2725 Define the annotate geometry string. 2726 */ 2727 annotate_info->x=(int) 2728 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width; 2729 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+ 2730 windows->image.y)/windows->image.ximage->height; 2731 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent, 2732 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width, 2733 height*annotate_info->height/windows->image.ximage->height, 2734 annotate_info->x+x,annotate_info->y+y); 2735 /* 2736 Annotate image with text. 2737 */ 2738 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image, 2739 exception); 2740 if (status == 0) 2741 return(MagickFalse); 2742 /* 2743 Free up memory. 2744 */ 2745 previous_info=annotate_info->previous; 2746 annotate_info->text=DestroyString(annotate_info->text); 2747 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2748 annotate_info=previous_info; 2749 } 2750 (void) XSetForeground(display,annotate_context, 2751 windows->pixel_info->foreground_color.pixel); 2752 (void) XSetBackground(display,annotate_context, 2753 windows->pixel_info->background_color.pixel); 2754 (void) XSetFont(display,annotate_context,windows->font_info->fid); 2755 XSetCursorState(display,windows,MagickFalse); 2756 (void) XFreeFont(display,font_info); 2757 /* 2758 Update image configuration. 2759 */ 2760 XConfigureImageColormap(display,resource_info,windows,image,exception); 2761 (void) XConfigureImage(display,resource_info,windows,image,exception); 2762 return(MagickTrue); 2763} 2764 2765/* 2766%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2767% % 2768% % 2769% % 2770+ X B a c k g r o u n d I m a g e % 2771% % 2772% % 2773% % 2774%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2775% 2776% XBackgroundImage() displays the image in the background of a window. 2777% 2778% The format of the XBackgroundImage method is: 2779% 2780% MagickBooleanType XBackgroundImage(Display *display, 2781% XResourceInfo *resource_info,XWindows *windows,Image **image, 2782% ExceptionInfo *exception) 2783% 2784% A description of each parameter follows: 2785% 2786% o display: Specifies a connection to an X server; returned from 2787% XOpenDisplay. 2788% 2789% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2790% 2791% o windows: Specifies a pointer to a XWindows structure. 2792% 2793% o image: the image. 2794% 2795% o exception: return any errors or warnings in this structure. 2796% 2797*/ 2798static MagickBooleanType XBackgroundImage(Display *display, 2799 XResourceInfo *resource_info,XWindows *windows,Image **image, 2800 ExceptionInfo *exception) 2801{ 2802#define BackgroundImageTag "Background/Image" 2803 2804 int 2805 status; 2806 2807 static char 2808 window_id[MaxTextExtent] = "root"; 2809 2810 XResourceInfo 2811 background_resources; 2812 2813 /* 2814 Put image in background. 2815 */ 2816 status=XDialogWidget(display,windows,"Background", 2817 "Enter window id (id 0x00 selects window with pointer):",window_id); 2818 if (*window_id == '\0') 2819 return(MagickFalse); 2820 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 2821 exception); 2822 XInfoWidget(display,windows,BackgroundImageTag); 2823 XSetCursorState(display,windows,MagickTrue); 2824 XCheckRefreshWindows(display,windows); 2825 background_resources=(*resource_info); 2826 background_resources.window_id=window_id; 2827 background_resources.backdrop=IsMagickTrue(status); 2828 status=XDisplayBackgroundImage(display,&background_resources,*image, 2829 exception); 2830 if (IfMagickTrue(status)) 2831 XClientMessage(display,windows->image.id,windows->im_protocols, 2832 windows->im_retain_colors,CurrentTime); 2833 XSetCursorState(display,windows,MagickFalse); 2834 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image, 2835 exception); 2836 return(MagickTrue); 2837} 2838 2839/* 2840%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2841% % 2842% % 2843% % 2844+ X C h o p I m a g e % 2845% % 2846% % 2847% % 2848%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2849% 2850% XChopImage() chops the X image. 2851% 2852% The format of the XChopImage method is: 2853% 2854% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info, 2855% XWindows *windows,Image **image,ExceptionInfo *exception) 2856% 2857% A description of each parameter follows: 2858% 2859% o display: Specifies a connection to an X server; returned from 2860% XOpenDisplay. 2861% 2862% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2863% 2864% o windows: Specifies a pointer to a XWindows structure. 2865% 2866% o image: the image. 2867% 2868% o exception: return any errors or warnings in this structure. 2869% 2870*/ 2871static MagickBooleanType XChopImage(Display *display, 2872 XResourceInfo *resource_info,XWindows *windows,Image **image, 2873 ExceptionInfo *exception) 2874{ 2875 static const char 2876 *ChopMenu[] = 2877 { 2878 "Direction", 2879 "Help", 2880 "Dismiss", 2881 (char *) NULL 2882 }; 2883 2884 static ModeType 2885 direction = HorizontalChopCommand; 2886 2887 static const ModeType 2888 ChopCommands[] = 2889 { 2890 ChopDirectionCommand, 2891 ChopHelpCommand, 2892 ChopDismissCommand 2893 }, 2894 DirectionCommands[] = 2895 { 2896 HorizontalChopCommand, 2897 VerticalChopCommand 2898 }; 2899 2900 char 2901 text[MaxTextExtent]; 2902 2903 Image 2904 *chop_image; 2905 2906 int 2907 id, 2908 x, 2909 y; 2910 2911 double 2912 scale_factor; 2913 2914 RectangleInfo 2915 chop_info; 2916 2917 unsigned int 2918 distance, 2919 height, 2920 width; 2921 2922 size_t 2923 state; 2924 2925 XEvent 2926 event; 2927 2928 XSegment 2929 segment_info; 2930 2931 /* 2932 Map Command widget. 2933 */ 2934 (void) CloneString(&windows->command.name,"Chop"); 2935 windows->command.data=1; 2936 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL); 2937 (void) XMapRaised(display,windows->command.id); 2938 XClientMessage(display,windows->image.id,windows->im_protocols, 2939 windows->im_update_widget,CurrentTime); 2940 /* 2941 Track pointer until button 1 is pressed. 2942 */ 2943 XQueryPosition(display,windows->image.id,&x,&y); 2944 (void) XSelectInput(display,windows->image.id, 2945 windows->image.attributes.event_mask | PointerMotionMask); 2946 state=DefaultState; 2947 do 2948 { 2949 if (IfMagickTrue(windows->info.mapped) ) 2950 { 2951 /* 2952 Display pointer position. 2953 */ 2954 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 2955 x+windows->image.x,y+windows->image.y); 2956 XInfoWidget(display,windows,text); 2957 } 2958 /* 2959 Wait for next event. 2960 */ 2961 XScreenEvent(display,windows,&event,exception); 2962 if (event.xany.window == windows->command.id) 2963 { 2964 /* 2965 Select a command from the Command widget. 2966 */ 2967 id=XCommandWidget(display,windows,ChopMenu,&event); 2968 if (id < 0) 2969 continue; 2970 switch (ChopCommands[id]) 2971 { 2972 case ChopDirectionCommand: 2973 { 2974 char 2975 command[MaxTextExtent]; 2976 2977 static const char 2978 *Directions[] = 2979 { 2980 "horizontal", 2981 "vertical", 2982 (char *) NULL, 2983 }; 2984 2985 /* 2986 Select a command from the pop-up menu. 2987 */ 2988 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 2989 if (id >= 0) 2990 direction=DirectionCommands[id]; 2991 break; 2992 } 2993 case ChopHelpCommand: 2994 { 2995 XTextViewWidget(display,resource_info,windows,MagickFalse, 2996 "Help Viewer - Image Chop",ImageChopHelp); 2997 break; 2998 } 2999 case ChopDismissCommand: 3000 { 3001 /* 3002 Prematurely exit. 3003 */ 3004 state|=EscapeState; 3005 state|=ExitState; 3006 break; 3007 } 3008 default: 3009 break; 3010 } 3011 continue; 3012 } 3013 switch (event.type) 3014 { 3015 case ButtonPress: 3016 { 3017 if (event.xbutton.button != Button1) 3018 break; 3019 if (event.xbutton.window != windows->image.id) 3020 break; 3021 /* 3022 User has committed to start point of chopping line. 3023 */ 3024 segment_info.x1=(short int) event.xbutton.x; 3025 segment_info.x2=(short int) event.xbutton.x; 3026 segment_info.y1=(short int) event.xbutton.y; 3027 segment_info.y2=(short int) event.xbutton.y; 3028 state|=ExitState; 3029 break; 3030 } 3031 case ButtonRelease: 3032 break; 3033 case Expose: 3034 break; 3035 case KeyPress: 3036 { 3037 char 3038 command[MaxTextExtent]; 3039 3040 KeySym 3041 key_symbol; 3042 3043 if (event.xkey.window != windows->image.id) 3044 break; 3045 /* 3046 Respond to a user key press. 3047 */ 3048 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3049 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3050 switch ((int) key_symbol) 3051 { 3052 case XK_Escape: 3053 case XK_F20: 3054 { 3055 /* 3056 Prematurely exit. 3057 */ 3058 state|=EscapeState; 3059 state|=ExitState; 3060 break; 3061 } 3062 case XK_F1: 3063 case XK_Help: 3064 { 3065 (void) XSetFunction(display,windows->image.highlight_context, 3066 GXcopy); 3067 XTextViewWidget(display,resource_info,windows,MagickFalse, 3068 "Help Viewer - Image Chop",ImageChopHelp); 3069 (void) XSetFunction(display,windows->image.highlight_context, 3070 GXinvert); 3071 break; 3072 } 3073 default: 3074 { 3075 (void) XBell(display,0); 3076 break; 3077 } 3078 } 3079 break; 3080 } 3081 case MotionNotify: 3082 { 3083 /* 3084 Map and unmap Info widget as text cursor crosses its boundaries. 3085 */ 3086 x=event.xmotion.x; 3087 y=event.xmotion.y; 3088 if (IfMagickTrue(windows->info.mapped) ) 3089 { 3090 if ((x < (int) (windows->info.x+windows->info.width)) && 3091 (y < (int) (windows->info.y+windows->info.height))) 3092 (void) XWithdrawWindow(display,windows->info.id, 3093 windows->info.screen); 3094 } 3095 else 3096 if ((x > (int) (windows->info.x+windows->info.width)) || 3097 (y > (int) (windows->info.y+windows->info.height))) 3098 (void) XMapWindow(display,windows->info.id); 3099 } 3100 } 3101 } while ((state & ExitState) == 0); 3102 (void) XSelectInput(display,windows->image.id, 3103 windows->image.attributes.event_mask); 3104 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3105 if ((state & EscapeState) != 0) 3106 return(MagickTrue); 3107 /* 3108 Draw line as pointer moves until the mouse button is released. 3109 */ 3110 chop_info.width=0; 3111 chop_info.height=0; 3112 chop_info.x=0; 3113 chop_info.y=0; 3114 distance=0; 3115 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3116 state=DefaultState; 3117 do 3118 { 3119 if (distance > 9) 3120 { 3121 /* 3122 Display info and draw chopping line. 3123 */ 3124 if (IfMagickFalse(windows->info.mapped) ) 3125 (void) XMapWindow(display,windows->info.id); 3126 (void) FormatLocaleString(text,MaxTextExtent, 3127 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 3128 chop_info.height,(double) chop_info.x,(double) chop_info.y); 3129 XInfoWidget(display,windows,text); 3130 XHighlightLine(display,windows->image.id, 3131 windows->image.highlight_context,&segment_info); 3132 } 3133 else 3134 if (IfMagickTrue(windows->info.mapped) ) 3135 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3136 /* 3137 Wait for next event. 3138 */ 3139 XScreenEvent(display,windows,&event,exception); 3140 if (distance > 9) 3141 XHighlightLine(display,windows->image.id, 3142 windows->image.highlight_context,&segment_info); 3143 switch (event.type) 3144 { 3145 case ButtonPress: 3146 { 3147 segment_info.x2=(short int) event.xmotion.x; 3148 segment_info.y2=(short int) event.xmotion.y; 3149 break; 3150 } 3151 case ButtonRelease: 3152 { 3153 /* 3154 User has committed to chopping line. 3155 */ 3156 segment_info.x2=(short int) event.xbutton.x; 3157 segment_info.y2=(short int) event.xbutton.y; 3158 state|=ExitState; 3159 break; 3160 } 3161 case Expose: 3162 break; 3163 case MotionNotify: 3164 { 3165 segment_info.x2=(short int) event.xmotion.x; 3166 segment_info.y2=(short int) event.xmotion.y; 3167 } 3168 default: 3169 break; 3170 } 3171 /* 3172 Check boundary conditions. 3173 */ 3174 if (segment_info.x2 < 0) 3175 segment_info.x2=0; 3176 else 3177 if (segment_info.x2 > windows->image.ximage->width) 3178 segment_info.x2=windows->image.ximage->width; 3179 if (segment_info.y2 < 0) 3180 segment_info.y2=0; 3181 else 3182 if (segment_info.y2 > windows->image.ximage->height) 3183 segment_info.y2=windows->image.ximage->height; 3184 distance=(unsigned int) 3185 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 3186 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 3187 /* 3188 Compute chopping geometry. 3189 */ 3190 if (direction == HorizontalChopCommand) 3191 { 3192 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 3193 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 3194 chop_info.height=0; 3195 chop_info.y=0; 3196 if (segment_info.x1 > (int) segment_info.x2) 3197 { 3198 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 3199 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 3200 } 3201 } 3202 else 3203 { 3204 chop_info.width=0; 3205 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 3206 chop_info.x=0; 3207 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 3208 if (segment_info.y1 > segment_info.y2) 3209 { 3210 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 3211 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 3212 } 3213 } 3214 } while ((state & ExitState) == 0); 3215 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 3216 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3217 if (distance <= 9) 3218 return(MagickTrue); 3219 /* 3220 Image chopping is relative to image configuration. 3221 */ 3222 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 3223 exception); 3224 XSetCursorState(display,windows,MagickTrue); 3225 XCheckRefreshWindows(display,windows); 3226 windows->image.window_changes.width=windows->image.ximage->width- 3227 (unsigned int) chop_info.width; 3228 windows->image.window_changes.height=windows->image.ximage->height- 3229 (unsigned int) chop_info.height; 3230 width=(unsigned int) (*image)->columns; 3231 height=(unsigned int) (*image)->rows; 3232 x=0; 3233 y=0; 3234 if (windows->image.crop_geometry != (char *) NULL) 3235 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 3236 scale_factor=(double) width/windows->image.ximage->width; 3237 chop_info.x+=x; 3238 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 3239 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 3240 scale_factor=(double) height/windows->image.ximage->height; 3241 chop_info.y+=y; 3242 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 3243 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 3244 /* 3245 Chop image. 3246 */ 3247 chop_image=ChopImage(*image,&chop_info,exception); 3248 XSetCursorState(display,windows,MagickFalse); 3249 if (chop_image == (Image *) NULL) 3250 return(MagickFalse); 3251 *image=DestroyImage(*image); 3252 *image=chop_image; 3253 /* 3254 Update image configuration. 3255 */ 3256 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3257 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3258 return(MagickTrue); 3259} 3260 3261/* 3262%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3263% % 3264% % 3265% % 3266+ X C o l o r E d i t I m a g e % 3267% % 3268% % 3269% % 3270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3271% 3272% XColorEditImage() allows the user to interactively change the color of one 3273% pixel for a DirectColor image or one colormap entry for a PseudoClass image. 3274% 3275% The format of the XColorEditImage method is: 3276% 3277% MagickBooleanType XColorEditImage(Display *display, 3278% XResourceInfo *resource_info,XWindows *windows,Image **image, 3279% ExceptionInfo *exception) 3280% 3281% A description of each parameter follows: 3282% 3283% o display: Specifies a connection to an X server; returned from 3284% XOpenDisplay. 3285% 3286% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3287% 3288% o windows: Specifies a pointer to a XWindows structure. 3289% 3290% o image: the image; returned from ReadImage. 3291% 3292% o exception: return any errors or warnings in this structure. 3293% 3294*/ 3295static MagickBooleanType XColorEditImage(Display *display, 3296 XResourceInfo *resource_info,XWindows *windows,Image **image, 3297 ExceptionInfo *exception) 3298{ 3299 static const char 3300 *ColorEditMenu[] = 3301 { 3302 "Method", 3303 "Pixel Color", 3304 "Border Color", 3305 "Fuzz", 3306 "Undo", 3307 "Help", 3308 "Dismiss", 3309 (char *) NULL 3310 }; 3311 3312 static const ModeType 3313 ColorEditCommands[] = 3314 { 3315 ColorEditMethodCommand, 3316 ColorEditColorCommand, 3317 ColorEditBorderCommand, 3318 ColorEditFuzzCommand, 3319 ColorEditUndoCommand, 3320 ColorEditHelpCommand, 3321 ColorEditDismissCommand 3322 }; 3323 3324 static PaintMethod 3325 method = PointMethod; 3326 3327 static unsigned int 3328 pen_id = 0; 3329 3330 static XColor 3331 border_color = { 0, 0, 0, 0, 0, 0 }; 3332 3333 char 3334 command[MaxTextExtent], 3335 text[MaxTextExtent]; 3336 3337 Cursor 3338 cursor; 3339 3340 int 3341 entry, 3342 id, 3343 x, 3344 x_offset, 3345 y, 3346 y_offset; 3347 3348 register Quantum 3349 *q; 3350 3351 register ssize_t 3352 i; 3353 3354 unsigned int 3355 height, 3356 width; 3357 3358 size_t 3359 state; 3360 3361 XColor 3362 color; 3363 3364 XEvent 3365 event; 3366 3367 /* 3368 Map Command widget. 3369 */ 3370 (void) CloneString(&windows->command.name,"Color Edit"); 3371 windows->command.data=4; 3372 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 3373 (void) XMapRaised(display,windows->command.id); 3374 XClientMessage(display,windows->image.id,windows->im_protocols, 3375 windows->im_update_widget,CurrentTime); 3376 /* 3377 Make cursor. 3378 */ 3379 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 3380 resource_info->background_color,resource_info->foreground_color); 3381 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3382 /* 3383 Track pointer until button 1 is pressed. 3384 */ 3385 XQueryPosition(display,windows->image.id,&x,&y); 3386 (void) XSelectInput(display,windows->image.id, 3387 windows->image.attributes.event_mask | PointerMotionMask); 3388 state=DefaultState; 3389 do 3390 { 3391 if (IfMagickTrue(windows->info.mapped) ) 3392 { 3393 /* 3394 Display pointer position. 3395 */ 3396 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 3397 x+windows->image.x,y+windows->image.y); 3398 XInfoWidget(display,windows,text); 3399 } 3400 /* 3401 Wait for next event. 3402 */ 3403 XScreenEvent(display,windows,&event,exception); 3404 if (event.xany.window == windows->command.id) 3405 { 3406 /* 3407 Select a command from the Command widget. 3408 */ 3409 id=XCommandWidget(display,windows,ColorEditMenu,&event); 3410 if (id < 0) 3411 { 3412 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3413 continue; 3414 } 3415 switch (ColorEditCommands[id]) 3416 { 3417 case ColorEditMethodCommand: 3418 { 3419 char 3420 **methods; 3421 3422 /* 3423 Select a method from the pop-up menu. 3424 */ 3425 methods=(char **) GetCommandOptions(MagickMethodOptions); 3426 if (methods == (char **) NULL) 3427 break; 3428 entry=XMenuWidget(display,windows,ColorEditMenu[id], 3429 (const char **) methods,command); 3430 if (entry >= 0) 3431 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 3432 MagickFalse,methods[entry]); 3433 methods=DestroyStringList(methods); 3434 break; 3435 } 3436 case ColorEditColorCommand: 3437 { 3438 const char 3439 *ColorMenu[MaxNumberPens]; 3440 3441 int 3442 pen_number; 3443 3444 /* 3445 Initialize menu selections. 3446 */ 3447 for (i=0; i < (int) (MaxNumberPens-2); i++) 3448 ColorMenu[i]=resource_info->pen_colors[i]; 3449 ColorMenu[MaxNumberPens-2]="Browser..."; 3450 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3451 /* 3452 Select a pen color from the pop-up menu. 3453 */ 3454 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3455 (const char **) ColorMenu,command); 3456 if (pen_number < 0) 3457 break; 3458 if (pen_number == (MaxNumberPens-2)) 3459 { 3460 static char 3461 color_name[MaxTextExtent] = "gray"; 3462 3463 /* 3464 Select a pen color from a dialog. 3465 */ 3466 resource_info->pen_colors[pen_number]=color_name; 3467 XColorBrowserWidget(display,windows,"Select",color_name); 3468 if (*color_name == '\0') 3469 break; 3470 } 3471 /* 3472 Set pen color. 3473 */ 3474 (void) XParseColor(display,windows->map_info->colormap, 3475 resource_info->pen_colors[pen_number],&color); 3476 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 3477 (unsigned int) MaxColors,&color); 3478 windows->pixel_info->pen_colors[pen_number]=color; 3479 pen_id=(unsigned int) pen_number; 3480 break; 3481 } 3482 case ColorEditBorderCommand: 3483 { 3484 const char 3485 *ColorMenu[MaxNumberPens]; 3486 3487 int 3488 pen_number; 3489 3490 /* 3491 Initialize menu selections. 3492 */ 3493 for (i=0; i < (int) (MaxNumberPens-2); i++) 3494 ColorMenu[i]=resource_info->pen_colors[i]; 3495 ColorMenu[MaxNumberPens-2]="Browser..."; 3496 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3497 /* 3498 Select a pen color from the pop-up menu. 3499 */ 3500 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3501 (const char **) ColorMenu,command); 3502 if (pen_number < 0) 3503 break; 3504 if (pen_number == (MaxNumberPens-2)) 3505 { 3506 static char 3507 color_name[MaxTextExtent] = "gray"; 3508 3509 /* 3510 Select a pen color from a dialog. 3511 */ 3512 resource_info->pen_colors[pen_number]=color_name; 3513 XColorBrowserWidget(display,windows,"Select",color_name); 3514 if (*color_name == '\0') 3515 break; 3516 } 3517 /* 3518 Set border color. 3519 */ 3520 (void) XParseColor(display,windows->map_info->colormap, 3521 resource_info->pen_colors[pen_number],&border_color); 3522 break; 3523 } 3524 case ColorEditFuzzCommand: 3525 { 3526 static char 3527 fuzz[MaxTextExtent]; 3528 3529 static const char 3530 *FuzzMenu[] = 3531 { 3532 "0%", 3533 "2%", 3534 "5%", 3535 "10%", 3536 "15%", 3537 "Dialog...", 3538 (char *) NULL, 3539 }; 3540 3541 /* 3542 Select a command from the pop-up menu. 3543 */ 3544 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 3545 command); 3546 if (entry < 0) 3547 break; 3548 if (entry != 5) 3549 { 3550 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 3551 QuantumRange+1.0); 3552 break; 3553 } 3554 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 3555 (void) XDialogWidget(display,windows,"Ok", 3556 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 3557 if (*fuzz == '\0') 3558 break; 3559 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 3560 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 3561 1.0); 3562 break; 3563 } 3564 case ColorEditUndoCommand: 3565 { 3566 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 3567 image,exception); 3568 break; 3569 } 3570 case ColorEditHelpCommand: 3571 default: 3572 { 3573 XTextViewWidget(display,resource_info,windows,MagickFalse, 3574 "Help Viewer - Image Annotation",ImageColorEditHelp); 3575 break; 3576 } 3577 case ColorEditDismissCommand: 3578 { 3579 /* 3580 Prematurely exit. 3581 */ 3582 state|=EscapeState; 3583 state|=ExitState; 3584 break; 3585 } 3586 } 3587 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3588 continue; 3589 } 3590 switch (event.type) 3591 { 3592 case ButtonPress: 3593 { 3594 if (event.xbutton.button != Button1) 3595 break; 3596 if ((event.xbutton.window != windows->image.id) && 3597 (event.xbutton.window != windows->magnify.id)) 3598 break; 3599 /* 3600 exit loop. 3601 */ 3602 x=event.xbutton.x; 3603 y=event.xbutton.y; 3604 (void) XMagickCommand(display,resource_info,windows, 3605 SaveToUndoBufferCommand,image,exception); 3606 state|=UpdateConfigurationState; 3607 break; 3608 } 3609 case ButtonRelease: 3610 { 3611 if (event.xbutton.button != Button1) 3612 break; 3613 if ((event.xbutton.window != windows->image.id) && 3614 (event.xbutton.window != windows->magnify.id)) 3615 break; 3616 /* 3617 Update colormap information. 3618 */ 3619 x=event.xbutton.x; 3620 y=event.xbutton.y; 3621 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3622 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3623 XInfoWidget(display,windows,text); 3624 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3625 state&=(~UpdateConfigurationState); 3626 break; 3627 } 3628 case Expose: 3629 break; 3630 case KeyPress: 3631 { 3632 KeySym 3633 key_symbol; 3634 3635 if (event.xkey.window == windows->magnify.id) 3636 { 3637 Window 3638 window; 3639 3640 window=windows->magnify.id; 3641 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 3642 } 3643 if (event.xkey.window != windows->image.id) 3644 break; 3645 /* 3646 Respond to a user key press. 3647 */ 3648 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3649 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3650 switch ((int) key_symbol) 3651 { 3652 case XK_Escape: 3653 case XK_F20: 3654 { 3655 /* 3656 Prematurely exit. 3657 */ 3658 state|=ExitState; 3659 break; 3660 } 3661 case XK_F1: 3662 case XK_Help: 3663 { 3664 XTextViewWidget(display,resource_info,windows,MagickFalse, 3665 "Help Viewer - Image Annotation",ImageColorEditHelp); 3666 break; 3667 } 3668 default: 3669 { 3670 (void) XBell(display,0); 3671 break; 3672 } 3673 } 3674 break; 3675 } 3676 case MotionNotify: 3677 { 3678 /* 3679 Map and unmap Info widget as cursor crosses its boundaries. 3680 */ 3681 x=event.xmotion.x; 3682 y=event.xmotion.y; 3683 if (IfMagickTrue(windows->info.mapped) ) 3684 { 3685 if ((x < (int) (windows->info.x+windows->info.width)) && 3686 (y < (int) (windows->info.y+windows->info.height))) 3687 (void) XWithdrawWindow(display,windows->info.id, 3688 windows->info.screen); 3689 } 3690 else 3691 if ((x > (int) (windows->info.x+windows->info.width)) || 3692 (y > (int) (windows->info.y+windows->info.height))) 3693 (void) XMapWindow(display,windows->info.id); 3694 break; 3695 } 3696 default: 3697 break; 3698 } 3699 if (event.xany.window == windows->magnify.id) 3700 { 3701 x=windows->magnify.x-windows->image.x; 3702 y=windows->magnify.y-windows->image.y; 3703 } 3704 x_offset=x; 3705 y_offset=y; 3706 if ((state & UpdateConfigurationState) != 0) 3707 { 3708 CacheView 3709 *image_view; 3710 3711 int 3712 x, 3713 y; 3714 3715 /* 3716 Pixel edit is relative to image configuration. 3717 */ 3718 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 3719 MagickTrue); 3720 color=windows->pixel_info->pen_colors[pen_id]; 3721 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 3722 width=(unsigned int) (*image)->columns; 3723 height=(unsigned int) (*image)->rows; 3724 x=0; 3725 y=0; 3726 if (windows->image.crop_geometry != (char *) NULL) 3727 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 3728 &width,&height); 3729 x_offset=(int) 3730 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 3731 y_offset=(int) 3732 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 3733 if ((x_offset < 0) || (y_offset < 0)) 3734 continue; 3735 if ((x_offset >= (int) (*image)->columns) || 3736 (y_offset >= (int) (*image)->rows)) 3737 continue; 3738 image_view=AcquireAuthenticCacheView(*image,exception); 3739 switch (method) 3740 { 3741 case PointMethod: 3742 default: 3743 { 3744 /* 3745 Update color information using point algorithm. 3746 */ 3747 if (IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) ) 3748 return(MagickFalse); 3749 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 3750 (ssize_t) y_offset,1,1,exception); 3751 if (q == (Quantum *) NULL) 3752 break; 3753 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3754 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3755 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3756 (void) SyncCacheViewAuthenticPixels(image_view,exception); 3757 break; 3758 } 3759 case ReplaceMethod: 3760 { 3761 PixelInfo 3762 pixel, 3763 target; 3764 3765 /* 3766 Update color information using replace algorithm. 3767 */ 3768 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t) 3769 x_offset,(ssize_t) y_offset,&target,exception); 3770 if ((*image)->storage_class == DirectClass) 3771 { 3772 for (y=0; y < (int) (*image)->rows; y++) 3773 { 3774 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3775 (*image)->columns,1,exception); 3776 if (q == (Quantum *) NULL) 3777 break; 3778 for (x=0; x < (int) (*image)->columns; x++) 3779 { 3780 GetPixelInfoPixel(*image,q,&pixel); 3781 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 3782 { 3783 SetPixelRed(*image,ScaleShortToQuantum( 3784 color.red),q); 3785 SetPixelGreen(*image,ScaleShortToQuantum( 3786 color.green),q); 3787 SetPixelBlue(*image,ScaleShortToQuantum( 3788 color.blue),q); 3789 } 3790 q+=GetPixelChannels(*image); 3791 } 3792 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 3793 break; 3794 } 3795 } 3796 else 3797 { 3798 for (i=0; i < (ssize_t) (*image)->colors; i++) 3799 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target)) 3800 { 3801 (*image)->colormap[i].red=(double) ScaleShortToQuantum( 3802 color.red); 3803 (*image)->colormap[i].green=(double) ScaleShortToQuantum( 3804 color.green); 3805 (*image)->colormap[i].blue=(double) ScaleShortToQuantum( 3806 color.blue); 3807 } 3808 (void) SyncImage(*image,exception); 3809 } 3810 break; 3811 } 3812 case FloodfillMethod: 3813 case FillToBorderMethod: 3814 { 3815 DrawInfo 3816 *draw_info; 3817 3818 PixelInfo 3819 target; 3820 3821 /* 3822 Update color information using floodfill algorithm. 3823 */ 3824 (void) GetOneVirtualPixelInfo(*image, 3825 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 3826 y_offset,&target,exception); 3827 if (method == FillToBorderMethod) 3828 { 3829 target.red=(double) 3830 ScaleShortToQuantum(border_color.red); 3831 target.green=(double) 3832 ScaleShortToQuantum(border_color.green); 3833 target.blue=(double) 3834 ScaleShortToQuantum(border_color.blue); 3835 } 3836 draw_info=CloneDrawInfo(resource_info->image_info, 3837 (DrawInfo *) NULL); 3838 (void) QueryColorCompliance(resource_info->pen_colors[pen_id], 3839 AllCompliance,&draw_info->fill,exception); 3840 (void) FloodfillPaintImage(*image,draw_info,&target, 3841 (ssize_t)x_offset,(ssize_t)y_offset, 3842 IsMagickFalse(method == FloodfillMethod),exception); 3843 draw_info=DestroyDrawInfo(draw_info); 3844 break; 3845 } 3846 case ResetMethod: 3847 { 3848 /* 3849 Update color information using reset algorithm. 3850 */ 3851 if (IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) ) 3852 return(MagickFalse); 3853 for (y=0; y < (int) (*image)->rows; y++) 3854 { 3855 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3856 (*image)->columns,1,exception); 3857 if (q == (Quantum *) NULL) 3858 break; 3859 for (x=0; x < (int) (*image)->columns; x++) 3860 { 3861 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3862 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3863 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3864 q+=GetPixelChannels(*image); 3865 } 3866 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 3867 break; 3868 } 3869 break; 3870 } 3871 } 3872 image_view=DestroyCacheView(image_view); 3873 state&=(~UpdateConfigurationState); 3874 } 3875 } while ((state & ExitState) == 0); 3876 (void) XSelectInput(display,windows->image.id, 3877 windows->image.attributes.event_mask); 3878 XSetCursorState(display,windows,MagickFalse); 3879 (void) XFreeCursor(display,cursor); 3880 return(MagickTrue); 3881} 3882 3883/* 3884%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3885% % 3886% % 3887% % 3888+ X C o m p o s i t e I m a g e % 3889% % 3890% % 3891% % 3892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3893% 3894% XCompositeImage() requests an image name from the user, reads the image and 3895% composites it with the X window image at a location the user chooses with 3896% the pointer. 3897% 3898% The format of the XCompositeImage method is: 3899% 3900% MagickBooleanType XCompositeImage(Display *display, 3901% XResourceInfo *resource_info,XWindows *windows,Image *image, 3902% ExceptionInfo *exception) 3903% 3904% A description of each parameter follows: 3905% 3906% o display: Specifies a connection to an X server; returned from 3907% XOpenDisplay. 3908% 3909% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3910% 3911% o windows: Specifies a pointer to a XWindows structure. 3912% 3913% o image: the image; returned from ReadImage. 3914% 3915% o exception: return any errors or warnings in this structure. 3916% 3917*/ 3918static MagickBooleanType XCompositeImage(Display *display, 3919 XResourceInfo *resource_info,XWindows *windows,Image *image, 3920 ExceptionInfo *exception) 3921{ 3922 static char 3923 displacement_geometry[MaxTextExtent] = "30x30", 3924 filename[MaxTextExtent] = "\0"; 3925 3926 static const char 3927 *CompositeMenu[] = 3928 { 3929 "Operators", 3930 "Dissolve", 3931 "Displace", 3932 "Help", 3933 "Dismiss", 3934 (char *) NULL 3935 }; 3936 3937 static CompositeOperator 3938 compose = CopyCompositeOp; 3939 3940 static const ModeType 3941 CompositeCommands[] = 3942 { 3943 CompositeOperatorsCommand, 3944 CompositeDissolveCommand, 3945 CompositeDisplaceCommand, 3946 CompositeHelpCommand, 3947 CompositeDismissCommand 3948 }; 3949 3950 char 3951 text[MaxTextExtent]; 3952 3953 Cursor 3954 cursor; 3955 3956 Image 3957 *composite_image; 3958 3959 int 3960 entry, 3961 id, 3962 x, 3963 y; 3964 3965 double 3966 blend, 3967 scale_factor; 3968 3969 RectangleInfo 3970 highlight_info, 3971 composite_info; 3972 3973 unsigned int 3974 height, 3975 width; 3976 3977 size_t 3978 state; 3979 3980 XEvent 3981 event; 3982 3983 /* 3984 Request image file name from user. 3985 */ 3986 XFileBrowserWidget(display,windows,"Composite",filename); 3987 if (*filename == '\0') 3988 return(MagickTrue); 3989 /* 3990 Read image. 3991 */ 3992 XSetCursorState(display,windows,MagickTrue); 3993 XCheckRefreshWindows(display,windows); 3994 (void) CopyMagickString(resource_info->image_info->filename,filename, 3995 MaxTextExtent); 3996 composite_image=ReadImage(resource_info->image_info,exception); 3997 CatchException(exception); 3998 XSetCursorState(display,windows,MagickFalse); 3999 if (composite_image == (Image *) NULL) 4000 return(MagickFalse); 4001 /* 4002 Map Command widget. 4003 */ 4004 (void) CloneString(&windows->command.name,"Composite"); 4005 windows->command.data=1; 4006 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 4007 (void) XMapRaised(display,windows->command.id); 4008 XClientMessage(display,windows->image.id,windows->im_protocols, 4009 windows->im_update_widget,CurrentTime); 4010 /* 4011 Track pointer until button 1 is pressed. 4012 */ 4013 XQueryPosition(display,windows->image.id,&x,&y); 4014 (void) XSelectInput(display,windows->image.id, 4015 windows->image.attributes.event_mask | PointerMotionMask); 4016 composite_info.x=(ssize_t) windows->image.x+x; 4017 composite_info.y=(ssize_t) windows->image.y+y; 4018 composite_info.width=0; 4019 composite_info.height=0; 4020 cursor=XCreateFontCursor(display,XC_ul_angle); 4021 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4022 blend=0.0; 4023 state=DefaultState; 4024 do 4025 { 4026 if (IfMagickTrue(windows->info.mapped) ) 4027 { 4028 /* 4029 Display pointer position. 4030 */ 4031 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4032 (long) composite_info.x,(long) composite_info.y); 4033 XInfoWidget(display,windows,text); 4034 } 4035 highlight_info=composite_info; 4036 highlight_info.x=composite_info.x-windows->image.x; 4037 highlight_info.y=composite_info.y-windows->image.y; 4038 XHighlightRectangle(display,windows->image.id, 4039 windows->image.highlight_context,&highlight_info); 4040 /* 4041 Wait for next event. 4042 */ 4043 XScreenEvent(display,windows,&event,exception); 4044 XHighlightRectangle(display,windows->image.id, 4045 windows->image.highlight_context,&highlight_info); 4046 if (event.xany.window == windows->command.id) 4047 { 4048 /* 4049 Select a command from the Command widget. 4050 */ 4051 id=XCommandWidget(display,windows,CompositeMenu,&event); 4052 if (id < 0) 4053 continue; 4054 switch (CompositeCommands[id]) 4055 { 4056 case CompositeOperatorsCommand: 4057 { 4058 char 4059 command[MaxTextExtent], 4060 **operators; 4061 4062 /* 4063 Select a command from the pop-up menu. 4064 */ 4065 operators=GetCommandOptions(MagickComposeOptions); 4066 if (operators == (char **) NULL) 4067 break; 4068 entry=XMenuWidget(display,windows,CompositeMenu[id], 4069 (const char **) operators,command); 4070 if (entry >= 0) 4071 compose=(CompositeOperator) ParseCommandOption( 4072 MagickComposeOptions,MagickFalse,operators[entry]); 4073 operators=DestroyStringList(operators); 4074 break; 4075 } 4076 case CompositeDissolveCommand: 4077 { 4078 static char 4079 factor[MaxTextExtent] = "20.0"; 4080 4081 /* 4082 Dissolve the two images a given percent. 4083 */ 4084 (void) XSetFunction(display,windows->image.highlight_context, 4085 GXcopy); 4086 (void) XDialogWidget(display,windows,"Dissolve", 4087 "Enter the blend factor (0.0 - 99.9%):",factor); 4088 (void) XSetFunction(display,windows->image.highlight_context, 4089 GXinvert); 4090 if (*factor == '\0') 4091 break; 4092 blend=StringToDouble(factor,(char **) NULL); 4093 compose=DissolveCompositeOp; 4094 break; 4095 } 4096 case CompositeDisplaceCommand: 4097 { 4098 /* 4099 Get horizontal and vertical scale displacement geometry. 4100 */ 4101 (void) XSetFunction(display,windows->image.highlight_context, 4102 GXcopy); 4103 (void) XDialogWidget(display,windows,"Displace", 4104 "Enter the horizontal and vertical scale:",displacement_geometry); 4105 (void) XSetFunction(display,windows->image.highlight_context, 4106 GXinvert); 4107 if (*displacement_geometry == '\0') 4108 break; 4109 compose=DisplaceCompositeOp; 4110 break; 4111 } 4112 case CompositeHelpCommand: 4113 { 4114 (void) XSetFunction(display,windows->image.highlight_context, 4115 GXcopy); 4116 XTextViewWidget(display,resource_info,windows,MagickFalse, 4117 "Help Viewer - Image Composite",ImageCompositeHelp); 4118 (void) XSetFunction(display,windows->image.highlight_context, 4119 GXinvert); 4120 break; 4121 } 4122 case CompositeDismissCommand: 4123 { 4124 /* 4125 Prematurely exit. 4126 */ 4127 state|=EscapeState; 4128 state|=ExitState; 4129 break; 4130 } 4131 default: 4132 break; 4133 } 4134 continue; 4135 } 4136 switch (event.type) 4137 { 4138 case ButtonPress: 4139 { 4140 if (IfMagickTrue(image->debug) ) 4141 (void) LogMagickEvent(X11Event,GetMagickModule(), 4142 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 4143 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4144 if (event.xbutton.button != Button1) 4145 break; 4146 if (event.xbutton.window != windows->image.id) 4147 break; 4148 /* 4149 Change cursor. 4150 */ 4151 composite_info.width=composite_image->columns; 4152 composite_info.height=composite_image->rows; 4153 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4154 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4155 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4156 break; 4157 } 4158 case ButtonRelease: 4159 { 4160 if (IfMagickTrue(image->debug) ) 4161 (void) LogMagickEvent(X11Event,GetMagickModule(), 4162 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 4163 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4164 if (event.xbutton.button != Button1) 4165 break; 4166 if (event.xbutton.window != windows->image.id) 4167 break; 4168 if ((composite_info.width != 0) && (composite_info.height != 0)) 4169 { 4170 /* 4171 User has selected the location of the composite image. 4172 */ 4173 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4174 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4175 state|=ExitState; 4176 } 4177 break; 4178 } 4179 case Expose: 4180 break; 4181 case KeyPress: 4182 { 4183 char 4184 command[MaxTextExtent]; 4185 4186 KeySym 4187 key_symbol; 4188 4189 int 4190 length; 4191 4192 if (event.xkey.window != windows->image.id) 4193 break; 4194 /* 4195 Respond to a user key press. 4196 */ 4197 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 4198 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4199 *(command+length)='\0'; 4200 if (IfMagickTrue(image->debug) ) 4201 (void) LogMagickEvent(X11Event,GetMagickModule(), 4202 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 4203 switch ((int) key_symbol) 4204 { 4205 case XK_Escape: 4206 case XK_F20: 4207 { 4208 /* 4209 Prematurely exit. 4210 */ 4211 composite_image=DestroyImage(composite_image); 4212 state|=EscapeState; 4213 state|=ExitState; 4214 break; 4215 } 4216 case XK_F1: 4217 case XK_Help: 4218 { 4219 (void) XSetFunction(display,windows->image.highlight_context, 4220 GXcopy); 4221 XTextViewWidget(display,resource_info,windows,MagickFalse, 4222 "Help Viewer - Image Composite",ImageCompositeHelp); 4223 (void) XSetFunction(display,windows->image.highlight_context, 4224 GXinvert); 4225 break; 4226 } 4227 default: 4228 { 4229 (void) XBell(display,0); 4230 break; 4231 } 4232 } 4233 break; 4234 } 4235 case MotionNotify: 4236 { 4237 /* 4238 Map and unmap Info widget as text cursor crosses its boundaries. 4239 */ 4240 x=event.xmotion.x; 4241 y=event.xmotion.y; 4242 if (IfMagickTrue(windows->info.mapped) ) 4243 { 4244 if ((x < (int) (windows->info.x+windows->info.width)) && 4245 (y < (int) (windows->info.y+windows->info.height))) 4246 (void) XWithdrawWindow(display,windows->info.id, 4247 windows->info.screen); 4248 } 4249 else 4250 if ((x > (int) (windows->info.x+windows->info.width)) || 4251 (y > (int) (windows->info.y+windows->info.height))) 4252 (void) XMapWindow(display,windows->info.id); 4253 composite_info.x=(ssize_t) windows->image.x+x; 4254 composite_info.y=(ssize_t) windows->image.y+y; 4255 break; 4256 } 4257 default: 4258 { 4259 if (IfMagickTrue(image->debug) ) 4260 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 4261 event.type); 4262 break; 4263 } 4264 } 4265 } while ((state & ExitState) == 0); 4266 (void) XSelectInput(display,windows->image.id, 4267 windows->image.attributes.event_mask); 4268 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4269 XSetCursorState(display,windows,MagickFalse); 4270 (void) XFreeCursor(display,cursor); 4271 if ((state & EscapeState) != 0) 4272 return(MagickTrue); 4273 /* 4274 Image compositing is relative to image configuration. 4275 */ 4276 XSetCursorState(display,windows,MagickTrue); 4277 XCheckRefreshWindows(display,windows); 4278 width=(unsigned int) image->columns; 4279 height=(unsigned int) image->rows; 4280 x=0; 4281 y=0; 4282 if (windows->image.crop_geometry != (char *) NULL) 4283 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 4284 scale_factor=(double) width/windows->image.ximage->width; 4285 composite_info.x+=x; 4286 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 4287 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 4288 scale_factor=(double) height/windows->image.ximage->height; 4289 composite_info.y+=y; 4290 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 4291 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 4292 if ((composite_info.width != composite_image->columns) || 4293 (composite_info.height != composite_image->rows)) 4294 { 4295 Image 4296 *resize_image; 4297 4298 /* 4299 Scale composite image. 4300 */ 4301 resize_image=ResizeImage(composite_image,composite_info.width, 4302 composite_info.height,composite_image->filter,exception); 4303 composite_image=DestroyImage(composite_image); 4304 if (resize_image == (Image *) NULL) 4305 { 4306 XSetCursorState(display,windows,MagickFalse); 4307 return(MagickFalse); 4308 } 4309 composite_image=resize_image; 4310 } 4311 if (compose == DisplaceCompositeOp) 4312 (void) SetImageArtifact(composite_image,"compose:args", 4313 displacement_geometry); 4314 if (blend != 0.0) 4315 { 4316 CacheView 4317 *image_view; 4318 4319 int 4320 y; 4321 4322 Quantum 4323 opacity; 4324 4325 register int 4326 x; 4327 4328 register Quantum 4329 *q; 4330 4331 /* 4332 Create mattes for blending. 4333 */ 4334 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception); 4335 opacity=(Quantum) (ScaleQuantumToChar(QuantumRange)- 4336 ((ssize_t) ScaleQuantumToChar(QuantumRange)*blend)/100); 4337 if (IfMagickFalse(SetImageStorageClass(image,DirectClass,exception)) ) 4338 return(MagickFalse); 4339 image->alpha_trait=BlendPixelTrait; 4340 image_view=AcquireAuthenticCacheView(image,exception); 4341 for (y=0; y < (int) image->rows; y++) 4342 { 4343 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 4344 exception); 4345 if (q == (Quantum *) NULL) 4346 break; 4347 for (x=0; x < (int) image->columns; x++) 4348 { 4349 SetPixelAlpha(image,opacity,q); 4350 q+=GetPixelChannels(image); 4351 } 4352 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 4353 break; 4354 } 4355 image_view=DestroyCacheView(image_view); 4356 } 4357 /* 4358 Composite image with X Image window. 4359 */ 4360 (void) CompositeImage(image,composite_image,compose,MagickTrue, 4361 composite_info.x,composite_info.y,exception); 4362 composite_image=DestroyImage(composite_image); 4363 XSetCursorState(display,windows,MagickFalse); 4364 /* 4365 Update image configuration. 4366 */ 4367 XConfigureImageColormap(display,resource_info,windows,image,exception); 4368 (void) XConfigureImage(display,resource_info,windows,image,exception); 4369 return(MagickTrue); 4370} 4371 4372/* 4373%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4374% % 4375% % 4376% % 4377+ X C o n f i g u r e I m a g e % 4378% % 4379% % 4380% % 4381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4382% 4383% XConfigureImage() creates a new X image. It also notifies the window 4384% manager of the new image size and configures the transient widows. 4385% 4386% The format of the XConfigureImage method is: 4387% 4388% MagickBooleanType XConfigureImage(Display *display, 4389% XResourceInfo *resource_info,XWindows *windows,Image *image, 4390% ExceptionInfo *exception) 4391% 4392% A description of each parameter follows: 4393% 4394% o display: Specifies a connection to an X server; returned from 4395% XOpenDisplay. 4396% 4397% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4398% 4399% o windows: Specifies a pointer to a XWindows structure. 4400% 4401% o image: the image. 4402% 4403% o exception: return any errors or warnings in this structure. 4404% 4405% o exception: return any errors or warnings in this structure. 4406% 4407*/ 4408static MagickBooleanType XConfigureImage(Display *display, 4409 XResourceInfo *resource_info,XWindows *windows,Image *image, 4410 ExceptionInfo *exception) 4411{ 4412 char 4413 geometry[MaxTextExtent]; 4414 4415 MagickStatusType 4416 status; 4417 4418 size_t 4419 mask, 4420 height, 4421 width; 4422 4423 ssize_t 4424 x, 4425 y; 4426 4427 XSizeHints 4428 *size_hints; 4429 4430 XWindowChanges 4431 window_changes; 4432 4433 /* 4434 Dismiss if window dimensions are zero. 4435 */ 4436 width=(unsigned int) windows->image.window_changes.width; 4437 height=(unsigned int) windows->image.window_changes.height; 4438 if (IfMagickTrue(image->debug) ) 4439 (void) LogMagickEvent(X11Event,GetMagickModule(), 4440 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 4441 windows->image.ximage->height,(double) width,(double) height); 4442 if ((width*height) == 0) 4443 return(MagickTrue); 4444 x=0; 4445 y=0; 4446 /* 4447 Resize image to fit Image window dimensions. 4448 */ 4449 XSetCursorState(display,windows,MagickTrue); 4450 (void) XFlush(display); 4451 if (((int) width != windows->image.ximage->width) || 4452 ((int) height != windows->image.ximage->height)) 4453 image->taint=MagickTrue; 4454 windows->magnify.x=(int) 4455 width*windows->magnify.x/windows->image.ximage->width; 4456 windows->magnify.y=(int) 4457 height*windows->magnify.y/windows->image.ximage->height; 4458 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 4459 windows->image.y=(int) 4460 (height*windows->image.y/windows->image.ximage->height); 4461 status=XMakeImage(display,resource_info,&windows->image,image, 4462 (unsigned int) width,(unsigned int) height,exception); 4463 if (IfMagickFalse(status) ) 4464 XNoticeWidget(display,windows,"Unable to configure X image:", 4465 windows->image.name); 4466 /* 4467 Notify window manager of the new configuration. 4468 */ 4469 if (resource_info->image_geometry != (char *) NULL) 4470 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!", 4471 resource_info->image_geometry); 4472 else 4473 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 4474 XDisplayWidth(display,windows->image.screen), 4475 XDisplayHeight(display,windows->image.screen)); 4476 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 4477 window_changes.width=(int) width; 4478 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 4479 window_changes.width=XDisplayWidth(display,windows->image.screen); 4480 window_changes.height=(int) height; 4481 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 4482 window_changes.height=XDisplayHeight(display,windows->image.screen); 4483 mask=(size_t) (CWWidth | CWHeight); 4484 if (resource_info->backdrop) 4485 { 4486 mask|=CWX | CWY; 4487 window_changes.x=(int) 4488 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 4489 window_changes.y=(int) 4490 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 4491 } 4492 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 4493 (unsigned int) mask,&window_changes); 4494 (void) XClearWindow(display,windows->image.id); 4495 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 4496 /* 4497 Update Magnify window configuration. 4498 */ 4499 if (IfMagickTrue(windows->magnify.mapped) ) 4500 XMakeMagnifyImage(display,windows,exception); 4501 windows->pan.crop_geometry=windows->image.crop_geometry; 4502 XBestIconSize(display,&windows->pan,image); 4503 while (((windows->pan.width << 1) < MaxIconSize) && 4504 ((windows->pan.height << 1) < MaxIconSize)) 4505 { 4506 windows->pan.width<<=1; 4507 windows->pan.height<<=1; 4508 } 4509 if (windows->pan.geometry != (char *) NULL) 4510 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 4511 &windows->pan.width,&windows->pan.height); 4512 window_changes.width=(int) windows->pan.width; 4513 window_changes.height=(int) windows->pan.height; 4514 size_hints=XAllocSizeHints(); 4515 if (size_hints != (XSizeHints *) NULL) 4516 { 4517 /* 4518 Set new size hints. 4519 */ 4520 size_hints->flags=PSize | PMinSize | PMaxSize; 4521 size_hints->width=window_changes.width; 4522 size_hints->height=window_changes.height; 4523 size_hints->min_width=size_hints->width; 4524 size_hints->min_height=size_hints->height; 4525 size_hints->max_width=size_hints->width; 4526 size_hints->max_height=size_hints->height; 4527 (void) XSetNormalHints(display,windows->pan.id,size_hints); 4528 (void) XFree((void *) size_hints); 4529 } 4530 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 4531 (unsigned int) (CWWidth | CWHeight),&window_changes); 4532 /* 4533 Update icon window configuration. 4534 */ 4535 windows->icon.crop_geometry=windows->image.crop_geometry; 4536 XBestIconSize(display,&windows->icon,image); 4537 window_changes.width=(int) windows->icon.width; 4538 window_changes.height=(int) windows->icon.height; 4539 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 4540 (unsigned int) (CWWidth | CWHeight),&window_changes); 4541 XSetCursorState(display,windows,MagickFalse); 4542 return(IsMagickTrue(status)); 4543} 4544 4545/* 4546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4547% % 4548% % 4549% % 4550+ X C r o p I m a g e % 4551% % 4552% % 4553% % 4554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4555% 4556% XCropImage() allows the user to select a region of the image and crop, copy, 4557% or cut it. For copy or cut, the image can subsequently be composited onto 4558% the image with XPasteImage. 4559% 4560% The format of the XCropImage method is: 4561% 4562% MagickBooleanType XCropImage(Display *display, 4563% XResourceInfo *resource_info,XWindows *windows,Image *image, 4564% const ClipboardMode mode,ExceptionInfo *exception) 4565% 4566% A description of each parameter follows: 4567% 4568% o display: Specifies a connection to an X server; returned from 4569% XOpenDisplay. 4570% 4571% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4572% 4573% o windows: Specifies a pointer to a XWindows structure. 4574% 4575% o image: the image; returned from ReadImage. 4576% 4577% o mode: This unsigned value specified whether the image should be 4578% cropped, copied, or cut. 4579% 4580% o exception: return any errors or warnings in this structure. 4581% 4582*/ 4583static MagickBooleanType XCropImage(Display *display, 4584 XResourceInfo *resource_info,XWindows *windows,Image *image, 4585 const ClipboardMode mode,ExceptionInfo *exception) 4586{ 4587 static const char 4588 *CropModeMenu[] = 4589 { 4590 "Help", 4591 "Dismiss", 4592 (char *) NULL 4593 }, 4594 *RectifyModeMenu[] = 4595 { 4596 "Crop", 4597 "Help", 4598 "Dismiss", 4599 (char *) NULL 4600 }; 4601 4602 static const ModeType 4603 CropCommands[] = 4604 { 4605 CropHelpCommand, 4606 CropDismissCommand 4607 }, 4608 RectifyCommands[] = 4609 { 4610 RectifyCopyCommand, 4611 RectifyHelpCommand, 4612 RectifyDismissCommand 4613 }; 4614 4615 CacheView 4616 *image_view; 4617 4618 char 4619 command[MaxTextExtent], 4620 text[MaxTextExtent]; 4621 4622 Cursor 4623 cursor; 4624 4625 int 4626 id, 4627 x, 4628 y; 4629 4630 KeySym 4631 key_symbol; 4632 4633 Image 4634 *crop_image; 4635 4636 double 4637 scale_factor; 4638 4639 RectangleInfo 4640 crop_info, 4641 highlight_info; 4642 4643 register Quantum 4644 *q; 4645 4646 unsigned int 4647 height, 4648 width; 4649 4650 size_t 4651 state; 4652 4653 XEvent 4654 event; 4655 4656 /* 4657 Map Command widget. 4658 */ 4659 switch (mode) 4660 { 4661 case CopyMode: 4662 { 4663 (void) CloneString(&windows->command.name,"Copy"); 4664 break; 4665 } 4666 case CropMode: 4667 { 4668 (void) CloneString(&windows->command.name,"Crop"); 4669 break; 4670 } 4671 case CutMode: 4672 { 4673 (void) CloneString(&windows->command.name,"Cut"); 4674 break; 4675 } 4676 } 4677 RectifyModeMenu[0]=windows->command.name; 4678 windows->command.data=0; 4679 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 4680 (void) XMapRaised(display,windows->command.id); 4681 XClientMessage(display,windows->image.id,windows->im_protocols, 4682 windows->im_update_widget,CurrentTime); 4683 /* 4684 Track pointer until button 1 is pressed. 4685 */ 4686 XQueryPosition(display,windows->image.id,&x,&y); 4687 (void) XSelectInput(display,windows->image.id, 4688 windows->image.attributes.event_mask | PointerMotionMask); 4689 crop_info.x=(ssize_t) windows->image.x+x; 4690 crop_info.y=(ssize_t) windows->image.y+y; 4691 crop_info.width=0; 4692 crop_info.height=0; 4693 cursor=XCreateFontCursor(display,XC_fleur); 4694 state=DefaultState; 4695 do 4696 { 4697 if (IfMagickTrue(windows->info.mapped) ) 4698 { 4699 /* 4700 Display pointer position. 4701 */ 4702 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4703 (long) crop_info.x,(long) crop_info.y); 4704 XInfoWidget(display,windows,text); 4705 } 4706 /* 4707 Wait for next event. 4708 */ 4709 XScreenEvent(display,windows,&event,exception); 4710 if (event.xany.window == windows->command.id) 4711 { 4712 /* 4713 Select a command from the Command widget. 4714 */ 4715 id=XCommandWidget(display,windows,CropModeMenu,&event); 4716 if (id < 0) 4717 continue; 4718 switch (CropCommands[id]) 4719 { 4720 case CropHelpCommand: 4721 { 4722 switch (mode) 4723 { 4724 case CopyMode: 4725 { 4726 XTextViewWidget(display,resource_info,windows,MagickFalse, 4727 "Help Viewer - Image Copy",ImageCopyHelp); 4728 break; 4729 } 4730 case CropMode: 4731 { 4732 XTextViewWidget(display,resource_info,windows,MagickFalse, 4733 "Help Viewer - Image Crop",ImageCropHelp); 4734 break; 4735 } 4736 case CutMode: 4737 { 4738 XTextViewWidget(display,resource_info,windows,MagickFalse, 4739 "Help Viewer - Image Cut",ImageCutHelp); 4740 break; 4741 } 4742 } 4743 break; 4744 } 4745 case CropDismissCommand: 4746 { 4747 /* 4748 Prematurely exit. 4749 */ 4750 state|=EscapeState; 4751 state|=ExitState; 4752 break; 4753 } 4754 default: 4755 break; 4756 } 4757 continue; 4758 } 4759 switch (event.type) 4760 { 4761 case ButtonPress: 4762 { 4763 if (event.xbutton.button != Button1) 4764 break; 4765 if (event.xbutton.window != windows->image.id) 4766 break; 4767 /* 4768 Note first corner of cropping rectangle-- exit loop. 4769 */ 4770 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4771 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4772 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4773 state|=ExitState; 4774 break; 4775 } 4776 case ButtonRelease: 4777 break; 4778 case Expose: 4779 break; 4780 case KeyPress: 4781 { 4782 if (event.xkey.window != windows->image.id) 4783 break; 4784 /* 4785 Respond to a user key press. 4786 */ 4787 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 4788 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4789 switch ((int) key_symbol) 4790 { 4791 case XK_Escape: 4792 case XK_F20: 4793 { 4794 /* 4795 Prematurely exit. 4796 */ 4797 state|=EscapeState; 4798 state|=ExitState; 4799 break; 4800 } 4801 case XK_F1: 4802 case XK_Help: 4803 { 4804 switch (mode) 4805 { 4806 case CopyMode: 4807 { 4808 XTextViewWidget(display,resource_info,windows,MagickFalse, 4809 "Help Viewer - Image Copy",ImageCopyHelp); 4810 break; 4811 } 4812 case CropMode: 4813 { 4814 XTextViewWidget(display,resource_info,windows,MagickFalse, 4815 "Help Viewer - Image Crop",ImageCropHelp); 4816 break; 4817 } 4818 case CutMode: 4819 { 4820 XTextViewWidget(display,resource_info,windows,MagickFalse, 4821 "Help Viewer - Image Cut",ImageCutHelp); 4822 break; 4823 } 4824 } 4825 break; 4826 } 4827 default: 4828 { 4829 (void) XBell(display,0); 4830 break; 4831 } 4832 } 4833 break; 4834 } 4835 case MotionNotify: 4836 { 4837 if (event.xmotion.window != windows->image.id) 4838 break; 4839 /* 4840 Map and unmap Info widget as text cursor crosses its boundaries. 4841 */ 4842 x=event.xmotion.x; 4843 y=event.xmotion.y; 4844 if (IfMagickTrue(windows->info.mapped) ) 4845 { 4846 if ((x < (int) (windows->info.x+windows->info.width)) && 4847 (y < (int) (windows->info.y+windows->info.height))) 4848 (void) XWithdrawWindow(display,windows->info.id, 4849 windows->info.screen); 4850 } 4851 else 4852 if ((x > (int) (windows->info.x+windows->info.width)) || 4853 (y > (int) (windows->info.y+windows->info.height))) 4854 (void) XMapWindow(display,windows->info.id); 4855 crop_info.x=(ssize_t) windows->image.x+x; 4856 crop_info.y=(ssize_t) windows->image.y+y; 4857 break; 4858 } 4859 default: 4860 break; 4861 } 4862 } while ((state & ExitState) == 0); 4863 (void) XSelectInput(display,windows->image.id, 4864 windows->image.attributes.event_mask); 4865 if ((state & EscapeState) != 0) 4866 { 4867 /* 4868 User want to exit without cropping. 4869 */ 4870 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4871 (void) XFreeCursor(display,cursor); 4872 return(MagickTrue); 4873 } 4874 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4875 do 4876 { 4877 /* 4878 Size rectangle as pointer moves until the mouse button is released. 4879 */ 4880 x=(int) crop_info.x; 4881 y=(int) crop_info.y; 4882 crop_info.width=0; 4883 crop_info.height=0; 4884 state=DefaultState; 4885 do 4886 { 4887 highlight_info=crop_info; 4888 highlight_info.x=crop_info.x-windows->image.x; 4889 highlight_info.y=crop_info.y-windows->image.y; 4890 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4891 { 4892 /* 4893 Display info and draw cropping rectangle. 4894 */ 4895 if (IfMagickFalse(windows->info.mapped) ) 4896 (void) XMapWindow(display,windows->info.id); 4897 (void) FormatLocaleString(text,MaxTextExtent, 4898 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4899 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4900 XInfoWidget(display,windows,text); 4901 XHighlightRectangle(display,windows->image.id, 4902 windows->image.highlight_context,&highlight_info); 4903 } 4904 else 4905 if (IfMagickTrue(windows->info.mapped) ) 4906 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4907 /* 4908 Wait for next event. 4909 */ 4910 XScreenEvent(display,windows,&event,exception); 4911 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4912 XHighlightRectangle(display,windows->image.id, 4913 windows->image.highlight_context,&highlight_info); 4914 switch (event.type) 4915 { 4916 case ButtonPress: 4917 { 4918 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4919 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4920 break; 4921 } 4922 case ButtonRelease: 4923 { 4924 /* 4925 User has committed to cropping rectangle. 4926 */ 4927 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4928 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4929 XSetCursorState(display,windows,MagickFalse); 4930 state|=ExitState; 4931 windows->command.data=0; 4932 (void) XCommandWidget(display,windows,RectifyModeMenu, 4933 (XEvent *) NULL); 4934 break; 4935 } 4936 case Expose: 4937 break; 4938 case MotionNotify: 4939 { 4940 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 4941 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 4942 } 4943 default: 4944 break; 4945 } 4946 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 4947 ((state & ExitState) != 0)) 4948 { 4949 /* 4950 Check boundary conditions. 4951 */ 4952 if (crop_info.x < 0) 4953 crop_info.x=0; 4954 else 4955 if (crop_info.x > (ssize_t) windows->image.ximage->width) 4956 crop_info.x=(ssize_t) windows->image.ximage->width; 4957 if ((int) crop_info.x < x) 4958 crop_info.width=(unsigned int) (x-crop_info.x); 4959 else 4960 { 4961 crop_info.width=(unsigned int) (crop_info.x-x); 4962 crop_info.x=(ssize_t) x; 4963 } 4964 if (crop_info.y < 0) 4965 crop_info.y=0; 4966 else 4967 if (crop_info.y > (ssize_t) windows->image.ximage->height) 4968 crop_info.y=(ssize_t) windows->image.ximage->height; 4969 if ((int) crop_info.y < y) 4970 crop_info.height=(unsigned int) (y-crop_info.y); 4971 else 4972 { 4973 crop_info.height=(unsigned int) (crop_info.y-y); 4974 crop_info.y=(ssize_t) y; 4975 } 4976 } 4977 } while ((state & ExitState) == 0); 4978 /* 4979 Wait for user to grab a corner of the rectangle or press return. 4980 */ 4981 state=DefaultState; 4982 (void) XMapWindow(display,windows->info.id); 4983 do 4984 { 4985 if (IfMagickTrue(windows->info.mapped) ) 4986 { 4987 /* 4988 Display pointer position. 4989 */ 4990 (void) FormatLocaleString(text,MaxTextExtent, 4991 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4992 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4993 XInfoWidget(display,windows,text); 4994 } 4995 highlight_info=crop_info; 4996 highlight_info.x=crop_info.x-windows->image.x; 4997 highlight_info.y=crop_info.y-windows->image.y; 4998 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 4999 { 5000 state|=EscapeState; 5001 state|=ExitState; 5002 break; 5003 } 5004 XHighlightRectangle(display,windows->image.id, 5005 windows->image.highlight_context,&highlight_info); 5006 XScreenEvent(display,windows,&event,exception); 5007 if (event.xany.window == windows->command.id) 5008 { 5009 /* 5010 Select a command from the Command widget. 5011 */ 5012 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5013 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 5014 (void) XSetFunction(display,windows->image.highlight_context, 5015 GXinvert); 5016 XHighlightRectangle(display,windows->image.id, 5017 windows->image.highlight_context,&highlight_info); 5018 if (id >= 0) 5019 switch (RectifyCommands[id]) 5020 { 5021 case RectifyCopyCommand: 5022 { 5023 state|=ExitState; 5024 break; 5025 } 5026 case RectifyHelpCommand: 5027 { 5028 (void) XSetFunction(display,windows->image.highlight_context, 5029 GXcopy); 5030 switch (mode) 5031 { 5032 case CopyMode: 5033 { 5034 XTextViewWidget(display,resource_info,windows,MagickFalse, 5035 "Help Viewer - Image Copy",ImageCopyHelp); 5036 break; 5037 } 5038 case CropMode: 5039 { 5040 XTextViewWidget(display,resource_info,windows,MagickFalse, 5041 "Help Viewer - Image Crop",ImageCropHelp); 5042 break; 5043 } 5044 case CutMode: 5045 { 5046 XTextViewWidget(display,resource_info,windows,MagickFalse, 5047 "Help Viewer - Image Cut",ImageCutHelp); 5048 break; 5049 } 5050 } 5051 (void) XSetFunction(display,windows->image.highlight_context, 5052 GXinvert); 5053 break; 5054 } 5055 case RectifyDismissCommand: 5056 { 5057 /* 5058 Prematurely exit. 5059 */ 5060 state|=EscapeState; 5061 state|=ExitState; 5062 break; 5063 } 5064 default: 5065 break; 5066 } 5067 continue; 5068 } 5069 XHighlightRectangle(display,windows->image.id, 5070 windows->image.highlight_context,&highlight_info); 5071 switch (event.type) 5072 { 5073 case ButtonPress: 5074 { 5075 if (event.xbutton.button != Button1) 5076 break; 5077 if (event.xbutton.window != windows->image.id) 5078 break; 5079 x=windows->image.x+event.xbutton.x; 5080 y=windows->image.y+event.xbutton.y; 5081 if ((x < (int) (crop_info.x+RoiDelta)) && 5082 (x > (int) (crop_info.x-RoiDelta)) && 5083 (y < (int) (crop_info.y+RoiDelta)) && 5084 (y > (int) (crop_info.y-RoiDelta))) 5085 { 5086 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5087 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5088 state|=UpdateConfigurationState; 5089 break; 5090 } 5091 if ((x < (int) (crop_info.x+RoiDelta)) && 5092 (x > (int) (crop_info.x-RoiDelta)) && 5093 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5094 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5095 { 5096 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5097 state|=UpdateConfigurationState; 5098 break; 5099 } 5100 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5101 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5102 (y < (int) (crop_info.y+RoiDelta)) && 5103 (y > (int) (crop_info.y-RoiDelta))) 5104 { 5105 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5106 state|=UpdateConfigurationState; 5107 break; 5108 } 5109 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5110 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5111 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5112 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5113 { 5114 state|=UpdateConfigurationState; 5115 break; 5116 } 5117 } 5118 case ButtonRelease: 5119 { 5120 if (event.xbutton.window == windows->pan.id) 5121 if ((highlight_info.x != crop_info.x-windows->image.x) || 5122 (highlight_info.y != crop_info.y-windows->image.y)) 5123 XHighlightRectangle(display,windows->image.id, 5124 windows->image.highlight_context,&highlight_info); 5125 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5126 event.xbutton.time); 5127 break; 5128 } 5129 case Expose: 5130 { 5131 if (event.xexpose.window == windows->image.id) 5132 if (event.xexpose.count == 0) 5133 { 5134 event.xexpose.x=(int) highlight_info.x; 5135 event.xexpose.y=(int) highlight_info.y; 5136 event.xexpose.width=(int) highlight_info.width; 5137 event.xexpose.height=(int) highlight_info.height; 5138 XRefreshWindow(display,&windows->image,&event); 5139 } 5140 if (event.xexpose.window == windows->info.id) 5141 if (event.xexpose.count == 0) 5142 XInfoWidget(display,windows,text); 5143 break; 5144 } 5145 case KeyPress: 5146 { 5147 if (event.xkey.window != windows->image.id) 5148 break; 5149 /* 5150 Respond to a user key press. 5151 */ 5152 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5153 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5154 switch ((int) key_symbol) 5155 { 5156 case XK_Escape: 5157 case XK_F20: 5158 state|=EscapeState; 5159 case XK_Return: 5160 { 5161 state|=ExitState; 5162 break; 5163 } 5164 case XK_Home: 5165 case XK_KP_Home: 5166 { 5167 crop_info.x=(ssize_t) (windows->image.width/2L- 5168 crop_info.width/2L); 5169 crop_info.y=(ssize_t) (windows->image.height/2L- 5170 crop_info.height/2L); 5171 break; 5172 } 5173 case XK_Left: 5174 case XK_KP_Left: 5175 { 5176 crop_info.x--; 5177 break; 5178 } 5179 case XK_Up: 5180 case XK_KP_Up: 5181 case XK_Next: 5182 { 5183 crop_info.y--; 5184 break; 5185 } 5186 case XK_Right: 5187 case XK_KP_Right: 5188 { 5189 crop_info.x++; 5190 break; 5191 } 5192 case XK_Prior: 5193 case XK_Down: 5194 case XK_KP_Down: 5195 { 5196 crop_info.y++; 5197 break; 5198 } 5199 case XK_F1: 5200 case XK_Help: 5201 { 5202 (void) XSetFunction(display,windows->image.highlight_context, 5203 GXcopy); 5204 switch (mode) 5205 { 5206 case CopyMode: 5207 { 5208 XTextViewWidget(display,resource_info,windows,MagickFalse, 5209 "Help Viewer - Image Copy",ImageCopyHelp); 5210 break; 5211 } 5212 case CropMode: 5213 { 5214 XTextViewWidget(display,resource_info,windows,MagickFalse, 5215 "Help Viewer - Image Cropg",ImageCropHelp); 5216 break; 5217 } 5218 case CutMode: 5219 { 5220 XTextViewWidget(display,resource_info,windows,MagickFalse, 5221 "Help Viewer - Image Cutg",ImageCutHelp); 5222 break; 5223 } 5224 } 5225 (void) XSetFunction(display,windows->image.highlight_context, 5226 GXinvert); 5227 break; 5228 } 5229 default: 5230 { 5231 (void) XBell(display,0); 5232 break; 5233 } 5234 } 5235 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5236 event.xkey.time); 5237 break; 5238 } 5239 case KeyRelease: 5240 break; 5241 case MotionNotify: 5242 { 5243 if (event.xmotion.window != windows->image.id) 5244 break; 5245 /* 5246 Map and unmap Info widget as text cursor crosses its boundaries. 5247 */ 5248 x=event.xmotion.x; 5249 y=event.xmotion.y; 5250 if (IfMagickTrue(windows->info.mapped) ) 5251 { 5252 if ((x < (int) (windows->info.x+windows->info.width)) && 5253 (y < (int) (windows->info.y+windows->info.height))) 5254 (void) XWithdrawWindow(display,windows->info.id, 5255 windows->info.screen); 5256 } 5257 else 5258 if ((x > (int) (windows->info.x+windows->info.width)) || 5259 (y > (int) (windows->info.y+windows->info.height))) 5260 (void) XMapWindow(display,windows->info.id); 5261 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 5262 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 5263 break; 5264 } 5265 case SelectionRequest: 5266 { 5267 XSelectionEvent 5268 notify; 5269 5270 XSelectionRequestEvent 5271 *request; 5272 5273 /* 5274 Set primary selection. 5275 */ 5276 (void) FormatLocaleString(text,MaxTextExtent, 5277 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 5278 crop_info.height,(double) crop_info.x,(double) crop_info.y); 5279 request=(&(event.xselectionrequest)); 5280 (void) XChangeProperty(request->display,request->requestor, 5281 request->property,request->target,8,PropModeReplace, 5282 (unsigned char *) text,(int) strlen(text)); 5283 notify.type=SelectionNotify; 5284 notify.display=request->display; 5285 notify.requestor=request->requestor; 5286 notify.selection=request->selection; 5287 notify.target=request->target; 5288 notify.time=request->time; 5289 if (request->property == None) 5290 notify.property=request->target; 5291 else 5292 notify.property=request->property; 5293 (void) XSendEvent(request->display,request->requestor,False,0, 5294 (XEvent *) ¬ify); 5295 } 5296 default: 5297 break; 5298 } 5299 if ((state & UpdateConfigurationState) != 0) 5300 { 5301 (void) XPutBackEvent(display,&event); 5302 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5303 break; 5304 } 5305 } while ((state & ExitState) == 0); 5306 } while ((state & ExitState) == 0); 5307 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5308 XSetCursorState(display,windows,MagickFalse); 5309 if ((state & EscapeState) != 0) 5310 return(MagickTrue); 5311 if (mode == CropMode) 5312 if (((int) crop_info.width != windows->image.ximage->width) || 5313 ((int) crop_info.height != windows->image.ximage->height)) 5314 { 5315 /* 5316 Reconfigure Image window as defined by cropping rectangle. 5317 */ 5318 XSetCropGeometry(display,windows,&crop_info,image); 5319 windows->image.window_changes.width=(int) crop_info.width; 5320 windows->image.window_changes.height=(int) crop_info.height; 5321 (void) XConfigureImage(display,resource_info,windows,image,exception); 5322 return(MagickTrue); 5323 } 5324 /* 5325 Copy image before applying image transforms. 5326 */ 5327 XSetCursorState(display,windows,MagickTrue); 5328 XCheckRefreshWindows(display,windows); 5329 width=(unsigned int) image->columns; 5330 height=(unsigned int) image->rows; 5331 x=0; 5332 y=0; 5333 if (windows->image.crop_geometry != (char *) NULL) 5334 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 5335 scale_factor=(double) width/windows->image.ximage->width; 5336 crop_info.x+=x; 5337 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 5338 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 5339 scale_factor=(double) height/windows->image.ximage->height; 5340 crop_info.y+=y; 5341 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 5342 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5); 5343 crop_image=CropImage(image,&crop_info,exception); 5344 XSetCursorState(display,windows,MagickFalse); 5345 if (crop_image == (Image *) NULL) 5346 return(MagickFalse); 5347 if (resource_info->copy_image != (Image *) NULL) 5348 resource_info->copy_image=DestroyImage(resource_info->copy_image); 5349 resource_info->copy_image=crop_image; 5350 if (mode == CopyMode) 5351 { 5352 (void) XConfigureImage(display,resource_info,windows,image,exception); 5353 return(MagickTrue); 5354 } 5355 /* 5356 Cut image. 5357 */ 5358 if (IfMagickFalse(SetImageStorageClass(image,DirectClass,exception)) ) 5359 return(MagickFalse); 5360 image->alpha_trait=BlendPixelTrait; 5361 image_view=AcquireAuthenticCacheView(image,exception); 5362 for (y=0; y < (int) crop_info.height; y++) 5363 { 5364 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y, 5365 crop_info.width,1,exception); 5366 if (q == (Quantum *) NULL) 5367 break; 5368 for (x=0; x < (int) crop_info.width; x++) 5369 { 5370 SetPixelAlpha(image,TransparentAlpha,q); 5371 q+=GetPixelChannels(image); 5372 } 5373 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 5374 break; 5375 } 5376 image_view=DestroyCacheView(image_view); 5377 /* 5378 Update image configuration. 5379 */ 5380 XConfigureImageColormap(display,resource_info,windows,image,exception); 5381 (void) XConfigureImage(display,resource_info,windows,image,exception); 5382 return(MagickTrue); 5383} 5384 5385/* 5386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5387% % 5388% % 5389% % 5390+ X D r a w I m a g e % 5391% % 5392% % 5393% % 5394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5395% 5396% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on 5397% the image. 5398% 5399% The format of the XDrawEditImage method is: 5400% 5401% MagickBooleanType XDrawEditImage(Display *display, 5402% XResourceInfo *resource_info,XWindows *windows,Image **image, 5403% ExceptionInfo *exception) 5404% 5405% A description of each parameter follows: 5406% 5407% o display: Specifies a connection to an X server; returned from 5408% XOpenDisplay. 5409% 5410% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 5411% 5412% o windows: Specifies a pointer to a XWindows structure. 5413% 5414% o image: the image. 5415% 5416% o exception: return any errors or warnings in this structure. 5417% 5418*/ 5419static MagickBooleanType XDrawEditImage(Display *display, 5420 XResourceInfo *resource_info,XWindows *windows,Image **image, 5421 ExceptionInfo *exception) 5422{ 5423 static const char 5424 *DrawMenu[] = 5425 { 5426 "Element", 5427 "Color", 5428 "Stipple", 5429 "Width", 5430 "Undo", 5431 "Help", 5432 "Dismiss", 5433 (char *) NULL 5434 }; 5435 5436 static ElementType 5437 element = PointElement; 5438 5439 static const ModeType 5440 DrawCommands[] = 5441 { 5442 DrawElementCommand, 5443 DrawColorCommand, 5444 DrawStippleCommand, 5445 DrawWidthCommand, 5446 DrawUndoCommand, 5447 DrawHelpCommand, 5448 DrawDismissCommand 5449 }; 5450 5451 static Pixmap 5452 stipple = (Pixmap) NULL; 5453 5454 static unsigned int 5455 pen_id = 0, 5456 line_width = 1; 5457 5458 char 5459 command[MaxTextExtent], 5460 text[MaxTextExtent]; 5461 5462 Cursor 5463 cursor; 5464 5465 int 5466 entry, 5467 id, 5468 number_coordinates, 5469 x, 5470 y; 5471 5472 double 5473 degrees; 5474 5475 MagickStatusType 5476 status; 5477 5478 RectangleInfo 5479 rectangle_info; 5480 5481 register int 5482 i; 5483 5484 unsigned int 5485 distance, 5486 height, 5487 max_coordinates, 5488 width; 5489 5490 size_t 5491 state; 5492 5493 Window 5494 root_window; 5495 5496 XDrawInfo 5497 draw_info; 5498 5499 XEvent 5500 event; 5501 5502 XPoint 5503 *coordinate_info; 5504 5505 XSegment 5506 line_info; 5507 5508 /* 5509 Allocate polygon info. 5510 */ 5511 max_coordinates=2048; 5512 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates, 5513 sizeof(*coordinate_info)); 5514 if (coordinate_info == (XPoint *) NULL) 5515 { 5516 (void) ThrowMagickException(exception,GetMagickModule(), 5517 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 5518 return(MagickFalse); 5519 } 5520 /* 5521 Map Command widget. 5522 */ 5523 (void) CloneString(&windows->command.name,"Draw"); 5524 windows->command.data=4; 5525 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL); 5526 (void) XMapRaised(display,windows->command.id); 5527 XClientMessage(display,windows->image.id,windows->im_protocols, 5528 windows->im_update_widget,CurrentTime); 5529 /* 5530 Wait for first button press. 5531 */ 5532 root_window=XRootWindow(display,XDefaultScreen(display)); 5533 draw_info.stencil=OpaqueStencil; 5534 status=MagickTrue; 5535 cursor=XCreateFontCursor(display,XC_tcross); 5536 for ( ; ; ) 5537 { 5538 XQueryPosition(display,windows->image.id,&x,&y); 5539 (void) XSelectInput(display,windows->image.id, 5540 windows->image.attributes.event_mask | PointerMotionMask); 5541 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5542 state=DefaultState; 5543 do 5544 { 5545 if (IfMagickTrue(windows->info.mapped) ) 5546 { 5547 /* 5548 Display pointer position. 5549 */ 5550 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 5551 x+windows->image.x,y+windows->image.y); 5552 XInfoWidget(display,windows,text); 5553 } 5554 /* 5555 Wait for next event. 5556 */ 5557 XScreenEvent(display,windows,&event,exception); 5558 if (event.xany.window == windows->command.id) 5559 { 5560 /* 5561 Select a command from the Command widget. 5562 */ 5563 id=XCommandWidget(display,windows,DrawMenu,&event); 5564 if (id < 0) 5565 continue; 5566 switch (DrawCommands[id]) 5567 { 5568 case DrawElementCommand: 5569 { 5570 static const char 5571 *Elements[] = 5572 { 5573 "point", 5574 "line", 5575 "rectangle", 5576 "fill rectangle", 5577 "circle", 5578 "fill circle", 5579 "ellipse", 5580 "fill ellipse", 5581 "polygon", 5582 "fill polygon", 5583 (char *) NULL, 5584 }; 5585 5586 /* 5587 Select a command from the pop-up menu. 5588 */ 5589 element=(ElementType) (XMenuWidget(display,windows, 5590 DrawMenu[id],Elements,command)+1); 5591 break; 5592 } 5593 case DrawColorCommand: 5594 { 5595 const char 5596 *ColorMenu[MaxNumberPens+1]; 5597 5598 int 5599 pen_number; 5600 5601 MagickBooleanType 5602 transparent; 5603 5604 XColor 5605 color; 5606 5607 /* 5608 Initialize menu selections. 5609 */ 5610 for (i=0; i < (int) (MaxNumberPens-2); i++) 5611 ColorMenu[i]=resource_info->pen_colors[i]; 5612 ColorMenu[MaxNumberPens-2]="transparent"; 5613 ColorMenu[MaxNumberPens-1]="Browser..."; 5614 ColorMenu[MaxNumberPens]=(char *) NULL; 5615 /* 5616 Select a pen color from the pop-up menu. 5617 */ 5618 pen_number=XMenuWidget(display,windows,DrawMenu[id], 5619 (const char **) ColorMenu,command); 5620 if (pen_number < 0) 5621 break; 5622 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue : 5623 MagickFalse; 5624 if (IfMagickTrue(transparent) ) 5625 { 5626 draw_info.stencil=TransparentStencil; 5627 break; 5628 } 5629 if (pen_number == (MaxNumberPens-1)) 5630 { 5631 static char 5632 color_name[MaxTextExtent] = "gray"; 5633 5634 /* 5635 Select a pen color from a dialog. 5636 */ 5637 resource_info->pen_colors[pen_number]=color_name; 5638 XColorBrowserWidget(display,windows,"Select",color_name); 5639 if (*color_name == '\0') 5640 break; 5641 } 5642 /* 5643 Set pen color. 5644 */ 5645 (void) XParseColor(display,windows->map_info->colormap, 5646 resource_info->pen_colors[pen_number],&color); 5647 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 5648 (unsigned int) MaxColors,&color); 5649 windows->pixel_info->pen_colors[pen_number]=color; 5650 pen_id=(unsigned int) pen_number; 5651 draw_info.stencil=OpaqueStencil; 5652 break; 5653 } 5654 case DrawStippleCommand: 5655 { 5656 Image 5657 *stipple_image; 5658 5659 ImageInfo 5660 *image_info; 5661 5662 int 5663 status; 5664 5665 static char 5666 filename[MaxTextExtent] = "\0"; 5667 5668 static const char 5669 *StipplesMenu[] = 5670 { 5671 "Brick", 5672 "Diagonal", 5673 "Scales", 5674 "Vertical", 5675 "Wavy", 5676 "Translucent", 5677 "Opaque", 5678 (char *) NULL, 5679 (char *) NULL, 5680 }; 5681 5682 /* 5683 Select a command from the pop-up menu. 5684 */ 5685 StipplesMenu[7]="Open..."; 5686 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu, 5687 command); 5688 if (entry < 0) 5689 break; 5690 if (stipple != (Pixmap) NULL) 5691 (void) XFreePixmap(display,stipple); 5692 stipple=(Pixmap) NULL; 5693 if (entry != 7) 5694 { 5695 switch (entry) 5696 { 5697 case 0: 5698 { 5699 stipple=XCreateBitmapFromData(display,root_window, 5700 (char *) BricksBitmap,BricksWidth,BricksHeight); 5701 break; 5702 } 5703 case 1: 5704 { 5705 stipple=XCreateBitmapFromData(display,root_window, 5706 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight); 5707 break; 5708 } 5709 case 2: 5710 { 5711 stipple=XCreateBitmapFromData(display,root_window, 5712 (char *) ScalesBitmap,ScalesWidth,ScalesHeight); 5713 break; 5714 } 5715 case 3: 5716 { 5717 stipple=XCreateBitmapFromData(display,root_window, 5718 (char *) VerticalBitmap,VerticalWidth,VerticalHeight); 5719 break; 5720 } 5721 case 4: 5722 { 5723 stipple=XCreateBitmapFromData(display,root_window, 5724 (char *) WavyBitmap,WavyWidth,WavyHeight); 5725 break; 5726 } 5727 case 5: 5728 { 5729 stipple=XCreateBitmapFromData(display,root_window, 5730 (char *) HighlightBitmap,HighlightWidth, 5731 HighlightHeight); 5732 break; 5733 } 5734 case 6: 5735 default: 5736 { 5737 stipple=XCreateBitmapFromData(display,root_window, 5738 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight); 5739 break; 5740 } 5741 } 5742 break; 5743 } 5744 XFileBrowserWidget(display,windows,"Stipple",filename); 5745 if (*filename == '\0') 5746 break; 5747 /* 5748 Read image. 5749 */ 5750 XSetCursorState(display,windows,MagickTrue); 5751 XCheckRefreshWindows(display,windows); 5752 image_info=AcquireImageInfo(); 5753 (void) CopyMagickString(image_info->filename,filename, 5754 MaxTextExtent); 5755 stipple_image=ReadImage(image_info,exception); 5756 CatchException(exception); 5757 XSetCursorState(display,windows,MagickFalse); 5758 if (stipple_image == (Image *) NULL) 5759 break; 5760 (void) AcquireUniqueFileResource(filename); 5761 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent, 5762 "xbm:%s",filename); 5763 (void) WriteImage(image_info,stipple_image,exception); 5764 stipple_image=DestroyImage(stipple_image); 5765 image_info=DestroyImageInfo(image_info); 5766 status=XReadBitmapFile(display,root_window,filename,&width, 5767 &height,&stipple,&x,&y); 5768 (void) RelinquishUniqueFileResource(filename); 5769 if ((status != BitmapSuccess) != 0) 5770 XNoticeWidget(display,windows,"Unable to read X bitmap image:", 5771 filename); 5772 break; 5773 } 5774 case DrawWidthCommand: 5775 { 5776 static char 5777 width[MaxTextExtent] = "0"; 5778 5779 static const char 5780 *WidthsMenu[] = 5781 { 5782 "1", 5783 "2", 5784 "4", 5785 "8", 5786 "16", 5787 "Dialog...", 5788 (char *) NULL, 5789 }; 5790 5791 /* 5792 Select a command from the pop-up menu. 5793 */ 5794 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu, 5795 command); 5796 if (entry < 0) 5797 break; 5798 if (entry != 5) 5799 { 5800 line_width=(unsigned int) StringToUnsignedLong( 5801 WidthsMenu[entry]); 5802 break; 5803 } 5804 (void) XDialogWidget(display,windows,"Ok","Enter line width:", 5805 width); 5806 if (*width == '\0') 5807 break; 5808 line_width=(unsigned int) StringToUnsignedLong(width); 5809 break; 5810 } 5811 case DrawUndoCommand: 5812 { 5813 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 5814 image,exception); 5815 break; 5816 } 5817 case DrawHelpCommand: 5818 { 5819 XTextViewWidget(display,resource_info,windows,MagickFalse, 5820 "Help Viewer - Image Rotation",ImageDrawHelp); 5821 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5822 break; 5823 } 5824 case DrawDismissCommand: 5825 { 5826 /* 5827 Prematurely exit. 5828 */ 5829 state|=EscapeState; 5830 state|=ExitState; 5831 break; 5832 } 5833 default: 5834 break; 5835 } 5836 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5837 continue; 5838 } 5839 switch (event.type) 5840 { 5841 case ButtonPress: 5842 { 5843 if (event.xbutton.button != Button1) 5844 break; 5845 if (event.xbutton.window != windows->image.id) 5846 break; 5847 /* 5848 exit loop. 5849 */ 5850 x=event.xbutton.x; 5851 y=event.xbutton.y; 5852 state|=ExitState; 5853 break; 5854 } 5855 case ButtonRelease: 5856 break; 5857 case Expose: 5858 break; 5859 case KeyPress: 5860 { 5861 KeySym 5862 key_symbol; 5863 5864 if (event.xkey.window != windows->image.id) 5865 break; 5866 /* 5867 Respond to a user key press. 5868 */ 5869 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5870 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5871 switch ((int) key_symbol) 5872 { 5873 case XK_Escape: 5874 case XK_F20: 5875 { 5876 /* 5877 Prematurely exit. 5878 */ 5879 state|=EscapeState; 5880 state|=ExitState; 5881 break; 5882 } 5883 case XK_F1: 5884 case XK_Help: 5885 { 5886 XTextViewWidget(display,resource_info,windows,MagickFalse, 5887 "Help Viewer - Image Rotation",ImageDrawHelp); 5888 break; 5889 } 5890 default: 5891 { 5892 (void) XBell(display,0); 5893 break; 5894 } 5895 } 5896 break; 5897 } 5898 case MotionNotify: 5899 { 5900 /* 5901 Map and unmap Info widget as text cursor crosses its boundaries. 5902 */ 5903 x=event.xmotion.x; 5904 y=event.xmotion.y; 5905 if (IfMagickTrue(windows->info.mapped) ) 5906 { 5907 if ((x < (int) (windows->info.x+windows->info.width)) && 5908 (y < (int) (windows->info.y+windows->info.height))) 5909 (void) XWithdrawWindow(display,windows->info.id, 5910 windows->info.screen); 5911 } 5912 else 5913 if ((x > (int) (windows->info.x+windows->info.width)) || 5914 (y > (int) (windows->info.y+windows->info.height))) 5915 (void) XMapWindow(display,windows->info.id); 5916 break; 5917 } 5918 } 5919 } while ((state & ExitState) == 0); 5920 (void) XSelectInput(display,windows->image.id, 5921 windows->image.attributes.event_mask); 5922 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 5923 if ((state & EscapeState) != 0) 5924 break; 5925 /* 5926 Draw element as pointer moves until the button is released. 5927 */ 5928 distance=0; 5929 degrees=0.0; 5930 line_info.x1=x; 5931 line_info.y1=y; 5932 line_info.x2=x; 5933 line_info.y2=y; 5934 rectangle_info.x=(ssize_t) x; 5935 rectangle_info.y=(ssize_t) y; 5936 rectangle_info.width=0; 5937 rectangle_info.height=0; 5938 number_coordinates=1; 5939 coordinate_info->x=x; 5940 coordinate_info->y=y; 5941 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 5942 state=DefaultState; 5943 do 5944 { 5945 switch (element) 5946 { 5947 case PointElement: 5948 default: 5949 { 5950 if (number_coordinates > 1) 5951 { 5952 (void) XDrawLines(display,windows->image.id, 5953 windows->image.highlight_context,coordinate_info, 5954 number_coordinates,CoordModeOrigin); 5955 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d", 5956 coordinate_info[number_coordinates-1].x, 5957 coordinate_info[number_coordinates-1].y); 5958 XInfoWidget(display,windows,text); 5959 } 5960 break; 5961 } 5962 case LineElement: 5963 { 5964 if (distance > 9) 5965 { 5966 /* 5967 Display angle of the line. 5968 */ 5969 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 5970 line_info.y1),(double) (line_info.x2-line_info.x1))); 5971 (void) FormatLocaleString(text,MaxTextExtent," %g", 5972 (double) degrees); 5973 XInfoWidget(display,windows,text); 5974 XHighlightLine(display,windows->image.id, 5975 windows->image.highlight_context,&line_info); 5976 } 5977 else 5978 if (IfMagickTrue(windows->info.mapped) ) 5979 (void) XWithdrawWindow(display,windows->info.id, 5980 windows->info.screen); 5981 break; 5982 } 5983 case RectangleElement: 5984 case FillRectangleElement: 5985 { 5986 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5987 { 5988 /* 5989 Display info and draw drawing rectangle. 5990 */ 5991 (void) FormatLocaleString(text,MaxTextExtent, 5992 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5993 (double) rectangle_info.height,(double) rectangle_info.x, 5994 (double) rectangle_info.y); 5995 XInfoWidget(display,windows,text); 5996 XHighlightRectangle(display,windows->image.id, 5997 windows->image.highlight_context,&rectangle_info); 5998 } 5999 else 6000 if (IfMagickTrue(windows->info.mapped) ) 6001 (void) XWithdrawWindow(display,windows->info.id, 6002 windows->info.screen); 6003 break; 6004 } 6005 case CircleElement: 6006 case FillCircleElement: 6007 case EllipseElement: 6008 case FillEllipseElement: 6009 { 6010 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6011 { 6012 /* 6013 Display info and draw drawing rectangle. 6014 */ 6015 (void) FormatLocaleString(text,MaxTextExtent, 6016 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 6017 (double) rectangle_info.height,(double) rectangle_info.x, 6018 (double) rectangle_info.y); 6019 XInfoWidget(display,windows,text); 6020 XHighlightEllipse(display,windows->image.id, 6021 windows->image.highlight_context,&rectangle_info); 6022 } 6023 else 6024 if (IfMagickTrue(windows->info.mapped) ) 6025 (void) XWithdrawWindow(display,windows->info.id, 6026 windows->info.screen); 6027 break; 6028 } 6029 case PolygonElement: 6030 case FillPolygonElement: 6031 { 6032 if (number_coordinates > 1) 6033 (void) XDrawLines(display,windows->image.id, 6034 windows->image.highlight_context,coordinate_info, 6035 number_coordinates,CoordModeOrigin); 6036 if (distance > 9) 6037 { 6038 /* 6039 Display angle of the line. 6040 */ 6041 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 6042 line_info.y1),(double) (line_info.x2-line_info.x1))); 6043 (void) FormatLocaleString(text,MaxTextExtent," %g", 6044 (double) degrees); 6045 XInfoWidget(display,windows,text); 6046 XHighlightLine(display,windows->image.id, 6047 windows->image.highlight_context,&line_info); 6048 } 6049 else 6050 if (IfMagickTrue(windows->info.mapped) ) 6051 (void) XWithdrawWindow(display,windows->info.id, 6052 windows->info.screen); 6053 break; 6054 } 6055 } 6056 /* 6057 Wait for next event. 6058 */ 6059 XScreenEvent(display,windows,&event,exception); 6060 switch (element) 6061 { 6062 case PointElement: 6063 default: 6064 { 6065 if (number_coordinates > 1) 6066 (void) XDrawLines(display,windows->image.id, 6067 windows->image.highlight_context,coordinate_info, 6068 number_coordinates,CoordModeOrigin); 6069 break; 6070 } 6071 case LineElement: 6072 { 6073 if (distance > 9) 6074 XHighlightLine(display,windows->image.id, 6075 windows->image.highlight_context,&line_info); 6076 break; 6077 } 6078 case RectangleElement: 6079 case FillRectangleElement: 6080 { 6081 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6082 XHighlightRectangle(display,windows->image.id, 6083 windows->image.highlight_context,&rectangle_info); 6084 break; 6085 } 6086 case CircleElement: 6087 case FillCircleElement: 6088 case EllipseElement: 6089 case FillEllipseElement: 6090 { 6091 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6092 XHighlightEllipse(display,windows->image.id, 6093 windows->image.highlight_context,&rectangle_info); 6094 break; 6095 } 6096 case PolygonElement: 6097 case FillPolygonElement: 6098 { 6099 if (number_coordinates > 1) 6100 (void) XDrawLines(display,windows->image.id, 6101 windows->image.highlight_context,coordinate_info, 6102 number_coordinates,CoordModeOrigin); 6103 if (distance > 9) 6104 XHighlightLine(display,windows->image.id, 6105 windows->image.highlight_context,&line_info); 6106 break; 6107 } 6108 } 6109 switch (event.type) 6110 { 6111 case ButtonPress: 6112 break; 6113 case ButtonRelease: 6114 { 6115 /* 6116 User has committed to element. 6117 */ 6118 line_info.x2=event.xbutton.x; 6119 line_info.y2=event.xbutton.y; 6120 rectangle_info.x=(ssize_t) event.xbutton.x; 6121 rectangle_info.y=(ssize_t) event.xbutton.y; 6122 coordinate_info[number_coordinates].x=event.xbutton.x; 6123 coordinate_info[number_coordinates].y=event.xbutton.y; 6124 if (((element != PolygonElement) && 6125 (element != FillPolygonElement)) || (distance <= 9)) 6126 { 6127 state|=ExitState; 6128 break; 6129 } 6130 number_coordinates++; 6131 if (number_coordinates < (int) max_coordinates) 6132 { 6133 line_info.x1=event.xbutton.x; 6134 line_info.y1=event.xbutton.y; 6135 break; 6136 } 6137 max_coordinates<<=1; 6138 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6139 max_coordinates,sizeof(*coordinate_info)); 6140 if (coordinate_info == (XPoint *) NULL) 6141 (void) ThrowMagickException(exception,GetMagickModule(), 6142 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6143 break; 6144 } 6145 case Expose: 6146 break; 6147 case MotionNotify: 6148 { 6149 if (event.xmotion.window != windows->image.id) 6150 break; 6151 if (element != PointElement) 6152 { 6153 line_info.x2=event.xmotion.x; 6154 line_info.y2=event.xmotion.y; 6155 rectangle_info.x=(ssize_t) event.xmotion.x; 6156 rectangle_info.y=(ssize_t) event.xmotion.y; 6157 break; 6158 } 6159 coordinate_info[number_coordinates].x=event.xbutton.x; 6160 coordinate_info[number_coordinates].y=event.xbutton.y; 6161 number_coordinates++; 6162 if (number_coordinates < (int) max_coordinates) 6163 break; 6164 max_coordinates<<=1; 6165 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6166 max_coordinates,sizeof(*coordinate_info)); 6167 if (coordinate_info == (XPoint *) NULL) 6168 (void) ThrowMagickException(exception,GetMagickModule(), 6169 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6170 break; 6171 } 6172 default: 6173 break; 6174 } 6175 /* 6176 Check boundary conditions. 6177 */ 6178 if (line_info.x2 < 0) 6179 line_info.x2=0; 6180 else 6181 if (line_info.x2 > (int) windows->image.width) 6182 line_info.x2=(short) windows->image.width; 6183 if (line_info.y2 < 0) 6184 line_info.y2=0; 6185 else 6186 if (line_info.y2 > (int) windows->image.height) 6187 line_info.y2=(short) windows->image.height; 6188 distance=(unsigned int) 6189 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+ 6190 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1))); 6191 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) || 6192 ((state & ExitState) != 0)) 6193 { 6194 if (rectangle_info.x < 0) 6195 rectangle_info.x=0; 6196 else 6197 if (rectangle_info.x > (ssize_t) windows->image.width) 6198 rectangle_info.x=(ssize_t) windows->image.width; 6199 if ((int) rectangle_info.x < x) 6200 rectangle_info.width=(unsigned int) (x-rectangle_info.x); 6201 else 6202 { 6203 rectangle_info.width=(unsigned int) (rectangle_info.x-x); 6204 rectangle_info.x=(ssize_t) x; 6205 } 6206 if (rectangle_info.y < 0) 6207 rectangle_info.y=0; 6208 else 6209 if (rectangle_info.y > (ssize_t) windows->image.height) 6210 rectangle_info.y=(ssize_t) windows->image.height; 6211 if ((int) rectangle_info.y < y) 6212 rectangle_info.height=(unsigned int) (y-rectangle_info.y); 6213 else 6214 { 6215 rectangle_info.height=(unsigned int) (rectangle_info.y-y); 6216 rectangle_info.y=(ssize_t) y; 6217 } 6218 } 6219 } while ((state & ExitState) == 0); 6220 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 6221 if ((element == PointElement) || (element == PolygonElement) || 6222 (element == FillPolygonElement)) 6223 { 6224 /* 6225 Determine polygon bounding box. 6226 */ 6227 rectangle_info.x=(ssize_t) coordinate_info->x; 6228 rectangle_info.y=(ssize_t) coordinate_info->y; 6229 x=coordinate_info->x; 6230 y=coordinate_info->y; 6231 for (i=1; i < number_coordinates; i++) 6232 { 6233 if (coordinate_info[i].x > x) 6234 x=coordinate_info[i].x; 6235 if (coordinate_info[i].y > y) 6236 y=coordinate_info[i].y; 6237 if ((ssize_t) coordinate_info[i].x < rectangle_info.x) 6238 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0); 6239 if ((ssize_t) coordinate_info[i].y < rectangle_info.y) 6240 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0); 6241 } 6242 rectangle_info.width=(size_t) (x-rectangle_info.x); 6243 rectangle_info.height=(size_t) (y-rectangle_info.y); 6244 for (i=0; i < number_coordinates; i++) 6245 { 6246 coordinate_info[i].x-=rectangle_info.x; 6247 coordinate_info[i].y-=rectangle_info.y; 6248 } 6249 } 6250 else 6251 if (distance <= 9) 6252 continue; 6253 else 6254 if ((element == RectangleElement) || 6255 (element == CircleElement) || (element == EllipseElement)) 6256 { 6257 rectangle_info.width--; 6258 rectangle_info.height--; 6259 } 6260 /* 6261 Drawing is relative to image configuration. 6262 */ 6263 draw_info.x=(int) rectangle_info.x; 6264 draw_info.y=(int) rectangle_info.y; 6265 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand, 6266 image,exception); 6267 width=(unsigned int) (*image)->columns; 6268 height=(unsigned int) (*image)->rows; 6269 x=0; 6270 y=0; 6271 if (windows->image.crop_geometry != (char *) NULL) 6272 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 6273 draw_info.x+=windows->image.x-(line_width/2); 6274 if (draw_info.x < 0) 6275 draw_info.x=0; 6276 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width); 6277 draw_info.y+=windows->image.y-(line_width/2); 6278 if (draw_info.y < 0) 6279 draw_info.y=0; 6280 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height; 6281 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1); 6282 if (draw_info.width > (unsigned int) (*image)->columns) 6283 draw_info.width=(unsigned int) (*image)->columns; 6284 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1); 6285 if (draw_info.height > (unsigned int) (*image)->rows) 6286 draw_info.height=(unsigned int) (*image)->rows; 6287 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d", 6288 width*draw_info.width/windows->image.ximage->width, 6289 height*draw_info.height/windows->image.ximage->height, 6290 draw_info.x+x,draw_info.y+y); 6291 /* 6292 Initialize drawing attributes. 6293 */ 6294 draw_info.degrees=0.0; 6295 draw_info.element=element; 6296 draw_info.stipple=stipple; 6297 draw_info.line_width=line_width; 6298 draw_info.line_info=line_info; 6299 if (line_info.x1 > (int) (line_width/2)) 6300 draw_info.line_info.x1=(short) line_width/2; 6301 if (line_info.y1 > (int) (line_width/2)) 6302 draw_info.line_info.y1=(short) line_width/2; 6303 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2)); 6304 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2)); 6305 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0)) 6306 { 6307 draw_info.line_info.x2=(-draw_info.line_info.x2); 6308 draw_info.line_info.y2=(-draw_info.line_info.y2); 6309 } 6310 if (draw_info.line_info.x2 < 0) 6311 { 6312 draw_info.line_info.x2=(-draw_info.line_info.x2); 6313 Swap(draw_info.line_info.x1,draw_info.line_info.x2); 6314 } 6315 if (draw_info.line_info.y2 < 0) 6316 { 6317 draw_info.line_info.y2=(-draw_info.line_info.y2); 6318 Swap(draw_info.line_info.y1,draw_info.line_info.y2); 6319 } 6320 draw_info.rectangle_info=rectangle_info; 6321 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2)) 6322 draw_info.rectangle_info.x=(ssize_t) line_width/2; 6323 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2)) 6324 draw_info.rectangle_info.y=(ssize_t) line_width/2; 6325 draw_info.number_coordinates=(unsigned int) number_coordinates; 6326 draw_info.coordinate_info=coordinate_info; 6327 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 6328 /* 6329 Draw element on image. 6330 */ 6331 XSetCursorState(display,windows,MagickTrue); 6332 XCheckRefreshWindows(display,windows); 6333 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception); 6334 XSetCursorState(display,windows,MagickFalse); 6335 /* 6336 Update image colormap and return to image drawing. 6337 */ 6338 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6339 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6340 } 6341 XSetCursorState(display,windows,MagickFalse); 6342 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info); 6343 return(IsMagickTrue(status)); 6344} 6345 6346/* 6347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6348% % 6349% % 6350% % 6351+ X D r a w P a n R e c t a n g l e % 6352% % 6353% % 6354% % 6355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6356% 6357% XDrawPanRectangle() draws a rectangle in the pan window. The pan window 6358% displays a zoom image and the rectangle shows which portion of the image is 6359% displayed in the Image window. 6360% 6361% The format of the XDrawPanRectangle method is: 6362% 6363% XDrawPanRectangle(Display *display,XWindows *windows) 6364% 6365% A description of each parameter follows: 6366% 6367% o display: Specifies a connection to an X server; returned from 6368% XOpenDisplay. 6369% 6370% o windows: Specifies a pointer to a XWindows structure. 6371% 6372*/ 6373static void XDrawPanRectangle(Display *display,XWindows *windows) 6374{ 6375 double 6376 scale_factor; 6377 6378 RectangleInfo 6379 highlight_info; 6380 6381 /* 6382 Determine dimensions of the panning rectangle. 6383 */ 6384 scale_factor=(double) windows->pan.width/windows->image.ximage->width; 6385 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5); 6386 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5); 6387 scale_factor=(double) 6388 windows->pan.height/windows->image.ximage->height; 6389 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5); 6390 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5); 6391 /* 6392 Display the panning rectangle. 6393 */ 6394 (void) XClearWindow(display,windows->pan.id); 6395 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context, 6396 &highlight_info); 6397} 6398 6399/* 6400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6401% % 6402% % 6403% % 6404+ X I m a g e C a c h e % 6405% % 6406% % 6407% % 6408%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6409% 6410% XImageCache() handles the creation, manipulation, and destruction of the 6411% image cache (undo and redo buffers). 6412% 6413% The format of the XImageCache method is: 6414% 6415% void XImageCache(Display *display,XResourceInfo *resource_info, 6416% XWindows *windows,const CommandType command,Image **image, 6417% ExceptionInfo *exception) 6418% 6419% A description of each parameter follows: 6420% 6421% o display: Specifies a connection to an X server; returned from 6422% XOpenDisplay. 6423% 6424% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6425% 6426% o windows: Specifies a pointer to a XWindows structure. 6427% 6428% o command: Specifies a command to perform. 6429% 6430% o image: the image; XImageCache may transform the image and return a new 6431% image pointer. 6432% 6433% o exception: return any errors or warnings in this structure. 6434% 6435*/ 6436static void XImageCache(Display *display,XResourceInfo *resource_info, 6437 XWindows *windows,const CommandType command,Image **image, 6438 ExceptionInfo *exception) 6439{ 6440 Image 6441 *cache_image; 6442 6443 static Image 6444 *redo_image = (Image *) NULL, 6445 *undo_image = (Image *) NULL; 6446 6447 switch (command) 6448 { 6449 case FreeBuffersCommand: 6450 { 6451 /* 6452 Free memory from the undo and redo cache. 6453 */ 6454 while (undo_image != (Image *) NULL) 6455 { 6456 cache_image=undo_image; 6457 undo_image=GetPreviousImageInList(undo_image); 6458 cache_image->list=DestroyImage(cache_image->list); 6459 cache_image=DestroyImage(cache_image); 6460 } 6461 undo_image=NewImageList(); 6462 if (redo_image != (Image *) NULL) 6463 redo_image=DestroyImage(redo_image); 6464 redo_image=NewImageList(); 6465 return; 6466 } 6467 case UndoCommand: 6468 { 6469 char 6470 image_geometry[MaxTextExtent]; 6471 6472 /* 6473 Undo the last image transformation. 6474 */ 6475 if (undo_image == (Image *) NULL) 6476 { 6477 (void) XBell(display,0); 6478 return; 6479 } 6480 cache_image=undo_image; 6481 undo_image=GetPreviousImageInList(undo_image); 6482 windows->image.window_changes.width=(int) cache_image->columns; 6483 windows->image.window_changes.height=(int) cache_image->rows; 6484 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 6485 windows->image.ximage->width,windows->image.ximage->height); 6486 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 6487 exception); 6488 if (windows->image.crop_geometry != (char *) NULL) 6489 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 6490 windows->image.crop_geometry); 6491 windows->image.crop_geometry=cache_image->geometry; 6492 if (redo_image != (Image *) NULL) 6493 redo_image=DestroyImage(redo_image); 6494 redo_image=(*image); 6495 *image=cache_image->list; 6496 cache_image=DestroyImage(cache_image); 6497 if (IfMagickTrue(windows->image.orphan) ) 6498 return; 6499 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6500 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6501 return; 6502 } 6503 case CutCommand: 6504 case PasteCommand: 6505 case ApplyCommand: 6506 case HalfSizeCommand: 6507 case OriginalSizeCommand: 6508 case DoubleSizeCommand: 6509 case ResizeCommand: 6510 case TrimCommand: 6511 case CropCommand: 6512 case ChopCommand: 6513 case FlipCommand: 6514 case FlopCommand: 6515 case RotateRightCommand: 6516 case RotateLeftCommand: 6517 case RotateCommand: 6518 case ShearCommand: 6519 case RollCommand: 6520 case NegateCommand: 6521 case ContrastStretchCommand: 6522 case SigmoidalContrastCommand: 6523 case NormalizeCommand: 6524 case EqualizeCommand: 6525 case HueCommand: 6526 case SaturationCommand: 6527 case BrightnessCommand: 6528 case GammaCommand: 6529 case SpiffCommand: 6530 case DullCommand: 6531 case GrayscaleCommand: 6532 case MapCommand: 6533 case QuantizeCommand: 6534 case DespeckleCommand: 6535 case EmbossCommand: 6536 case ReduceNoiseCommand: 6537 case AddNoiseCommand: 6538 case SharpenCommand: 6539 case BlurCommand: 6540 case ThresholdCommand: 6541 case EdgeDetectCommand: 6542 case SpreadCommand: 6543 case ShadeCommand: 6544 case RaiseCommand: 6545 case SegmentCommand: 6546 case SolarizeCommand: 6547 case SepiaToneCommand: 6548 case SwirlCommand: 6549 case ImplodeCommand: 6550 case VignetteCommand: 6551 case WaveCommand: 6552 case OilPaintCommand: 6553 case CharcoalDrawCommand: 6554 case AnnotateCommand: 6555 case AddBorderCommand: 6556 case AddFrameCommand: 6557 case CompositeCommand: 6558 case CommentCommand: 6559 case LaunchCommand: 6560 case RegionofInterestCommand: 6561 case SaveToUndoBufferCommand: 6562 case RedoCommand: 6563 { 6564 Image 6565 *previous_image; 6566 6567 ssize_t 6568 bytes; 6569 6570 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo)); 6571 if (undo_image != (Image *) NULL) 6572 { 6573 /* 6574 Ensure the undo cache has enough memory available. 6575 */ 6576 previous_image=undo_image; 6577 while (previous_image != (Image *) NULL) 6578 { 6579 bytes+=previous_image->list->columns*previous_image->list->rows* 6580 sizeof(PixelInfo); 6581 if (bytes <= (ssize_t) (resource_info->undo_cache << 20)) 6582 { 6583 previous_image=GetPreviousImageInList(previous_image); 6584 continue; 6585 } 6586 bytes-=previous_image->list->columns*previous_image->list->rows* 6587 sizeof(PixelInfo); 6588 if (previous_image == undo_image) 6589 undo_image=NewImageList(); 6590 else 6591 previous_image->next->previous=NewImageList(); 6592 break; 6593 } 6594 while (previous_image != (Image *) NULL) 6595 { 6596 /* 6597 Delete any excess memory from undo cache. 6598 */ 6599 cache_image=previous_image; 6600 previous_image=GetPreviousImageInList(previous_image); 6601 cache_image->list=DestroyImage(cache_image->list); 6602 cache_image=DestroyImage(cache_image); 6603 } 6604 } 6605 if (bytes > (ssize_t) (resource_info->undo_cache << 20)) 6606 break; 6607 /* 6608 Save image before transformations are applied. 6609 */ 6610 cache_image=AcquireImage((ImageInfo *) NULL,exception); 6611 if (cache_image == (Image *) NULL) 6612 break; 6613 XSetCursorState(display,windows,MagickTrue); 6614 XCheckRefreshWindows(display,windows); 6615 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception); 6616 XSetCursorState(display,windows,MagickFalse); 6617 if (cache_image->list == (Image *) NULL) 6618 { 6619 cache_image=DestroyImage(cache_image); 6620 break; 6621 } 6622 cache_image->columns=(size_t) windows->image.ximage->width; 6623 cache_image->rows=(size_t) windows->image.ximage->height; 6624 cache_image->geometry=windows->image.crop_geometry; 6625 if (windows->image.crop_geometry != (char *) NULL) 6626 { 6627 cache_image->geometry=AcquireString((char *) NULL); 6628 (void) CopyMagickString(cache_image->geometry, 6629 windows->image.crop_geometry,MaxTextExtent); 6630 } 6631 if (undo_image == (Image *) NULL) 6632 { 6633 undo_image=cache_image; 6634 break; 6635 } 6636 undo_image->next=cache_image; 6637 undo_image->next->previous=undo_image; 6638 undo_image=undo_image->next; 6639 break; 6640 } 6641 default: 6642 break; 6643 } 6644 if (command == RedoCommand) 6645 { 6646 /* 6647 Redo the last image transformation. 6648 */ 6649 if (redo_image == (Image *) NULL) 6650 { 6651 (void) XBell(display,0); 6652 return; 6653 } 6654 windows->image.window_changes.width=(int) redo_image->columns; 6655 windows->image.window_changes.height=(int) redo_image->rows; 6656 if (windows->image.crop_geometry != (char *) NULL) 6657 windows->image.crop_geometry=(char *) 6658 RelinquishMagickMemory(windows->image.crop_geometry); 6659 windows->image.crop_geometry=redo_image->geometry; 6660 *image=DestroyImage(*image); 6661 *image=redo_image; 6662 redo_image=NewImageList(); 6663 if (IfMagickTrue(windows->image.orphan) ) 6664 return; 6665 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6666 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6667 return; 6668 } 6669 if (command != InfoCommand) 6670 return; 6671 /* 6672 Display image info. 6673 */ 6674 XSetCursorState(display,windows,MagickTrue); 6675 XCheckRefreshWindows(display,windows); 6676 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception); 6677 XSetCursorState(display,windows,MagickFalse); 6678} 6679 6680/* 6681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6682% % 6683% % 6684% % 6685+ X I m a g e W i n d o w C o m m a n d % 6686% % 6687% % 6688% % 6689%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6690% 6691% XImageWindowCommand() makes a transform to the image or Image window as 6692% specified by a user menu button or keyboard command. 6693% 6694% The format of the XImageWindowCommand method is: 6695% 6696% CommandType XImageWindowCommand(Display *display, 6697% XResourceInfo *resource_info,XWindows *windows, 6698% const MagickStatusType state,KeySym key_symbol,Image **image, 6699% ExceptionInfo *exception) 6700% 6701% A description of each parameter follows: 6702% 6703% o nexus: Method XImageWindowCommand returns an image when the 6704% user chooses 'Open Image' from the command menu. Otherwise a null 6705% image is returned. 6706% 6707% o display: Specifies a connection to an X server; returned from 6708% XOpenDisplay. 6709% 6710% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6711% 6712% o windows: Specifies a pointer to a XWindows structure. 6713% 6714% o state: key mask. 6715% 6716% o key_symbol: Specifies a command to perform. 6717% 6718% o image: the image; XImageWIndowCommand may transform the image and 6719% return a new image pointer. 6720% 6721% o exception: return any errors or warnings in this structure. 6722% 6723*/ 6724static CommandType XImageWindowCommand(Display *display, 6725 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state, 6726 KeySym key_symbol,Image **image,ExceptionInfo *exception) 6727{ 6728 static char 6729 delta[MaxTextExtent] = ""; 6730 6731 static const char 6732 Digits[] = "01234567890"; 6733 6734 static KeySym 6735 last_symbol = XK_0; 6736 6737 if ((key_symbol >= XK_0) && (key_symbol <= XK_9)) 6738 { 6739 if (((last_symbol < XK_0) || (last_symbol > XK_9))) 6740 { 6741 *delta='\0'; 6742 resource_info->quantum=1; 6743 } 6744 last_symbol=key_symbol; 6745 delta[strlen(delta)+1]='\0'; 6746 delta[strlen(delta)]=Digits[key_symbol-XK_0]; 6747 resource_info->quantum=StringToLong(delta); 6748 return(NullCommand); 6749 } 6750 last_symbol=key_symbol; 6751 if (resource_info->immutable) 6752 { 6753 /* 6754 Virtual image window has a restricted command set. 6755 */ 6756 switch (key_symbol) 6757 { 6758 case XK_question: 6759 return(InfoCommand); 6760 case XK_p: 6761 case XK_Print: 6762 return(PrintCommand); 6763 case XK_space: 6764 return(NextCommand); 6765 case XK_q: 6766 case XK_Escape: 6767 return(QuitCommand); 6768 default: 6769 break; 6770 } 6771 return(NullCommand); 6772 } 6773 switch ((int) key_symbol) 6774 { 6775 case XK_o: 6776 { 6777 if ((state & ControlMask) == 0) 6778 break; 6779 return(OpenCommand); 6780 } 6781 case XK_space: 6782 return(NextCommand); 6783 case XK_BackSpace: 6784 return(FormerCommand); 6785 case XK_s: 6786 { 6787 if ((state & Mod1Mask) != 0) 6788 return(SwirlCommand); 6789 if ((state & ControlMask) == 0) 6790 return(ShearCommand); 6791 return(SaveCommand); 6792 } 6793 case XK_p: 6794 case XK_Print: 6795 { 6796 if ((state & Mod1Mask) != 0) 6797 return(OilPaintCommand); 6798 if ((state & Mod4Mask) != 0) 6799 return(ColorCommand); 6800 if ((state & ControlMask) == 0) 6801 return(NullCommand); 6802 return(PrintCommand); 6803 } 6804 case XK_d: 6805 { 6806 if ((state & Mod4Mask) != 0) 6807 return(DrawCommand); 6808 if ((state & ControlMask) == 0) 6809 return(NullCommand); 6810 return(DeleteCommand); 6811 } 6812 case XK_Select: 6813 { 6814 if ((state & ControlMask) == 0) 6815 return(NullCommand); 6816 return(SelectCommand); 6817 } 6818 case XK_n: 6819 { 6820 if ((state & ControlMask) == 0) 6821 return(NullCommand); 6822 return(NewCommand); 6823 } 6824 case XK_q: 6825 case XK_Escape: 6826 return(QuitCommand); 6827 case XK_z: 6828 case XK_Undo: 6829 { 6830 if ((state & ControlMask) == 0) 6831 return(NullCommand); 6832 return(UndoCommand); 6833 } 6834 case XK_r: 6835 case XK_Redo: 6836 { 6837 if ((state & ControlMask) == 0) 6838 return(RollCommand); 6839 return(RedoCommand); 6840 } 6841 case XK_x: 6842 { 6843 if ((state & ControlMask) == 0) 6844 return(NullCommand); 6845 return(CutCommand); 6846 } 6847 case XK_c: 6848 { 6849 if ((state & Mod1Mask) != 0) 6850 return(CharcoalDrawCommand); 6851 if ((state & ControlMask) == 0) 6852 return(CropCommand); 6853 return(CopyCommand); 6854 } 6855 case XK_v: 6856 case XK_Insert: 6857 { 6858 if ((state & Mod4Mask) != 0) 6859 return(CompositeCommand); 6860 if ((state & ControlMask) == 0) 6861 return(FlipCommand); 6862 return(PasteCommand); 6863 } 6864 case XK_less: 6865 return(HalfSizeCommand); 6866 case XK_minus: 6867 return(OriginalSizeCommand); 6868 case XK_greater: 6869 return(DoubleSizeCommand); 6870 case XK_percent: 6871 return(ResizeCommand); 6872 case XK_at: 6873 return(RefreshCommand); 6874 case XK_bracketleft: 6875 return(ChopCommand); 6876 case XK_h: 6877 return(FlopCommand); 6878 case XK_slash: 6879 return(RotateRightCommand); 6880 case XK_backslash: 6881 return(RotateLeftCommand); 6882 case XK_asterisk: 6883 return(RotateCommand); 6884 case XK_t: 6885 return(TrimCommand); 6886 case XK_H: 6887 return(HueCommand); 6888 case XK_S: 6889 return(SaturationCommand); 6890 case XK_L: 6891 return(BrightnessCommand); 6892 case XK_G: 6893 return(GammaCommand); 6894 case XK_C: 6895 return(SpiffCommand); 6896 case XK_Z: 6897 return(DullCommand); 6898 case XK_N: 6899 return(NormalizeCommand); 6900 case XK_equal: 6901 return(EqualizeCommand); 6902 case XK_asciitilde: 6903 return(NegateCommand); 6904 case XK_period: 6905 return(GrayscaleCommand); 6906 case XK_numbersign: 6907 return(QuantizeCommand); 6908 case XK_F2: 6909 return(DespeckleCommand); 6910 case XK_F3: 6911 return(EmbossCommand); 6912 case XK_F4: 6913 return(ReduceNoiseCommand); 6914 case XK_F5: 6915 return(AddNoiseCommand); 6916 case XK_F6: 6917 return(SharpenCommand); 6918 case XK_F7: 6919 return(BlurCommand); 6920 case XK_F8: 6921 return(ThresholdCommand); 6922 case XK_F9: 6923 return(EdgeDetectCommand); 6924 case XK_F10: 6925 return(SpreadCommand); 6926 case XK_F11: 6927 return(ShadeCommand); 6928 case XK_F12: 6929 return(RaiseCommand); 6930 case XK_F13: 6931 return(SegmentCommand); 6932 case XK_i: 6933 { 6934 if ((state & Mod1Mask) == 0) 6935 return(NullCommand); 6936 return(ImplodeCommand); 6937 } 6938 case XK_w: 6939 { 6940 if ((state & Mod1Mask) == 0) 6941 return(NullCommand); 6942 return(WaveCommand); 6943 } 6944 case XK_m: 6945 { 6946 if ((state & Mod4Mask) == 0) 6947 return(NullCommand); 6948 return(MatteCommand); 6949 } 6950 case XK_b: 6951 { 6952 if ((state & Mod4Mask) == 0) 6953 return(NullCommand); 6954 return(AddBorderCommand); 6955 } 6956 case XK_f: 6957 { 6958 if ((state & Mod4Mask) == 0) 6959 return(NullCommand); 6960 return(AddFrameCommand); 6961 } 6962 case XK_exclam: 6963 { 6964 if ((state & Mod4Mask) == 0) 6965 return(NullCommand); 6966 return(CommentCommand); 6967 } 6968 case XK_a: 6969 { 6970 if ((state & Mod1Mask) != 0) 6971 return(ApplyCommand); 6972 if ((state & Mod4Mask) != 0) 6973 return(AnnotateCommand); 6974 if ((state & ControlMask) == 0) 6975 return(NullCommand); 6976 return(RegionofInterestCommand); 6977 } 6978 case XK_question: 6979 return(InfoCommand); 6980 case XK_plus: 6981 return(ZoomCommand); 6982 case XK_P: 6983 { 6984 if ((state & ShiftMask) == 0) 6985 return(NullCommand); 6986 return(ShowPreviewCommand); 6987 } 6988 case XK_Execute: 6989 return(LaunchCommand); 6990 case XK_F1: 6991 return(HelpCommand); 6992 case XK_Find: 6993 return(BrowseDocumentationCommand); 6994 case XK_Menu: 6995 { 6996 (void) XMapRaised(display,windows->command.id); 6997 return(NullCommand); 6998 } 6999 case XK_Next: 7000 case XK_Prior: 7001 case XK_Home: 7002 case XK_KP_Home: 7003 { 7004 XTranslateImage(display,windows,*image,key_symbol); 7005 return(NullCommand); 7006 } 7007 case XK_Up: 7008 case XK_KP_Up: 7009 case XK_Down: 7010 case XK_KP_Down: 7011 case XK_Left: 7012 case XK_KP_Left: 7013 case XK_Right: 7014 case XK_KP_Right: 7015 { 7016 if ((state & Mod1Mask) != 0) 7017 { 7018 RectangleInfo 7019 crop_info; 7020 7021 /* 7022 Trim one pixel from edge of image. 7023 */ 7024 crop_info.x=0; 7025 crop_info.y=0; 7026 crop_info.width=(size_t) windows->image.ximage->width; 7027 crop_info.height=(size_t) windows->image.ximage->height; 7028 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up)) 7029 { 7030 if (resource_info->quantum >= (int) crop_info.height) 7031 resource_info->quantum=(int) crop_info.height-1; 7032 crop_info.height-=resource_info->quantum; 7033 } 7034 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down)) 7035 { 7036 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y)) 7037 resource_info->quantum=(int) (crop_info.height-crop_info.y-1); 7038 crop_info.y+=resource_info->quantum; 7039 crop_info.height-=resource_info->quantum; 7040 } 7041 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left)) 7042 { 7043 if (resource_info->quantum >= (int) crop_info.width) 7044 resource_info->quantum=(int) crop_info.width-1; 7045 crop_info.width-=resource_info->quantum; 7046 } 7047 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right)) 7048 { 7049 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x)) 7050 resource_info->quantum=(int) (crop_info.width-crop_info.x-1); 7051 crop_info.x+=resource_info->quantum; 7052 crop_info.width-=resource_info->quantum; 7053 } 7054 if ((int) (windows->image.x+windows->image.width) > 7055 (int) crop_info.width) 7056 windows->image.x=(int) (crop_info.width-windows->image.width); 7057 if ((int) (windows->image.y+windows->image.height) > 7058 (int) crop_info.height) 7059 windows->image.y=(int) (crop_info.height-windows->image.height); 7060 XSetCropGeometry(display,windows,&crop_info,*image); 7061 windows->image.window_changes.width=(int) crop_info.width; 7062 windows->image.window_changes.height=(int) crop_info.height; 7063 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None); 7064 (void) XConfigureImage(display,resource_info,windows,*image, 7065 exception); 7066 return(NullCommand); 7067 } 7068 XTranslateImage(display,windows,*image,key_symbol); 7069 return(NullCommand); 7070 } 7071 default: 7072 return(NullCommand); 7073 } 7074 return(NullCommand); 7075} 7076 7077/* 7078%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7079% % 7080% % 7081% % 7082+ X M a g i c k C o m m a n d % 7083% % 7084% % 7085% % 7086%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7087% 7088% XMagickCommand() makes a transform to the image or Image window as 7089% specified by a user menu button or keyboard command. 7090% 7091% The format of the XMagickCommand method is: 7092% 7093% Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7094% XWindows *windows,const CommandType command,Image **image, 7095% ExceptionInfo *exception) 7096% 7097% A description of each parameter follows: 7098% 7099% o display: Specifies a connection to an X server; returned from 7100% XOpenDisplay. 7101% 7102% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 7103% 7104% o windows: Specifies a pointer to a XWindows structure. 7105% 7106% o command: Specifies a command to perform. 7107% 7108% o image: the image; XMagickCommand may transform the image and return a 7109% new image pointer. 7110% 7111% o exception: return any errors or warnings in this structure. 7112% 7113*/ 7114static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7115 XWindows *windows,const CommandType command,Image **image, 7116 ExceptionInfo *exception) 7117{ 7118 char 7119 filename[MaxTextExtent], 7120 geometry[MaxTextExtent], 7121 modulate_factors[MaxTextExtent]; 7122 7123 GeometryInfo 7124 geometry_info; 7125 7126 Image 7127 *nexus; 7128 7129 ImageInfo 7130 *image_info; 7131 7132 int 7133 x, 7134 y; 7135 7136 MagickStatusType 7137 flags, 7138 status; 7139 7140 QuantizeInfo 7141 quantize_info; 7142 7143 RectangleInfo 7144 page_geometry; 7145 7146 register int 7147 i; 7148 7149 static char 7150 color[MaxTextExtent] = "gray"; 7151 7152 unsigned int 7153 height, 7154 width; 7155 7156 /* 7157 Process user command. 7158 */ 7159 XCheckRefreshWindows(display,windows); 7160 XImageCache(display,resource_info,windows,command,image,exception); 7161 nexus=NewImageList(); 7162 windows->image.window_changes.width=windows->image.ximage->width; 7163 windows->image.window_changes.height=windows->image.ximage->height; 7164 image_info=CloneImageInfo(resource_info->image_info); 7165 SetGeometryInfo(&geometry_info); 7166 GetQuantizeInfo(&quantize_info); 7167 switch (command) 7168 { 7169 case OpenCommand: 7170 { 7171 /* 7172 Load image. 7173 */ 7174 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 7175 break; 7176 } 7177 case NextCommand: 7178 { 7179 /* 7180 Display next image. 7181 */ 7182 for (i=0; i < resource_info->quantum; i++) 7183 XClientMessage(display,windows->image.id,windows->im_protocols, 7184 windows->im_next_image,CurrentTime); 7185 break; 7186 } 7187 case FormerCommand: 7188 { 7189 /* 7190 Display former image. 7191 */ 7192 for (i=0; i < resource_info->quantum; i++) 7193 XClientMessage(display,windows->image.id,windows->im_protocols, 7194 windows->im_former_image,CurrentTime); 7195 break; 7196 } 7197 case SelectCommand: 7198 { 7199 int 7200 status; 7201 7202 /* 7203 Select image. 7204 */ 7205 if (*resource_info->home_directory == '\0') 7206 (void) CopyMagickString(resource_info->home_directory,".", 7207 MaxTextExtent); 7208 status=chdir(resource_info->home_directory); 7209 if (status == -1) 7210 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 7211 "UnableToOpenFile","%s",resource_info->home_directory); 7212 nexus=XOpenImage(display,resource_info,windows,MagickTrue); 7213 break; 7214 } 7215 case SaveCommand: 7216 { 7217 /* 7218 Save image. 7219 */ 7220 status=XSaveImage(display,resource_info,windows,*image,exception); 7221 if (IfMagickFalse(status) ) 7222 { 7223 char 7224 message[MaxTextExtent]; 7225 7226 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7227 exception->reason != (char *) NULL ? exception->reason : "", 7228 exception->description != (char *) NULL ? exception->description : 7229 ""); 7230 XNoticeWidget(display,windows,"Unable to save file:",message); 7231 break; 7232 } 7233 break; 7234 } 7235 case PrintCommand: 7236 { 7237 /* 7238 Print image. 7239 */ 7240 status=XPrintImage(display,resource_info,windows,*image,exception); 7241 if (IfMagickFalse(status) ) 7242 { 7243 char 7244 message[MaxTextExtent]; 7245 7246 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7247 exception->reason != (char *) NULL ? exception->reason : "", 7248 exception->description != (char *) NULL ? exception->description : 7249 ""); 7250 XNoticeWidget(display,windows,"Unable to print file:",message); 7251 break; 7252 } 7253 break; 7254 } 7255 case DeleteCommand: 7256 { 7257 static char 7258 filename[MaxTextExtent] = "\0"; 7259 7260 /* 7261 Delete image file. 7262 */ 7263 XFileBrowserWidget(display,windows,"Delete",filename); 7264 if (*filename == '\0') 7265 break; 7266 status=ShredFile(filename); 7267 if (IfMagickTrue(status) ) 7268 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7269 break; 7270 } 7271 case NewCommand: 7272 { 7273 int 7274 status; 7275 7276 static char 7277 color[MaxTextExtent] = "gray", 7278 geometry[MaxTextExtent] = "640x480"; 7279 7280 static const char 7281 *format = "gradient"; 7282 7283 /* 7284 Query user for canvas geometry. 7285 */ 7286 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7287 geometry); 7288 if (*geometry == '\0') 7289 break; 7290 if (status == 0) 7291 format="xc"; 7292 XColorBrowserWidget(display,windows,"Select",color); 7293 if (*color == '\0') 7294 break; 7295 /* 7296 Create canvas. 7297 */ 7298 (void) FormatLocaleString(image_info->filename,MaxTextExtent, 7299 "%s:%s",format,color); 7300 (void) CloneString(&image_info->size,geometry); 7301 nexus=ReadImage(image_info,exception); 7302 CatchException(exception); 7303 XClientMessage(display,windows->image.id,windows->im_protocols, 7304 windows->im_next_image,CurrentTime); 7305 break; 7306 } 7307 case VisualDirectoryCommand: 7308 { 7309 /* 7310 Visual Image directory. 7311 */ 7312 nexus=XVisualDirectoryImage(display,resource_info,windows,exception); 7313 break; 7314 } 7315 case QuitCommand: 7316 { 7317 /* 7318 exit program. 7319 */ 7320 if (IfMagickFalse(resource_info->confirm_exit) ) 7321 XClientMessage(display,windows->image.id,windows->im_protocols, 7322 windows->im_exit,CurrentTime); 7323 else 7324 { 7325 int 7326 status; 7327 7328 /* 7329 Confirm program exit. 7330 */ 7331 status=XConfirmWidget(display,windows,"Do you really want to exit", 7332 resource_info->client_name); 7333 if (status > 0) 7334 XClientMessage(display,windows->image.id,windows->im_protocols, 7335 windows->im_exit,CurrentTime); 7336 } 7337 break; 7338 } 7339 case CutCommand: 7340 { 7341 /* 7342 Cut image. 7343 */ 7344 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception); 7345 break; 7346 } 7347 case CopyCommand: 7348 { 7349 /* 7350 Copy image. 7351 */ 7352 (void) XCropImage(display,resource_info,windows,*image,CopyMode, 7353 exception); 7354 break; 7355 } 7356 case PasteCommand: 7357 { 7358 /* 7359 Paste image. 7360 */ 7361 status=XPasteImage(display,resource_info,windows,*image,exception); 7362 if (IfMagickFalse(status) ) 7363 { 7364 XNoticeWidget(display,windows,"Unable to paste X image", 7365 (*image)->filename); 7366 break; 7367 } 7368 break; 7369 } 7370 case HalfSizeCommand: 7371 { 7372 /* 7373 Half image size. 7374 */ 7375 windows->image.window_changes.width=windows->image.ximage->width/2; 7376 windows->image.window_changes.height=windows->image.ximage->height/2; 7377 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7378 break; 7379 } 7380 case OriginalSizeCommand: 7381 { 7382 /* 7383 Original image size. 7384 */ 7385 windows->image.window_changes.width=(int) (*image)->columns; 7386 windows->image.window_changes.height=(int) (*image)->rows; 7387 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7388 break; 7389 } 7390 case DoubleSizeCommand: 7391 { 7392 /* 7393 Double the image size. 7394 */ 7395 windows->image.window_changes.width=windows->image.ximage->width << 1; 7396 windows->image.window_changes.height=windows->image.ximage->height << 1; 7397 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7398 break; 7399 } 7400 case ResizeCommand: 7401 { 7402 int 7403 status; 7404 7405 size_t 7406 height, 7407 width; 7408 7409 ssize_t 7410 x, 7411 y; 7412 7413 /* 7414 Resize image. 7415 */ 7416 width=(size_t) windows->image.ximage->width; 7417 height=(size_t) windows->image.ximage->height; 7418 x=0; 7419 y=0; 7420 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0", 7421 (double) width,(double) height); 7422 status=XDialogWidget(display,windows,"Resize", 7423 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7424 if (*geometry == '\0') 7425 break; 7426 if (status == 0) 7427 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent); 7428 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7429 windows->image.window_changes.width=(int) width; 7430 windows->image.window_changes.height=(int) height; 7431 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7432 break; 7433 } 7434 case ApplyCommand: 7435 { 7436 char 7437 image_geometry[MaxTextExtent]; 7438 7439 if ((windows->image.crop_geometry == (char *) NULL) && 7440 ((int) (*image)->columns == windows->image.ximage->width) && 7441 ((int) (*image)->rows == windows->image.ximage->height)) 7442 break; 7443 /* 7444 Apply size transforms to image. 7445 */ 7446 XSetCursorState(display,windows,MagickTrue); 7447 XCheckRefreshWindows(display,windows); 7448 /* 7449 Crop and/or scale displayed image. 7450 */ 7451 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 7452 windows->image.ximage->width,windows->image.ximage->height); 7453 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 7454 exception); 7455 if (windows->image.crop_geometry != (char *) NULL) 7456 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 7457 windows->image.crop_geometry); 7458 windows->image.x=0; 7459 windows->image.y=0; 7460 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7461 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7462 break; 7463 } 7464 case RefreshCommand: 7465 { 7466 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7467 break; 7468 } 7469 case RestoreCommand: 7470 { 7471 /* 7472 Restore Image window to its original size. 7473 */ 7474 if ((windows->image.width == (unsigned int) (*image)->columns) && 7475 (windows->image.height == (unsigned int) (*image)->rows) && 7476 (windows->image.crop_geometry == (char *) NULL)) 7477 { 7478 (void) XBell(display,0); 7479 break; 7480 } 7481 windows->image.window_changes.width=(int) (*image)->columns; 7482 windows->image.window_changes.height=(int) (*image)->rows; 7483 if (windows->image.crop_geometry != (char *) NULL) 7484 { 7485 windows->image.crop_geometry=(char *) 7486 RelinquishMagickMemory(windows->image.crop_geometry); 7487 windows->image.crop_geometry=(char *) NULL; 7488 windows->image.x=0; 7489 windows->image.y=0; 7490 } 7491 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7492 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7493 break; 7494 } 7495 case CropCommand: 7496 { 7497 /* 7498 Crop image. 7499 */ 7500 (void) XCropImage(display,resource_info,windows,*image,CropMode, 7501 exception); 7502 break; 7503 } 7504 case ChopCommand: 7505 { 7506 /* 7507 Chop image. 7508 */ 7509 status=XChopImage(display,resource_info,windows,image,exception); 7510 if (IfMagickFalse(status) ) 7511 { 7512 XNoticeWidget(display,windows,"Unable to cut X image", 7513 (*image)->filename); 7514 break; 7515 } 7516 break; 7517 } 7518 case FlopCommand: 7519 { 7520 Image 7521 *flop_image; 7522 7523 /* 7524 Flop image scanlines. 7525 */ 7526 XSetCursorState(display,windows,MagickTrue); 7527 XCheckRefreshWindows(display,windows); 7528 flop_image=FlopImage(*image,exception); 7529 if (flop_image != (Image *) NULL) 7530 { 7531 *image=DestroyImage(*image); 7532 *image=flop_image; 7533 } 7534 CatchException(exception); 7535 XSetCursorState(display,windows,MagickFalse); 7536 if (windows->image.crop_geometry != (char *) NULL) 7537 { 7538 /* 7539 Flop crop geometry. 7540 */ 7541 width=(unsigned int) (*image)->columns; 7542 height=(unsigned int) (*image)->rows; 7543 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7544 &width,&height); 7545 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7546 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7547 } 7548 if (IfMagickTrue(windows->image.orphan) ) 7549 break; 7550 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7551 break; 7552 } 7553 case FlipCommand: 7554 { 7555 Image 7556 *flip_image; 7557 7558 /* 7559 Flip image scanlines. 7560 */ 7561 XSetCursorState(display,windows,MagickTrue); 7562 XCheckRefreshWindows(display,windows); 7563 flip_image=FlipImage(*image,exception); 7564 if (flip_image != (Image *) NULL) 7565 { 7566 *image=DestroyImage(*image); 7567 *image=flip_image; 7568 } 7569 CatchException(exception); 7570 XSetCursorState(display,windows,MagickFalse); 7571 if (windows->image.crop_geometry != (char *) NULL) 7572 { 7573 /* 7574 Flip crop geometry. 7575 */ 7576 width=(unsigned int) (*image)->columns; 7577 height=(unsigned int) (*image)->rows; 7578 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7579 &width,&height); 7580 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7581 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7582 } 7583 if (IfMagickTrue(windows->image.orphan) ) 7584 break; 7585 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7586 break; 7587 } 7588 case RotateRightCommand: 7589 { 7590 /* 7591 Rotate image 90 degrees clockwise. 7592 */ 7593 status=XRotateImage(display,resource_info,windows,90.0,image,exception); 7594 if (IfMagickFalse(status) ) 7595 { 7596 XNoticeWidget(display,windows,"Unable to rotate X image", 7597 (*image)->filename); 7598 break; 7599 } 7600 break; 7601 } 7602 case RotateLeftCommand: 7603 { 7604 /* 7605 Rotate image 90 degrees counter-clockwise. 7606 */ 7607 status=XRotateImage(display,resource_info,windows,-90.0,image,exception); 7608 if (IfMagickFalse(status) ) 7609 { 7610 XNoticeWidget(display,windows,"Unable to rotate X image", 7611 (*image)->filename); 7612 break; 7613 } 7614 break; 7615 } 7616 case RotateCommand: 7617 { 7618 /* 7619 Rotate image. 7620 */ 7621 status=XRotateImage(display,resource_info,windows,0.0,image,exception); 7622 if (IfMagickFalse(status) ) 7623 { 7624 XNoticeWidget(display,windows,"Unable to rotate X image", 7625 (*image)->filename); 7626 break; 7627 } 7628 break; 7629 } 7630 case ShearCommand: 7631 { 7632 Image 7633 *shear_image; 7634 7635 static char 7636 geometry[MaxTextExtent] = "45.0x45.0"; 7637 7638 /* 7639 Query user for shear color and geometry. 7640 */ 7641 XColorBrowserWidget(display,windows,"Select",color); 7642 if (*color == '\0') 7643 break; 7644 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7645 geometry); 7646 if (*geometry == '\0') 7647 break; 7648 /* 7649 Shear image. 7650 */ 7651 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7652 exception); 7653 XSetCursorState(display,windows,MagickTrue); 7654 XCheckRefreshWindows(display,windows); 7655 (void) QueryColorCompliance(color,AllCompliance, 7656 &(*image)->background_color,exception); 7657 flags=ParseGeometry(geometry,&geometry_info); 7658 if ((flags & SigmaValue) == 0) 7659 geometry_info.sigma=geometry_info.rho; 7660 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7661 exception); 7662 if (shear_image != (Image *) NULL) 7663 { 7664 *image=DestroyImage(*image); 7665 *image=shear_image; 7666 } 7667 CatchException(exception); 7668 XSetCursorState(display,windows,MagickFalse); 7669 if (IfMagickTrue(windows->image.orphan) ) 7670 break; 7671 windows->image.window_changes.width=(int) (*image)->columns; 7672 windows->image.window_changes.height=(int) (*image)->rows; 7673 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7674 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7675 break; 7676 } 7677 case RollCommand: 7678 { 7679 Image 7680 *roll_image; 7681 7682 static char 7683 geometry[MaxTextExtent] = "+2+2"; 7684 7685 /* 7686 Query user for the roll geometry. 7687 */ 7688 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7689 geometry); 7690 if (*geometry == '\0') 7691 break; 7692 /* 7693 Roll image. 7694 */ 7695 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7696 exception); 7697 XSetCursorState(display,windows,MagickTrue); 7698 XCheckRefreshWindows(display,windows); 7699 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7700 exception); 7701 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7702 exception); 7703 if (roll_image != (Image *) NULL) 7704 { 7705 *image=DestroyImage(*image); 7706 *image=roll_image; 7707 } 7708 CatchException(exception); 7709 XSetCursorState(display,windows,MagickFalse); 7710 if (IfMagickTrue(windows->image.orphan) ) 7711 break; 7712 windows->image.window_changes.width=(int) (*image)->columns; 7713 windows->image.window_changes.height=(int) (*image)->rows; 7714 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7715 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7716 break; 7717 } 7718 case TrimCommand: 7719 { 7720 static char 7721 fuzz[MaxTextExtent]; 7722 7723 /* 7724 Query user for the fuzz factor. 7725 */ 7726 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0* 7727 (*image)->fuzz/(QuantumRange+1.0)); 7728 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7729 if (*fuzz == '\0') 7730 break; 7731 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0); 7732 /* 7733 Trim image. 7734 */ 7735 status=XTrimImage(display,resource_info,windows,*image,exception); 7736 if (IfMagickFalse(status) ) 7737 { 7738 XNoticeWidget(display,windows,"Unable to trim X image", 7739 (*image)->filename); 7740 break; 7741 } 7742 break; 7743 } 7744 case HueCommand: 7745 { 7746 static char 7747 hue_percent[MaxTextExtent] = "110"; 7748 7749 /* 7750 Query user for percent hue change. 7751 */ 7752 (void) XDialogWidget(display,windows,"Apply", 7753 "Enter percent change in image hue (0-200):",hue_percent); 7754 if (*hue_percent == '\0') 7755 break; 7756 /* 7757 Vary the image hue. 7758 */ 7759 XSetCursorState(display,windows,MagickTrue); 7760 XCheckRefreshWindows(display,windows); 7761 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent); 7762 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7763 MaxTextExtent); 7764 (void) ModulateImage(*image,modulate_factors,exception); 7765 XSetCursorState(display,windows,MagickFalse); 7766 if (IfMagickTrue(windows->image.orphan) ) 7767 break; 7768 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7769 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7770 break; 7771 } 7772 case SaturationCommand: 7773 { 7774 static char 7775 saturation_percent[MaxTextExtent] = "110"; 7776 7777 /* 7778 Query user for percent saturation change. 7779 */ 7780 (void) XDialogWidget(display,windows,"Apply", 7781 "Enter percent change in color saturation (0-200):",saturation_percent); 7782 if (*saturation_percent == '\0') 7783 break; 7784 /* 7785 Vary color saturation. 7786 */ 7787 XSetCursorState(display,windows,MagickTrue); 7788 XCheckRefreshWindows(display,windows); 7789 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent); 7790 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7791 MaxTextExtent); 7792 (void) ModulateImage(*image,modulate_factors,exception); 7793 XSetCursorState(display,windows,MagickFalse); 7794 if (IfMagickTrue(windows->image.orphan) ) 7795 break; 7796 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7797 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7798 break; 7799 } 7800 case BrightnessCommand: 7801 { 7802 static char 7803 brightness_percent[MaxTextExtent] = "110"; 7804 7805 /* 7806 Query user for percent brightness change. 7807 */ 7808 (void) XDialogWidget(display,windows,"Apply", 7809 "Enter percent change in color brightness (0-200):",brightness_percent); 7810 if (*brightness_percent == '\0') 7811 break; 7812 /* 7813 Vary the color brightness. 7814 */ 7815 XSetCursorState(display,windows,MagickTrue); 7816 XCheckRefreshWindows(display,windows); 7817 (void) CopyMagickString(modulate_factors,brightness_percent, 7818 MaxTextExtent); 7819 (void) ModulateImage(*image,modulate_factors,exception); 7820 XSetCursorState(display,windows,MagickFalse); 7821 if (IfMagickTrue(windows->image.orphan) ) 7822 break; 7823 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7824 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7825 break; 7826 } 7827 case GammaCommand: 7828 { 7829 static char 7830 factor[MaxTextExtent] = "1.6"; 7831 7832 /* 7833 Query user for gamma value. 7834 */ 7835 (void) XDialogWidget(display,windows,"Gamma", 7836 "Enter gamma value (e.g. 1.2):",factor); 7837 if (*factor == '\0') 7838 break; 7839 /* 7840 Gamma correct image. 7841 */ 7842 XSetCursorState(display,windows,MagickTrue); 7843 XCheckRefreshWindows(display,windows); 7844 (void) GammaImage(*image,atof(factor),exception); 7845 XSetCursorState(display,windows,MagickFalse); 7846 if (IfMagickTrue(windows->image.orphan) ) 7847 break; 7848 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7849 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7850 break; 7851 } 7852 case SpiffCommand: 7853 { 7854 /* 7855 Sharpen the image contrast. 7856 */ 7857 XSetCursorState(display,windows,MagickTrue); 7858 XCheckRefreshWindows(display,windows); 7859 (void) ContrastImage(*image,MagickTrue,exception); 7860 XSetCursorState(display,windows,MagickFalse); 7861 if (IfMagickTrue(windows->image.orphan) ) 7862 break; 7863 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7864 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7865 break; 7866 } 7867 case DullCommand: 7868 { 7869 /* 7870 Dull the image contrast. 7871 */ 7872 XSetCursorState(display,windows,MagickTrue); 7873 XCheckRefreshWindows(display,windows); 7874 (void) ContrastImage(*image,MagickFalse,exception); 7875 XSetCursorState(display,windows,MagickFalse); 7876 if (IfMagickTrue(windows->image.orphan) ) 7877 break; 7878 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7879 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7880 break; 7881 } 7882 case ContrastStretchCommand: 7883 { 7884 double 7885 black_point, 7886 white_point; 7887 7888 static char 7889 levels[MaxTextExtent] = "1%"; 7890 7891 /* 7892 Query user for gamma value. 7893 */ 7894 (void) XDialogWidget(display,windows,"Contrast Stretch", 7895 "Enter black and white points:",levels); 7896 if (*levels == '\0') 7897 break; 7898 /* 7899 Contrast stretch image. 7900 */ 7901 XSetCursorState(display,windows,MagickTrue); 7902 XCheckRefreshWindows(display,windows); 7903 flags=ParseGeometry(levels,&geometry_info); 7904 black_point=geometry_info.rho; 7905 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7906 if ((flags & PercentValue) != 0) 7907 { 7908 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7909 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7910 } 7911 white_point=(double) (*image)->columns*(*image)->rows-white_point; 7912 (void) ContrastStretchImage(*image,black_point,white_point, 7913 exception); 7914 XSetCursorState(display,windows,MagickFalse); 7915 if (IfMagickTrue(windows->image.orphan) ) 7916 break; 7917 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7918 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7919 break; 7920 } 7921 case SigmoidalContrastCommand: 7922 { 7923 GeometryInfo 7924 geometry_info; 7925 7926 MagickStatusType 7927 flags; 7928 7929 static char 7930 levels[MaxTextExtent] = "3x50%"; 7931 7932 /* 7933 Query user for gamma value. 7934 */ 7935 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7936 "Enter contrast and midpoint:",levels); 7937 if (*levels == '\0') 7938 break; 7939 /* 7940 Contrast stretch image. 7941 */ 7942 XSetCursorState(display,windows,MagickTrue); 7943 XCheckRefreshWindows(display,windows); 7944 flags=ParseGeometry(levels,&geometry_info); 7945 if ((flags & SigmaValue) == 0) 7946 geometry_info.sigma=1.0*QuantumRange/2.0; 7947 if ((flags & PercentValue) != 0) 7948 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0; 7949 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho, 7950 geometry_info.sigma,exception); 7951 XSetCursorState(display,windows,MagickFalse); 7952 if (IfMagickTrue(windows->image.orphan) ) 7953 break; 7954 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7955 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7956 break; 7957 } 7958 case NormalizeCommand: 7959 { 7960 /* 7961 Perform histogram normalization on the image. 7962 */ 7963 XSetCursorState(display,windows,MagickTrue); 7964 XCheckRefreshWindows(display,windows); 7965 (void) NormalizeImage(*image,exception); 7966 XSetCursorState(display,windows,MagickFalse); 7967 if (IfMagickTrue(windows->image.orphan) ) 7968 break; 7969 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7970 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7971 break; 7972 } 7973 case EqualizeCommand: 7974 { 7975 /* 7976 Perform histogram equalization on the image. 7977 */ 7978 XSetCursorState(display,windows,MagickTrue); 7979 XCheckRefreshWindows(display,windows); 7980 (void) EqualizeImage(*image,exception); 7981 XSetCursorState(display,windows,MagickFalse); 7982 if (IfMagickTrue(windows->image.orphan) ) 7983 break; 7984 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7985 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7986 break; 7987 } 7988 case NegateCommand: 7989 { 7990 /* 7991 Negate colors in image. 7992 */ 7993 XSetCursorState(display,windows,MagickTrue); 7994 XCheckRefreshWindows(display,windows); 7995 (void) NegateImage(*image,MagickFalse,exception); 7996 XSetCursorState(display,windows,MagickFalse); 7997 if (IfMagickTrue(windows->image.orphan) ) 7998 break; 7999 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8000 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8001 break; 8002 } 8003 case GrayscaleCommand: 8004 { 8005 /* 8006 Convert image to grayscale. 8007 */ 8008 XSetCursorState(display,windows,MagickTrue); 8009 XCheckRefreshWindows(display,windows); 8010 (void) SetImageType(*image,(*image)->alpha_trait != BlendPixelTrait ? 8011 GrayscaleType : GrayscaleMatteType,exception); 8012 XSetCursorState(display,windows,MagickFalse); 8013 if (IfMagickTrue(windows->image.orphan) ) 8014 break; 8015 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8016 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8017 break; 8018 } 8019 case MapCommand: 8020 { 8021 Image 8022 *affinity_image; 8023 8024 static char 8025 filename[MaxTextExtent] = "\0"; 8026 8027 /* 8028 Request image file name from user. 8029 */ 8030 XFileBrowserWidget(display,windows,"Map",filename); 8031 if (*filename == '\0') 8032 break; 8033 /* 8034 Map image. 8035 */ 8036 XSetCursorState(display,windows,MagickTrue); 8037 XCheckRefreshWindows(display,windows); 8038 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 8039 affinity_image=ReadImage(image_info,exception); 8040 if (affinity_image != (Image *) NULL) 8041 { 8042 (void) RemapImage(&quantize_info,*image,affinity_image,exception); 8043 affinity_image=DestroyImage(affinity_image); 8044 } 8045 CatchException(exception); 8046 XSetCursorState(display,windows,MagickFalse); 8047 if (IfMagickTrue(windows->image.orphan) ) 8048 break; 8049 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8050 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8051 break; 8052 } 8053 case QuantizeCommand: 8054 { 8055 int 8056 status; 8057 8058 static char 8059 colors[MaxTextExtent] = "256"; 8060 8061 /* 8062 Query user for maximum number of colors. 8063 */ 8064 status=XDialogWidget(display,windows,"Quantize", 8065 "Maximum number of colors:",colors); 8066 if (*colors == '\0') 8067 break; 8068 /* 8069 Color reduce the image. 8070 */ 8071 XSetCursorState(display,windows,MagickTrue); 8072 XCheckRefreshWindows(display,windows); 8073 quantize_info.number_colors=StringToUnsignedLong(colors); 8074 quantize_info.dither_method=status != 0 ? RiemersmaDitherMethod : 8075 NoDitherMethod; 8076 (void) QuantizeImage(&quantize_info,*image,exception); 8077 XSetCursorState(display,windows,MagickFalse); 8078 if (IfMagickTrue(windows->image.orphan) ) 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 (IfMagickTrue(windows->image.orphan) ) 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 (IfMagickTrue(windows->image.orphan) ) 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 (IfMagickTrue(windows->image.orphan) ) 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 (IfMagickTrue(windows->image.orphan) ) 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 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 (IfMagickTrue(windows->image.orphan) ) 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 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 (IfMagickTrue(windows->image.orphan) ) 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 (IfMagickTrue(windows->image.orphan) ) 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,exception); 8345 if (edge_image != (Image *) NULL) 8346 { 8347 *image=DestroyImage(*image); 8348 *image=edge_image; 8349 } 8350 CatchException(exception); 8351 XSetCursorState(display,windows,MagickFalse); 8352 if (IfMagickTrue(windows->image.orphan) ) 8353 break; 8354 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8355 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8356 break; 8357 } 8358 case SpreadCommand: 8359 { 8360 Image 8361 *spread_image; 8362 8363 static char 8364 amount[MaxTextExtent] = "2"; 8365 8366 /* 8367 Query user for spread amount. 8368 */ 8369 (void) XDialogWidget(display,windows,"Spread", 8370 "Enter the displacement amount:",amount); 8371 if (*amount == '\0') 8372 break; 8373 /* 8374 Displace image pixels by a random amount. 8375 */ 8376 XSetCursorState(display,windows,MagickTrue); 8377 XCheckRefreshWindows(display,windows); 8378 flags=ParseGeometry(amount,&geometry_info); 8379 spread_image=EdgeImage(*image,geometry_info.rho,exception); 8380 if (spread_image != (Image *) NULL) 8381 { 8382 *image=DestroyImage(*image); 8383 *image=spread_image; 8384 } 8385 CatchException(exception); 8386 XSetCursorState(display,windows,MagickFalse); 8387 if (IfMagickTrue(windows->image.orphan) ) 8388 break; 8389 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8390 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8391 break; 8392 } 8393 case ShadeCommand: 8394 { 8395 Image 8396 *shade_image; 8397 8398 int 8399 status; 8400 8401 static char 8402 geometry[MaxTextExtent] = "30x30"; 8403 8404 /* 8405 Query user for the shade geometry. 8406 */ 8407 status=XDialogWidget(display,windows,"Shade", 8408 "Enter the azimuth and elevation of the light source:",geometry); 8409 if (*geometry == '\0') 8410 break; 8411 /* 8412 Shade image pixels. 8413 */ 8414 XSetCursorState(display,windows,MagickTrue); 8415 XCheckRefreshWindows(display,windows); 8416 flags=ParseGeometry(geometry,&geometry_info); 8417 if ((flags & SigmaValue) == 0) 8418 geometry_info.sigma=1.0; 8419 shade_image=ShadeImage(*image,IsMagickTrue(status), 8420 geometry_info.rho,geometry_info.sigma,exception); 8421 if (shade_image != (Image *) NULL) 8422 { 8423 *image=DestroyImage(*image); 8424 *image=shade_image; 8425 } 8426 CatchException(exception); 8427 XSetCursorState(display,windows,MagickFalse); 8428 if (IfMagickTrue(windows->image.orphan) ) 8429 break; 8430 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8431 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8432 break; 8433 } 8434 case RaiseCommand: 8435 { 8436 static char 8437 bevel_width[MaxTextExtent] = "10"; 8438 8439 /* 8440 Query user for bevel width. 8441 */ 8442 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8443 if (*bevel_width == '\0') 8444 break; 8445 /* 8446 Raise an image. 8447 */ 8448 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8449 exception); 8450 XSetCursorState(display,windows,MagickTrue); 8451 XCheckRefreshWindows(display,windows); 8452 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8453 exception); 8454 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception); 8455 XSetCursorState(display,windows,MagickFalse); 8456 if (IfMagickTrue(windows->image.orphan) ) 8457 break; 8458 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8459 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8460 break; 8461 } 8462 case SegmentCommand: 8463 { 8464 static char 8465 threshold[MaxTextExtent] = "1.0x1.5"; 8466 8467 /* 8468 Query user for smoothing threshold. 8469 */ 8470 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8471 threshold); 8472 if (*threshold == '\0') 8473 break; 8474 /* 8475 Segment an image. 8476 */ 8477 XSetCursorState(display,windows,MagickTrue); 8478 XCheckRefreshWindows(display,windows); 8479 flags=ParseGeometry(threshold,&geometry_info); 8480 if ((flags & SigmaValue) == 0) 8481 geometry_info.sigma=1.0; 8482 (void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho, 8483 geometry_info.sigma,exception); 8484 XSetCursorState(display,windows,MagickFalse); 8485 if (IfMagickTrue(windows->image.orphan) ) 8486 break; 8487 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8488 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8489 break; 8490 } 8491 case SepiaToneCommand: 8492 { 8493 double 8494 threshold; 8495 8496 Image 8497 *sepia_image; 8498 8499 static char 8500 factor[MaxTextExtent] = "80%"; 8501 8502 /* 8503 Query user for sepia-tone factor. 8504 */ 8505 (void) XDialogWidget(display,windows,"Sepia Tone", 8506 "Enter the sepia tone factor (0 - 99.9%):",factor); 8507 if (*factor == '\0') 8508 break; 8509 /* 8510 Sepia tone image pixels. 8511 */ 8512 XSetCursorState(display,windows,MagickTrue); 8513 XCheckRefreshWindows(display,windows); 8514 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8515 sepia_image=SepiaToneImage(*image,threshold,exception); 8516 if (sepia_image != (Image *) NULL) 8517 { 8518 *image=DestroyImage(*image); 8519 *image=sepia_image; 8520 } 8521 CatchException(exception); 8522 XSetCursorState(display,windows,MagickFalse); 8523 if (IfMagickTrue(windows->image.orphan) ) 8524 break; 8525 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8526 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8527 break; 8528 } 8529 case SolarizeCommand: 8530 { 8531 double 8532 threshold; 8533 8534 static char 8535 factor[MaxTextExtent] = "60%"; 8536 8537 /* 8538 Query user for solarize factor. 8539 */ 8540 (void) XDialogWidget(display,windows,"Solarize", 8541 "Enter the solarize factor (0 - 99.9%):",factor); 8542 if (*factor == '\0') 8543 break; 8544 /* 8545 Solarize image pixels. 8546 */ 8547 XSetCursorState(display,windows,MagickTrue); 8548 XCheckRefreshWindows(display,windows); 8549 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8550 (void) SolarizeImage(*image,threshold,exception); 8551 XSetCursorState(display,windows,MagickFalse); 8552 if (IfMagickTrue(windows->image.orphan) ) 8553 break; 8554 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8555 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8556 break; 8557 } 8558 case SwirlCommand: 8559 { 8560 Image 8561 *swirl_image; 8562 8563 static char 8564 degrees[MaxTextExtent] = "60"; 8565 8566 /* 8567 Query user for swirl angle. 8568 */ 8569 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8570 degrees); 8571 if (*degrees == '\0') 8572 break; 8573 /* 8574 Swirl image pixels about the center. 8575 */ 8576 XSetCursorState(display,windows,MagickTrue); 8577 XCheckRefreshWindows(display,windows); 8578 flags=ParseGeometry(degrees,&geometry_info); 8579 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate, 8580 exception); 8581 if (swirl_image != (Image *) NULL) 8582 { 8583 *image=DestroyImage(*image); 8584 *image=swirl_image; 8585 } 8586 CatchException(exception); 8587 XSetCursorState(display,windows,MagickFalse); 8588 if (IfMagickTrue(windows->image.orphan) ) 8589 break; 8590 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8591 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8592 break; 8593 } 8594 case ImplodeCommand: 8595 { 8596 Image 8597 *implode_image; 8598 8599 static char 8600 factor[MaxTextExtent] = "0.3"; 8601 8602 /* 8603 Query user for implode factor. 8604 */ 8605 (void) XDialogWidget(display,windows,"Implode", 8606 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8607 if (*factor == '\0') 8608 break; 8609 /* 8610 Implode image pixels about the center. 8611 */ 8612 XSetCursorState(display,windows,MagickTrue); 8613 XCheckRefreshWindows(display,windows); 8614 flags=ParseGeometry(factor,&geometry_info); 8615 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate, 8616 exception); 8617 if (implode_image != (Image *) NULL) 8618 { 8619 *image=DestroyImage(*image); 8620 *image=implode_image; 8621 } 8622 CatchException(exception); 8623 XSetCursorState(display,windows,MagickFalse); 8624 if (IfMagickTrue(windows->image.orphan) ) 8625 break; 8626 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8627 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8628 break; 8629 } 8630 case VignetteCommand: 8631 { 8632 Image 8633 *vignette_image; 8634 8635 static char 8636 geometry[MaxTextExtent] = "0x20"; 8637 8638 /* 8639 Query user for the vignette geometry. 8640 */ 8641 (void) XDialogWidget(display,windows,"Vignette", 8642 "Enter the radius, sigma, and x and y offsets:",geometry); 8643 if (*geometry == '\0') 8644 break; 8645 /* 8646 Soften the edges of the image in vignette style 8647 */ 8648 XSetCursorState(display,windows,MagickTrue); 8649 XCheckRefreshWindows(display,windows); 8650 flags=ParseGeometry(geometry,&geometry_info); 8651 if ((flags & SigmaValue) == 0) 8652 geometry_info.sigma=1.0; 8653 if ((flags & XiValue) == 0) 8654 geometry_info.xi=0.1*(*image)->columns; 8655 if ((flags & PsiValue) == 0) 8656 geometry_info.psi=0.1*(*image)->rows; 8657 vignette_image=VignetteImage(*image,geometry_info.rho,0.0,(ssize_t) 8658 ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5), 8659 exception); 8660 if (vignette_image != (Image *) NULL) 8661 { 8662 *image=DestroyImage(*image); 8663 *image=vignette_image; 8664 } 8665 CatchException(exception); 8666 XSetCursorState(display,windows,MagickFalse); 8667 if (IfMagickTrue(windows->image.orphan) ) 8668 break; 8669 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8670 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8671 break; 8672 } 8673 case WaveCommand: 8674 { 8675 Image 8676 *wave_image; 8677 8678 static char 8679 geometry[MaxTextExtent] = "25x150"; 8680 8681 /* 8682 Query user for the wave geometry. 8683 */ 8684 (void) XDialogWidget(display,windows,"Wave", 8685 "Enter the amplitude and length of the wave:",geometry); 8686 if (*geometry == '\0') 8687 break; 8688 /* 8689 Alter an image along a sine wave. 8690 */ 8691 XSetCursorState(display,windows,MagickTrue); 8692 XCheckRefreshWindows(display,windows); 8693 flags=ParseGeometry(geometry,&geometry_info); 8694 if ((flags & SigmaValue) == 0) 8695 geometry_info.sigma=1.0; 8696 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8697 (*image)->interpolate,exception); 8698 if (wave_image != (Image *) NULL) 8699 { 8700 *image=DestroyImage(*image); 8701 *image=wave_image; 8702 } 8703 CatchException(exception); 8704 XSetCursorState(display,windows,MagickFalse); 8705 if (IfMagickTrue(windows->image.orphan) ) 8706 break; 8707 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8708 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8709 break; 8710 } 8711 case OilPaintCommand: 8712 { 8713 Image 8714 *paint_image; 8715 8716 static char 8717 radius[MaxTextExtent] = "0"; 8718 8719 /* 8720 Query user for circular neighborhood radius. 8721 */ 8722 (void) XDialogWidget(display,windows,"Oil Paint", 8723 "Enter the mask radius:",radius); 8724 if (*radius == '\0') 8725 break; 8726 /* 8727 OilPaint image scanlines. 8728 */ 8729 XSetCursorState(display,windows,MagickTrue); 8730 XCheckRefreshWindows(display,windows); 8731 flags=ParseGeometry(radius,&geometry_info); 8732 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma, 8733 exception); 8734 if (paint_image != (Image *) NULL) 8735 { 8736 *image=DestroyImage(*image); 8737 *image=paint_image; 8738 } 8739 CatchException(exception); 8740 XSetCursorState(display,windows,MagickFalse); 8741 if (IfMagickTrue(windows->image.orphan) ) 8742 break; 8743 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8744 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8745 break; 8746 } 8747 case CharcoalDrawCommand: 8748 { 8749 Image 8750 *charcoal_image; 8751 8752 static char 8753 radius[MaxTextExtent] = "0x1"; 8754 8755 /* 8756 Query user for charcoal radius. 8757 */ 8758 (void) XDialogWidget(display,windows,"Charcoal Draw", 8759 "Enter the charcoal radius and sigma:",radius); 8760 if (*radius == '\0') 8761 break; 8762 /* 8763 Charcoal the image. 8764 */ 8765 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8766 exception); 8767 XSetCursorState(display,windows,MagickTrue); 8768 XCheckRefreshWindows(display,windows); 8769 flags=ParseGeometry(radius,&geometry_info); 8770 if ((flags & SigmaValue) == 0) 8771 geometry_info.sigma=geometry_info.rho; 8772 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8773 exception); 8774 if (charcoal_image != (Image *) NULL) 8775 { 8776 *image=DestroyImage(*image); 8777 *image=charcoal_image; 8778 } 8779 CatchException(exception); 8780 XSetCursorState(display,windows,MagickFalse); 8781 if (IfMagickTrue(windows->image.orphan) ) 8782 break; 8783 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8784 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8785 break; 8786 } 8787 case AnnotateCommand: 8788 { 8789 /* 8790 Annotate the image with text. 8791 */ 8792 status=XAnnotateEditImage(display,resource_info,windows,*image,exception); 8793 if (IfMagickFalse(status) ) 8794 { 8795 XNoticeWidget(display,windows,"Unable to annotate X image", 8796 (*image)->filename); 8797 break; 8798 } 8799 break; 8800 } 8801 case DrawCommand: 8802 { 8803 /* 8804 Draw image. 8805 */ 8806 status=XDrawEditImage(display,resource_info,windows,image,exception); 8807 if (IfMagickFalse(status) ) 8808 { 8809 XNoticeWidget(display,windows,"Unable to draw on the X image", 8810 (*image)->filename); 8811 break; 8812 } 8813 break; 8814 } 8815 case ColorCommand: 8816 { 8817 /* 8818 Color edit. 8819 */ 8820 status=XColorEditImage(display,resource_info,windows,image,exception); 8821 if (IfMagickFalse(status) ) 8822 { 8823 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8824 (*image)->filename); 8825 break; 8826 } 8827 break; 8828 } 8829 case MatteCommand: 8830 { 8831 /* 8832 Matte edit. 8833 */ 8834 status=XMatteEditImage(display,resource_info,windows,image,exception); 8835 if (IfMagickFalse(status) ) 8836 { 8837 XNoticeWidget(display,windows,"Unable to matte edit X image", 8838 (*image)->filename); 8839 break; 8840 } 8841 break; 8842 } 8843 case CompositeCommand: 8844 { 8845 /* 8846 Composite image. 8847 */ 8848 status=XCompositeImage(display,resource_info,windows,*image, 8849 exception); 8850 if (IfMagickFalse(status) ) 8851 { 8852 XNoticeWidget(display,windows,"Unable to composite X image", 8853 (*image)->filename); 8854 break; 8855 } 8856 break; 8857 } 8858 case AddBorderCommand: 8859 { 8860 Image 8861 *border_image; 8862 8863 static char 8864 geometry[MaxTextExtent] = "6x6"; 8865 8866 /* 8867 Query user for border color and geometry. 8868 */ 8869 XColorBrowserWidget(display,windows,"Select",color); 8870 if (*color == '\0') 8871 break; 8872 (void) XDialogWidget(display,windows,"Add Border", 8873 "Enter border geometry:",geometry); 8874 if (*geometry == '\0') 8875 break; 8876 /* 8877 Add a border to the image. 8878 */ 8879 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8880 exception); 8881 XSetCursorState(display,windows,MagickTrue); 8882 XCheckRefreshWindows(display,windows); 8883 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color, 8884 exception); 8885 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8886 exception); 8887 border_image=BorderImage(*image,&page_geometry,(*image)->compose, 8888 exception); 8889 if (border_image != (Image *) NULL) 8890 { 8891 *image=DestroyImage(*image); 8892 *image=border_image; 8893 } 8894 CatchException(exception); 8895 XSetCursorState(display,windows,MagickFalse); 8896 if (IfMagickTrue(windows->image.orphan) ) 8897 break; 8898 windows->image.window_changes.width=(int) (*image)->columns; 8899 windows->image.window_changes.height=(int) (*image)->rows; 8900 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8901 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8902 break; 8903 } 8904 case AddFrameCommand: 8905 { 8906 FrameInfo 8907 frame_info; 8908 8909 Image 8910 *frame_image; 8911 8912 static char 8913 geometry[MaxTextExtent] = "6x6"; 8914 8915 /* 8916 Query user for frame color and geometry. 8917 */ 8918 XColorBrowserWidget(display,windows,"Select",color); 8919 if (*color == '\0') 8920 break; 8921 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8922 geometry); 8923 if (*geometry == '\0') 8924 break; 8925 /* 8926 Surround image with an ornamental border. 8927 */ 8928 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8929 exception); 8930 XSetCursorState(display,windows,MagickTrue); 8931 XCheckRefreshWindows(display,windows); 8932 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color, 8933 exception); 8934 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8935 exception); 8936 frame_info.width=page_geometry.width; 8937 frame_info.height=page_geometry.height; 8938 frame_info.outer_bevel=page_geometry.x; 8939 frame_info.inner_bevel=page_geometry.y; 8940 frame_info.x=(ssize_t) frame_info.width; 8941 frame_info.y=(ssize_t) frame_info.height; 8942 frame_info.width=(*image)->columns+2*frame_info.width; 8943 frame_info.height=(*image)->rows+2*frame_info.height; 8944 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception); 8945 if (frame_image != (Image *) NULL) 8946 { 8947 *image=DestroyImage(*image); 8948 *image=frame_image; 8949 } 8950 CatchException(exception); 8951 XSetCursorState(display,windows,MagickFalse); 8952 if (IfMagickTrue(windows->image.orphan) ) 8953 break; 8954 windows->image.window_changes.width=(int) (*image)->columns; 8955 windows->image.window_changes.height=(int) (*image)->rows; 8956 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8957 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8958 break; 8959 } 8960 case CommentCommand: 8961 { 8962 const char 8963 *value; 8964 8965 FILE 8966 *file; 8967 8968 int 8969 unique_file; 8970 8971 /* 8972 Edit image comment. 8973 */ 8974 unique_file=AcquireUniqueFileResource(image_info->filename); 8975 if (unique_file == -1) 8976 XNoticeWidget(display,windows,"Unable to edit image comment", 8977 image_info->filename); 8978 value=GetImageProperty(*image,"comment",exception); 8979 if (value == (char *) NULL) 8980 unique_file=close(unique_file)-1; 8981 else 8982 { 8983 register const char 8984 *p; 8985 8986 file=fdopen(unique_file,"w"); 8987 if (file == (FILE *) NULL) 8988 { 8989 XNoticeWidget(display,windows,"Unable to edit image comment", 8990 image_info->filename); 8991 break; 8992 } 8993 for (p=value; *p != '\0'; p++) 8994 (void) fputc((int) *p,file); 8995 (void) fputc('\n',file); 8996 (void) fclose(file); 8997 } 8998 XSetCursorState(display,windows,MagickTrue); 8999 XCheckRefreshWindows(display,windows); 9000 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 9001 exception); 9002 if (IfMagickFalse(status) ) 9003 XNoticeWidget(display,windows,"Unable to edit image comment", 9004 (char *) NULL); 9005 else 9006 { 9007 char 9008 *comment; 9009 9010 comment=FileToString(image_info->filename,~0UL,exception); 9011 if (comment != (char *) NULL) 9012 { 9013 (void) SetImageProperty(*image,"comment",comment,exception); 9014 (*image)->taint=MagickTrue; 9015 } 9016 } 9017 (void) RelinquishUniqueFileResource(image_info->filename); 9018 XSetCursorState(display,windows,MagickFalse); 9019 break; 9020 } 9021 case LaunchCommand: 9022 { 9023 /* 9024 Launch program. 9025 */ 9026 XSetCursorState(display,windows,MagickTrue); 9027 XCheckRefreshWindows(display,windows); 9028 (void) AcquireUniqueFilename(filename); 9029 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s", 9030 filename); 9031 status=WriteImage(image_info,*image,exception); 9032 if (IfMagickFalse(status) ) 9033 XNoticeWidget(display,windows,"Unable to launch image editor", 9034 (char *) NULL); 9035 else 9036 { 9037 nexus=ReadImage(resource_info->image_info,exception); 9038 CatchException(exception); 9039 XClientMessage(display,windows->image.id,windows->im_protocols, 9040 windows->im_next_image,CurrentTime); 9041 } 9042 (void) RelinquishUniqueFileResource(filename); 9043 XSetCursorState(display,windows,MagickFalse); 9044 break; 9045 } 9046 case RegionofInterestCommand: 9047 { 9048 /* 9049 Apply an image processing technique to a region of interest. 9050 */ 9051 (void) XROIImage(display,resource_info,windows,image,exception); 9052 break; 9053 } 9054 case InfoCommand: 9055 break; 9056 case ZoomCommand: 9057 { 9058 /* 9059 Zoom image. 9060 */ 9061 if (IfMagickTrue(windows->magnify.mapped) ) 9062 (void) XRaiseWindow(display,windows->magnify.id); 9063 else 9064 { 9065 /* 9066 Make magnify image. 9067 */ 9068 XSetCursorState(display,windows,MagickTrue); 9069 (void) XMapRaised(display,windows->magnify.id); 9070 XSetCursorState(display,windows,MagickFalse); 9071 } 9072 break; 9073 } 9074 case ShowPreviewCommand: 9075 { 9076 char 9077 **previews; 9078 9079 Image 9080 *preview_image; 9081 9082 static char 9083 preview_type[MaxTextExtent] = "Gamma"; 9084 9085 /* 9086 Select preview type from menu. 9087 */ 9088 previews=GetCommandOptions(MagickPreviewOptions); 9089 if (previews == (char **) NULL) 9090 break; 9091 XListBrowserWidget(display,windows,&windows->widget, 9092 (const char **) previews,"Preview", 9093 "Select an enhancement, effect, or F/X:",preview_type); 9094 previews=DestroyStringList(previews); 9095 if (*preview_type == '\0') 9096 break; 9097 /* 9098 Show image preview. 9099 */ 9100 XSetCursorState(display,windows,MagickTrue); 9101 XCheckRefreshWindows(display,windows); 9102 image_info->preview_type=(PreviewType) 9103 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type); 9104 image_info->group=(ssize_t) windows->image.id; 9105 (void) DeleteImageProperty(*image,"label"); 9106 (void) SetImageProperty(*image,"label","Preview",exception); 9107 (void) AcquireUniqueFilename(filename); 9108 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s", 9109 filename); 9110 status=WriteImage(image_info,*image,exception); 9111 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9112 preview_image=ReadImage(image_info,exception); 9113 (void) RelinquishUniqueFileResource(filename); 9114 if (preview_image == (Image *) NULL) 9115 break; 9116 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s", 9117 filename); 9118 status=WriteImage(image_info,preview_image,exception); 9119 preview_image=DestroyImage(preview_image); 9120 if (IfMagickFalse(status) ) 9121 XNoticeWidget(display,windows,"Unable to show image preview", 9122 (*image)->filename); 9123 XDelay(display,1500); 9124 XSetCursorState(display,windows,MagickFalse); 9125 break; 9126 } 9127 case ShowHistogramCommand: 9128 { 9129 Image 9130 *histogram_image; 9131 9132 /* 9133 Show image histogram. 9134 */ 9135 XSetCursorState(display,windows,MagickTrue); 9136 XCheckRefreshWindows(display,windows); 9137 image_info->group=(ssize_t) windows->image.id; 9138 (void) DeleteImageProperty(*image,"label"); 9139 (void) SetImageProperty(*image,"label","Histogram",exception); 9140 (void) AcquireUniqueFilename(filename); 9141 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s", 9142 filename); 9143 status=WriteImage(image_info,*image,exception); 9144 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9145 histogram_image=ReadImage(image_info,exception); 9146 (void) RelinquishUniqueFileResource(filename); 9147 if (histogram_image == (Image *) NULL) 9148 break; 9149 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent, 9150 "show:%s",filename); 9151 status=WriteImage(image_info,histogram_image,exception); 9152 histogram_image=DestroyImage(histogram_image); 9153 if (IfMagickFalse(status) ) 9154 XNoticeWidget(display,windows,"Unable to show histogram", 9155 (*image)->filename); 9156 XDelay(display,1500); 9157 XSetCursorState(display,windows,MagickFalse); 9158 break; 9159 } 9160 case ShowMatteCommand: 9161 { 9162 Image 9163 *matte_image; 9164 9165 if ((*image)->alpha_trait != BlendPixelTrait) 9166 { 9167 XNoticeWidget(display,windows, 9168 "Image does not have any matte information",(*image)->filename); 9169 break; 9170 } 9171 /* 9172 Show image matte. 9173 */ 9174 XSetCursorState(display,windows,MagickTrue); 9175 XCheckRefreshWindows(display,windows); 9176 image_info->group=(ssize_t) windows->image.id; 9177 (void) DeleteImageProperty(*image,"label"); 9178 (void) SetImageProperty(*image,"label","Matte",exception); 9179 (void) AcquireUniqueFilename(filename); 9180 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s", 9181 filename); 9182 status=WriteImage(image_info,*image,exception); 9183 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9184 matte_image=ReadImage(image_info,exception); 9185 (void) RelinquishUniqueFileResource(filename); 9186 if (matte_image == (Image *) NULL) 9187 break; 9188 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s", 9189 filename); 9190 status=WriteImage(image_info,matte_image,exception); 9191 matte_image=DestroyImage(matte_image); 9192 if (IfMagickFalse(status) ) 9193 XNoticeWidget(display,windows,"Unable to show matte", 9194 (*image)->filename); 9195 XDelay(display,1500); 9196 XSetCursorState(display,windows,MagickFalse); 9197 break; 9198 } 9199 case BackgroundCommand: 9200 { 9201 /* 9202 Background image. 9203 */ 9204 status=XBackgroundImage(display,resource_info,windows,image,exception); 9205 if (IfMagickFalse(status) ) 9206 break; 9207 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9208 if (nexus != (Image *) NULL) 9209 XClientMessage(display,windows->image.id,windows->im_protocols, 9210 windows->im_next_image,CurrentTime); 9211 break; 9212 } 9213 case SlideShowCommand: 9214 { 9215 static char 9216 delay[MaxTextExtent] = "5"; 9217 9218 /* 9219 Display next image after pausing. 9220 */ 9221 (void) XDialogWidget(display,windows,"Slide Show", 9222 "Pause how many 1/100ths of a second between images:",delay); 9223 if (*delay == '\0') 9224 break; 9225 resource_info->delay=StringToUnsignedLong(delay); 9226 XClientMessage(display,windows->image.id,windows->im_protocols, 9227 windows->im_next_image,CurrentTime); 9228 break; 9229 } 9230 case PreferencesCommand: 9231 { 9232 /* 9233 Set user preferences. 9234 */ 9235 status=XPreferencesWidget(display,resource_info,windows); 9236 if (IfMagickFalse(status) ) 9237 break; 9238 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9239 if (nexus != (Image *) NULL) 9240 XClientMessage(display,windows->image.id,windows->im_protocols, 9241 windows->im_next_image,CurrentTime); 9242 break; 9243 } 9244 case HelpCommand: 9245 { 9246 /* 9247 User requested help. 9248 */ 9249 XTextViewWidget(display,resource_info,windows,MagickFalse, 9250 "Help Viewer - Display",DisplayHelp); 9251 break; 9252 } 9253 case BrowseDocumentationCommand: 9254 { 9255 Atom 9256 mozilla_atom; 9257 9258 Window 9259 mozilla_window, 9260 root_window; 9261 9262 /* 9263 Browse the ImageMagick documentation. 9264 */ 9265 root_window=XRootWindow(display,XDefaultScreen(display)); 9266 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); 9267 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); 9268 if (mozilla_window != (Window) NULL) 9269 { 9270 char 9271 command[MaxTextExtent], 9272 *url; 9273 9274 /* 9275 Display documentation using Netscape remote control. 9276 */ 9277 url=GetMagickHomeURL(); 9278 (void) FormatLocaleString(command,MaxTextExtent, 9279 "openurl(%s,new-tab)",url); 9280 url=DestroyString(url); 9281 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); 9282 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING, 9283 8,PropModeReplace,(unsigned char *) command,(int) strlen(command)); 9284 XSetCursorState(display,windows,MagickFalse); 9285 break; 9286 } 9287 XSetCursorState(display,windows,MagickTrue); 9288 XCheckRefreshWindows(display,windows); 9289 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL, 9290 exception); 9291 if (IfMagickFalse(status) ) 9292 XNoticeWidget(display,windows,"Unable to browse documentation", 9293 (char *) NULL); 9294 XDelay(display,1500); 9295 XSetCursorState(display,windows,MagickFalse); 9296 break; 9297 } 9298 case VersionCommand: 9299 { 9300 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), 9301 GetMagickCopyright()); 9302 break; 9303 } 9304 case SaveToUndoBufferCommand: 9305 break; 9306 default: 9307 { 9308 (void) XBell(display,0); 9309 break; 9310 } 9311 } 9312 image_info=DestroyImageInfo(image_info); 9313 return(nexus); 9314} 9315 9316/* 9317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9318% % 9319% % 9320% % 9321+ X M a g n i f y I m a g e % 9322% % 9323% % 9324% % 9325%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9326% 9327% XMagnifyImage() magnifies portions of the image as indicated by the pointer. 9328% The magnified portion is displayed in a separate window. 9329% 9330% The format of the XMagnifyImage method is: 9331% 9332% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9333% ExceptionInfo *exception) 9334% 9335% A description of each parameter follows: 9336% 9337% o display: Specifies a connection to an X server; returned from 9338% XOpenDisplay. 9339% 9340% o windows: Specifies a pointer to a XWindows structure. 9341% 9342% o event: Specifies a pointer to a XEvent structure. If it is NULL, 9343% the entire image is refreshed. 9344% 9345% o exception: return any errors or warnings in this structure. 9346% 9347*/ 9348static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9349 ExceptionInfo *exception) 9350{ 9351 char 9352 text[MaxTextExtent]; 9353 9354 register int 9355 x, 9356 y; 9357 9358 size_t 9359 state; 9360 9361 /* 9362 Update magnified image until the mouse button is released. 9363 */ 9364 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor); 9365 state=DefaultState; 9366 x=event->xbutton.x; 9367 y=event->xbutton.y; 9368 windows->magnify.x=(int) windows->image.x+x; 9369 windows->magnify.y=(int) windows->image.y+y; 9370 do 9371 { 9372 /* 9373 Map and unmap Info widget as text cursor crosses its boundaries. 9374 */ 9375 if (IfMagickTrue(windows->info.mapped) ) 9376 { 9377 if ((x < (int) (windows->info.x+windows->info.width)) && 9378 (y < (int) (windows->info.y+windows->info.height))) 9379 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 9380 } 9381 else 9382 if ((x > (int) (windows->info.x+windows->info.width)) || 9383 (y > (int) (windows->info.y+windows->info.height))) 9384 (void) XMapWindow(display,windows->info.id); 9385 if (IfMagickTrue(windows->info.mapped) ) 9386 { 9387 /* 9388 Display pointer position. 9389 */ 9390 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9391 windows->magnify.x,windows->magnify.y); 9392 XInfoWidget(display,windows,text); 9393 } 9394 /* 9395 Wait for next event. 9396 */ 9397 XScreenEvent(display,windows,event,exception); 9398 switch (event->type) 9399 { 9400 case ButtonPress: 9401 break; 9402 case ButtonRelease: 9403 { 9404 /* 9405 User has finished magnifying image. 9406 */ 9407 x=event->xbutton.x; 9408 y=event->xbutton.y; 9409 state|=ExitState; 9410 break; 9411 } 9412 case Expose: 9413 break; 9414 case MotionNotify: 9415 { 9416 x=event->xmotion.x; 9417 y=event->xmotion.y; 9418 break; 9419 } 9420 default: 9421 break; 9422 } 9423 /* 9424 Check boundary conditions. 9425 */ 9426 if (x < 0) 9427 x=0; 9428 else 9429 if (x >= (int) windows->image.width) 9430 x=(int) windows->image.width-1; 9431 if (y < 0) 9432 y=0; 9433 else 9434 if (y >= (int) windows->image.height) 9435 y=(int) windows->image.height-1; 9436 } while ((state & ExitState) == 0); 9437 /* 9438 Display magnified image. 9439 */ 9440 XSetCursorState(display,windows,MagickFalse); 9441} 9442 9443/* 9444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9445% % 9446% % 9447% % 9448+ X M a g n i f y W i n d o w C o m m a n d % 9449% % 9450% % 9451% % 9452%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9453% 9454% XMagnifyWindowCommand() moves the image within an Magnify window by one 9455% pixel as specified by the key symbol. 9456% 9457% The format of the XMagnifyWindowCommand method is: 9458% 9459% void XMagnifyWindowCommand(Display *display,XWindows *windows, 9460% const MagickStatusType state,const KeySym key_symbol, 9461% ExceptionInfo *exception) 9462% 9463% A description of each parameter follows: 9464% 9465% o display: Specifies a connection to an X server; returned from 9466% XOpenDisplay. 9467% 9468% o windows: Specifies a pointer to a XWindows structure. 9469% 9470% o state: key mask. 9471% 9472% o key_symbol: Specifies a KeySym which indicates which side of the image 9473% to trim. 9474% 9475% o exception: return any errors or warnings in this structure. 9476% 9477*/ 9478static void XMagnifyWindowCommand(Display *display,XWindows *windows, 9479 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception) 9480{ 9481 unsigned int 9482 quantum; 9483 9484 /* 9485 User specified a magnify factor or position. 9486 */ 9487 quantum=1; 9488 if ((state & Mod1Mask) != 0) 9489 quantum=10; 9490 switch ((int) key_symbol) 9491 { 9492 case QuitCommand: 9493 { 9494 (void) XWithdrawWindow(display,windows->magnify.id, 9495 windows->magnify.screen); 9496 break; 9497 } 9498 case XK_Home: 9499 case XK_KP_Home: 9500 { 9501 windows->magnify.x=(int) windows->image.width/2; 9502 windows->magnify.y=(int) windows->image.height/2; 9503 break; 9504 } 9505 case XK_Left: 9506 case XK_KP_Left: 9507 { 9508 if (windows->magnify.x > 0) 9509 windows->magnify.x-=quantum; 9510 break; 9511 } 9512 case XK_Up: 9513 case XK_KP_Up: 9514 { 9515 if (windows->magnify.y > 0) 9516 windows->magnify.y-=quantum; 9517 break; 9518 } 9519 case XK_Right: 9520 case XK_KP_Right: 9521 { 9522 if (windows->magnify.x < (int) (windows->image.ximage->width-1)) 9523 windows->magnify.x+=quantum; 9524 break; 9525 } 9526 case XK_Down: 9527 case XK_KP_Down: 9528 { 9529 if (windows->magnify.y < (int) (windows->image.ximage->height-1)) 9530 windows->magnify.y+=quantum; 9531 break; 9532 } 9533 case XK_0: 9534 case XK_1: 9535 case XK_2: 9536 case XK_3: 9537 case XK_4: 9538 case XK_5: 9539 case XK_6: 9540 case XK_7: 9541 case XK_8: 9542 case XK_9: 9543 { 9544 windows->magnify.data=(key_symbol-XK_0); 9545 break; 9546 } 9547 case XK_KP_0: 9548 case XK_KP_1: 9549 case XK_KP_2: 9550 case XK_KP_3: 9551 case XK_KP_4: 9552 case XK_KP_5: 9553 case XK_KP_6: 9554 case XK_KP_7: 9555 case XK_KP_8: 9556 case XK_KP_9: 9557 { 9558 windows->magnify.data=(key_symbol-XK_KP_0); 9559 break; 9560 } 9561 default: 9562 break; 9563 } 9564 XMakeMagnifyImage(display,windows,exception); 9565} 9566 9567/* 9568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9569% % 9570% % 9571% % 9572+ X M a k e P a n I m a g e % 9573% % 9574% % 9575% % 9576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9577% 9578% XMakePanImage() creates a thumbnail of the image and displays it in the Pan 9579% icon window. 9580% 9581% The format of the XMakePanImage method is: 9582% 9583% void XMakePanImage(Display *display,XResourceInfo *resource_info, 9584% XWindows *windows,Image *image,ExceptionInfo *exception) 9585% 9586% A description of each parameter follows: 9587% 9588% o display: Specifies a connection to an X server; returned from 9589% XOpenDisplay. 9590% 9591% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9592% 9593% o windows: Specifies a pointer to a XWindows structure. 9594% 9595% o image: the image. 9596% 9597% o exception: return any errors or warnings in this structure. 9598% 9599*/ 9600static void XMakePanImage(Display *display,XResourceInfo *resource_info, 9601 XWindows *windows,Image *image,ExceptionInfo *exception) 9602{ 9603 MagickStatusType 9604 status; 9605 9606 /* 9607 Create and display image for panning icon. 9608 */ 9609 XSetCursorState(display,windows,MagickTrue); 9610 XCheckRefreshWindows(display,windows); 9611 windows->pan.x=(int) windows->image.x; 9612 windows->pan.y=(int) windows->image.y; 9613 status=XMakeImage(display,resource_info,&windows->pan,image, 9614 windows->pan.width,windows->pan.height,exception); 9615 if (IfMagickFalse(status) ) 9616 ThrowXWindowException(ResourceLimitError, 9617 "MemoryAllocationFailed",image->filename); 9618 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 9619 windows->pan.pixmap); 9620 (void) XClearWindow(display,windows->pan.id); 9621 XDrawPanRectangle(display,windows); 9622 XSetCursorState(display,windows,MagickFalse); 9623} 9624 9625/* 9626%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9627% % 9628% % 9629% % 9630+ X M a t t a E d i t I m a g e % 9631% % 9632% % 9633% % 9634%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9635% 9636% XMatteEditImage() allows the user to interactively change the Matte channel 9637% of an image. If the image is PseudoClass it is promoted to DirectClass 9638% before the matte information is stored. 9639% 9640% The format of the XMatteEditImage method is: 9641% 9642% MagickBooleanType XMatteEditImage(Display *display, 9643% XResourceInfo *resource_info,XWindows *windows,Image **image, 9644% ExceptionInfo *exception) 9645% 9646% A description of each parameter follows: 9647% 9648% o display: Specifies a connection to an X server; returned from 9649% XOpenDisplay. 9650% 9651% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9652% 9653% o windows: Specifies a pointer to a XWindows structure. 9654% 9655% o image: the image; returned from ReadImage. 9656% 9657% o exception: return any errors or warnings in this structure. 9658% 9659*/ 9660static MagickBooleanType XMatteEditImage(Display *display, 9661 XResourceInfo *resource_info,XWindows *windows,Image **image, 9662 ExceptionInfo *exception) 9663{ 9664 static char 9665 matte[MaxTextExtent] = "0"; 9666 9667 static const char 9668 *MatteEditMenu[] = 9669 { 9670 "Method", 9671 "Border Color", 9672 "Fuzz", 9673 "Matte Value", 9674 "Undo", 9675 "Help", 9676 "Dismiss", 9677 (char *) NULL 9678 }; 9679 9680 static const ModeType 9681 MatteEditCommands[] = 9682 { 9683 MatteEditMethod, 9684 MatteEditBorderCommand, 9685 MatteEditFuzzCommand, 9686 MatteEditValueCommand, 9687 MatteEditUndoCommand, 9688 MatteEditHelpCommand, 9689 MatteEditDismissCommand 9690 }; 9691 9692 static PaintMethod 9693 method = PointMethod; 9694 9695 static XColor 9696 border_color = { 0, 0, 0, 0, 0, 0 }; 9697 9698 char 9699 command[MaxTextExtent], 9700 text[MaxTextExtent]; 9701 9702 Cursor 9703 cursor; 9704 9705 int 9706 entry, 9707 id, 9708 x, 9709 x_offset, 9710 y, 9711 y_offset; 9712 9713 register int 9714 i; 9715 9716 register Quantum 9717 *q; 9718 9719 unsigned int 9720 height, 9721 width; 9722 9723 size_t 9724 state; 9725 9726 XEvent 9727 event; 9728 9729 /* 9730 Map Command widget. 9731 */ 9732 (void) CloneString(&windows->command.name,"Matte Edit"); 9733 windows->command.data=4; 9734 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL); 9735 (void) XMapRaised(display,windows->command.id); 9736 XClientMessage(display,windows->image.id,windows->im_protocols, 9737 windows->im_update_widget,CurrentTime); 9738 /* 9739 Make cursor. 9740 */ 9741 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 9742 resource_info->background_color,resource_info->foreground_color); 9743 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9744 /* 9745 Track pointer until button 1 is pressed. 9746 */ 9747 XQueryPosition(display,windows->image.id,&x,&y); 9748 (void) XSelectInput(display,windows->image.id, 9749 windows->image.attributes.event_mask | PointerMotionMask); 9750 state=DefaultState; 9751 do 9752 { 9753 if (IfMagickTrue(windows->info.mapped) ) 9754 { 9755 /* 9756 Display pointer position. 9757 */ 9758 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9759 x+windows->image.x,y+windows->image.y); 9760 XInfoWidget(display,windows,text); 9761 } 9762 /* 9763 Wait for next event. 9764 */ 9765 XScreenEvent(display,windows,&event,exception); 9766 if (event.xany.window == windows->command.id) 9767 { 9768 /* 9769 Select a command from the Command widget. 9770 */ 9771 id=XCommandWidget(display,windows,MatteEditMenu,&event); 9772 if (id < 0) 9773 { 9774 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9775 continue; 9776 } 9777 switch (MatteEditCommands[id]) 9778 { 9779 case MatteEditMethod: 9780 { 9781 char 9782 **methods; 9783 9784 /* 9785 Select a method from the pop-up menu. 9786 */ 9787 methods=GetCommandOptions(MagickMethodOptions); 9788 if (methods == (char **) NULL) 9789 break; 9790 entry=XMenuWidget(display,windows,MatteEditMenu[id], 9791 (const char **) methods,command); 9792 if (entry >= 0) 9793 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 9794 MagickFalse,methods[entry]); 9795 methods=DestroyStringList(methods); 9796 break; 9797 } 9798 case MatteEditBorderCommand: 9799 { 9800 const char 9801 *ColorMenu[MaxNumberPens]; 9802 9803 int 9804 pen_number; 9805 9806 /* 9807 Initialize menu selections. 9808 */ 9809 for (i=0; i < (int) (MaxNumberPens-2); i++) 9810 ColorMenu[i]=resource_info->pen_colors[i]; 9811 ColorMenu[MaxNumberPens-2]="Browser..."; 9812 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 9813 /* 9814 Select a pen color from the pop-up menu. 9815 */ 9816 pen_number=XMenuWidget(display,windows,MatteEditMenu[id], 9817 (const char **) ColorMenu,command); 9818 if (pen_number < 0) 9819 break; 9820 if (pen_number == (MaxNumberPens-2)) 9821 { 9822 static char 9823 color_name[MaxTextExtent] = "gray"; 9824 9825 /* 9826 Select a pen color from a dialog. 9827 */ 9828 resource_info->pen_colors[pen_number]=color_name; 9829 XColorBrowserWidget(display,windows,"Select",color_name); 9830 if (*color_name == '\0') 9831 break; 9832 } 9833 /* 9834 Set border color. 9835 */ 9836 (void) XParseColor(display,windows->map_info->colormap, 9837 resource_info->pen_colors[pen_number],&border_color); 9838 break; 9839 } 9840 case MatteEditFuzzCommand: 9841 { 9842 static char 9843 fuzz[MaxTextExtent]; 9844 9845 static const char 9846 *FuzzMenu[] = 9847 { 9848 "0%", 9849 "2%", 9850 "5%", 9851 "10%", 9852 "15%", 9853 "Dialog...", 9854 (char *) NULL, 9855 }; 9856 9857 /* 9858 Select a command from the pop-up menu. 9859 */ 9860 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu, 9861 command); 9862 if (entry < 0) 9863 break; 9864 if (entry != 5) 9865 { 9866 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 9867 QuantumRange+1.0); 9868 break; 9869 } 9870 (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 9871 (void) XDialogWidget(display,windows,"Ok", 9872 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 9873 if (*fuzz == '\0') 9874 break; 9875 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 9876 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 9877 1.0); 9878 break; 9879 } 9880 case MatteEditValueCommand: 9881 { 9882 static char 9883 message[MaxTextExtent]; 9884 9885 static const char 9886 *MatteMenu[] = 9887 { 9888 "Opaque", 9889 "Transparent", 9890 "Dialog...", 9891 (char *) NULL, 9892 }; 9893 9894 /* 9895 Select a command from the pop-up menu. 9896 */ 9897 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu, 9898 command); 9899 if (entry < 0) 9900 break; 9901 if (entry != 2) 9902 { 9903 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9904 OpaqueAlpha); 9905 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9906 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9907 (Quantum) TransparentAlpha); 9908 break; 9909 } 9910 (void) FormatLocaleString(message,MaxTextExtent, 9911 "Enter matte value (0 - " QuantumFormat "):",(Quantum) 9912 QuantumRange); 9913 (void) XDialogWidget(display,windows,"Matte",message,matte); 9914 if (*matte == '\0') 9915 break; 9916 break; 9917 } 9918 case MatteEditUndoCommand: 9919 { 9920 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 9921 image,exception); 9922 break; 9923 } 9924 case MatteEditHelpCommand: 9925 { 9926 XTextViewWidget(display,resource_info,windows,MagickFalse, 9927 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9928 break; 9929 } 9930 case MatteEditDismissCommand: 9931 { 9932 /* 9933 Prematurely exit. 9934 */ 9935 state|=EscapeState; 9936 state|=ExitState; 9937 break; 9938 } 9939 default: 9940 break; 9941 } 9942 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9943 continue; 9944 } 9945 switch (event.type) 9946 { 9947 case ButtonPress: 9948 { 9949 if (event.xbutton.button != Button1) 9950 break; 9951 if ((event.xbutton.window != windows->image.id) && 9952 (event.xbutton.window != windows->magnify.id)) 9953 break; 9954 /* 9955 Update matte data. 9956 */ 9957 x=event.xbutton.x; 9958 y=event.xbutton.y; 9959 (void) XMagickCommand(display,resource_info,windows, 9960 SaveToUndoBufferCommand,image,exception); 9961 state|=UpdateConfigurationState; 9962 break; 9963 } 9964 case ButtonRelease: 9965 { 9966 if (event.xbutton.button != Button1) 9967 break; 9968 if ((event.xbutton.window != windows->image.id) && 9969 (event.xbutton.window != windows->magnify.id)) 9970 break; 9971 /* 9972 Update colormap information. 9973 */ 9974 x=event.xbutton.x; 9975 y=event.xbutton.y; 9976 XConfigureImageColormap(display,resource_info,windows,*image,exception); 9977 (void) XConfigureImage(display,resource_info,windows,*image,exception); 9978 XInfoWidget(display,windows,text); 9979 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9980 state&=(~UpdateConfigurationState); 9981 break; 9982 } 9983 case Expose: 9984 break; 9985 case KeyPress: 9986 { 9987 char 9988 command[MaxTextExtent]; 9989 9990 KeySym 9991 key_symbol; 9992 9993 if (event.xkey.window == windows->magnify.id) 9994 { 9995 Window 9996 window; 9997 9998 window=windows->magnify.id; 9999 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 10000 } 10001 if (event.xkey.window != windows->image.id) 10002 break; 10003 /* 10004 Respond to a user key press. 10005 */ 10006 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 10007 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10008 switch ((int) key_symbol) 10009 { 10010 case XK_Escape: 10011 case XK_F20: 10012 { 10013 /* 10014 Prematurely exit. 10015 */ 10016 state|=ExitState; 10017 break; 10018 } 10019 case XK_F1: 10020 case XK_Help: 10021 { 10022 XTextViewWidget(display,resource_info,windows,MagickFalse, 10023 "Help Viewer - Matte Edit",ImageMatteEditHelp); 10024 break; 10025 } 10026 default: 10027 { 10028 (void) XBell(display,0); 10029 break; 10030 } 10031 } 10032 break; 10033 } 10034 case MotionNotify: 10035 { 10036 /* 10037 Map and unmap Info widget as cursor crosses its boundaries. 10038 */ 10039 x=event.xmotion.x; 10040 y=event.xmotion.y; 10041 if (IfMagickTrue(windows->info.mapped) ) 10042 { 10043 if ((x < (int) (windows->info.x+windows->info.width)) && 10044 (y < (int) (windows->info.y+windows->info.height))) 10045 (void) XWithdrawWindow(display,windows->info.id, 10046 windows->info.screen); 10047 } 10048 else 10049 if ((x > (int) (windows->info.x+windows->info.width)) || 10050 (y > (int) (windows->info.y+windows->info.height))) 10051 (void) XMapWindow(display,windows->info.id); 10052 break; 10053 } 10054 default: 10055 break; 10056 } 10057 if (event.xany.window == windows->magnify.id) 10058 { 10059 x=windows->magnify.x-windows->image.x; 10060 y=windows->magnify.y-windows->image.y; 10061 } 10062 x_offset=x; 10063 y_offset=y; 10064 if ((state & UpdateConfigurationState) != 0) 10065 { 10066 CacheView 10067 *image_view; 10068 10069 int 10070 x, 10071 y; 10072 10073 /* 10074 Matte edit is relative to image configuration. 10075 */ 10076 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 10077 MagickTrue); 10078 XPutPixel(windows->image.ximage,x_offset,y_offset, 10079 windows->pixel_info->background_color.pixel); 10080 width=(unsigned int) (*image)->columns; 10081 height=(unsigned int) (*image)->rows; 10082 x=0; 10083 y=0; 10084 if (windows->image.crop_geometry != (char *) NULL) 10085 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width, 10086 &height); 10087 x_offset=(int) (width*(windows->image.x+x_offset)/ 10088 windows->image.ximage->width+x); 10089 y_offset=(int) (height*(windows->image.y+y_offset)/ 10090 windows->image.ximage->height+y); 10091 if ((x_offset < 0) || (y_offset < 0)) 10092 continue; 10093 if ((x_offset >= (int) (*image)->columns) || 10094 (y_offset >= (int) (*image)->rows)) 10095 continue; 10096 if (IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) ) 10097 return(MagickFalse); 10098 if ((*image)->alpha_trait != BlendPixelTrait) 10099 (void) SetImageAlphaChannel(*image,OpaqueAlphaChannel,exception); 10100 image_view=AcquireAuthenticCacheView(*image,exception); 10101 switch (method) 10102 { 10103 case PointMethod: 10104 default: 10105 { 10106 /* 10107 Update matte information using point algorithm. 10108 */ 10109 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset, 10110 (ssize_t) y_offset,1,1,exception); 10111 if (q == (Quantum *) NULL) 10112 break; 10113 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10114 (void) SyncCacheViewAuthenticPixels(image_view,exception); 10115 break; 10116 } 10117 case ReplaceMethod: 10118 { 10119 PixelInfo 10120 pixel, 10121 target; 10122 10123 /* 10124 Update matte information using replace algorithm. 10125 */ 10126 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t) 10127 x_offset,(ssize_t) y_offset,&target,exception); 10128 for (y=0; y < (int) (*image)->rows; y++) 10129 { 10130 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10131 (*image)->columns,1,exception); 10132 if (q == (Quantum *) NULL) 10133 break; 10134 for (x=0; x < (int) (*image)->columns; x++) 10135 { 10136 GetPixelInfoPixel(*image,q,&pixel); 10137 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 10138 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10139 q+=GetPixelChannels(*image); 10140 } 10141 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 10142 break; 10143 } 10144 break; 10145 } 10146 case FloodfillMethod: 10147 case FillToBorderMethod: 10148 { 10149 ChannelType 10150 channel_mask; 10151 10152 DrawInfo 10153 *draw_info; 10154 10155 PixelInfo 10156 target; 10157 10158 /* 10159 Update matte information using floodfill algorithm. 10160 */ 10161 (void) GetOneVirtualPixelInfo(*image, 10162 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 10163 y_offset,&target,exception); 10164 if (method == FillToBorderMethod) 10165 { 10166 target.red=(double) ScaleShortToQuantum( 10167 border_color.red); 10168 target.green=(double) ScaleShortToQuantum( 10169 border_color.green); 10170 target.blue=(double) ScaleShortToQuantum( 10171 border_color.blue); 10172 } 10173 draw_info=CloneDrawInfo(resource_info->image_info, 10174 (DrawInfo *) NULL); 10175 draw_info->fill.alpha=(double) ClampToQuantum( 10176 StringToDouble(matte,(char **) NULL)); 10177 channel_mask=SetImageChannelMask(*image,AlphaChannel); 10178 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 10179 x_offset,(ssize_t) y_offset, 10180 IsMagickFalse(method == FloodfillMethod),exception); 10181 (void) SetPixelChannelMask(*image,channel_mask); 10182 draw_info=DestroyDrawInfo(draw_info); 10183 break; 10184 } 10185 case ResetMethod: 10186 { 10187 /* 10188 Update matte information using reset algorithm. 10189 */ 10190 if (IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) ) 10191 return(MagickFalse); 10192 for (y=0; y < (int) (*image)->rows; y++) 10193 { 10194 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10195 (*image)->columns,1,exception); 10196 if (q == (Quantum *) NULL) 10197 break; 10198 for (x=0; x < (int) (*image)->columns; x++) 10199 { 10200 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10201 q+=GetPixelChannels(*image); 10202 } 10203 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 10204 break; 10205 } 10206 if (StringToLong(matte) == (long) OpaqueAlpha) 10207 (*image)->alpha_trait=UndefinedPixelTrait; 10208 break; 10209 } 10210 } 10211 image_view=DestroyCacheView(image_view); 10212 state&=(~UpdateConfigurationState); 10213 } 10214 } while ((state & ExitState) == 0); 10215 (void) XSelectInput(display,windows->image.id, 10216 windows->image.attributes.event_mask); 10217 XSetCursorState(display,windows,MagickFalse); 10218 (void) XFreeCursor(display,cursor); 10219 return(MagickTrue); 10220} 10221 10222/* 10223%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10224% % 10225% % 10226% % 10227+ X O p e n I m a g e % 10228% % 10229% % 10230% % 10231%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10232% 10233% XOpenImage() loads an image from a file. 10234% 10235% The format of the XOpenImage method is: 10236% 10237% Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10238% XWindows *windows,const unsigned int command) 10239% 10240% A description of each parameter follows: 10241% 10242% o display: Specifies a connection to an X server; returned from 10243% XOpenDisplay. 10244% 10245% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10246% 10247% o windows: Specifies a pointer to a XWindows structure. 10248% 10249% o command: A value other than zero indicates that the file is selected 10250% from the command line argument list. 10251% 10252*/ 10253static Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10254 XWindows *windows,const MagickBooleanType command) 10255{ 10256 const MagickInfo 10257 *magick_info; 10258 10259 ExceptionInfo 10260 *exception; 10261 10262 Image 10263 *nexus; 10264 10265 ImageInfo 10266 *image_info; 10267 10268 static char 10269 filename[MaxTextExtent] = "\0"; 10270 10271 /* 10272 Request file name from user. 10273 */ 10274 if (IfMagickFalse(command) ) 10275 XFileBrowserWidget(display,windows,"Open",filename); 10276 else 10277 { 10278 char 10279 **filelist, 10280 **files; 10281 10282 int 10283 count, 10284 status; 10285 10286 register int 10287 i, 10288 j; 10289 10290 /* 10291 Select next image from the command line. 10292 */ 10293 status=XGetCommand(display,windows->image.id,&files,&count); 10294 if (status == 0) 10295 { 10296 ThrowXWindowException(XServerError,"UnableToGetProperty","..."); 10297 return((Image *) NULL); 10298 } 10299 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10300 if (filelist == (char **) NULL) 10301 { 10302 ThrowXWindowException(ResourceLimitError, 10303 "MemoryAllocationFailed","..."); 10304 (void) XFreeStringList(files); 10305 return((Image *) NULL); 10306 } 10307 j=0; 10308 for (i=1; i < count; i++) 10309 if (*files[i] != '-') 10310 filelist[j++]=files[i]; 10311 filelist[j]=(char *) NULL; 10312 XListBrowserWidget(display,windows,&windows->widget, 10313 (const char **) filelist,"Load","Select Image to Load:",filename); 10314 filelist=(char **) RelinquishMagickMemory(filelist); 10315 (void) XFreeStringList(files); 10316 } 10317 if (*filename == '\0') 10318 return((Image *) NULL); 10319 image_info=CloneImageInfo(resource_info->image_info); 10320 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL, 10321 (void *) NULL); 10322 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10323 exception=AcquireExceptionInfo(); 10324 (void) SetImageInfo(image_info,0,exception); 10325 if (LocaleCompare(image_info->magick,"X") == 0) 10326 { 10327 char 10328 seconds[MaxTextExtent]; 10329 10330 /* 10331 User may want to delay the X server screen grab. 10332 */ 10333 (void) CopyMagickString(seconds,"0",MaxTextExtent); 10334 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:", 10335 seconds); 10336 if (*seconds == '\0') 10337 return((Image *) NULL); 10338 XDelay(display,(size_t) (1000*StringToLong(seconds))); 10339 } 10340 magick_info=GetMagickInfo(image_info->magick,exception); 10341 if ((magick_info != (const MagickInfo *) NULL) && 10342 IfMagickTrue(magick_info->raw)) 10343 { 10344 char 10345 geometry[MaxTextExtent]; 10346 10347 /* 10348 Request image size from the user. 10349 */ 10350 (void) CopyMagickString(geometry,"512x512",MaxTextExtent); 10351 if (image_info->size != (char *) NULL) 10352 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent); 10353 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:", 10354 geometry); 10355 (void) CloneString(&image_info->size,geometry); 10356 } 10357 /* 10358 Load the image. 10359 */ 10360 XSetCursorState(display,windows,MagickTrue); 10361 XCheckRefreshWindows(display,windows); 10362 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10363 nexus=ReadImage(image_info,exception); 10364 CatchException(exception); 10365 XSetCursorState(display,windows,MagickFalse); 10366 if (nexus != (Image *) NULL) 10367 XClientMessage(display,windows->image.id,windows->im_protocols, 10368 windows->im_next_image,CurrentTime); 10369 else 10370 { 10371 char 10372 *text, 10373 **textlist; 10374 10375 /* 10376 Unknown image format. 10377 */ 10378 text=FileToString(filename,~0UL,exception); 10379 if (text == (char *) NULL) 10380 return((Image *) NULL); 10381 textlist=StringToList(text); 10382 if (textlist != (char **) NULL) 10383 { 10384 char 10385 title[MaxTextExtent]; 10386 10387 register int 10388 i; 10389 10390 (void) FormatLocaleString(title,MaxTextExtent, 10391 "Unknown format: %s",filename); 10392 XTextViewWidget(display,resource_info,windows,MagickTrue,title, 10393 (const char **) textlist); 10394 for (i=0; textlist[i] != (char *) NULL; i++) 10395 textlist[i]=DestroyString(textlist[i]); 10396 textlist=(char **) RelinquishMagickMemory(textlist); 10397 } 10398 text=DestroyString(text); 10399 } 10400 exception=DestroyExceptionInfo(exception); 10401 image_info=DestroyImageInfo(image_info); 10402 return(nexus); 10403} 10404 10405/* 10406%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10407% % 10408% % 10409% % 10410+ X P a n I m a g e % 10411% % 10412% % 10413% % 10414%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10415% 10416% XPanImage() pans the image until the mouse button is released. 10417% 10418% The format of the XPanImage method is: 10419% 10420% void XPanImage(Display *display,XWindows *windows,XEvent *event, 10421% ExceptionInfo *exception) 10422% 10423% A description of each parameter follows: 10424% 10425% o display: Specifies a connection to an X server; returned from 10426% XOpenDisplay. 10427% 10428% o windows: Specifies a pointer to a XWindows structure. 10429% 10430% o event: Specifies a pointer to a XEvent structure. If it is NULL, 10431% the entire image is refreshed. 10432% 10433% o exception: return any errors or warnings in this structure. 10434% 10435*/ 10436static void XPanImage(Display *display,XWindows *windows,XEvent *event, 10437 ExceptionInfo *exception) 10438{ 10439 char 10440 text[MaxTextExtent]; 10441 10442 Cursor 10443 cursor; 10444 10445 double 10446 x_factor, 10447 y_factor; 10448 10449 RectangleInfo 10450 pan_info; 10451 10452 size_t 10453 state; 10454 10455 /* 10456 Define cursor. 10457 */ 10458 if ((windows->image.ximage->width > (int) windows->image.width) && 10459 (windows->image.ximage->height > (int) windows->image.height)) 10460 cursor=XCreateFontCursor(display,XC_fleur); 10461 else 10462 if (windows->image.ximage->width > (int) windows->image.width) 10463 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow); 10464 else 10465 if (windows->image.ximage->height > (int) windows->image.height) 10466 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow); 10467 else 10468 cursor=XCreateFontCursor(display,XC_arrow); 10469 (void) XCheckDefineCursor(display,windows->pan.id,cursor); 10470 /* 10471 Pan image as pointer moves until the mouse button is released. 10472 */ 10473 x_factor=(double) windows->image.ximage->width/windows->pan.width; 10474 y_factor=(double) windows->image.ximage->height/windows->pan.height; 10475 pan_info.width=windows->pan.width*windows->image.width/ 10476 windows->image.ximage->width; 10477 pan_info.height=windows->pan.height*windows->image.height/ 10478 windows->image.ximage->height; 10479 pan_info.x=0; 10480 pan_info.y=0; 10481 state=UpdateConfigurationState; 10482 do 10483 { 10484 switch (event->type) 10485 { 10486 case ButtonPress: 10487 { 10488 /* 10489 User choose an initial pan location. 10490 */ 10491 pan_info.x=(ssize_t) event->xbutton.x; 10492 pan_info.y=(ssize_t) event->xbutton.y; 10493 state|=UpdateConfigurationState; 10494 break; 10495 } 10496 case ButtonRelease: 10497 { 10498 /* 10499 User has finished panning the image. 10500 */ 10501 pan_info.x=(ssize_t) event->xbutton.x; 10502 pan_info.y=(ssize_t) event->xbutton.y; 10503 state|=UpdateConfigurationState | ExitState; 10504 break; 10505 } 10506 case MotionNotify: 10507 { 10508 pan_info.x=(ssize_t) event->xmotion.x; 10509 pan_info.y=(ssize_t) event->xmotion.y; 10510 state|=UpdateConfigurationState; 10511 } 10512 default: 10513 break; 10514 } 10515 if ((state & UpdateConfigurationState) != 0) 10516 { 10517 /* 10518 Check boundary conditions. 10519 */ 10520 if (pan_info.x < (ssize_t) (pan_info.width/2)) 10521 pan_info.x=0; 10522 else 10523 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2))); 10524 if (pan_info.x < 0) 10525 pan_info.x=0; 10526 else 10527 if ((int) (pan_info.x+windows->image.width) > 10528 windows->image.ximage->width) 10529 pan_info.x=(ssize_t) 10530 (windows->image.ximage->width-windows->image.width); 10531 if (pan_info.y < (ssize_t) (pan_info.height/2)) 10532 pan_info.y=0; 10533 else 10534 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2))); 10535 if (pan_info.y < 0) 10536 pan_info.y=0; 10537 else 10538 if ((int) (pan_info.y+windows->image.height) > 10539 windows->image.ximage->height) 10540 pan_info.y=(ssize_t) 10541 (windows->image.ximage->height-windows->image.height); 10542 if ((windows->image.x != (int) pan_info.x) || 10543 (windows->image.y != (int) pan_info.y)) 10544 { 10545 /* 10546 Display image pan offset. 10547 */ 10548 windows->image.x=(int) pan_info.x; 10549 windows->image.y=(int) pan_info.y; 10550 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 10551 windows->image.width,windows->image.height,windows->image.x, 10552 windows->image.y); 10553 XInfoWidget(display,windows,text); 10554 /* 10555 Refresh Image window. 10556 */ 10557 XDrawPanRectangle(display,windows); 10558 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 10559 } 10560 state&=(~UpdateConfigurationState); 10561 } 10562 /* 10563 Wait for next event. 10564 */ 10565 if ((state & ExitState) == 0) 10566 XScreenEvent(display,windows,event,exception); 10567 } while ((state & ExitState) == 0); 10568 /* 10569 Restore cursor. 10570 */ 10571 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor); 10572 (void) XFreeCursor(display,cursor); 10573 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 10574} 10575 10576/* 10577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10578% % 10579% % 10580% % 10581+ X P a s t e I m a g e % 10582% % 10583% % 10584% % 10585%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10586% 10587% XPasteImage() pastes an image previously saved with XCropImage in the X 10588% window image at a location the user chooses with the pointer. 10589% 10590% The format of the XPasteImage method is: 10591% 10592% MagickBooleanType XPasteImage(Display *display, 10593% XResourceInfo *resource_info,XWindows *windows,Image *image, 10594% ExceptionInfo *exception) 10595% 10596% A description of each parameter follows: 10597% 10598% o display: Specifies a connection to an X server; returned from 10599% XOpenDisplay. 10600% 10601% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10602% 10603% o windows: Specifies a pointer to a XWindows structure. 10604% 10605% o image: the image; returned from ReadImage. 10606% 10607% o exception: return any errors or warnings in this structure. 10608% 10609*/ 10610static MagickBooleanType XPasteImage(Display *display, 10611 XResourceInfo *resource_info,XWindows *windows,Image *image, 10612 ExceptionInfo *exception) 10613{ 10614 static const char 10615 *PasteMenu[] = 10616 { 10617 "Operator", 10618 "Help", 10619 "Dismiss", 10620 (char *) NULL 10621 }; 10622 10623 static const ModeType 10624 PasteCommands[] = 10625 { 10626 PasteOperatorsCommand, 10627 PasteHelpCommand, 10628 PasteDismissCommand 10629 }; 10630 10631 static CompositeOperator 10632 compose = CopyCompositeOp; 10633 10634 char 10635 text[MaxTextExtent]; 10636 10637 Cursor 10638 cursor; 10639 10640 Image 10641 *paste_image; 10642 10643 int 10644 entry, 10645 id, 10646 x, 10647 y; 10648 10649 double 10650 scale_factor; 10651 10652 RectangleInfo 10653 highlight_info, 10654 paste_info; 10655 10656 unsigned int 10657 height, 10658 width; 10659 10660 size_t 10661 state; 10662 10663 XEvent 10664 event; 10665 10666 /* 10667 Copy image. 10668 */ 10669 if (resource_info->copy_image == (Image *) NULL) 10670 return(MagickFalse); 10671 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception); 10672 /* 10673 Map Command widget. 10674 */ 10675 (void) CloneString(&windows->command.name,"Paste"); 10676 windows->command.data=1; 10677 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL); 10678 (void) XMapRaised(display,windows->command.id); 10679 XClientMessage(display,windows->image.id,windows->im_protocols, 10680 windows->im_update_widget,CurrentTime); 10681 /* 10682 Track pointer until button 1 is pressed. 10683 */ 10684 XSetCursorState(display,windows,MagickFalse); 10685 XQueryPosition(display,windows->image.id,&x,&y); 10686 (void) XSelectInput(display,windows->image.id, 10687 windows->image.attributes.event_mask | PointerMotionMask); 10688 paste_info.x=(ssize_t) windows->image.x+x; 10689 paste_info.y=(ssize_t) windows->image.y+y; 10690 paste_info.width=0; 10691 paste_info.height=0; 10692 cursor=XCreateFontCursor(display,XC_ul_angle); 10693 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 10694 state=DefaultState; 10695 do 10696 { 10697 if (IfMagickTrue(windows->info.mapped) ) 10698 { 10699 /* 10700 Display pointer position. 10701 */ 10702 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 10703 (long) paste_info.x,(long) paste_info.y); 10704 XInfoWidget(display,windows,text); 10705 } 10706 highlight_info=paste_info; 10707 highlight_info.x=paste_info.x-windows->image.x; 10708 highlight_info.y=paste_info.y-windows->image.y; 10709 XHighlightRectangle(display,windows->image.id, 10710 windows->image.highlight_context,&highlight_info); 10711 /* 10712 Wait for next event. 10713 */ 10714 XScreenEvent(display,windows,&event,exception); 10715 XHighlightRectangle(display,windows->image.id, 10716 windows->image.highlight_context,&highlight_info); 10717 if (event.xany.window == windows->command.id) 10718 { 10719 /* 10720 Select a command from the Command widget. 10721 */ 10722 id=XCommandWidget(display,windows,PasteMenu,&event); 10723 if (id < 0) 10724 continue; 10725 switch (PasteCommands[id]) 10726 { 10727 case PasteOperatorsCommand: 10728 { 10729 char 10730 command[MaxTextExtent], 10731 **operators; 10732 10733 /* 10734 Select a command from the pop-up menu. 10735 */ 10736 operators=GetCommandOptions(MagickComposeOptions); 10737 if (operators == (char **) NULL) 10738 break; 10739 entry=XMenuWidget(display,windows,PasteMenu[id], 10740 (const char **) operators,command); 10741 if (entry >= 0) 10742 compose=(CompositeOperator) ParseCommandOption( 10743 MagickComposeOptions,MagickFalse,operators[entry]); 10744 operators=DestroyStringList(operators); 10745 break; 10746 } 10747 case PasteHelpCommand: 10748 { 10749 XTextViewWidget(display,resource_info,windows,MagickFalse, 10750 "Help Viewer - Image Composite",ImagePasteHelp); 10751 break; 10752 } 10753 case PasteDismissCommand: 10754 { 10755 /* 10756 Prematurely exit. 10757 */ 10758 state|=EscapeState; 10759 state|=ExitState; 10760 break; 10761 } 10762 default: 10763 break; 10764 } 10765 continue; 10766 } 10767 switch (event.type) 10768 { 10769 case ButtonPress: 10770 { 10771 if (IfMagickTrue(image->debug) ) 10772 (void) LogMagickEvent(X11Event,GetMagickModule(), 10773 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 10774 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10775 if (event.xbutton.button != Button1) 10776 break; 10777 if (event.xbutton.window != windows->image.id) 10778 break; 10779 /* 10780 Paste rectangle is relative to image configuration. 10781 */ 10782 width=(unsigned int) image->columns; 10783 height=(unsigned int) image->rows; 10784 x=0; 10785 y=0; 10786 if (windows->image.crop_geometry != (char *) NULL) 10787 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 10788 &width,&height); 10789 scale_factor=(double) windows->image.ximage->width/width; 10790 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5); 10791 scale_factor=(double) windows->image.ximage->height/height; 10792 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5); 10793 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10794 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10795 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10796 break; 10797 } 10798 case ButtonRelease: 10799 { 10800 if (IfMagickTrue(image->debug) ) 10801 (void) LogMagickEvent(X11Event,GetMagickModule(), 10802 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 10803 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10804 if (event.xbutton.button != Button1) 10805 break; 10806 if (event.xbutton.window != windows->image.id) 10807 break; 10808 if ((paste_info.width != 0) && (paste_info.height != 0)) 10809 { 10810 /* 10811 User has selected the location of the paste image. 10812 */ 10813 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10814 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10815 state|=ExitState; 10816 } 10817 break; 10818 } 10819 case Expose: 10820 break; 10821 case KeyPress: 10822 { 10823 char 10824 command[MaxTextExtent]; 10825 10826 KeySym 10827 key_symbol; 10828 10829 int 10830 length; 10831 10832 if (event.xkey.window != windows->image.id) 10833 break; 10834 /* 10835 Respond to a user key press. 10836 */ 10837 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 10838 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10839 *(command+length)='\0'; 10840 if (IfMagickTrue(image->debug) ) 10841 (void) LogMagickEvent(X11Event,GetMagickModule(), 10842 "Key press: 0x%lx (%s)",(long) key_symbol,command); 10843 switch ((int) key_symbol) 10844 { 10845 case XK_Escape: 10846 case XK_F20: 10847 { 10848 /* 10849 Prematurely exit. 10850 */ 10851 paste_image=DestroyImage(paste_image); 10852 state|=EscapeState; 10853 state|=ExitState; 10854 break; 10855 } 10856 case XK_F1: 10857 case XK_Help: 10858 { 10859 (void) XSetFunction(display,windows->image.highlight_context, 10860 GXcopy); 10861 XTextViewWidget(display,resource_info,windows,MagickFalse, 10862 "Help Viewer - Image Composite",ImagePasteHelp); 10863 (void) XSetFunction(display,windows->image.highlight_context, 10864 GXinvert); 10865 break; 10866 } 10867 default: 10868 { 10869 (void) XBell(display,0); 10870 break; 10871 } 10872 } 10873 break; 10874 } 10875 case MotionNotify: 10876 { 10877 /* 10878 Map and unmap Info widget as text cursor crosses its boundaries. 10879 */ 10880 x=event.xmotion.x; 10881 y=event.xmotion.y; 10882 if (IfMagickTrue(windows->info.mapped) ) 10883 { 10884 if ((x < (int) (windows->info.x+windows->info.width)) && 10885 (y < (int) (windows->info.y+windows->info.height))) 10886 (void) XWithdrawWindow(display,windows->info.id, 10887 windows->info.screen); 10888 } 10889 else 10890 if ((x > (int) (windows->info.x+windows->info.width)) || 10891 (y > (int) (windows->info.y+windows->info.height))) 10892 (void) XMapWindow(display,windows->info.id); 10893 paste_info.x=(ssize_t) windows->image.x+x; 10894 paste_info.y=(ssize_t) windows->image.y+y; 10895 break; 10896 } 10897 default: 10898 { 10899 if (IfMagickTrue(image->debug) ) 10900 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 10901 event.type); 10902 break; 10903 } 10904 } 10905 } while ((state & ExitState) == 0); 10906 (void) XSelectInput(display,windows->image.id, 10907 windows->image.attributes.event_mask); 10908 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 10909 XSetCursorState(display,windows,MagickFalse); 10910 (void) XFreeCursor(display,cursor); 10911 if ((state & EscapeState) != 0) 10912 return(MagickTrue); 10913 /* 10914 Image pasting is relative to image configuration. 10915 */ 10916 XSetCursorState(display,windows,MagickTrue); 10917 XCheckRefreshWindows(display,windows); 10918 width=(unsigned int) image->columns; 10919 height=(unsigned int) image->rows; 10920 x=0; 10921 y=0; 10922 if (windows->image.crop_geometry != (char *) NULL) 10923 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 10924 scale_factor=(double) width/windows->image.ximage->width; 10925 paste_info.x+=x; 10926 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5); 10927 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5); 10928 scale_factor=(double) height/windows->image.ximage->height; 10929 paste_info.y+=y; 10930 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5); 10931 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5); 10932 /* 10933 Paste image with X Image window. 10934 */ 10935 (void) CompositeImage(image,paste_image,compose,MagickTrue,paste_info.x, 10936 paste_info.y,exception); 10937 paste_image=DestroyImage(paste_image); 10938 XSetCursorState(display,windows,MagickFalse); 10939 /* 10940 Update image colormap. 10941 */ 10942 XConfigureImageColormap(display,resource_info,windows,image,exception); 10943 (void) XConfigureImage(display,resource_info,windows,image,exception); 10944 return(MagickTrue); 10945} 10946 10947/* 10948%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10949% % 10950% % 10951% % 10952+ X P r i n t I m a g e % 10953% % 10954% % 10955% % 10956%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10957% 10958% XPrintImage() prints an image to a Postscript printer. 10959% 10960% The format of the XPrintImage method is: 10961% 10962% MagickBooleanType XPrintImage(Display *display, 10963% XResourceInfo *resource_info,XWindows *windows,Image *image, 10964% ExceptionInfo *exception) 10965% 10966% A description of each parameter follows: 10967% 10968% o display: Specifies a connection to an X server; returned from 10969% XOpenDisplay. 10970% 10971% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10972% 10973% o windows: Specifies a pointer to a XWindows structure. 10974% 10975% o image: the image. 10976% 10977% o exception: return any errors or warnings in this structure. 10978% 10979*/ 10980static MagickBooleanType XPrintImage(Display *display, 10981 XResourceInfo *resource_info,XWindows *windows,Image *image, 10982 ExceptionInfo *exception) 10983{ 10984 char 10985 filename[MaxTextExtent], 10986 geometry[MaxTextExtent]; 10987 10988 Image 10989 *print_image; 10990 10991 ImageInfo 10992 *image_info; 10993 10994 MagickStatusType 10995 status; 10996 10997 /* 10998 Request Postscript page geometry from user. 10999 */ 11000 image_info=CloneImageInfo(resource_info->image_info); 11001 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter"); 11002 if (image_info->page != (char *) NULL) 11003 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 11004 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 11005 "Select Postscript Page Geometry:",geometry); 11006 if (*geometry == '\0') 11007 return(MagickTrue); 11008 image_info->page=GetPageGeometry(geometry); 11009 /* 11010 Apply image transforms. 11011 */ 11012 XSetCursorState(display,windows,MagickTrue); 11013 XCheckRefreshWindows(display,windows); 11014 print_image=CloneImage(image,0,0,MagickTrue,exception); 11015 if (print_image == (Image *) NULL) 11016 return(MagickFalse); 11017 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 11018 windows->image.ximage->width,windows->image.ximage->height); 11019 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry, 11020 exception); 11021 /* 11022 Print image. 11023 */ 11024 (void) AcquireUniqueFilename(filename); 11025 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s", 11026 filename); 11027 status=WriteImage(image_info,print_image,exception); 11028 (void) RelinquishUniqueFileResource(filename); 11029 print_image=DestroyImage(print_image); 11030 image_info=DestroyImageInfo(image_info); 11031 XSetCursorState(display,windows,MagickFalse); 11032 return(IsMagickTrue(status)); 11033} 11034 11035/* 11036%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11037% % 11038% % 11039% % 11040+ X R O I I m a g e % 11041% % 11042% % 11043% % 11044%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11045% 11046% XROIImage() applies an image processing technique to a region of interest. 11047% 11048% The format of the XROIImage method is: 11049% 11050% MagickBooleanType XROIImage(Display *display, 11051% XResourceInfo *resource_info,XWindows *windows,Image **image, 11052% ExceptionInfo *exception) 11053% 11054% A description of each parameter follows: 11055% 11056% o display: Specifies a connection to an X server; returned from 11057% XOpenDisplay. 11058% 11059% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11060% 11061% o windows: Specifies a pointer to a XWindows structure. 11062% 11063% o image: the image; returned from ReadImage. 11064% 11065% o exception: return any errors or warnings in this structure. 11066% 11067*/ 11068static MagickBooleanType XROIImage(Display *display, 11069 XResourceInfo *resource_info,XWindows *windows,Image **image, 11070 ExceptionInfo *exception) 11071{ 11072#define ApplyMenus 7 11073 11074 static const char 11075 *ROIMenu[] = 11076 { 11077 "Help", 11078 "Dismiss", 11079 (char *) NULL 11080 }, 11081 *ApplyMenu[] = 11082 { 11083 "File", 11084 "Edit", 11085 "Transform", 11086 "Enhance", 11087 "Effects", 11088 "F/X", 11089 "Miscellany", 11090 "Help", 11091 "Dismiss", 11092 (char *) NULL 11093 }, 11094 *FileMenu[] = 11095 { 11096 "Save...", 11097 "Print...", 11098 (char *) NULL 11099 }, 11100 *EditMenu[] = 11101 { 11102 "Undo", 11103 "Redo", 11104 (char *) NULL 11105 }, 11106 *TransformMenu[] = 11107 { 11108 "Flop", 11109 "Flip", 11110 "Rotate Right", 11111 "Rotate Left", 11112 (char *) NULL 11113 }, 11114 *EnhanceMenu[] = 11115 { 11116 "Hue...", 11117 "Saturation...", 11118 "Brightness...", 11119 "Gamma...", 11120 "Spiff", 11121 "Dull", 11122 "Contrast Stretch...", 11123 "Sigmoidal Contrast...", 11124 "Normalize", 11125 "Equalize", 11126 "Negate", 11127 "Grayscale", 11128 "Map...", 11129 "Quantize...", 11130 (char *) NULL 11131 }, 11132 *EffectsMenu[] = 11133 { 11134 "Despeckle", 11135 "Emboss", 11136 "Reduce Noise", 11137 "Add Noise", 11138 "Sharpen...", 11139 "Blur...", 11140 "Threshold...", 11141 "Edge Detect...", 11142 "Spread...", 11143 "Shade...", 11144 "Raise...", 11145 "Segment...", 11146 (char *) NULL 11147 }, 11148 *FXMenu[] = 11149 { 11150 "Solarize...", 11151 "Sepia Tone...", 11152 "Swirl...", 11153 "Implode...", 11154 "Vignette...", 11155 "Wave...", 11156 "Oil Paint...", 11157 "Charcoal Draw...", 11158 (char *) NULL 11159 }, 11160 *MiscellanyMenu[] = 11161 { 11162 "Image Info", 11163 "Zoom Image", 11164 "Show Preview...", 11165 "Show Histogram", 11166 "Show Matte", 11167 (char *) NULL 11168 }; 11169 11170 static const char 11171 **Menus[ApplyMenus] = 11172 { 11173 FileMenu, 11174 EditMenu, 11175 TransformMenu, 11176 EnhanceMenu, 11177 EffectsMenu, 11178 FXMenu, 11179 MiscellanyMenu 11180 }; 11181 11182 static const CommandType 11183 ApplyCommands[] = 11184 { 11185 NullCommand, 11186 NullCommand, 11187 NullCommand, 11188 NullCommand, 11189 NullCommand, 11190 NullCommand, 11191 NullCommand, 11192 HelpCommand, 11193 QuitCommand 11194 }, 11195 FileCommands[] = 11196 { 11197 SaveCommand, 11198 PrintCommand 11199 }, 11200 EditCommands[] = 11201 { 11202 UndoCommand, 11203 RedoCommand 11204 }, 11205 TransformCommands[] = 11206 { 11207 FlopCommand, 11208 FlipCommand, 11209 RotateRightCommand, 11210 RotateLeftCommand 11211 }, 11212 EnhanceCommands[] = 11213 { 11214 HueCommand, 11215 SaturationCommand, 11216 BrightnessCommand, 11217 GammaCommand, 11218 SpiffCommand, 11219 DullCommand, 11220 ContrastStretchCommand, 11221 SigmoidalContrastCommand, 11222 NormalizeCommand, 11223 EqualizeCommand, 11224 NegateCommand, 11225 GrayscaleCommand, 11226 MapCommand, 11227 QuantizeCommand 11228 }, 11229 EffectsCommands[] = 11230 { 11231 DespeckleCommand, 11232 EmbossCommand, 11233 ReduceNoiseCommand, 11234 AddNoiseCommand, 11235 SharpenCommand, 11236 BlurCommand, 11237 EdgeDetectCommand, 11238 SpreadCommand, 11239 ShadeCommand, 11240 RaiseCommand, 11241 SegmentCommand 11242 }, 11243 FXCommands[] = 11244 { 11245 SolarizeCommand, 11246 SepiaToneCommand, 11247 SwirlCommand, 11248 ImplodeCommand, 11249 VignetteCommand, 11250 WaveCommand, 11251 OilPaintCommand, 11252 CharcoalDrawCommand 11253 }, 11254 MiscellanyCommands[] = 11255 { 11256 InfoCommand, 11257 ZoomCommand, 11258 ShowPreviewCommand, 11259 ShowHistogramCommand, 11260 ShowMatteCommand 11261 }, 11262 ROICommands[] = 11263 { 11264 ROIHelpCommand, 11265 ROIDismissCommand 11266 }; 11267 11268 static const CommandType 11269 *Commands[ApplyMenus] = 11270 { 11271 FileCommands, 11272 EditCommands, 11273 TransformCommands, 11274 EnhanceCommands, 11275 EffectsCommands, 11276 FXCommands, 11277 MiscellanyCommands 11278 }; 11279 11280 char 11281 command[MaxTextExtent], 11282 text[MaxTextExtent]; 11283 11284 CommandType 11285 command_type; 11286 11287 Cursor 11288 cursor; 11289 11290 Image 11291 *roi_image; 11292 11293 int 11294 entry, 11295 id, 11296 x, 11297 y; 11298 11299 double 11300 scale_factor; 11301 11302 MagickProgressMonitor 11303 progress_monitor; 11304 11305 RectangleInfo 11306 crop_info, 11307 highlight_info, 11308 roi_info; 11309 11310 unsigned int 11311 height, 11312 width; 11313 11314 size_t 11315 state; 11316 11317 XEvent 11318 event; 11319 11320 /* 11321 Map Command widget. 11322 */ 11323 (void) CloneString(&windows->command.name,"ROI"); 11324 windows->command.data=0; 11325 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL); 11326 (void) XMapRaised(display,windows->command.id); 11327 XClientMessage(display,windows->image.id,windows->im_protocols, 11328 windows->im_update_widget,CurrentTime); 11329 /* 11330 Track pointer until button 1 is pressed. 11331 */ 11332 XQueryPosition(display,windows->image.id,&x,&y); 11333 (void) XSelectInput(display,windows->image.id, 11334 windows->image.attributes.event_mask | PointerMotionMask); 11335 roi_info.x=(ssize_t) windows->image.x+x; 11336 roi_info.y=(ssize_t) windows->image.y+y; 11337 roi_info.width=0; 11338 roi_info.height=0; 11339 cursor=XCreateFontCursor(display,XC_fleur); 11340 state=DefaultState; 11341 do 11342 { 11343 if (IfMagickTrue(windows->info.mapped) ) 11344 { 11345 /* 11346 Display pointer position. 11347 */ 11348 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 11349 (long) roi_info.x,(long) roi_info.y); 11350 XInfoWidget(display,windows,text); 11351 } 11352 /* 11353 Wait for next event. 11354 */ 11355 XScreenEvent(display,windows,&event,exception); 11356 if (event.xany.window == windows->command.id) 11357 { 11358 /* 11359 Select a command from the Command widget. 11360 */ 11361 id=XCommandWidget(display,windows,ROIMenu,&event); 11362 if (id < 0) 11363 continue; 11364 switch (ROICommands[id]) 11365 { 11366 case ROIHelpCommand: 11367 { 11368 XTextViewWidget(display,resource_info,windows,MagickFalse, 11369 "Help Viewer - Region of Interest",ImageROIHelp); 11370 break; 11371 } 11372 case ROIDismissCommand: 11373 { 11374 /* 11375 Prematurely exit. 11376 */ 11377 state|=EscapeState; 11378 state|=ExitState; 11379 break; 11380 } 11381 default: 11382 break; 11383 } 11384 continue; 11385 } 11386 switch (event.type) 11387 { 11388 case ButtonPress: 11389 { 11390 if (event.xbutton.button != Button1) 11391 break; 11392 if (event.xbutton.window != windows->image.id) 11393 break; 11394 /* 11395 Note first corner of region of interest rectangle-- exit loop. 11396 */ 11397 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11398 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11399 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11400 state|=ExitState; 11401 break; 11402 } 11403 case ButtonRelease: 11404 break; 11405 case Expose: 11406 break; 11407 case KeyPress: 11408 { 11409 KeySym 11410 key_symbol; 11411 11412 if (event.xkey.window != windows->image.id) 11413 break; 11414 /* 11415 Respond to a user key press. 11416 */ 11417 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11418 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11419 switch ((int) key_symbol) 11420 { 11421 case XK_Escape: 11422 case XK_F20: 11423 { 11424 /* 11425 Prematurely exit. 11426 */ 11427 state|=EscapeState; 11428 state|=ExitState; 11429 break; 11430 } 11431 case XK_F1: 11432 case XK_Help: 11433 { 11434 XTextViewWidget(display,resource_info,windows,MagickFalse, 11435 "Help Viewer - Region of Interest",ImageROIHelp); 11436 break; 11437 } 11438 default: 11439 { 11440 (void) XBell(display,0); 11441 break; 11442 } 11443 } 11444 break; 11445 } 11446 case MotionNotify: 11447 { 11448 /* 11449 Map and unmap Info widget as text cursor crosses its boundaries. 11450 */ 11451 x=event.xmotion.x; 11452 y=event.xmotion.y; 11453 if (IfMagickTrue(windows->info.mapped) ) 11454 { 11455 if ((x < (int) (windows->info.x+windows->info.width)) && 11456 (y < (int) (windows->info.y+windows->info.height))) 11457 (void) XWithdrawWindow(display,windows->info.id, 11458 windows->info.screen); 11459 } 11460 else 11461 if ((x > (int) (windows->info.x+windows->info.width)) || 11462 (y > (int) (windows->info.y+windows->info.height))) 11463 (void) XMapWindow(display,windows->info.id); 11464 roi_info.x=(ssize_t) windows->image.x+x; 11465 roi_info.y=(ssize_t) windows->image.y+y; 11466 break; 11467 } 11468 default: 11469 break; 11470 } 11471 } while ((state & ExitState) == 0); 11472 (void) XSelectInput(display,windows->image.id, 11473 windows->image.attributes.event_mask); 11474 if ((state & EscapeState) != 0) 11475 { 11476 /* 11477 User want to exit without region of interest. 11478 */ 11479 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11480 (void) XFreeCursor(display,cursor); 11481 return(MagickTrue); 11482 } 11483 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11484 do 11485 { 11486 /* 11487 Size rectangle as pointer moves until the mouse button is released. 11488 */ 11489 x=(int) roi_info.x; 11490 y=(int) roi_info.y; 11491 roi_info.width=0; 11492 roi_info.height=0; 11493 state=DefaultState; 11494 do 11495 { 11496 highlight_info=roi_info; 11497 highlight_info.x=roi_info.x-windows->image.x; 11498 highlight_info.y=roi_info.y-windows->image.y; 11499 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11500 { 11501 /* 11502 Display info and draw region of interest rectangle. 11503 */ 11504 if (IfMagickFalse(windows->info.mapped) ) 11505 (void) XMapWindow(display,windows->info.id); 11506 (void) FormatLocaleString(text,MaxTextExtent, 11507 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11508 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11509 XInfoWidget(display,windows,text); 11510 XHighlightRectangle(display,windows->image.id, 11511 windows->image.highlight_context,&highlight_info); 11512 } 11513 else 11514 if (IfMagickTrue(windows->info.mapped) ) 11515 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11516 /* 11517 Wait for next event. 11518 */ 11519 XScreenEvent(display,windows,&event,exception); 11520 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11521 XHighlightRectangle(display,windows->image.id, 11522 windows->image.highlight_context,&highlight_info); 11523 switch (event.type) 11524 { 11525 case ButtonPress: 11526 { 11527 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11528 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11529 break; 11530 } 11531 case ButtonRelease: 11532 { 11533 /* 11534 User has committed to region of interest rectangle. 11535 */ 11536 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11537 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11538 XSetCursorState(display,windows,MagickFalse); 11539 state|=ExitState; 11540 if (LocaleCompare(windows->command.name,"Apply") == 0) 11541 break; 11542 (void) CloneString(&windows->command.name,"Apply"); 11543 windows->command.data=ApplyMenus; 11544 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL); 11545 break; 11546 } 11547 case Expose: 11548 break; 11549 case MotionNotify: 11550 { 11551 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11552 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11553 } 11554 default: 11555 break; 11556 } 11557 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) || 11558 ((state & ExitState) != 0)) 11559 { 11560 /* 11561 Check boundary conditions. 11562 */ 11563 if (roi_info.x < 0) 11564 roi_info.x=0; 11565 else 11566 if (roi_info.x > (ssize_t) windows->image.ximage->width) 11567 roi_info.x=(ssize_t) windows->image.ximage->width; 11568 if ((int) roi_info.x < x) 11569 roi_info.width=(unsigned int) (x-roi_info.x); 11570 else 11571 { 11572 roi_info.width=(unsigned int) (roi_info.x-x); 11573 roi_info.x=(ssize_t) x; 11574 } 11575 if (roi_info.y < 0) 11576 roi_info.y=0; 11577 else 11578 if (roi_info.y > (ssize_t) windows->image.ximage->height) 11579 roi_info.y=(ssize_t) windows->image.ximage->height; 11580 if ((int) roi_info.y < y) 11581 roi_info.height=(unsigned int) (y-roi_info.y); 11582 else 11583 { 11584 roi_info.height=(unsigned int) (roi_info.y-y); 11585 roi_info.y=(ssize_t) y; 11586 } 11587 } 11588 } while ((state & ExitState) == 0); 11589 /* 11590 Wait for user to grab a corner of the rectangle or press return. 11591 */ 11592 state=DefaultState; 11593 command_type=NullCommand; 11594 crop_info.x=0; 11595 crop_info.y=0; 11596 (void) XMapWindow(display,windows->info.id); 11597 do 11598 { 11599 if (IfMagickTrue(windows->info.mapped) ) 11600 { 11601 /* 11602 Display pointer position. 11603 */ 11604 (void) FormatLocaleString(text,MaxTextExtent, 11605 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11606 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11607 XInfoWidget(display,windows,text); 11608 } 11609 highlight_info=roi_info; 11610 highlight_info.x=roi_info.x-windows->image.x; 11611 highlight_info.y=roi_info.y-windows->image.y; 11612 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11613 { 11614 state|=EscapeState; 11615 state|=ExitState; 11616 break; 11617 } 11618 if ((state & UpdateRegionState) != 0) 11619 { 11620 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11621 switch (command_type) 11622 { 11623 case UndoCommand: 11624 case RedoCommand: 11625 { 11626 (void) XMagickCommand(display,resource_info,windows,command_type, 11627 image,exception); 11628 break; 11629 } 11630 default: 11631 { 11632 /* 11633 Region of interest is relative to image configuration. 11634 */ 11635 progress_monitor=SetImageProgressMonitor(*image, 11636 (MagickProgressMonitor) NULL,(*image)->client_data); 11637 crop_info=roi_info; 11638 width=(unsigned int) (*image)->columns; 11639 height=(unsigned int) (*image)->rows; 11640 x=0; 11641 y=0; 11642 if (windows->image.crop_geometry != (char *) NULL) 11643 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11644 &width,&height); 11645 scale_factor=(double) width/windows->image.ximage->width; 11646 crop_info.x+=x; 11647 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11648 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11649 scale_factor=(double) 11650 height/windows->image.ximage->height; 11651 crop_info.y+=y; 11652 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11653 crop_info.height=(unsigned int) 11654 (scale_factor*crop_info.height+0.5); 11655 roi_image=CropImage(*image,&crop_info,exception); 11656 (void) SetImageProgressMonitor(*image,progress_monitor, 11657 (*image)->client_data); 11658 if (roi_image == (Image *) NULL) 11659 continue; 11660 /* 11661 Apply image processing technique to the region of interest. 11662 */ 11663 windows->image.orphan=MagickTrue; 11664 (void) XMagickCommand(display,resource_info,windows,command_type, 11665 &roi_image,exception); 11666 progress_monitor=SetImageProgressMonitor(*image, 11667 (MagickProgressMonitor) NULL,(*image)->client_data); 11668 (void) XMagickCommand(display,resource_info,windows, 11669 SaveToUndoBufferCommand,image,exception); 11670 windows->image.orphan=MagickFalse; 11671 (void) CompositeImage(*image,roi_image,CopyCompositeOp, 11672 MagickTrue,crop_info.x,crop_info.y,exception); 11673 roi_image=DestroyImage(roi_image); 11674 (void) SetImageProgressMonitor(*image,progress_monitor, 11675 (*image)->client_data); 11676 break; 11677 } 11678 } 11679 if (command_type != InfoCommand) 11680 { 11681 XConfigureImageColormap(display,resource_info,windows,*image, 11682 exception); 11683 (void) XConfigureImage(display,resource_info,windows,*image, 11684 exception); 11685 } 11686 XCheckRefreshWindows(display,windows); 11687 XInfoWidget(display,windows,text); 11688 (void) XSetFunction(display,windows->image.highlight_context, 11689 GXinvert); 11690 state&=(~UpdateRegionState); 11691 } 11692 XHighlightRectangle(display,windows->image.id, 11693 windows->image.highlight_context,&highlight_info); 11694 XScreenEvent(display,windows,&event,exception); 11695 if (event.xany.window == windows->command.id) 11696 { 11697 /* 11698 Select a command from the Command widget. 11699 */ 11700 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11701 command_type=NullCommand; 11702 id=XCommandWidget(display,windows,ApplyMenu,&event); 11703 if (id >= 0) 11704 { 11705 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent); 11706 command_type=ApplyCommands[id]; 11707 if (id < ApplyMenus) 11708 { 11709 /* 11710 Select a command from a pop-up menu. 11711 */ 11712 entry=XMenuWidget(display,windows,ApplyMenu[id], 11713 (const char **) Menus[id],command); 11714 if (entry >= 0) 11715 { 11716 (void) CopyMagickString(command,Menus[id][entry], 11717 MaxTextExtent); 11718 command_type=Commands[id][entry]; 11719 } 11720 } 11721 } 11722 (void) XSetFunction(display,windows->image.highlight_context, 11723 GXinvert); 11724 XHighlightRectangle(display,windows->image.id, 11725 windows->image.highlight_context,&highlight_info); 11726 if (command_type == HelpCommand) 11727 { 11728 (void) XSetFunction(display,windows->image.highlight_context, 11729 GXcopy); 11730 XTextViewWidget(display,resource_info,windows,MagickFalse, 11731 "Help Viewer - Region of Interest",ImageROIHelp); 11732 (void) XSetFunction(display,windows->image.highlight_context, 11733 GXinvert); 11734 continue; 11735 } 11736 if (command_type == QuitCommand) 11737 { 11738 /* 11739 exit. 11740 */ 11741 state|=EscapeState; 11742 state|=ExitState; 11743 continue; 11744 } 11745 if (command_type != NullCommand) 11746 state|=UpdateRegionState; 11747 continue; 11748 } 11749 XHighlightRectangle(display,windows->image.id, 11750 windows->image.highlight_context,&highlight_info); 11751 switch (event.type) 11752 { 11753 case ButtonPress: 11754 { 11755 x=windows->image.x; 11756 y=windows->image.y; 11757 if (event.xbutton.button != Button1) 11758 break; 11759 if (event.xbutton.window != windows->image.id) 11760 break; 11761 x=windows->image.x+event.xbutton.x; 11762 y=windows->image.y+event.xbutton.y; 11763 if ((x < (int) (roi_info.x+RoiDelta)) && 11764 (x > (int) (roi_info.x-RoiDelta)) && 11765 (y < (int) (roi_info.y+RoiDelta)) && 11766 (y > (int) (roi_info.y-RoiDelta))) 11767 { 11768 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11769 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11770 state|=UpdateConfigurationState; 11771 break; 11772 } 11773 if ((x < (int) (roi_info.x+RoiDelta)) && 11774 (x > (int) (roi_info.x-RoiDelta)) && 11775 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11776 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11777 { 11778 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11779 state|=UpdateConfigurationState; 11780 break; 11781 } 11782 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11783 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11784 (y < (int) (roi_info.y+RoiDelta)) && 11785 (y > (int) (roi_info.y-RoiDelta))) 11786 { 11787 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11788 state|=UpdateConfigurationState; 11789 break; 11790 } 11791 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11792 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11793 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11794 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11795 { 11796 state|=UpdateConfigurationState; 11797 break; 11798 } 11799 } 11800 case ButtonRelease: 11801 { 11802 if (event.xbutton.window == windows->pan.id) 11803 if ((highlight_info.x != crop_info.x-windows->image.x) || 11804 (highlight_info.y != crop_info.y-windows->image.y)) 11805 XHighlightRectangle(display,windows->image.id, 11806 windows->image.highlight_context,&highlight_info); 11807 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11808 event.xbutton.time); 11809 break; 11810 } 11811 case Expose: 11812 { 11813 if (event.xexpose.window == windows->image.id) 11814 if (event.xexpose.count == 0) 11815 { 11816 event.xexpose.x=(int) highlight_info.x; 11817 event.xexpose.y=(int) highlight_info.y; 11818 event.xexpose.width=(int) highlight_info.width; 11819 event.xexpose.height=(int) highlight_info.height; 11820 XRefreshWindow(display,&windows->image,&event); 11821 } 11822 if (event.xexpose.window == windows->info.id) 11823 if (event.xexpose.count == 0) 11824 XInfoWidget(display,windows,text); 11825 break; 11826 } 11827 case KeyPress: 11828 { 11829 KeySym 11830 key_symbol; 11831 11832 if (event.xkey.window != windows->image.id) 11833 break; 11834 /* 11835 Respond to a user key press. 11836 */ 11837 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11838 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11839 switch ((int) key_symbol) 11840 { 11841 case XK_Shift_L: 11842 case XK_Shift_R: 11843 break; 11844 case XK_Escape: 11845 case XK_F20: 11846 state|=EscapeState; 11847 case XK_Return: 11848 { 11849 state|=ExitState; 11850 break; 11851 } 11852 case XK_Home: 11853 case XK_KP_Home: 11854 { 11855 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11856 roi_info.y=(ssize_t) (windows->image.height/2L- 11857 roi_info.height/2L); 11858 break; 11859 } 11860 case XK_Left: 11861 case XK_KP_Left: 11862 { 11863 roi_info.x--; 11864 break; 11865 } 11866 case XK_Up: 11867 case XK_KP_Up: 11868 case XK_Next: 11869 { 11870 roi_info.y--; 11871 break; 11872 } 11873 case XK_Right: 11874 case XK_KP_Right: 11875 { 11876 roi_info.x++; 11877 break; 11878 } 11879 case XK_Prior: 11880 case XK_Down: 11881 case XK_KP_Down: 11882 { 11883 roi_info.y++; 11884 break; 11885 } 11886 case XK_F1: 11887 case XK_Help: 11888 { 11889 (void) XSetFunction(display,windows->image.highlight_context, 11890 GXcopy); 11891 XTextViewWidget(display,resource_info,windows,MagickFalse, 11892 "Help Viewer - Region of Interest",ImageROIHelp); 11893 (void) XSetFunction(display,windows->image.highlight_context, 11894 GXinvert); 11895 break; 11896 } 11897 default: 11898 { 11899 command_type=XImageWindowCommand(display,resource_info,windows, 11900 event.xkey.state,key_symbol,image,exception); 11901 if (command_type != NullCommand) 11902 state|=UpdateRegionState; 11903 break; 11904 } 11905 } 11906 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11907 event.xkey.time); 11908 break; 11909 } 11910 case KeyRelease: 11911 break; 11912 case MotionNotify: 11913 { 11914 if (event.xbutton.window != windows->image.id) 11915 break; 11916 /* 11917 Map and unmap Info widget as text cursor crosses its boundaries. 11918 */ 11919 x=event.xmotion.x; 11920 y=event.xmotion.y; 11921 if (IfMagickTrue(windows->info.mapped) ) 11922 { 11923 if ((x < (int) (windows->info.x+windows->info.width)) && 11924 (y < (int) (windows->info.y+windows->info.height))) 11925 (void) XWithdrawWindow(display,windows->info.id, 11926 windows->info.screen); 11927 } 11928 else 11929 if ((x > (int) (windows->info.x+windows->info.width)) || 11930 (y > (int) (windows->info.y+windows->info.height))) 11931 (void) XMapWindow(display,windows->info.id); 11932 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11933 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11934 break; 11935 } 11936 case SelectionRequest: 11937 { 11938 XSelectionEvent 11939 notify; 11940 11941 XSelectionRequestEvent 11942 *request; 11943 11944 /* 11945 Set primary selection. 11946 */ 11947 (void) FormatLocaleString(text,MaxTextExtent, 11948 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11949 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11950 request=(&(event.xselectionrequest)); 11951 (void) XChangeProperty(request->display,request->requestor, 11952 request->property,request->target,8,PropModeReplace, 11953 (unsigned char *) text,(int) strlen(text)); 11954 notify.type=SelectionNotify; 11955 notify.display=request->display; 11956 notify.requestor=request->requestor; 11957 notify.selection=request->selection; 11958 notify.target=request->target; 11959 notify.time=request->time; 11960 if (request->property == None) 11961 notify.property=request->target; 11962 else 11963 notify.property=request->property; 11964 (void) XSendEvent(request->display,request->requestor,False,0, 11965 (XEvent *) ¬ify); 11966 } 11967 default: 11968 break; 11969 } 11970 if ((state & UpdateConfigurationState) != 0) 11971 { 11972 (void) XPutBackEvent(display,&event); 11973 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11974 break; 11975 } 11976 } while ((state & ExitState) == 0); 11977 } while ((state & ExitState) == 0); 11978 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11979 XSetCursorState(display,windows,MagickFalse); 11980 if ((state & EscapeState) != 0) 11981 return(MagickTrue); 11982 return(MagickTrue); 11983} 11984 11985/* 11986%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11987% % 11988% % 11989% % 11990+ X R o t a t e I m a g e % 11991% % 11992% % 11993% % 11994%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11995% 11996% XRotateImage() rotates the X image. If the degrees parameter if zero, the 11997% rotation angle is computed from the slope of a line drawn by the user. 11998% 11999% The format of the XRotateImage method is: 12000% 12001% MagickBooleanType XRotateImage(Display *display, 12002% XResourceInfo *resource_info,XWindows *windows,double degrees, 12003% Image **image,ExceptionInfo *exception) 12004% 12005% A description of each parameter follows: 12006% 12007% o display: Specifies a connection to an X server; returned from 12008% XOpenDisplay. 12009% 12010% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12011% 12012% o windows: Specifies a pointer to a XWindows structure. 12013% 12014% o degrees: Specifies the number of degrees to rotate the image. 12015% 12016% o image: the image. 12017% 12018% o exception: return any errors or warnings in this structure. 12019% 12020*/ 12021static MagickBooleanType XRotateImage(Display *display, 12022 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image, 12023 ExceptionInfo *exception) 12024{ 12025 static const char 12026 *RotateMenu[] = 12027 { 12028 "Pixel Color", 12029 "Direction", 12030 "Help", 12031 "Dismiss", 12032 (char *) NULL 12033 }; 12034 12035 static ModeType 12036 direction = HorizontalRotateCommand; 12037 12038 static const ModeType 12039 DirectionCommands[] = 12040 { 12041 HorizontalRotateCommand, 12042 VerticalRotateCommand 12043 }, 12044 RotateCommands[] = 12045 { 12046 RotateColorCommand, 12047 RotateDirectionCommand, 12048 RotateHelpCommand, 12049 RotateDismissCommand 12050 }; 12051 12052 static unsigned int 12053 pen_id = 0; 12054 12055 char 12056 command[MaxTextExtent], 12057 text[MaxTextExtent]; 12058 12059 Image 12060 *rotate_image; 12061 12062 int 12063 id, 12064 x, 12065 y; 12066 12067 double 12068 normalized_degrees; 12069 12070 register int 12071 i; 12072 12073 unsigned int 12074 height, 12075 rotations, 12076 width; 12077 12078 if (degrees == 0.0) 12079 { 12080 unsigned int 12081 distance; 12082 12083 size_t 12084 state; 12085 12086 XEvent 12087 event; 12088 12089 XSegment 12090 rotate_info; 12091 12092 /* 12093 Map Command widget. 12094 */ 12095 (void) CloneString(&windows->command.name,"Rotate"); 12096 windows->command.data=2; 12097 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 12098 (void) XMapRaised(display,windows->command.id); 12099 XClientMessage(display,windows->image.id,windows->im_protocols, 12100 windows->im_update_widget,CurrentTime); 12101 /* 12102 Wait for first button press. 12103 */ 12104 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12105 XQueryPosition(display,windows->image.id,&x,&y); 12106 rotate_info.x1=x; 12107 rotate_info.y1=y; 12108 rotate_info.x2=x; 12109 rotate_info.y2=y; 12110 state=DefaultState; 12111 do 12112 { 12113 XHighlightLine(display,windows->image.id, 12114 windows->image.highlight_context,&rotate_info); 12115 /* 12116 Wait for next event. 12117 */ 12118 XScreenEvent(display,windows,&event,exception); 12119 XHighlightLine(display,windows->image.id, 12120 windows->image.highlight_context,&rotate_info); 12121 if (event.xany.window == windows->command.id) 12122 { 12123 /* 12124 Select a command from the Command widget. 12125 */ 12126 id=XCommandWidget(display,windows,RotateMenu,&event); 12127 if (id < 0) 12128 continue; 12129 (void) XSetFunction(display,windows->image.highlight_context, 12130 GXcopy); 12131 switch (RotateCommands[id]) 12132 { 12133 case RotateColorCommand: 12134 { 12135 const char 12136 *ColorMenu[MaxNumberPens]; 12137 12138 int 12139 pen_number; 12140 12141 XColor 12142 color; 12143 12144 /* 12145 Initialize menu selections. 12146 */ 12147 for (i=0; i < (int) (MaxNumberPens-2); i++) 12148 ColorMenu[i]=resource_info->pen_colors[i]; 12149 ColorMenu[MaxNumberPens-2]="Browser..."; 12150 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12151 /* 12152 Select a pen color from the pop-up menu. 12153 */ 12154 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12155 (const char **) ColorMenu,command); 12156 if (pen_number < 0) 12157 break; 12158 if (pen_number == (MaxNumberPens-2)) 12159 { 12160 static char 12161 color_name[MaxTextExtent] = "gray"; 12162 12163 /* 12164 Select a pen color from a dialog. 12165 */ 12166 resource_info->pen_colors[pen_number]=color_name; 12167 XColorBrowserWidget(display,windows,"Select",color_name); 12168 if (*color_name == '\0') 12169 break; 12170 } 12171 /* 12172 Set pen color. 12173 */ 12174 (void) XParseColor(display,windows->map_info->colormap, 12175 resource_info->pen_colors[pen_number],&color); 12176 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12177 (unsigned int) MaxColors,&color); 12178 windows->pixel_info->pen_colors[pen_number]=color; 12179 pen_id=(unsigned int) pen_number; 12180 break; 12181 } 12182 case RotateDirectionCommand: 12183 { 12184 static const char 12185 *Directions[] = 12186 { 12187 "horizontal", 12188 "vertical", 12189 (char *) NULL, 12190 }; 12191 12192 /* 12193 Select a command from the pop-up menu. 12194 */ 12195 id=XMenuWidget(display,windows,RotateMenu[id], 12196 Directions,command); 12197 if (id >= 0) 12198 direction=DirectionCommands[id]; 12199 break; 12200 } 12201 case RotateHelpCommand: 12202 { 12203 XTextViewWidget(display,resource_info,windows,MagickFalse, 12204 "Help Viewer - Image Rotation",ImageRotateHelp); 12205 break; 12206 } 12207 case RotateDismissCommand: 12208 { 12209 /* 12210 Prematurely exit. 12211 */ 12212 state|=EscapeState; 12213 state|=ExitState; 12214 break; 12215 } 12216 default: 12217 break; 12218 } 12219 (void) XSetFunction(display,windows->image.highlight_context, 12220 GXinvert); 12221 continue; 12222 } 12223 switch (event.type) 12224 { 12225 case ButtonPress: 12226 { 12227 if (event.xbutton.button != Button1) 12228 break; 12229 if (event.xbutton.window != windows->image.id) 12230 break; 12231 /* 12232 exit loop. 12233 */ 12234 (void) XSetFunction(display,windows->image.highlight_context, 12235 GXcopy); 12236 rotate_info.x1=event.xbutton.x; 12237 rotate_info.y1=event.xbutton.y; 12238 state|=ExitState; 12239 break; 12240 } 12241 case ButtonRelease: 12242 break; 12243 case Expose: 12244 break; 12245 case KeyPress: 12246 { 12247 char 12248 command[MaxTextExtent]; 12249 12250 KeySym 12251 key_symbol; 12252 12253 if (event.xkey.window != windows->image.id) 12254 break; 12255 /* 12256 Respond to a user key press. 12257 */ 12258 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12259 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12260 switch ((int) key_symbol) 12261 { 12262 case XK_Escape: 12263 case XK_F20: 12264 { 12265 /* 12266 Prematurely exit. 12267 */ 12268 state|=EscapeState; 12269 state|=ExitState; 12270 break; 12271 } 12272 case XK_F1: 12273 case XK_Help: 12274 { 12275 (void) XSetFunction(display,windows->image.highlight_context, 12276 GXcopy); 12277 XTextViewWidget(display,resource_info,windows,MagickFalse, 12278 "Help Viewer - Image Rotation",ImageRotateHelp); 12279 (void) XSetFunction(display,windows->image.highlight_context, 12280 GXinvert); 12281 break; 12282 } 12283 default: 12284 { 12285 (void) XBell(display,0); 12286 break; 12287 } 12288 } 12289 break; 12290 } 12291 case MotionNotify: 12292 { 12293 rotate_info.x1=event.xmotion.x; 12294 rotate_info.y1=event.xmotion.y; 12295 } 12296 } 12297 rotate_info.x2=rotate_info.x1; 12298 rotate_info.y2=rotate_info.y1; 12299 if (direction == HorizontalRotateCommand) 12300 rotate_info.x2+=32; 12301 else 12302 rotate_info.y2-=32; 12303 } while ((state & ExitState) == 0); 12304 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12305 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12306 if ((state & EscapeState) != 0) 12307 return(MagickTrue); 12308 /* 12309 Draw line as pointer moves until the mouse button is released. 12310 */ 12311 distance=0; 12312 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12313 state=DefaultState; 12314 do 12315 { 12316 if (distance > 9) 12317 { 12318 /* 12319 Display info and draw rotation line. 12320 */ 12321 if (IfMagickFalse(windows->info.mapped) ) 12322 (void) XMapWindow(display,windows->info.id); 12323 (void) FormatLocaleString(text,MaxTextExtent," %g", 12324 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12325 XInfoWidget(display,windows,text); 12326 XHighlightLine(display,windows->image.id, 12327 windows->image.highlight_context,&rotate_info); 12328 } 12329 else 12330 if (IfMagickTrue(windows->info.mapped) ) 12331 (void) XWithdrawWindow(display,windows->info.id, 12332 windows->info.screen); 12333 /* 12334 Wait for next event. 12335 */ 12336 XScreenEvent(display,windows,&event,exception); 12337 if (distance > 9) 12338 XHighlightLine(display,windows->image.id, 12339 windows->image.highlight_context,&rotate_info); 12340 switch (event.type) 12341 { 12342 case ButtonPress: 12343 break; 12344 case ButtonRelease: 12345 { 12346 /* 12347 User has committed to rotation line. 12348 */ 12349 rotate_info.x2=event.xbutton.x; 12350 rotate_info.y2=event.xbutton.y; 12351 state|=ExitState; 12352 break; 12353 } 12354 case Expose: 12355 break; 12356 case MotionNotify: 12357 { 12358 rotate_info.x2=event.xmotion.x; 12359 rotate_info.y2=event.xmotion.y; 12360 } 12361 default: 12362 break; 12363 } 12364 /* 12365 Check boundary conditions. 12366 */ 12367 if (rotate_info.x2 < 0) 12368 rotate_info.x2=0; 12369 else 12370 if (rotate_info.x2 > (int) windows->image.width) 12371 rotate_info.x2=(short) windows->image.width; 12372 if (rotate_info.y2 < 0) 12373 rotate_info.y2=0; 12374 else 12375 if (rotate_info.y2 > (int) windows->image.height) 12376 rotate_info.y2=(short) windows->image.height; 12377 /* 12378 Compute rotation angle from the slope of the line. 12379 */ 12380 degrees=0.0; 12381 distance=(unsigned int) 12382 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12383 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12384 if (distance > 9) 12385 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12386 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12387 } while ((state & ExitState) == 0); 12388 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12389 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12390 if (distance <= 9) 12391 return(MagickTrue); 12392 } 12393 if (direction == VerticalRotateCommand) 12394 degrees-=90.0; 12395 if (degrees == 0.0) 12396 return(MagickTrue); 12397 /* 12398 Rotate image. 12399 */ 12400 normalized_degrees=degrees; 12401 while (normalized_degrees < -45.0) 12402 normalized_degrees+=360.0; 12403 for (rotations=0; normalized_degrees > 45.0; rotations++) 12404 normalized_degrees-=90.0; 12405 if (normalized_degrees != 0.0) 12406 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 12407 exception); 12408 XSetCursorState(display,windows,MagickTrue); 12409 XCheckRefreshWindows(display,windows); 12410 (*image)->background_color.red=(double) ScaleShortToQuantum( 12411 windows->pixel_info->pen_colors[pen_id].red); 12412 (*image)->background_color.green=(double) ScaleShortToQuantum( 12413 windows->pixel_info->pen_colors[pen_id].green); 12414 (*image)->background_color.blue=(double) ScaleShortToQuantum( 12415 windows->pixel_info->pen_colors[pen_id].blue); 12416 rotate_image=RotateImage(*image,degrees,exception); 12417 XSetCursorState(display,windows,MagickFalse); 12418 if (rotate_image == (Image *) NULL) 12419 return(MagickFalse); 12420 *image=DestroyImage(*image); 12421 *image=rotate_image; 12422 if (windows->image.crop_geometry != (char *) NULL) 12423 { 12424 /* 12425 Rotate crop geometry. 12426 */ 12427 width=(unsigned int) (*image)->columns; 12428 height=(unsigned int) (*image)->rows; 12429 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12430 switch (rotations % 4) 12431 { 12432 default: 12433 case 0: 12434 break; 12435 case 1: 12436 { 12437 /* 12438 Rotate 90 degrees. 12439 */ 12440 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12441 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12442 (int) height-y,x); 12443 break; 12444 } 12445 case 2: 12446 { 12447 /* 12448 Rotate 180 degrees. 12449 */ 12450 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12451 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12452 break; 12453 } 12454 case 3: 12455 { 12456 /* 12457 Rotate 270 degrees. 12458 */ 12459 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12460 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12461 break; 12462 } 12463 } 12464 } 12465 if (IfMagickTrue(windows->image.orphan) ) 12466 return(MagickTrue); 12467 if (normalized_degrees != 0.0) 12468 { 12469 /* 12470 Update image colormap. 12471 */ 12472 windows->image.window_changes.width=(int) (*image)->columns; 12473 windows->image.window_changes.height=(int) (*image)->rows; 12474 if (windows->image.crop_geometry != (char *) NULL) 12475 { 12476 /* 12477 Obtain dimensions of image from crop geometry. 12478 */ 12479 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12480 &width,&height); 12481 windows->image.window_changes.width=(int) width; 12482 windows->image.window_changes.height=(int) height; 12483 } 12484 XConfigureImageColormap(display,resource_info,windows,*image,exception); 12485 } 12486 else 12487 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12488 { 12489 windows->image.window_changes.width=windows->image.ximage->height; 12490 windows->image.window_changes.height=windows->image.ximage->width; 12491 } 12492 /* 12493 Update image configuration. 12494 */ 12495 (void) XConfigureImage(display,resource_info,windows,*image,exception); 12496 return(MagickTrue); 12497} 12498 12499/* 12500%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12501% % 12502% % 12503% % 12504+ X S a v e I m a g e % 12505% % 12506% % 12507% % 12508%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12509% 12510% XSaveImage() saves an image to a file. 12511% 12512% The format of the XSaveImage method is: 12513% 12514% MagickBooleanType XSaveImage(Display *display, 12515% XResourceInfo *resource_info,XWindows *windows,Image *image, 12516% ExceptionInfo *exception) 12517% 12518% A description of each parameter follows: 12519% 12520% o display: Specifies a connection to an X server; returned from 12521% XOpenDisplay. 12522% 12523% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12524% 12525% o windows: Specifies a pointer to a XWindows structure. 12526% 12527% o image: the image. 12528% 12529% o exception: return any errors or warnings in this structure. 12530% 12531*/ 12532static MagickBooleanType XSaveImage(Display *display, 12533 XResourceInfo *resource_info,XWindows *windows,Image *image, 12534 ExceptionInfo *exception) 12535{ 12536 char 12537 filename[MaxTextExtent], 12538 geometry[MaxTextExtent]; 12539 12540 Image 12541 *save_image; 12542 12543 ImageInfo 12544 *image_info; 12545 12546 MagickStatusType 12547 status; 12548 12549 /* 12550 Request file name from user. 12551 */ 12552 if (resource_info->write_filename != (char *) NULL) 12553 (void) CopyMagickString(filename,resource_info->write_filename, 12554 MaxTextExtent); 12555 else 12556 { 12557 char 12558 path[MaxTextExtent]; 12559 12560 int 12561 status; 12562 12563 GetPathComponent(image->filename,HeadPath,path); 12564 GetPathComponent(image->filename,TailPath,filename); 12565 if (*path != '\0') 12566 { 12567 status=chdir(path); 12568 if (status == -1) 12569 (void) ThrowMagickException(exception,GetMagickModule(), 12570 FileOpenError,"UnableToOpenFile","%s",path); 12571 } 12572 } 12573 XFileBrowserWidget(display,windows,"Save",filename); 12574 if (*filename == '\0') 12575 return(MagickTrue); 12576 if (IfMagickTrue(IsPathAccessible(filename)) ) 12577 { 12578 int 12579 status; 12580 12581 /* 12582 File exists-- seek user's permission before overwriting. 12583 */ 12584 status=XConfirmWidget(display,windows,"Overwrite",filename); 12585 if (status <= 0) 12586 return(MagickTrue); 12587 } 12588 image_info=CloneImageInfo(resource_info->image_info); 12589 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 12590 (void) SetImageInfo(image_info,1,exception); 12591 if ((LocaleCompare(image_info->magick,"JPEG") == 0) || 12592 (LocaleCompare(image_info->magick,"JPG") == 0)) 12593 { 12594 char 12595 quality[MaxTextExtent]; 12596 12597 int 12598 status; 12599 12600 /* 12601 Request JPEG quality from user. 12602 */ 12603 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double) 12604 image->quality); 12605 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", 12606 quality); 12607 if (*quality == '\0') 12608 return(MagickTrue); 12609 image->quality=StringToUnsignedLong(quality); 12610 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace; 12611 } 12612 if ((LocaleCompare(image_info->magick,"EPS") == 0) || 12613 (LocaleCompare(image_info->magick,"PDF") == 0) || 12614 (LocaleCompare(image_info->magick,"PS") == 0) || 12615 (LocaleCompare(image_info->magick,"PS2") == 0)) 12616 { 12617 char 12618 geometry[MaxTextExtent]; 12619 12620 /* 12621 Request page geometry from user. 12622 */ 12623 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12624 if (LocaleCompare(image_info->magick,"PDF") == 0) 12625 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12626 if (image_info->page != (char *) NULL) 12627 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 12628 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 12629 "Select page geometry:",geometry); 12630 if (*geometry != '\0') 12631 image_info->page=GetPageGeometry(geometry); 12632 } 12633 /* 12634 Apply image transforms. 12635 */ 12636 XSetCursorState(display,windows,MagickTrue); 12637 XCheckRefreshWindows(display,windows); 12638 save_image=CloneImage(image,0,0,MagickTrue,exception); 12639 if (save_image == (Image *) NULL) 12640 return(MagickFalse); 12641 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 12642 windows->image.ximage->width,windows->image.ximage->height); 12643 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry, 12644 exception); 12645 /* 12646 Write image. 12647 */ 12648 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent); 12649 status=WriteImage(image_info,save_image,exception); 12650 if (IfMagickTrue(status) ) 12651 image->taint=MagickFalse; 12652 save_image=DestroyImage(save_image); 12653 image_info=DestroyImageInfo(image_info); 12654 XSetCursorState(display,windows,MagickFalse); 12655 return(IsMagickTrue(status)); 12656} 12657 12658/* 12659%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12660% % 12661% % 12662% % 12663+ X S c r e e n E v e n t % 12664% % 12665% % 12666% % 12667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12668% 12669% XScreenEvent() handles global events associated with the Pan and Magnify 12670% windows. 12671% 12672% The format of the XScreenEvent function is: 12673% 12674% void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12675% ExceptionInfo *exception) 12676% 12677% A description of each parameter follows: 12678% 12679% o display: Specifies a pointer to the Display structure; returned from 12680% XOpenDisplay. 12681% 12682% o windows: Specifies a pointer to a XWindows structure. 12683% 12684% o event: Specifies a pointer to a X11 XEvent structure. 12685% 12686% o exception: return any errors or warnings in this structure. 12687% 12688*/ 12689 12690#if defined(__cplusplus) || defined(c_plusplus) 12691extern "C" { 12692#endif 12693 12694static int XPredicate(Display *magick_unused(display),XEvent *event,char *data) 12695{ 12696 register XWindows 12697 *windows; 12698 12699 windows=(XWindows *) data; 12700 if ((event->type == ClientMessage) && 12701 (event->xclient.window == windows->image.id)) 12702 return(MagickFalse); 12703 return(MagickTrue); 12704} 12705 12706#if defined(__cplusplus) || defined(c_plusplus) 12707} 12708#endif 12709 12710static void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12711 ExceptionInfo *exception) 12712{ 12713 register int 12714 x, 12715 y; 12716 12717 (void) XIfEvent(display,event,XPredicate,(char *) windows); 12718 if (event->xany.window == windows->command.id) 12719 return; 12720 switch (event->type) 12721 { 12722 case ButtonPress: 12723 case ButtonRelease: 12724 { 12725 if ((event->xbutton.button == Button3) && 12726 (event->xbutton.state & Mod1Mask)) 12727 { 12728 /* 12729 Convert Alt-Button3 to Button2. 12730 */ 12731 event->xbutton.button=Button2; 12732 event->xbutton.state&=(~Mod1Mask); 12733 } 12734 if (event->xbutton.window == windows->backdrop.id) 12735 { 12736 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent, 12737 event->xbutton.time); 12738 break; 12739 } 12740 if (event->xbutton.window == windows->pan.id) 12741 { 12742 XPanImage(display,windows,event,exception); 12743 break; 12744 } 12745 if (event->xbutton.window == windows->image.id) 12746 if (event->xbutton.button == Button2) 12747 { 12748 /* 12749 Update magnified image. 12750 */ 12751 x=event->xbutton.x; 12752 y=event->xbutton.y; 12753 if (x < 0) 12754 x=0; 12755 else 12756 if (x >= (int) windows->image.width) 12757 x=(int) (windows->image.width-1); 12758 windows->magnify.x=(int) windows->image.x+x; 12759 if (y < 0) 12760 y=0; 12761 else 12762 if (y >= (int) windows->image.height) 12763 y=(int) (windows->image.height-1); 12764 windows->magnify.y=windows->image.y+y; 12765 if (IfMagickFalse(windows->magnify.mapped) ) 12766 (void) XMapRaised(display,windows->magnify.id); 12767 XMakeMagnifyImage(display,windows,exception); 12768 if (event->type == ButtonRelease) 12769 (void) XWithdrawWindow(display,windows->info.id, 12770 windows->info.screen); 12771 break; 12772 } 12773 break; 12774 } 12775 case ClientMessage: 12776 { 12777 /* 12778 If client window delete message, exit. 12779 */ 12780 if (event->xclient.message_type != windows->wm_protocols) 12781 break; 12782 if (*event->xclient.data.l != (long) windows->wm_delete_window) 12783 break; 12784 if (event->xclient.window == windows->magnify.id) 12785 { 12786 (void) XWithdrawWindow(display,windows->magnify.id, 12787 windows->magnify.screen); 12788 break; 12789 } 12790 break; 12791 } 12792 case ConfigureNotify: 12793 { 12794 if (event->xconfigure.window == windows->magnify.id) 12795 { 12796 unsigned int 12797 magnify; 12798 12799 /* 12800 Magnify window has a new configuration. 12801 */ 12802 windows->magnify.width=(unsigned int) event->xconfigure.width; 12803 windows->magnify.height=(unsigned int) event->xconfigure.height; 12804 if (IfMagickFalse(windows->magnify.mapped) ) 12805 break; 12806 magnify=1; 12807 while ((int) magnify <= event->xconfigure.width) 12808 magnify<<=1; 12809 while ((int) magnify <= event->xconfigure.height) 12810 magnify<<=1; 12811 magnify>>=1; 12812 if (((int) magnify != event->xconfigure.width) || 12813 ((int) magnify != event->xconfigure.height)) 12814 { 12815 XWindowChanges 12816 window_changes; 12817 12818 window_changes.width=(int) magnify; 12819 window_changes.height=(int) magnify; 12820 (void) XReconfigureWMWindow(display,windows->magnify.id, 12821 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 12822 &window_changes); 12823 break; 12824 } 12825 XMakeMagnifyImage(display,windows,exception); 12826 break; 12827 } 12828 break; 12829 } 12830 case Expose: 12831 { 12832 if (event->xexpose.window == windows->image.id) 12833 { 12834 XRefreshWindow(display,&windows->image,event); 12835 break; 12836 } 12837 if (event->xexpose.window == windows->pan.id) 12838 if (event->xexpose.count == 0) 12839 { 12840 XDrawPanRectangle(display,windows); 12841 break; 12842 } 12843 if (event->xexpose.window == windows->magnify.id) 12844 if (event->xexpose.count == 0) 12845 { 12846 XMakeMagnifyImage(display,windows,exception); 12847 break; 12848 } 12849 break; 12850 } 12851 case KeyPress: 12852 { 12853 char 12854 command[MaxTextExtent]; 12855 12856 KeySym 12857 key_symbol; 12858 12859 if (event->xkey.window != windows->magnify.id) 12860 break; 12861 /* 12862 Respond to a user key press. 12863 */ 12864 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int) 12865 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12866 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol, 12867 exception); 12868 break; 12869 } 12870 case MapNotify: 12871 { 12872 if (event->xmap.window == windows->magnify.id) 12873 { 12874 windows->magnify.mapped=MagickTrue; 12875 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12876 break; 12877 } 12878 if (event->xmap.window == windows->info.id) 12879 { 12880 windows->info.mapped=MagickTrue; 12881 break; 12882 } 12883 break; 12884 } 12885 case MotionNotify: 12886 { 12887 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; 12888 if (event->xmotion.window == windows->image.id) 12889 if (IfMagickTrue(windows->magnify.mapped) ) 12890 { 12891 /* 12892 Update magnified image. 12893 */ 12894 x=event->xmotion.x; 12895 y=event->xmotion.y; 12896 if (x < 0) 12897 x=0; 12898 else 12899 if (x >= (int) windows->image.width) 12900 x=(int) (windows->image.width-1); 12901 windows->magnify.x=(int) windows->image.x+x; 12902 if (y < 0) 12903 y=0; 12904 else 12905 if (y >= (int) windows->image.height) 12906 y=(int) (windows->image.height-1); 12907 windows->magnify.y=windows->image.y+y; 12908 XMakeMagnifyImage(display,windows,exception); 12909 } 12910 break; 12911 } 12912 case UnmapNotify: 12913 { 12914 if (event->xunmap.window == windows->magnify.id) 12915 { 12916 windows->magnify.mapped=MagickFalse; 12917 break; 12918 } 12919 if (event->xunmap.window == windows->info.id) 12920 { 12921 windows->info.mapped=MagickFalse; 12922 break; 12923 } 12924 break; 12925 } 12926 default: 12927 break; 12928 } 12929} 12930 12931/* 12932%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12933% % 12934% % 12935% % 12936+ X S e t C r o p G e o m e t r y % 12937% % 12938% % 12939% % 12940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12941% 12942% XSetCropGeometry() accepts a cropping geometry relative to the Image window 12943% and translates it to a cropping geometry relative to the image. 12944% 12945% The format of the XSetCropGeometry method is: 12946% 12947% void XSetCropGeometry(Display *display,XWindows *windows, 12948% RectangleInfo *crop_info,Image *image) 12949% 12950% A description of each parameter follows: 12951% 12952% o display: Specifies a connection to an X server; returned from 12953% XOpenDisplay. 12954% 12955% o windows: Specifies a pointer to a XWindows structure. 12956% 12957% o crop_info: A pointer to a RectangleInfo that defines a region of the 12958% Image window to crop. 12959% 12960% o image: the image. 12961% 12962*/ 12963static void XSetCropGeometry(Display *display,XWindows *windows, 12964 RectangleInfo *crop_info,Image *image) 12965{ 12966 char 12967 text[MaxTextExtent]; 12968 12969 int 12970 x, 12971 y; 12972 12973 double 12974 scale_factor; 12975 12976 unsigned int 12977 height, 12978 width; 12979 12980 if (IfMagickTrue(windows->info.mapped) ) 12981 { 12982 /* 12983 Display info on cropping rectangle. 12984 */ 12985 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g", 12986 (double) crop_info->width,(double) crop_info->height,(double) 12987 crop_info->x,(double) crop_info->y); 12988 XInfoWidget(display,windows,text); 12989 } 12990 /* 12991 Cropping geometry is relative to any previous crop geometry. 12992 */ 12993 x=0; 12994 y=0; 12995 width=(unsigned int) image->columns; 12996 height=(unsigned int) image->rows; 12997 if (windows->image.crop_geometry != (char *) NULL) 12998 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12999 else 13000 windows->image.crop_geometry=AcquireString((char *) NULL); 13001 /* 13002 Define the crop geometry string from the cropping rectangle. 13003 */ 13004 scale_factor=(double) width/windows->image.ximage->width; 13005 if (crop_info->x > 0) 13006 x+=(int) (scale_factor*crop_info->x+0.5); 13007 width=(unsigned int) (scale_factor*crop_info->width+0.5); 13008 if (width == 0) 13009 width=1; 13010 scale_factor=(double) height/windows->image.ximage->height; 13011 if (crop_info->y > 0) 13012 y+=(int) (scale_factor*crop_info->y+0.5); 13013 height=(unsigned int) (scale_factor*crop_info->height+0.5); 13014 if (height == 0) 13015 height=1; 13016 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 13017 "%ux%u%+d%+d",width,height,x,y); 13018} 13019 13020/* 13021%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13022% % 13023% % 13024% % 13025+ X T i l e I m a g e % 13026% % 13027% % 13028% % 13029%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13030% 13031% XTileImage() loads or deletes a selected tile from a visual image directory. 13032% The load or delete command is chosen from a menu. 13033% 13034% The format of the XTileImage method is: 13035% 13036% Image *XTileImage(Display *display,XResourceInfo *resource_info, 13037% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13038% 13039% A description of each parameter follows: 13040% 13041% o tile_image: XTileImage reads or deletes the tile image 13042% and returns it. A null image is returned if an error occurs. 13043% 13044% o display: Specifies a connection to an X server; returned from 13045% XOpenDisplay. 13046% 13047% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13048% 13049% o windows: Specifies a pointer to a XWindows structure. 13050% 13051% o image: the image; returned from ReadImage. 13052% 13053% o event: Specifies a pointer to a XEvent structure. If it is NULL, 13054% the entire image is refreshed. 13055% 13056% o exception: return any errors or warnings in this structure. 13057% 13058*/ 13059static Image *XTileImage(Display *display,XResourceInfo *resource_info, 13060 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13061{ 13062 static const char 13063 *VerbMenu[] = 13064 { 13065 "Load", 13066 "Next", 13067 "Former", 13068 "Delete", 13069 "Update", 13070 (char *) NULL, 13071 }; 13072 13073 static const ModeType 13074 TileCommands[] = 13075 { 13076 TileLoadCommand, 13077 TileNextCommand, 13078 TileFormerCommand, 13079 TileDeleteCommand, 13080 TileUpdateCommand 13081 }; 13082 13083 char 13084 command[MaxTextExtent], 13085 filename[MaxTextExtent]; 13086 13087 Image 13088 *tile_image; 13089 13090 int 13091 id, 13092 status, 13093 tile, 13094 x, 13095 y; 13096 13097 double 13098 scale_factor; 13099 13100 register char 13101 *p, 13102 *q; 13103 13104 register int 13105 i; 13106 13107 unsigned int 13108 height, 13109 width; 13110 13111 /* 13112 Tile image is relative to montage image configuration. 13113 */ 13114 x=0; 13115 y=0; 13116 width=(unsigned int) image->columns; 13117 height=(unsigned int) image->rows; 13118 if (windows->image.crop_geometry != (char *) NULL) 13119 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13120 scale_factor=(double) width/windows->image.ximage->width; 13121 event->xbutton.x+=windows->image.x; 13122 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5); 13123 scale_factor=(double) height/windows->image.ximage->height; 13124 event->xbutton.y+=windows->image.y; 13125 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5); 13126 /* 13127 Determine size and location of each tile in the visual image directory. 13128 */ 13129 width=(unsigned int) image->columns; 13130 height=(unsigned int) image->rows; 13131 x=0; 13132 y=0; 13133 (void) XParseGeometry(image->montage,&x,&y,&width,&height); 13134 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+ 13135 (event->xbutton.x-x)/width; 13136 if (tile < 0) 13137 { 13138 /* 13139 Button press is outside any tile. 13140 */ 13141 (void) XBell(display,0); 13142 return((Image *) NULL); 13143 } 13144 /* 13145 Determine file name from the tile directory. 13146 */ 13147 p=image->directory; 13148 for (i=tile; (i != 0) && (*p != '\0'); ) 13149 { 13150 if (*p == '\n') 13151 i--; 13152 p++; 13153 } 13154 if (*p == '\0') 13155 { 13156 /* 13157 Button press is outside any tile. 13158 */ 13159 (void) XBell(display,0); 13160 return((Image *) NULL); 13161 } 13162 /* 13163 Select a command from the pop-up menu. 13164 */ 13165 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command); 13166 if (id < 0) 13167 return((Image *) NULL); 13168 q=p; 13169 while ((*q != '\n') && (*q != '\0')) 13170 q++; 13171 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13172 /* 13173 Perform command for the selected tile. 13174 */ 13175 XSetCursorState(display,windows,MagickTrue); 13176 XCheckRefreshWindows(display,windows); 13177 tile_image=NewImageList(); 13178 switch (TileCommands[id]) 13179 { 13180 case TileLoadCommand: 13181 { 13182 /* 13183 Load tile image. 13184 */ 13185 XCheckRefreshWindows(display,windows); 13186 (void) CopyMagickString(resource_info->image_info->magick,"MIFF", 13187 MaxTextExtent); 13188 (void) CopyMagickString(resource_info->image_info->filename,filename, 13189 MaxTextExtent); 13190 tile_image=ReadImage(resource_info->image_info,exception); 13191 CatchException(exception); 13192 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13193 break; 13194 } 13195 case TileNextCommand: 13196 { 13197 /* 13198 Display next image. 13199 */ 13200 XClientMessage(display,windows->image.id,windows->im_protocols, 13201 windows->im_next_image,CurrentTime); 13202 break; 13203 } 13204 case TileFormerCommand: 13205 { 13206 /* 13207 Display former image. 13208 */ 13209 XClientMessage(display,windows->image.id,windows->im_protocols, 13210 windows->im_former_image,CurrentTime); 13211 break; 13212 } 13213 case TileDeleteCommand: 13214 { 13215 /* 13216 Delete tile image. 13217 */ 13218 if (IfMagickFalse(IsPathAccessible(filename)) ) 13219 { 13220 XNoticeWidget(display,windows,"Image file does not exist:",filename); 13221 break; 13222 } 13223 status=XConfirmWidget(display,windows,"Really delete tile",filename); 13224 if (status <= 0) 13225 break; 13226 status=ShredFile(filename); 13227 if (IfMagickTrue(status) ) 13228 { 13229 XNoticeWidget(display,windows,"Unable to delete image file:", 13230 filename); 13231 break; 13232 } 13233 } 13234 case TileUpdateCommand: 13235 { 13236 int 13237 x_offset, 13238 y_offset; 13239 13240 PixelInfo 13241 pixel; 13242 13243 register int 13244 j; 13245 13246 register Quantum 13247 *s; 13248 13249 /* 13250 Ensure all the images exist. 13251 */ 13252 tile=0; 13253 GetPixelInfo(image,&pixel); 13254 for (p=image->directory; *p != '\0'; p++) 13255 { 13256 CacheView 13257 *image_view; 13258 13259 q=p; 13260 while ((*q != '\n') && (*q != '\0')) 13261 q++; 13262 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13263 p=q; 13264 if (IfMagickTrue(IsPathAccessible(filename)) ) 13265 { 13266 tile++; 13267 continue; 13268 } 13269 /* 13270 Overwrite tile with background color. 13271 */ 13272 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x); 13273 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y); 13274 image_view=AcquireAuthenticCacheView(image,exception); 13275 (void) GetOneCacheViewVirtualPixelInfo(image_view,0,0,&pixel,exception); 13276 for (i=0; i < (int) height; i++) 13277 { 13278 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t) 13279 y_offset+i,width,1,exception); 13280 if (s == (Quantum *) NULL) 13281 break; 13282 for (j=0; j < (int) width; j++) 13283 { 13284 SetPixelInfoPixel(image,&pixel,s); 13285 s+=GetPixelChannels(image); 13286 } 13287 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 13288 break; 13289 } 13290 image_view=DestroyCacheView(image_view); 13291 tile++; 13292 } 13293 windows->image.window_changes.width=(int) image->columns; 13294 windows->image.window_changes.height=(int) image->rows; 13295 XConfigureImageColormap(display,resource_info,windows,image,exception); 13296 (void) XConfigureImage(display,resource_info,windows,image,exception); 13297 break; 13298 } 13299 default: 13300 break; 13301 } 13302 XSetCursorState(display,windows,MagickFalse); 13303 return(tile_image); 13304} 13305 13306/* 13307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13308% % 13309% % 13310% % 13311+ X T r a n s l a t e I m a g e % 13312% % 13313% % 13314% % 13315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13316% 13317% XTranslateImage() translates the image within an Image window by one pixel 13318% as specified by the key symbol. If the image has a montage string the 13319% translation is respect to the width and height contained within the string. 13320% 13321% The format of the XTranslateImage method is: 13322% 13323% void XTranslateImage(Display *display,XWindows *windows, 13324% Image *image,const KeySym key_symbol) 13325% 13326% A description of each parameter follows: 13327% 13328% o display: Specifies a connection to an X server; returned from 13329% XOpenDisplay. 13330% 13331% o windows: Specifies a pointer to a XWindows structure. 13332% 13333% o image: the image. 13334% 13335% o key_symbol: Specifies a KeySym which indicates which side of the image 13336% to trim. 13337% 13338*/ 13339static void XTranslateImage(Display *display,XWindows *windows, 13340 Image *image,const KeySym key_symbol) 13341{ 13342 char 13343 text[MaxTextExtent]; 13344 13345 int 13346 x, 13347 y; 13348 13349 unsigned int 13350 x_offset, 13351 y_offset; 13352 13353 /* 13354 User specified a pan position offset. 13355 */ 13356 x_offset=windows->image.width; 13357 y_offset=windows->image.height; 13358 if (image->montage != (char *) NULL) 13359 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset); 13360 switch ((int) key_symbol) 13361 { 13362 case XK_Home: 13363 case XK_KP_Home: 13364 { 13365 windows->image.x=(int) windows->image.width/2; 13366 windows->image.y=(int) windows->image.height/2; 13367 break; 13368 } 13369 case XK_Left: 13370 case XK_KP_Left: 13371 { 13372 windows->image.x-=x_offset; 13373 break; 13374 } 13375 case XK_Next: 13376 case XK_Up: 13377 case XK_KP_Up: 13378 { 13379 windows->image.y-=y_offset; 13380 break; 13381 } 13382 case XK_Right: 13383 case XK_KP_Right: 13384 { 13385 windows->image.x+=x_offset; 13386 break; 13387 } 13388 case XK_Prior: 13389 case XK_Down: 13390 case XK_KP_Down: 13391 { 13392 windows->image.y+=y_offset; 13393 break; 13394 } 13395 default: 13396 return; 13397 } 13398 /* 13399 Check boundary conditions. 13400 */ 13401 if (windows->image.x < 0) 13402 windows->image.x=0; 13403 else 13404 if ((int) (windows->image.x+windows->image.width) > 13405 windows->image.ximage->width) 13406 windows->image.x=(int) windows->image.ximage->width-windows->image.width; 13407 if (windows->image.y < 0) 13408 windows->image.y=0; 13409 else 13410 if ((int) (windows->image.y+windows->image.height) > 13411 windows->image.ximage->height) 13412 windows->image.y=(int) windows->image.ximage->height-windows->image.height; 13413 /* 13414 Refresh Image window. 13415 */ 13416 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 13417 windows->image.width,windows->image.height,windows->image.x, 13418 windows->image.y); 13419 XInfoWidget(display,windows,text); 13420 XCheckRefreshWindows(display,windows); 13421 XDrawPanRectangle(display,windows); 13422 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 13423 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13424} 13425 13426/* 13427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13428% % 13429% % 13430% % 13431+ X T r i m I m a g e % 13432% % 13433% % 13434% % 13435%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13436% 13437% XTrimImage() trims the edges from the Image window. 13438% 13439% The format of the XTrimImage method is: 13440% 13441% MagickBooleanType XTrimImage(Display *display, 13442% XResourceInfo *resource_info,XWindows *windows,Image *image, 13443% ExceptionInfo *exception) 13444% 13445% A description of each parameter follows: 13446% 13447% o display: Specifies a connection to an X server; returned from 13448% XOpenDisplay. 13449% 13450% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13451% 13452% o windows: Specifies a pointer to a XWindows structure. 13453% 13454% o image: the image. 13455% 13456% o exception: return any errors or warnings in this structure. 13457% 13458*/ 13459static MagickBooleanType XTrimImage(Display *display, 13460 XResourceInfo *resource_info,XWindows *windows,Image *image, 13461 ExceptionInfo *exception) 13462{ 13463 RectangleInfo 13464 trim_info; 13465 13466 register int 13467 x, 13468 y; 13469 13470 size_t 13471 background, 13472 pixel; 13473 13474 /* 13475 Trim edges from image. 13476 */ 13477 XSetCursorState(display,windows,MagickTrue); 13478 XCheckRefreshWindows(display,windows); 13479 /* 13480 Crop the left edge. 13481 */ 13482 background=XGetPixel(windows->image.ximage,0,0); 13483 trim_info.width=(size_t) windows->image.ximage->width; 13484 for (x=0; x < windows->image.ximage->width; x++) 13485 { 13486 for (y=0; y < windows->image.ximage->height; y++) 13487 { 13488 pixel=XGetPixel(windows->image.ximage,x,y); 13489 if (pixel != background) 13490 break; 13491 } 13492 if (y < windows->image.ximage->height) 13493 break; 13494 } 13495 trim_info.x=(ssize_t) x; 13496 if (trim_info.x == (ssize_t) windows->image.ximage->width) 13497 { 13498 XSetCursorState(display,windows,MagickFalse); 13499 return(MagickFalse); 13500 } 13501 /* 13502 Crop the right edge. 13503 */ 13504 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0); 13505 for (x=windows->image.ximage->width-1; x != 0; x--) 13506 { 13507 for (y=0; y < windows->image.ximage->height; y++) 13508 { 13509 pixel=XGetPixel(windows->image.ximage,x,y); 13510 if (pixel != background) 13511 break; 13512 } 13513 if (y < windows->image.ximage->height) 13514 break; 13515 } 13516 trim_info.width=(size_t) (x-trim_info.x+1); 13517 /* 13518 Crop the top edge. 13519 */ 13520 background=XGetPixel(windows->image.ximage,0,0); 13521 trim_info.height=(size_t) windows->image.ximage->height; 13522 for (y=0; y < windows->image.ximage->height; y++) 13523 { 13524 for (x=0; x < windows->image.ximage->width; x++) 13525 { 13526 pixel=XGetPixel(windows->image.ximage,x,y); 13527 if (pixel != background) 13528 break; 13529 } 13530 if (x < windows->image.ximage->width) 13531 break; 13532 } 13533 trim_info.y=(ssize_t) y; 13534 /* 13535 Crop the bottom edge. 13536 */ 13537 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1); 13538 for (y=windows->image.ximage->height-1; y != 0; y--) 13539 { 13540 for (x=0; x < windows->image.ximage->width; x++) 13541 { 13542 pixel=XGetPixel(windows->image.ximage,x,y); 13543 if (pixel != background) 13544 break; 13545 } 13546 if (x < windows->image.ximage->width) 13547 break; 13548 } 13549 trim_info.height=(size_t) y-trim_info.y+1; 13550 if (((unsigned int) trim_info.width != windows->image.width) || 13551 ((unsigned int) trim_info.height != windows->image.height)) 13552 { 13553 /* 13554 Reconfigure Image window as defined by the trimming rectangle. 13555 */ 13556 XSetCropGeometry(display,windows,&trim_info,image); 13557 windows->image.window_changes.width=(int) trim_info.width; 13558 windows->image.window_changes.height=(int) trim_info.height; 13559 (void) XConfigureImage(display,resource_info,windows,image,exception); 13560 } 13561 XSetCursorState(display,windows,MagickFalse); 13562 return(MagickTrue); 13563} 13564 13565/* 13566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13567% % 13568% % 13569% % 13570+ X V i s u a l D i r e c t o r y I m a g e % 13571% % 13572% % 13573% % 13574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13575% 13576% XVisualDirectoryImage() creates a Visual Image Directory. 13577% 13578% The format of the XVisualDirectoryImage method is: 13579% 13580% Image *XVisualDirectoryImage(Display *display, 13581% XResourceInfo *resource_info,XWindows *windows, 13582% ExceptionInfo *exception) 13583% 13584% A description of each parameter follows: 13585% 13586% o display: Specifies a connection to an X server; returned from 13587% XOpenDisplay. 13588% 13589% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13590% 13591% o windows: Specifies a pointer to a XWindows structure. 13592% 13593% o exception: return any errors or warnings in this structure. 13594% 13595*/ 13596static Image *XVisualDirectoryImage(Display *display, 13597 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception) 13598{ 13599#define TileImageTag "Scale/Image" 13600#define XClientName "montage" 13601 13602 char 13603 **filelist; 13604 13605 Image 13606 *images, 13607 *montage_image, 13608 *next_image, 13609 *thumbnail_image; 13610 13611 ImageInfo 13612 *read_info; 13613 13614 int 13615 number_files; 13616 13617 MagickBooleanType 13618 backdrop; 13619 13620 MagickStatusType 13621 status; 13622 13623 MontageInfo 13624 *montage_info; 13625 13626 RectangleInfo 13627 geometry; 13628 13629 register int 13630 i; 13631 13632 static char 13633 filename[MaxTextExtent] = "\0", 13634 filenames[MaxTextExtent] = "*"; 13635 13636 XResourceInfo 13637 background_resources; 13638 13639 /* 13640 Request file name from user. 13641 */ 13642 XFileBrowserWidget(display,windows,"Directory",filenames); 13643 if (*filenames == '\0') 13644 return((Image *) NULL); 13645 /* 13646 Expand the filenames. 13647 */ 13648 filelist=(char **) AcquireMagickMemory(sizeof(*filelist)); 13649 if (filelist == (char **) NULL) 13650 { 13651 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed", 13652 filenames); 13653 return((Image *) NULL); 13654 } 13655 number_files=1; 13656 filelist[0]=filenames; 13657 status=ExpandFilenames(&number_files,&filelist); 13658 if (IfMagickFalse(status) || (number_files == 0)) 13659 { 13660 if (number_files == 0) 13661 ThrowXWindowException(ImageError,"NoImagesWereFound",filenames) 13662 else 13663 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed", 13664 filenames); 13665 return((Image *) NULL); 13666 } 13667 /* 13668 Set image background resources. 13669 */ 13670 background_resources=(*resource_info); 13671 background_resources.window_id=AcquireString(""); 13672 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent, 13673 "0x%lx",windows->image.id); 13674 background_resources.backdrop=MagickTrue; 13675 /* 13676 Read each image and convert them to a tile. 13677 */ 13678 backdrop=IsMagickTrue( (windows->visual_info->klass == TrueColor) || 13679 (windows->visual_info->klass == DirectColor) ); 13680 read_info=CloneImageInfo(resource_info->image_info); 13681 (void) SetImageOption(read_info,"jpeg:size","120x120"); 13682 (void) CloneString(&read_info->size,DefaultTileGeometry); 13683 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 13684 (void *) NULL); 13685 images=NewImageList(); 13686 XSetCursorState(display,windows,MagickTrue); 13687 XCheckRefreshWindows(display,windows); 13688 for (i=0; i < (int) number_files; i++) 13689 { 13690 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent); 13691 filelist[i]=DestroyString(filelist[i]); 13692 *read_info->magick='\0'; 13693 next_image=ReadImage(read_info,exception); 13694 CatchException(exception); 13695 if (next_image != (Image *) NULL) 13696 { 13697 (void) DeleteImageProperty(next_image,"label"); 13698 (void) SetImageProperty(next_image,"label",InterpretImageProperties( 13699 read_info,next_image,DefaultTileLabel,exception),exception); 13700 (void) ParseRegionGeometry(next_image,read_info->size,&geometry, 13701 exception); 13702 thumbnail_image=ThumbnailImage(next_image,geometry.width, 13703 geometry.height,exception); 13704 if (thumbnail_image != (Image *) NULL) 13705 { 13706 next_image=DestroyImage(next_image); 13707 next_image=thumbnail_image; 13708 } 13709 if (backdrop) 13710 { 13711 (void) XDisplayBackgroundImage(display,&background_resources, 13712 next_image,exception); 13713 XSetCursorState(display,windows,MagickTrue); 13714 } 13715 AppendImageToList(&images,next_image); 13716 if (images->progress_monitor != (MagickProgressMonitor) NULL) 13717 { 13718 MagickBooleanType 13719 proceed; 13720 13721 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i, 13722 (MagickSizeType) number_files); 13723 if (IfMagickFalse(proceed) ) 13724 break; 13725 } 13726 } 13727 } 13728 filelist=(char **) RelinquishMagickMemory(filelist); 13729 if (images == (Image *) NULL) 13730 { 13731 read_info=DestroyImageInfo(read_info); 13732 XSetCursorState(display,windows,MagickFalse); 13733 ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames); 13734 return((Image *) NULL); 13735 } 13736 /* 13737 Create the Visual Image Directory. 13738 */ 13739 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL); 13740 montage_info->pointsize=10; 13741 if (resource_info->font != (char *) NULL) 13742 (void) CloneString(&montage_info->font,resource_info->font); 13743 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent); 13744 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList( 13745 images),exception); 13746 images=DestroyImageList(images); 13747 montage_info=DestroyMontageInfo(montage_info); 13748 read_info=DestroyImageInfo(read_info); 13749 XSetCursorState(display,windows,MagickFalse); 13750 if (montage_image == (Image *) NULL) 13751 return(montage_image); 13752 XClientMessage(display,windows->image.id,windows->im_protocols, 13753 windows->im_next_image,CurrentTime); 13754 return(montage_image); 13755} 13756 13757/* 13758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13759% % 13760% % 13761% % 13762% X D i s p l a y B a c k g r o u n d I m a g e % 13763% % 13764% % 13765% % 13766%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13767% 13768% XDisplayBackgroundImage() displays an image in the background of a window. 13769% 13770% The format of the XDisplayBackgroundImage method is: 13771% 13772% MagickBooleanType XDisplayBackgroundImage(Display *display, 13773% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13774% 13775% A description of each parameter follows: 13776% 13777% o display: Specifies a connection to an X server; returned from 13778% XOpenDisplay. 13779% 13780% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13781% 13782% o image: the image. 13783% 13784% o exception: return any errors or warnings in this structure. 13785% 13786*/ 13787MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display, 13788 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13789{ 13790 char 13791 geometry[MaxTextExtent], 13792 visual_type[MaxTextExtent]; 13793 13794 int 13795 height, 13796 status, 13797 width; 13798 13799 RectangleInfo 13800 geometry_info; 13801 13802 static XPixelInfo 13803 pixel; 13804 13805 static XStandardColormap 13806 *map_info; 13807 13808 static XVisualInfo 13809 *visual_info = (XVisualInfo *) NULL; 13810 13811 static XWindowInfo 13812 window_info; 13813 13814 size_t 13815 delay; 13816 13817 Window 13818 root_window; 13819 13820 XGCValues 13821 context_values; 13822 13823 XResourceInfo 13824 resources; 13825 13826 XWindowAttributes 13827 window_attributes; 13828 13829 /* 13830 Determine target window. 13831 */ 13832 assert(image != (Image *) NULL); 13833 assert(image->signature == MagickSignature); 13834 if (IfMagickTrue(image->debug) ) 13835 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 13836 resources=(*resource_info); 13837 window_info.id=(Window) NULL; 13838 root_window=XRootWindow(display,XDefaultScreen(display)); 13839 if (LocaleCompare(resources.window_id,"root") == 0) 13840 window_info.id=root_window; 13841 else 13842 { 13843 if (isdigit((int) ((unsigned char) *resources.window_id)) != 0) 13844 window_info.id=XWindowByID(display,root_window, 13845 (Window) strtol((char *) resources.window_id,(char **) NULL,0)); 13846 if (window_info.id == (Window) NULL) 13847 window_info.id=XWindowByName(display,root_window,resources.window_id); 13848 } 13849 if (window_info.id == (Window) NULL) 13850 { 13851 ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists", 13852 resources.window_id); 13853 return(MagickFalse); 13854 } 13855 /* 13856 Determine window visual id. 13857 */ 13858 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); 13859 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); 13860 (void) CopyMagickString(visual_type,"default",MaxTextExtent); 13861 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13862 if (status != 0) 13863 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx", 13864 XVisualIDFromVisual(window_attributes.visual)); 13865 if (visual_info == (XVisualInfo *) NULL) 13866 { 13867 /* 13868 Allocate standard colormap. 13869 */ 13870 map_info=XAllocStandardColormap(); 13871 if (map_info == (XStandardColormap *) NULL) 13872 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", 13873 image->filename); 13874 map_info->colormap=(Colormap) NULL; 13875 pixel.pixels=(unsigned long *) NULL; 13876 /* 13877 Initialize visual info. 13878 */ 13879 resources.map_type=(char *) NULL; 13880 resources.visual_type=visual_type; 13881 visual_info=XBestVisualInfo(display,map_info,&resources); 13882 if (visual_info == (XVisualInfo *) NULL) 13883 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", 13884 resources.visual_type); 13885 /* 13886 Initialize window info. 13887 */ 13888 window_info.ximage=(XImage *) NULL; 13889 window_info.matte_image=(XImage *) NULL; 13890 window_info.pixmap=(Pixmap) NULL; 13891 window_info.matte_pixmap=(Pixmap) NULL; 13892 } 13893 /* 13894 Free previous root colors. 13895 */ 13896 if (window_info.id == root_window) 13897 (void) XDestroyWindowColors(display,root_window); 13898 /* 13899 Initialize Standard Colormap. 13900 */ 13901 resources.colormap=SharedColormap; 13902 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel, 13903 exception); 13904 /* 13905 Graphic context superclass. 13906 */ 13907 context_values.background=pixel.background_color.pixel; 13908 context_values.foreground=pixel.foreground_color.pixel; 13909 pixel.annotate_context=XCreateGC(display,window_info.id, 13910 (size_t) (GCBackground | GCForeground),&context_values); 13911 if (pixel.annotate_context == (GC) NULL) 13912 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 13913 image->filename); 13914 /* 13915 Initialize Image window attributes. 13916 */ 13917 window_info.name=AcquireString("\0"); 13918 window_info.icon_name=AcquireString("\0"); 13919 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, 13920 &resources,&window_info); 13921 /* 13922 Create the X image. 13923 */ 13924 window_info.width=(unsigned int) image->columns; 13925 window_info.height=(unsigned int) image->rows; 13926 if ((image->columns != window_info.width) || 13927 (image->rows != window_info.height)) 13928 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13929 image->filename); 13930 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>", 13931 window_attributes.width,window_attributes.height); 13932 geometry_info.width=window_info.width; 13933 geometry_info.height=window_info.height; 13934 geometry_info.x=(ssize_t) window_info.x; 13935 geometry_info.y=(ssize_t) window_info.y; 13936 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 13937 &geometry_info.width,&geometry_info.height); 13938 window_info.width=(unsigned int) geometry_info.width; 13939 window_info.height=(unsigned int) geometry_info.height; 13940 window_info.x=(int) geometry_info.x; 13941 window_info.y=(int) geometry_info.y; 13942 status=XMakeImage(display,&resources,&window_info,image,window_info.width, 13943 window_info.height,exception); 13944 if (IfMagickFalse(status) ) 13945 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13946 image->filename); 13947 window_info.x=0; 13948 window_info.y=0; 13949 if (IfMagickTrue(image->debug) ) 13950 { 13951 (void) LogMagickEvent(X11Event,GetMagickModule(), 13952 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene, 13953 (double) image->columns,(double) image->rows); 13954 if (image->colors != 0) 13955 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 13956 image->colors); 13957 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick); 13958 } 13959 /* 13960 Adjust image dimensions as specified by backdrop or geometry options. 13961 */ 13962 width=(int) window_info.width; 13963 height=(int) window_info.height; 13964 if (IfMagickTrue(resources.backdrop) ) 13965 { 13966 /* 13967 Center image on window. 13968 */ 13969 window_info.x=(window_attributes.width/2)- 13970 (window_info.ximage->width/2); 13971 window_info.y=(window_attributes.height/2)- 13972 (window_info.ximage->height/2); 13973 width=window_attributes.width; 13974 height=window_attributes.height; 13975 } 13976 if ((resources.image_geometry != (char *) NULL) && 13977 (*resources.image_geometry != '\0')) 13978 { 13979 char 13980 default_geometry[MaxTextExtent]; 13981 13982 int 13983 flags, 13984 gravity; 13985 13986 XSizeHints 13987 *size_hints; 13988 13989 /* 13990 User specified geometry. 13991 */ 13992 size_hints=XAllocSizeHints(); 13993 if (size_hints == (XSizeHints *) NULL) 13994 ThrowXWindowFatalException(ResourceLimitFatalError, 13995 "MemoryAllocationFailed",image->filename); 13996 size_hints->flags=0L; 13997 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d", 13998 width,height); 13999 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, 14000 default_geometry,window_info.border_width,size_hints,&window_info.x, 14001 &window_info.y,&width,&height,&gravity); 14002 if (flags & (XValue | YValue)) 14003 { 14004 width=window_attributes.width; 14005 height=window_attributes.height; 14006 } 14007 (void) XFree((void *) size_hints); 14008 } 14009 /* 14010 Create the X pixmap. 14011 */ 14012 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, 14013 (unsigned int) height,window_info.depth); 14014 if (window_info.pixmap == (Pixmap) NULL) 14015 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", 14016 image->filename); 14017 /* 14018 Display pixmap on the window. 14019 */ 14020 if (((unsigned int) width > window_info.width) || 14021 ((unsigned int) height > window_info.height)) 14022 (void) XFillRectangle(display,window_info.pixmap, 14023 window_info.annotate_context,0,0,(unsigned int) width, 14024 (unsigned int) height); 14025 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, 14026 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int) 14027 window_info.width,(unsigned int) window_info.height); 14028 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); 14029 (void) XClearWindow(display,window_info.id); 14030 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); 14031 XDelay(display,delay == 0UL ? 10UL : delay); 14032 (void) XSync(display,MagickFalse); 14033 return(IsMagickTrue(window_info.id == root_window)); 14034} 14035 14036/* 14037%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14038% % 14039% % 14040% % 14041+ X D i s p l a y I m a g e % 14042% % 14043% % 14044% % 14045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14046% 14047% XDisplayImage() displays an image via X11. A new image is created and 14048% returned if the user interactively transforms the displayed image. 14049% 14050% The format of the XDisplayImage method is: 14051% 14052% Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14053% char **argv,int argc,Image **image,size_t *state, 14054% ExceptionInfo *exception) 14055% 14056% A description of each parameter follows: 14057% 14058% o nexus: Method XDisplayImage returns an image when the 14059% user chooses 'Open Image' from the command menu or picks a tile 14060% from the image directory. Otherwise a null image is returned. 14061% 14062% o display: Specifies a connection to an X server; returned from 14063% XOpenDisplay. 14064% 14065% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 14066% 14067% o argv: Specifies the application's argument list. 14068% 14069% o argc: Specifies the number of arguments. 14070% 14071% o image: Specifies an address to an address of an Image structure; 14072% 14073% o exception: return any errors or warnings in this structure. 14074% 14075*/ 14076MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14077 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception) 14078{ 14079#define MagnifySize 256 /* must be a power of 2 */ 14080#define MagickMenus 10 14081#define MagickTitle "Commands" 14082 14083 static const char 14084 *CommandMenu[] = 14085 { 14086 "File", 14087 "Edit", 14088 "View", 14089 "Transform", 14090 "Enhance", 14091 "Effects", 14092 "F/X", 14093 "Image Edit", 14094 "Miscellany", 14095 "Help", 14096 (char *) NULL 14097 }, 14098 *FileMenu[] = 14099 { 14100 "Open...", 14101 "Next", 14102 "Former", 14103 "Select...", 14104 "Save...", 14105 "Print...", 14106 "Delete...", 14107 "New...", 14108 "Visual Directory...", 14109 "Quit", 14110 (char *) NULL 14111 }, 14112 *EditMenu[] = 14113 { 14114 "Undo", 14115 "Redo", 14116 "Cut", 14117 "Copy", 14118 "Paste", 14119 (char *) NULL 14120 }, 14121 *ViewMenu[] = 14122 { 14123 "Half Size", 14124 "Original Size", 14125 "Double Size", 14126 "Resize...", 14127 "Apply", 14128 "Refresh", 14129 "Restore", 14130 (char *) NULL 14131 }, 14132 *TransformMenu[] = 14133 { 14134 "Crop", 14135 "Chop", 14136 "Flop", 14137 "Flip", 14138 "Rotate Right", 14139 "Rotate Left", 14140 "Rotate...", 14141 "Shear...", 14142 "Roll...", 14143 "Trim Edges", 14144 (char *) NULL 14145 }, 14146 *EnhanceMenu[] = 14147 { 14148 "Hue...", 14149 "Saturation...", 14150 "Brightness...", 14151 "Gamma...", 14152 "Spiff", 14153 "Dull", 14154 "Contrast Stretch...", 14155 "Sigmoidal Contrast...", 14156 "Normalize", 14157 "Equalize", 14158 "Negate", 14159 "Grayscale", 14160 "Map...", 14161 "Quantize...", 14162 (char *) NULL 14163 }, 14164 *EffectsMenu[] = 14165 { 14166 "Despeckle", 14167 "Emboss", 14168 "Reduce Noise", 14169 "Add Noise...", 14170 "Sharpen...", 14171 "Blur...", 14172 "Threshold...", 14173 "Edge Detect...", 14174 "Spread...", 14175 "Shade...", 14176 "Raise...", 14177 "Segment...", 14178 (char *) NULL 14179 }, 14180 *FXMenu[] = 14181 { 14182 "Solarize...", 14183 "Sepia Tone...", 14184 "Swirl...", 14185 "Implode...", 14186 "Vignette...", 14187 "Wave...", 14188 "Oil Paint...", 14189 "Charcoal Draw...", 14190 (char *) NULL 14191 }, 14192 *ImageEditMenu[] = 14193 { 14194 "Annotate...", 14195 "Draw...", 14196 "Color...", 14197 "Matte...", 14198 "Composite...", 14199 "Add Border...", 14200 "Add Frame...", 14201 "Comment...", 14202 "Launch...", 14203 "Region of Interest...", 14204 (char *) NULL 14205 }, 14206 *MiscellanyMenu[] = 14207 { 14208 "Image Info", 14209 "Zoom Image", 14210 "Show Preview...", 14211 "Show Histogram", 14212 "Show Matte", 14213 "Background...", 14214 "Slide Show...", 14215 "Preferences...", 14216 (char *) NULL 14217 }, 14218 *HelpMenu[] = 14219 { 14220 "Overview", 14221 "Browse Documentation", 14222 "About Display", 14223 (char *) NULL 14224 }, 14225 *ShortCutsMenu[] = 14226 { 14227 "Next", 14228 "Former", 14229 "Open...", 14230 "Save...", 14231 "Print...", 14232 "Undo", 14233 "Restore", 14234 "Image Info", 14235 "Quit", 14236 (char *) NULL 14237 }, 14238 *VirtualMenu[] = 14239 { 14240 "Image Info", 14241 "Print", 14242 "Next", 14243 "Quit", 14244 (char *) NULL 14245 }; 14246 14247 static const char 14248 **Menus[MagickMenus] = 14249 { 14250 FileMenu, 14251 EditMenu, 14252 ViewMenu, 14253 TransformMenu, 14254 EnhanceMenu, 14255 EffectsMenu, 14256 FXMenu, 14257 ImageEditMenu, 14258 MiscellanyMenu, 14259 HelpMenu 14260 }; 14261 14262 static CommandType 14263 CommandMenus[] = 14264 { 14265 NullCommand, 14266 NullCommand, 14267 NullCommand, 14268 NullCommand, 14269 NullCommand, 14270 NullCommand, 14271 NullCommand, 14272 NullCommand, 14273 NullCommand, 14274 NullCommand, 14275 }, 14276 FileCommands[] = 14277 { 14278 OpenCommand, 14279 NextCommand, 14280 FormerCommand, 14281 SelectCommand, 14282 SaveCommand, 14283 PrintCommand, 14284 DeleteCommand, 14285 NewCommand, 14286 VisualDirectoryCommand, 14287 QuitCommand 14288 }, 14289 EditCommands[] = 14290 { 14291 UndoCommand, 14292 RedoCommand, 14293 CutCommand, 14294 CopyCommand, 14295 PasteCommand 14296 }, 14297 ViewCommands[] = 14298 { 14299 HalfSizeCommand, 14300 OriginalSizeCommand, 14301 DoubleSizeCommand, 14302 ResizeCommand, 14303 ApplyCommand, 14304 RefreshCommand, 14305 RestoreCommand 14306 }, 14307 TransformCommands[] = 14308 { 14309 CropCommand, 14310 ChopCommand, 14311 FlopCommand, 14312 FlipCommand, 14313 RotateRightCommand, 14314 RotateLeftCommand, 14315 RotateCommand, 14316 ShearCommand, 14317 RollCommand, 14318 TrimCommand 14319 }, 14320 EnhanceCommands[] = 14321 { 14322 HueCommand, 14323 SaturationCommand, 14324 BrightnessCommand, 14325 GammaCommand, 14326 SpiffCommand, 14327 DullCommand, 14328 ContrastStretchCommand, 14329 SigmoidalContrastCommand, 14330 NormalizeCommand, 14331 EqualizeCommand, 14332 NegateCommand, 14333 GrayscaleCommand, 14334 MapCommand, 14335 QuantizeCommand 14336 }, 14337 EffectsCommands[] = 14338 { 14339 DespeckleCommand, 14340 EmbossCommand, 14341 ReduceNoiseCommand, 14342 AddNoiseCommand, 14343 SharpenCommand, 14344 BlurCommand, 14345 ThresholdCommand, 14346 EdgeDetectCommand, 14347 SpreadCommand, 14348 ShadeCommand, 14349 RaiseCommand, 14350 SegmentCommand 14351 }, 14352 FXCommands[] = 14353 { 14354 SolarizeCommand, 14355 SepiaToneCommand, 14356 SwirlCommand, 14357 ImplodeCommand, 14358 VignetteCommand, 14359 WaveCommand, 14360 OilPaintCommand, 14361 CharcoalDrawCommand 14362 }, 14363 ImageEditCommands[] = 14364 { 14365 AnnotateCommand, 14366 DrawCommand, 14367 ColorCommand, 14368 MatteCommand, 14369 CompositeCommand, 14370 AddBorderCommand, 14371 AddFrameCommand, 14372 CommentCommand, 14373 LaunchCommand, 14374 RegionofInterestCommand 14375 }, 14376 MiscellanyCommands[] = 14377 { 14378 InfoCommand, 14379 ZoomCommand, 14380 ShowPreviewCommand, 14381 ShowHistogramCommand, 14382 ShowMatteCommand, 14383 BackgroundCommand, 14384 SlideShowCommand, 14385 PreferencesCommand 14386 }, 14387 HelpCommands[] = 14388 { 14389 HelpCommand, 14390 BrowseDocumentationCommand, 14391 VersionCommand 14392 }, 14393 ShortCutsCommands[] = 14394 { 14395 NextCommand, 14396 FormerCommand, 14397 OpenCommand, 14398 SaveCommand, 14399 PrintCommand, 14400 UndoCommand, 14401 RestoreCommand, 14402 InfoCommand, 14403 QuitCommand 14404 }, 14405 VirtualCommands[] = 14406 { 14407 InfoCommand, 14408 PrintCommand, 14409 NextCommand, 14410 QuitCommand 14411 }; 14412 14413 static CommandType 14414 *Commands[MagickMenus] = 14415 { 14416 FileCommands, 14417 EditCommands, 14418 ViewCommands, 14419 TransformCommands, 14420 EnhanceCommands, 14421 EffectsCommands, 14422 FXCommands, 14423 ImageEditCommands, 14424 MiscellanyCommands, 14425 HelpCommands 14426 }; 14427 14428 char 14429 command[MaxTextExtent], 14430 *directory, 14431 geometry[MaxTextExtent], 14432 resource_name[MaxTextExtent]; 14433 14434 CommandType 14435 command_type; 14436 14437 Image 14438 *display_image, 14439 *nexus; 14440 14441 int 14442 entry, 14443 id; 14444 14445 KeySym 14446 key_symbol; 14447 14448 MagickStatusType 14449 context_mask, 14450 status; 14451 14452 RectangleInfo 14453 geometry_info; 14454 14455 register int 14456 i; 14457 14458 static char 14459 working_directory[MaxTextExtent]; 14460 14461 static XPoint 14462 vid_info; 14463 14464 static XWindowInfo 14465 *magick_windows[MaxXWindows]; 14466 14467 static unsigned int 14468 number_windows; 14469 14470 struct stat 14471 attributes; 14472 14473 time_t 14474 timer, 14475 timestamp, 14476 update_time; 14477 14478 unsigned int 14479 height, 14480 width; 14481 14482 size_t 14483 delay; 14484 14485 WarningHandler 14486 warning_handler; 14487 14488 Window 14489 root_window; 14490 14491 XClassHint 14492 *class_hints; 14493 14494 XEvent 14495 event; 14496 14497 XFontStruct 14498 *font_info; 14499 14500 XGCValues 14501 context_values; 14502 14503 XPixelInfo 14504 *icon_pixel, 14505 *pixel; 14506 14507 XResourceInfo 14508 *icon_resources; 14509 14510 XStandardColormap 14511 *icon_map, 14512 *map_info; 14513 14514 XVisualInfo 14515 *icon_visual, 14516 *visual_info; 14517 14518 XWindowChanges 14519 window_changes; 14520 14521 XWindows 14522 *windows; 14523 14524 XWMHints 14525 *manager_hints; 14526 14527 assert(image != (Image **) NULL); 14528 assert((*image)->signature == MagickSignature); 14529 if (IfMagickTrue((*image)->debug) ) 14530 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 14531 display_image=(*image); 14532 warning_handler=(WarningHandler) NULL; 14533 windows=XSetWindows((XWindows *) ~0); 14534 if (windows != (XWindows *) NULL) 14535 { 14536 int 14537 status; 14538 14539 if (*working_directory == '\0') 14540 (void) CopyMagickString(working_directory,".",MaxTextExtent); 14541 status=chdir(working_directory); 14542 if (status == -1) 14543 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 14544 "UnableToOpenFile","%s",working_directory); 14545 warning_handler=resource_info->display_warnings ? 14546 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14547 warning_handler=resource_info->display_warnings ? 14548 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14549 } 14550 else 14551 { 14552 /* 14553 Allocate windows structure. 14554 */ 14555 resource_info->colors=display_image->colors; 14556 windows=XSetWindows(XInitializeWindows(display,resource_info)); 14557 if (windows == (XWindows *) NULL) 14558 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow", 14559 (*image)->filename); 14560 /* 14561 Initialize window id's. 14562 */ 14563 number_windows=0; 14564 magick_windows[number_windows++]=(&windows->icon); 14565 magick_windows[number_windows++]=(&windows->backdrop); 14566 magick_windows[number_windows++]=(&windows->image); 14567 magick_windows[number_windows++]=(&windows->info); 14568 magick_windows[number_windows++]=(&windows->command); 14569 magick_windows[number_windows++]=(&windows->widget); 14570 magick_windows[number_windows++]=(&windows->popup); 14571 magick_windows[number_windows++]=(&windows->magnify); 14572 magick_windows[number_windows++]=(&windows->pan); 14573 for (i=0; i < (int) number_windows; i++) 14574 magick_windows[i]->id=(Window) NULL; 14575 vid_info.x=0; 14576 vid_info.y=0; 14577 } 14578 /* 14579 Initialize font info. 14580 */ 14581 if (windows->font_info != (XFontStruct *) NULL) 14582 (void) XFreeFont(display,windows->font_info); 14583 windows->font_info=XBestFont(display,resource_info,MagickFalse); 14584 if (windows->font_info == (XFontStruct *) NULL) 14585 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", 14586 resource_info->font); 14587 /* 14588 Initialize Standard Colormap. 14589 */ 14590 map_info=windows->map_info; 14591 icon_map=windows->icon_map; 14592 visual_info=windows->visual_info; 14593 icon_visual=windows->icon_visual; 14594 pixel=windows->pixel_info; 14595 icon_pixel=windows->icon_pixel; 14596 font_info=windows->font_info; 14597 icon_resources=windows->icon_resources; 14598 class_hints=windows->class_hints; 14599 manager_hints=windows->manager_hints; 14600 root_window=XRootWindow(display,visual_info->screen); 14601 nexus=NewImageList(); 14602 if (IfMagickTrue(display_image->debug) ) 14603 { 14604 (void) LogMagickEvent(X11Event,GetMagickModule(), 14605 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename, 14606 (double) display_image->scene,(double) display_image->columns, 14607 (double) display_image->rows); 14608 if (display_image->colors != 0) 14609 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 14610 display_image->colors); 14611 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", 14612 display_image->magick); 14613 } 14614 XMakeStandardColormap(display,visual_info,resource_info,display_image, 14615 map_info,pixel,exception); 14616 display_image->taint=MagickFalse; 14617 /* 14618 Initialize graphic context. 14619 */ 14620 windows->context.id=(Window) NULL; 14621 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14622 resource_info,&windows->context); 14623 (void) CloneString(&class_hints->res_name,resource_info->client_name); 14624 (void) CloneString(&class_hints->res_class,resource_info->client_name); 14625 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]); 14626 manager_hints->flags=InputHint | StateHint; 14627 manager_hints->input=MagickFalse; 14628 manager_hints->initial_state=WithdrawnState; 14629 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14630 &windows->context); 14631 if (IfMagickTrue(display_image->debug) ) 14632 (void) LogMagickEvent(X11Event,GetMagickModule(), 14633 "Window id: 0x%lx (context)",windows->context.id); 14634 context_values.background=pixel->background_color.pixel; 14635 context_values.font=font_info->fid; 14636 context_values.foreground=pixel->foreground_color.pixel; 14637 context_values.graphics_exposures=MagickFalse; 14638 context_mask=(MagickStatusType) 14639 (GCBackground | GCFont | GCForeground | GCGraphicsExposures); 14640 if (pixel->annotate_context != (GC) NULL) 14641 (void) XFreeGC(display,pixel->annotate_context); 14642 pixel->annotate_context=XCreateGC(display,windows->context.id, 14643 context_mask,&context_values); 14644 if (pixel->annotate_context == (GC) NULL) 14645 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14646 display_image->filename); 14647 context_values.background=pixel->depth_color.pixel; 14648 if (pixel->widget_context != (GC) NULL) 14649 (void) XFreeGC(display,pixel->widget_context); 14650 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask, 14651 &context_values); 14652 if (pixel->widget_context == (GC) NULL) 14653 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14654 display_image->filename); 14655 context_values.background=pixel->foreground_color.pixel; 14656 context_values.foreground=pixel->background_color.pixel; 14657 context_values.plane_mask=context_values.background ^ 14658 context_values.foreground; 14659 if (pixel->highlight_context != (GC) NULL) 14660 (void) XFreeGC(display,pixel->highlight_context); 14661 pixel->highlight_context=XCreateGC(display,windows->context.id, 14662 (size_t) (context_mask | GCPlaneMask),&context_values); 14663 if (pixel->highlight_context == (GC) NULL) 14664 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14665 display_image->filename); 14666 (void) XDestroyWindow(display,windows->context.id); 14667 /* 14668 Initialize icon window. 14669 */ 14670 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, 14671 icon_resources,&windows->icon); 14672 windows->icon.geometry=resource_info->icon_geometry; 14673 XBestIconSize(display,&windows->icon,display_image); 14674 windows->icon.attributes.colormap=XDefaultColormap(display, 14675 icon_visual->screen); 14676 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; 14677 manager_hints->flags=InputHint | StateHint; 14678 manager_hints->input=MagickFalse; 14679 manager_hints->initial_state=IconicState; 14680 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14681 &windows->icon); 14682 if (IfMagickTrue(display_image->debug) ) 14683 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", 14684 windows->icon.id); 14685 /* 14686 Initialize graphic context for icon window. 14687 */ 14688 if (icon_pixel->annotate_context != (GC) NULL) 14689 (void) XFreeGC(display,icon_pixel->annotate_context); 14690 context_values.background=icon_pixel->background_color.pixel; 14691 context_values.foreground=icon_pixel->foreground_color.pixel; 14692 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, 14693 (size_t) (GCBackground | GCForeground),&context_values); 14694 if (icon_pixel->annotate_context == (GC) NULL) 14695 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14696 display_image->filename); 14697 windows->icon.annotate_context=icon_pixel->annotate_context; 14698 /* 14699 Initialize Image window. 14700 */ 14701 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14702 &windows->image); 14703 windows->image.shape=MagickTrue; /* non-rectangular shape hint */ 14704 if (IfMagickFalse(resource_info->use_shared_memory) ) 14705 windows->image.shared_memory=MagickFalse; 14706 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState)) 14707 { 14708 char 14709 *title; 14710 14711 title=InterpretImageProperties(resource_info->image_info,display_image, 14712 resource_info->title,exception); 14713 (void) CopyMagickString(windows->image.name,title,MaxTextExtent); 14714 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent); 14715 title=DestroyString(title); 14716 } 14717 else 14718 { 14719 char 14720 filename[MaxTextExtent]; 14721 14722 /* 14723 Window name is the base of the filename. 14724 */ 14725 GetPathComponent(display_image->magick_filename,TailPath,filename); 14726 if (display_image->scene == 0) 14727 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14728 "%s: %s",MagickPackageName,filename); 14729 else 14730 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14731 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename, 14732 (double) display_image->scene,(double) GetImageListLength( 14733 display_image)); 14734 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent); 14735 } 14736 if (resource_info->immutable) 14737 windows->image.immutable=MagickTrue; 14738 windows->image.use_pixmap=resource_info->use_pixmap; 14739 windows->image.geometry=resource_info->image_geometry; 14740 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 14741 XDisplayWidth(display,visual_info->screen), 14742 XDisplayHeight(display,visual_info->screen)); 14743 geometry_info.width=display_image->columns; 14744 geometry_info.height=display_image->rows; 14745 geometry_info.x=0; 14746 geometry_info.y=0; 14747 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 14748 &geometry_info.width,&geometry_info.height); 14749 windows->image.width=(unsigned int) geometry_info.width; 14750 windows->image.height=(unsigned int) geometry_info.height; 14751 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14752 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14753 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14754 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; 14755 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14756 resource_info,&windows->backdrop); 14757 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) 14758 { 14759 /* 14760 Initialize backdrop window. 14761 */ 14762 windows->backdrop.x=0; 14763 windows->backdrop.y=0; 14764 (void) CloneString(&windows->backdrop.name,"Backdrop"); 14765 windows->backdrop.flags=(size_t) (USSize | USPosition); 14766 windows->backdrop.width=(unsigned int) 14767 XDisplayWidth(display,visual_info->screen); 14768 windows->backdrop.height=(unsigned int) 14769 XDisplayHeight(display,visual_info->screen); 14770 windows->backdrop.border_width=0; 14771 windows->backdrop.immutable=MagickTrue; 14772 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | 14773 ButtonReleaseMask; 14774 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | 14775 StructureNotifyMask; 14776 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14777 manager_hints->icon_window=windows->icon.id; 14778 manager_hints->input=MagickTrue; 14779 manager_hints->initial_state=resource_info->iconic ? IconicState : 14780 NormalState; 14781 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14782 &windows->backdrop); 14783 if (IfMagickTrue(display_image->debug) ) 14784 (void) LogMagickEvent(X11Event,GetMagickModule(), 14785 "Window id: 0x%lx (backdrop)",windows->backdrop.id); 14786 (void) XMapWindow(display,windows->backdrop.id); 14787 (void) XClearWindow(display,windows->backdrop.id); 14788 if (windows->image.id != (Window) NULL) 14789 { 14790 (void) XDestroyWindow(display,windows->image.id); 14791 windows->image.id=(Window) NULL; 14792 } 14793 /* 14794 Position image in the center the backdrop. 14795 */ 14796 windows->image.flags|=USPosition; 14797 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- 14798 (windows->image.width/2); 14799 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- 14800 (windows->image.height/2); 14801 } 14802 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14803 manager_hints->icon_window=windows->icon.id; 14804 manager_hints->input=MagickTrue; 14805 manager_hints->initial_state=resource_info->iconic ? IconicState : 14806 NormalState; 14807 if (windows->group_leader.id != (Window) NULL) 14808 { 14809 /* 14810 Follow the leader. 14811 */ 14812 manager_hints->flags|=WindowGroupHint; 14813 manager_hints->window_group=windows->group_leader.id; 14814 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); 14815 if (IfMagickTrue(display_image->debug) ) 14816 (void) LogMagickEvent(X11Event,GetMagickModule(), 14817 "Window id: 0x%lx (group leader)",windows->group_leader.id); 14818 } 14819 XMakeWindow(display, 14820 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), 14821 argv,argc,class_hints,manager_hints,&windows->image); 14822 (void) XChangeProperty(display,windows->image.id,windows->im_protocols, 14823 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); 14824 if (windows->group_leader.id != (Window) NULL) 14825 (void) XSetTransientForHint(display,windows->image.id, 14826 windows->group_leader.id); 14827 if (IfMagickTrue(display_image->debug) ) 14828 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", 14829 windows->image.id); 14830 /* 14831 Initialize Info widget. 14832 */ 14833 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14834 &windows->info); 14835 (void) CloneString(&windows->info.name,"Info"); 14836 (void) CloneString(&windows->info.icon_name,"Info"); 14837 windows->info.border_width=1; 14838 windows->info.x=2; 14839 windows->info.y=2; 14840 windows->info.flags|=PPosition; 14841 windows->info.attributes.win_gravity=UnmapGravity; 14842 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | 14843 StructureNotifyMask; 14844 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14845 manager_hints->input=MagickFalse; 14846 manager_hints->initial_state=NormalState; 14847 manager_hints->window_group=windows->image.id; 14848 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, 14849 &windows->info); 14850 windows->info.highlight_stipple=XCreateBitmapFromData(display, 14851 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14852 windows->info.shadow_stipple=XCreateBitmapFromData(display, 14853 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14854 (void) XSetTransientForHint(display,windows->info.id,windows->image.id); 14855 if (IfMagickTrue(windows->image.mapped) ) 14856 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14857 if (IfMagickTrue(display_image->debug) ) 14858 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", 14859 windows->info.id); 14860 /* 14861 Initialize Command widget. 14862 */ 14863 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14864 resource_info,&windows->command); 14865 windows->command.data=MagickMenus; 14866 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); 14867 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command", 14868 resource_info->client_name); 14869 windows->command.geometry=XGetResourceClass(resource_info->resource_database, 14870 resource_name,"geometry",(char *) NULL); 14871 (void) CloneString(&windows->command.name,MagickTitle); 14872 windows->command.border_width=0; 14873 windows->command.flags|=PPosition; 14874 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14875 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | 14876 OwnerGrabButtonMask | StructureNotifyMask; 14877 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14878 manager_hints->input=MagickTrue; 14879 manager_hints->initial_state=NormalState; 14880 manager_hints->window_group=windows->image.id; 14881 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14882 &windows->command); 14883 windows->command.highlight_stipple=XCreateBitmapFromData(display, 14884 windows->command.id,(char *) HighlightBitmap,HighlightWidth, 14885 HighlightHeight); 14886 windows->command.shadow_stipple=XCreateBitmapFromData(display, 14887 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14888 (void) XSetTransientForHint(display,windows->command.id,windows->image.id); 14889 if (IfMagickTrue(windows->command.mapped) ) 14890 (void) XMapRaised(display,windows->command.id); 14891 if (IfMagickTrue(display_image->debug) ) 14892 (void) LogMagickEvent(X11Event,GetMagickModule(), 14893 "Window id: 0x%lx (command)",windows->command.id); 14894 /* 14895 Initialize Widget window. 14896 */ 14897 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14898 resource_info,&windows->widget); 14899 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget", 14900 resource_info->client_name); 14901 windows->widget.geometry=XGetResourceClass(resource_info->resource_database, 14902 resource_name,"geometry",(char *) NULL); 14903 windows->widget.border_width=0; 14904 windows->widget.flags|=PPosition; 14905 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14906 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14907 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14908 StructureNotifyMask; 14909 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14910 manager_hints->input=MagickTrue; 14911 manager_hints->initial_state=NormalState; 14912 manager_hints->window_group=windows->image.id; 14913 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14914 &windows->widget); 14915 windows->widget.highlight_stipple=XCreateBitmapFromData(display, 14916 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14917 windows->widget.shadow_stipple=XCreateBitmapFromData(display, 14918 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14919 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); 14920 if (IfMagickTrue(display_image->debug) ) 14921 (void) LogMagickEvent(X11Event,GetMagickModule(), 14922 "Window id: 0x%lx (widget)",windows->widget.id); 14923 /* 14924 Initialize popup window. 14925 */ 14926 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14927 resource_info,&windows->popup); 14928 windows->popup.border_width=0; 14929 windows->popup.flags|=PPosition; 14930 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14931 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14932 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask; 14933 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14934 manager_hints->input=MagickTrue; 14935 manager_hints->initial_state=NormalState; 14936 manager_hints->window_group=windows->image.id; 14937 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14938 &windows->popup); 14939 windows->popup.highlight_stipple=XCreateBitmapFromData(display, 14940 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14941 windows->popup.shadow_stipple=XCreateBitmapFromData(display, 14942 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14943 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); 14944 if (IfMagickTrue(display_image->debug) ) 14945 (void) LogMagickEvent(X11Event,GetMagickModule(), 14946 "Window id: 0x%lx (pop up)",windows->popup.id); 14947 /* 14948 Initialize Magnify window and cursor. 14949 */ 14950 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14951 resource_info,&windows->magnify); 14952 if (IfMagickFalse(resource_info->use_shared_memory) ) 14953 windows->magnify.shared_memory=MagickFalse; 14954 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify", 14955 resource_info->client_name); 14956 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database, 14957 resource_name,"geometry",(char *) NULL); 14958 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX", 14959 resource_info->magnify); 14960 if (windows->magnify.cursor != (Cursor) NULL) 14961 (void) XFreeCursor(display,windows->magnify.cursor); 14962 windows->magnify.cursor=XMakeCursor(display,windows->image.id, 14963 map_info->colormap,resource_info->background_color, 14964 resource_info->foreground_color); 14965 if (windows->magnify.cursor == (Cursor) NULL) 14966 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor", 14967 display_image->filename); 14968 windows->magnify.width=MagnifySize; 14969 windows->magnify.height=MagnifySize; 14970 windows->magnify.flags|=PPosition; 14971 windows->magnify.min_width=MagnifySize; 14972 windows->magnify.min_height=MagnifySize; 14973 windows->magnify.width_inc=MagnifySize; 14974 windows->magnify.height_inc=MagnifySize; 14975 windows->magnify.data=resource_info->magnify; 14976 windows->magnify.attributes.cursor=windows->magnify.cursor; 14977 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask | 14978 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask | 14979 StructureNotifyMask; 14980 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14981 manager_hints->input=MagickTrue; 14982 manager_hints->initial_state=NormalState; 14983 manager_hints->window_group=windows->image.id; 14984 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14985 &windows->magnify); 14986 if (IfMagickTrue(display_image->debug) ) 14987 (void) LogMagickEvent(X11Event,GetMagickModule(), 14988 "Window id: 0x%lx (magnify)",windows->magnify.id); 14989 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id); 14990 /* 14991 Initialize panning window. 14992 */ 14993 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14994 resource_info,&windows->pan); 14995 (void) CloneString(&windows->pan.name,"Pan Icon"); 14996 windows->pan.width=windows->icon.width; 14997 windows->pan.height=windows->icon.height; 14998 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan", 14999 resource_info->client_name); 15000 windows->pan.geometry=XGetResourceClass(resource_info->resource_database, 15001 resource_name,"geometry",(char *) NULL); 15002 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 15003 &windows->pan.width,&windows->pan.height); 15004 windows->pan.flags|=PPosition; 15005 windows->pan.immutable=MagickTrue; 15006 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 15007 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask | 15008 StructureNotifyMask; 15009 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 15010 manager_hints->input=MagickFalse; 15011 manager_hints->initial_state=NormalState; 15012 manager_hints->window_group=windows->image.id; 15013 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 15014 &windows->pan); 15015 if (IfMagickTrue(display_image->debug) ) 15016 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)", 15017 windows->pan.id); 15018 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id); 15019 if (IfMagickTrue(windows->info.mapped) ) 15020 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15021 if (IfMagickFalse(windows->image.mapped) || 15022 (windows->backdrop.id != (Window) NULL)) 15023 (void) XMapWindow(display,windows->image.id); 15024 /* 15025 Set our progress monitor and warning handlers. 15026 */ 15027 if (warning_handler == (WarningHandler) NULL) 15028 { 15029 warning_handler=resource_info->display_warnings ? 15030 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 15031 warning_handler=resource_info->display_warnings ? 15032 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 15033 } 15034 /* 15035 Initialize Image and Magnify X images. 15036 */ 15037 windows->image.x=0; 15038 windows->image.y=0; 15039 windows->magnify.shape=MagickFalse; 15040 width=(unsigned int) display_image->columns; 15041 height=(unsigned int) display_image->rows; 15042 if ((display_image->columns != width) || (display_image->rows != height)) 15043 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15044 display_image->filename); 15045 status=XMakeImage(display,resource_info,&windows->image,display_image, 15046 width,height,exception); 15047 if (IfMagickFalse(status) ) 15048 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15049 display_image->filename); 15050 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL, 15051 windows->magnify.width,windows->magnify.height,exception); 15052 if (IfMagickFalse(status)) 15053 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15054 display_image->filename); 15055 if (IfMagickTrue(windows->magnify.mapped) ) 15056 (void) XMapRaised(display,windows->magnify.id); 15057 if (IfMagickTrue(windows->pan.mapped) ) 15058 (void) XMapRaised(display,windows->pan.id); 15059 windows->image.window_changes.width=(int) display_image->columns; 15060 windows->image.window_changes.height=(int) display_image->rows; 15061 (void) XConfigureImage(display,resource_info,windows,display_image,exception); 15062 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15063 (void) XSync(display,MagickFalse); 15064 /* 15065 Respond to events. 15066 */ 15067 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L); 15068 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15069 update_time=0; 15070 if (IfMagickTrue(resource_info->update) ) 15071 { 15072 MagickBooleanType 15073 status; 15074 15075 /* 15076 Determine when file data was last modified. 15077 */ 15078 status=GetPathAttributes(display_image->filename,&attributes); 15079 if (IfMagickTrue(status) ) 15080 update_time=attributes.st_mtime; 15081 } 15082 *state&=(~FormerImageState); 15083 *state&=(~MontageImageState); 15084 *state&=(~NextImageState); 15085 do 15086 { 15087 /* 15088 Handle a window event. 15089 */ 15090 if (IfMagickTrue(windows->image.mapped) ) 15091 if ((display_image->delay != 0) || (resource_info->update != 0)) 15092 { 15093 if (timer < time((time_t *) NULL)) 15094 { 15095 if (IfMagickFalse(resource_info->update) ) 15096 *state|=NextImageState | ExitState; 15097 else 15098 { 15099 MagickBooleanType 15100 status; 15101 15102 /* 15103 Determine if image file was modified. 15104 */ 15105 status=GetPathAttributes(display_image->filename,&attributes); 15106 if (IfMagickTrue(status) ) 15107 if (update_time != attributes.st_mtime) 15108 { 15109 /* 15110 Redisplay image. 15111 */ 15112 (void) FormatLocaleString( 15113 resource_info->image_info->filename,MaxTextExtent, 15114 "%s:%s",display_image->magick, 15115 display_image->filename); 15116 nexus=ReadImage(resource_info->image_info,exception); 15117 if (nexus != (Image *) NULL) 15118 { 15119 nexus=DestroyImage(nexus); 15120 *state|=NextImageState | ExitState; 15121 } 15122 } 15123 delay=display_image->delay/MagickMax( 15124 display_image->ticks_per_second,1L); 15125 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15126 } 15127 } 15128 if (XEventsQueued(display,QueuedAfterFlush) == 0) 15129 { 15130 /* 15131 Do not block if delay > 0. 15132 */ 15133 XDelay(display,SuspendTime << 2); 15134 continue; 15135 } 15136 } 15137 timestamp=time((time_t *) NULL); 15138 (void) XNextEvent(display,&event); 15139 if (IfMagickFalse(windows->image.stasis) ) 15140 windows->image.stasis=IsMagickTrue((time((time_t *) NULL)-timestamp) > 0); 15141 if (IfMagickFalse(windows->magnify.stasis) ) 15142 windows->magnify.stasis=IsMagickTrue((time((time_t *) NULL)-timestamp) > 0); 15143 if (event.xany.window == windows->command.id) 15144 { 15145 /* 15146 Select a command from the Command widget. 15147 */ 15148 id=XCommandWidget(display,windows,CommandMenu,&event); 15149 if (id < 0) 15150 continue; 15151 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent); 15152 command_type=CommandMenus[id]; 15153 if (id < MagickMenus) 15154 { 15155 /* 15156 Select a command from a pop-up menu. 15157 */ 15158 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15159 command); 15160 if (entry < 0) 15161 continue; 15162 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent); 15163 command_type=Commands[id][entry]; 15164 } 15165 if (command_type != NullCommand) 15166 nexus=XMagickCommand(display,resource_info,windows,command_type, 15167 &display_image,exception); 15168 continue; 15169 } 15170 switch (event.type) 15171 { 15172 case ButtonPress: 15173 { 15174 if (IfMagickTrue(display_image->debug) ) 15175 (void) LogMagickEvent(X11Event,GetMagickModule(), 15176 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15177 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15178 if ((event.xbutton.button == Button3) && 15179 (event.xbutton.state & Mod1Mask)) 15180 { 15181 /* 15182 Convert Alt-Button3 to Button2. 15183 */ 15184 event.xbutton.button=Button2; 15185 event.xbutton.state&=(~Mod1Mask); 15186 } 15187 if (event.xbutton.window == windows->backdrop.id) 15188 { 15189 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15190 event.xbutton.time); 15191 break; 15192 } 15193 if (event.xbutton.window == windows->image.id) 15194 { 15195 switch (event.xbutton.button) 15196 { 15197 case Button1: 15198 { 15199 if (resource_info->immutable) 15200 { 15201 /* 15202 Select a command from the Virtual menu. 15203 */ 15204 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15205 command); 15206 if (entry >= 0) 15207 nexus=XMagickCommand(display,resource_info,windows, 15208 VirtualCommands[entry],&display_image,exception); 15209 break; 15210 } 15211 /* 15212 Map/unmap Command widget. 15213 */ 15214 if (IfMagickTrue(windows->command.mapped) ) 15215 (void) XWithdrawWindow(display,windows->command.id, 15216 windows->command.screen); 15217 else 15218 { 15219 (void) XCommandWidget(display,windows,CommandMenu, 15220 (XEvent *) NULL); 15221 (void) XMapRaised(display,windows->command.id); 15222 } 15223 break; 15224 } 15225 case Button2: 15226 { 15227 /* 15228 User pressed the image magnify button. 15229 */ 15230 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15231 &display_image,exception); 15232 XMagnifyImage(display,windows,&event,exception); 15233 break; 15234 } 15235 case Button3: 15236 { 15237 if (resource_info->immutable) 15238 { 15239 /* 15240 Select a command from the Virtual menu. 15241 */ 15242 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15243 command); 15244 if (entry >= 0) 15245 nexus=XMagickCommand(display,resource_info,windows, 15246 VirtualCommands[entry],&display_image,exception); 15247 break; 15248 } 15249 if (display_image->montage != (char *) NULL) 15250 { 15251 /* 15252 Open or delete a tile from a visual image directory. 15253 */ 15254 nexus=XTileImage(display,resource_info,windows, 15255 display_image,&event,exception); 15256 if (nexus != (Image *) NULL) 15257 *state|=MontageImageState | NextImageState | ExitState; 15258 vid_info.x=(short int) windows->image.x; 15259 vid_info.y=(short int) windows->image.y; 15260 break; 15261 } 15262 /* 15263 Select a command from the Short Cuts menu. 15264 */ 15265 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15266 command); 15267 if (entry >= 0) 15268 nexus=XMagickCommand(display,resource_info,windows, 15269 ShortCutsCommands[entry],&display_image,exception); 15270 break; 15271 } 15272 case Button4: 15273 { 15274 /* 15275 Wheel up. 15276 */ 15277 XTranslateImage(display,windows,*image,XK_Up); 15278 break; 15279 } 15280 case Button5: 15281 { 15282 /* 15283 Wheel down. 15284 */ 15285 XTranslateImage(display,windows,*image,XK_Down); 15286 break; 15287 } 15288 default: 15289 break; 15290 } 15291 break; 15292 } 15293 if (event.xbutton.window == windows->magnify.id) 15294 { 15295 int 15296 factor; 15297 15298 static const char 15299 *MagnifyMenu[] = 15300 { 15301 "2", 15302 "4", 15303 "5", 15304 "6", 15305 "7", 15306 "8", 15307 "9", 15308 "3", 15309 (char *) NULL, 15310 }; 15311 15312 static KeySym 15313 MagnifyCommands[] = 15314 { 15315 XK_2, 15316 XK_4, 15317 XK_5, 15318 XK_6, 15319 XK_7, 15320 XK_8, 15321 XK_9, 15322 XK_3 15323 }; 15324 15325 /* 15326 Select a magnify factor from the pop-up menu. 15327 */ 15328 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15329 if (factor >= 0) 15330 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor], 15331 exception); 15332 break; 15333 } 15334 if (event.xbutton.window == windows->pan.id) 15335 { 15336 switch (event.xbutton.button) 15337 { 15338 case Button4: 15339 { 15340 /* 15341 Wheel up. 15342 */ 15343 XTranslateImage(display,windows,*image,XK_Up); 15344 break; 15345 } 15346 case Button5: 15347 { 15348 /* 15349 Wheel down. 15350 */ 15351 XTranslateImage(display,windows,*image,XK_Down); 15352 break; 15353 } 15354 default: 15355 { 15356 XPanImage(display,windows,&event,exception); 15357 break; 15358 } 15359 } 15360 break; 15361 } 15362 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15363 1L); 15364 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15365 break; 15366 } 15367 case ButtonRelease: 15368 { 15369 if (IfMagickTrue(display_image->debug) ) 15370 (void) LogMagickEvent(X11Event,GetMagickModule(), 15371 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15372 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15373 break; 15374 } 15375 case ClientMessage: 15376 { 15377 if (IfMagickTrue(display_image->debug) ) 15378 (void) LogMagickEvent(X11Event,GetMagickModule(), 15379 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15380 event.xclient.message_type,event.xclient.format,(unsigned long) 15381 event.xclient.data.l[0]); 15382 if (event.xclient.message_type == windows->im_protocols) 15383 { 15384 if (*event.xclient.data.l == (long) windows->im_update_widget) 15385 { 15386 (void) CloneString(&windows->command.name,MagickTitle); 15387 windows->command.data=MagickMenus; 15388 (void) XCommandWidget(display,windows,CommandMenu, 15389 (XEvent *) NULL); 15390 break; 15391 } 15392 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15393 { 15394 /* 15395 Update graphic context and window colormap. 15396 */ 15397 for (i=0; i < (int) number_windows; i++) 15398 { 15399 if (magick_windows[i]->id == windows->icon.id) 15400 continue; 15401 context_values.background=pixel->background_color.pixel; 15402 context_values.foreground=pixel->foreground_color.pixel; 15403 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15404 context_mask,&context_values); 15405 (void) XChangeGC(display,magick_windows[i]->widget_context, 15406 context_mask,&context_values); 15407 context_values.background=pixel->foreground_color.pixel; 15408 context_values.foreground=pixel->background_color.pixel; 15409 context_values.plane_mask=context_values.background ^ 15410 context_values.foreground; 15411 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15412 (size_t) (context_mask | GCPlaneMask), 15413 &context_values); 15414 magick_windows[i]->attributes.background_pixel= 15415 pixel->background_color.pixel; 15416 magick_windows[i]->attributes.border_pixel= 15417 pixel->border_color.pixel; 15418 magick_windows[i]->attributes.colormap=map_info->colormap; 15419 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15420 (unsigned long) magick_windows[i]->mask, 15421 &magick_windows[i]->attributes); 15422 } 15423 if (IfMagickTrue(windows->pan.mapped) ) 15424 { 15425 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15426 windows->pan.pixmap); 15427 (void) XClearWindow(display,windows->pan.id); 15428 XDrawPanRectangle(display,windows); 15429 } 15430 if (windows->backdrop.id != (Window) NULL) 15431 (void) XInstallColormap(display,map_info->colormap); 15432 break; 15433 } 15434 if (*event.xclient.data.l == (long) windows->im_former_image) 15435 { 15436 *state|=FormerImageState | ExitState; 15437 break; 15438 } 15439 if (*event.xclient.data.l == (long) windows->im_next_image) 15440 { 15441 *state|=NextImageState | ExitState; 15442 break; 15443 } 15444 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15445 { 15446 *state|=RetainColorsState; 15447 break; 15448 } 15449 if (*event.xclient.data.l == (long) windows->im_exit) 15450 { 15451 *state|=ExitState; 15452 break; 15453 } 15454 break; 15455 } 15456 if (event.xclient.message_type == windows->dnd_protocols) 15457 { 15458 Atom 15459 selection, 15460 type; 15461 15462 int 15463 format, 15464 status; 15465 15466 unsigned char 15467 *data; 15468 15469 unsigned long 15470 after, 15471 length; 15472 15473 /* 15474 Display image named by the Drag-and-Drop selection. 15475 */ 15476 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15477 break; 15478 selection=XInternAtom(display,"DndSelection",MagickFalse); 15479 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15480 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15481 &length,&after,&data); 15482 if ((status != Success) || (length == 0)) 15483 break; 15484 if (*event.xclient.data.l == 2) 15485 { 15486 /* 15487 Offix DND. 15488 */ 15489 (void) CopyMagickString(resource_info->image_info->filename, 15490 (char *) data,MaxTextExtent); 15491 } 15492 else 15493 { 15494 /* 15495 XDND. 15496 */ 15497 if (strncmp((char *) data, "file:", 5) != 0) 15498 { 15499 (void) XFree((void *) data); 15500 break; 15501 } 15502 (void) CopyMagickString(resource_info->image_info->filename, 15503 ((char *) data)+5,MaxTextExtent); 15504 } 15505 nexus=ReadImage(resource_info->image_info,exception); 15506 CatchException(exception); 15507 if (nexus != (Image *) NULL) 15508 *state|=NextImageState | ExitState; 15509 (void) XFree((void *) data); 15510 break; 15511 } 15512 /* 15513 If client window delete message, exit. 15514 */ 15515 if (event.xclient.message_type != windows->wm_protocols) 15516 break; 15517 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15518 break; 15519 (void) XWithdrawWindow(display,event.xclient.window, 15520 visual_info->screen); 15521 if (event.xclient.window == windows->image.id) 15522 { 15523 *state|=ExitState; 15524 break; 15525 } 15526 if (event.xclient.window == windows->pan.id) 15527 { 15528 /* 15529 Restore original image size when pan window is deleted. 15530 */ 15531 windows->image.window_changes.width=windows->image.ximage->width; 15532 windows->image.window_changes.height=windows->image.ximage->height; 15533 (void) XConfigureImage(display,resource_info,windows, 15534 display_image,exception); 15535 } 15536 break; 15537 } 15538 case ConfigureNotify: 15539 { 15540 if (IfMagickTrue(display_image->debug) ) 15541 (void) LogMagickEvent(X11Event,GetMagickModule(), 15542 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15543 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15544 event.xconfigure.y,event.xconfigure.send_event); 15545 if (event.xconfigure.window == windows->image.id) 15546 { 15547 /* 15548 Image window has a new configuration. 15549 */ 15550 if (event.xconfigure.send_event != 0) 15551 { 15552 XWindowChanges 15553 window_changes; 15554 15555 /* 15556 Position the transient windows relative of the Image window. 15557 */ 15558 if (windows->command.geometry == (char *) NULL) 15559 if (IfMagickFalse(windows->command.mapped) ) 15560 { 15561 windows->command.x=event.xconfigure.x- 15562 windows->command.width-25; 15563 windows->command.y=event.xconfigure.y; 15564 XConstrainWindowPosition(display,&windows->command); 15565 window_changes.x=windows->command.x; 15566 window_changes.y=windows->command.y; 15567 (void) XReconfigureWMWindow(display,windows->command.id, 15568 windows->command.screen,(unsigned int) (CWX | CWY), 15569 &window_changes); 15570 } 15571 if (windows->widget.geometry == (char *) NULL) 15572 if (IfMagickFalse(windows->widget.mapped) ) 15573 { 15574 windows->widget.x=event.xconfigure.x+ 15575 event.xconfigure.width/10; 15576 windows->widget.y=event.xconfigure.y+ 15577 event.xconfigure.height/10; 15578 XConstrainWindowPosition(display,&windows->widget); 15579 window_changes.x=windows->widget.x; 15580 window_changes.y=windows->widget.y; 15581 (void) XReconfigureWMWindow(display,windows->widget.id, 15582 windows->widget.screen,(unsigned int) (CWX | CWY), 15583 &window_changes); 15584 } 15585 if (windows->magnify.geometry == (char *) NULL) 15586 if (IfMagickFalse(windows->magnify.mapped) ) 15587 { 15588 windows->magnify.x=event.xconfigure.x+ 15589 event.xconfigure.width+25; 15590 windows->magnify.y=event.xconfigure.y; 15591 XConstrainWindowPosition(display,&windows->magnify); 15592 window_changes.x=windows->magnify.x; 15593 window_changes.y=windows->magnify.y; 15594 (void) XReconfigureWMWindow(display,windows->magnify.id, 15595 windows->magnify.screen,(unsigned int) (CWX | CWY), 15596 &window_changes); 15597 } 15598 if (windows->pan.geometry == (char *) NULL) 15599 if (IfMagickFalse(windows->pan.mapped) ) 15600 { 15601 windows->pan.x=event.xconfigure.x+ 15602 event.xconfigure.width+25; 15603 windows->pan.y=event.xconfigure.y+ 15604 windows->magnify.height+50; 15605 XConstrainWindowPosition(display,&windows->pan); 15606 window_changes.x=windows->pan.x; 15607 window_changes.y=windows->pan.y; 15608 (void) XReconfigureWMWindow(display,windows->pan.id, 15609 windows->pan.screen,(unsigned int) (CWX | CWY), 15610 &window_changes); 15611 } 15612 } 15613 if ((event.xconfigure.width == (int) windows->image.width) && 15614 (event.xconfigure.height == (int) windows->image.height)) 15615 break; 15616 windows->image.width=(unsigned int) event.xconfigure.width; 15617 windows->image.height=(unsigned int) event.xconfigure.height; 15618 windows->image.x=0; 15619 windows->image.y=0; 15620 if (display_image->montage != (char *) NULL) 15621 { 15622 windows->image.x=vid_info.x; 15623 windows->image.y=vid_info.y; 15624 } 15625 if (IfMagickTrue(windows->image.mapped) && 15626 IfMagickTrue(windows->image.stasis) ) 15627 { 15628 /* 15629 Update image window configuration. 15630 */ 15631 windows->image.window_changes.width=event.xconfigure.width; 15632 windows->image.window_changes.height=event.xconfigure.height; 15633 (void) XConfigureImage(display,resource_info,windows, 15634 display_image,exception); 15635 } 15636 /* 15637 Update pan window configuration. 15638 */ 15639 if ((event.xconfigure.width < windows->image.ximage->width) || 15640 (event.xconfigure.height < windows->image.ximage->height)) 15641 { 15642 (void) XMapRaised(display,windows->pan.id); 15643 XDrawPanRectangle(display,windows); 15644 } 15645 else 15646 if (IfMagickTrue(windows->pan.mapped) ) 15647 (void) XWithdrawWindow(display,windows->pan.id, 15648 windows->pan.screen); 15649 break; 15650 } 15651 if (event.xconfigure.window == windows->magnify.id) 15652 { 15653 unsigned int 15654 magnify; 15655 15656 /* 15657 Magnify window has a new configuration. 15658 */ 15659 windows->magnify.width=(unsigned int) event.xconfigure.width; 15660 windows->magnify.height=(unsigned int) event.xconfigure.height; 15661 if (IfMagickFalse(windows->magnify.mapped) ) 15662 break; 15663 magnify=1; 15664 while ((int) magnify <= event.xconfigure.width) 15665 magnify<<=1; 15666 while ((int) magnify <= event.xconfigure.height) 15667 magnify<<=1; 15668 magnify>>=1; 15669 if (((int) magnify != event.xconfigure.width) || 15670 ((int) magnify != event.xconfigure.height)) 15671 { 15672 window_changes.width=(int) magnify; 15673 window_changes.height=(int) magnify; 15674 (void) XReconfigureWMWindow(display,windows->magnify.id, 15675 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15676 &window_changes); 15677 break; 15678 } 15679 if (IfMagickTrue(windows->magnify.mapped) && 15680 IfMagickTrue(windows->magnify.stasis) ) 15681 { 15682 status=XMakeImage(display,resource_info,&windows->magnify, 15683 display_image,windows->magnify.width,windows->magnify.height, 15684 exception); 15685 XMakeMagnifyImage(display,windows,exception); 15686 } 15687 break; 15688 } 15689 if (IfMagickTrue(windows->magnify.mapped) && 15690 (event.xconfigure.window == windows->pan.id)) 15691 { 15692 /* 15693 Pan icon window has a new configuration. 15694 */ 15695 if (event.xconfigure.send_event != 0) 15696 { 15697 windows->pan.x=event.xconfigure.x; 15698 windows->pan.y=event.xconfigure.y; 15699 } 15700 windows->pan.width=(unsigned int) event.xconfigure.width; 15701 windows->pan.height=(unsigned int) event.xconfigure.height; 15702 break; 15703 } 15704 if (event.xconfigure.window == windows->icon.id) 15705 { 15706 /* 15707 Icon window has a new configuration. 15708 */ 15709 windows->icon.width=(unsigned int) event.xconfigure.width; 15710 windows->icon.height=(unsigned int) event.xconfigure.height; 15711 break; 15712 } 15713 break; 15714 } 15715 case DestroyNotify: 15716 { 15717 /* 15718 Group leader has exited. 15719 */ 15720 if (IfMagickTrue(display_image->debug) ) 15721 (void) LogMagickEvent(X11Event,GetMagickModule(), 15722 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15723 if (event.xdestroywindow.window == windows->group_leader.id) 15724 { 15725 *state|=ExitState; 15726 break; 15727 } 15728 break; 15729 } 15730 case EnterNotify: 15731 { 15732 /* 15733 Selectively install colormap. 15734 */ 15735 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15736 if (event.xcrossing.mode != NotifyUngrab) 15737 XInstallColormap(display,map_info->colormap); 15738 break; 15739 } 15740 case Expose: 15741 { 15742 if (IfMagickTrue(display_image->debug) ) 15743 (void) LogMagickEvent(X11Event,GetMagickModule(), 15744 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15745 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15746 event.xexpose.y); 15747 /* 15748 Refresh windows that are now exposed. 15749 */ 15750 if ((event.xexpose.window == windows->image.id) && 15751 IfMagickTrue(windows->image.mapped) ) 15752 { 15753 XRefreshWindow(display,&windows->image,&event); 15754 delay=display_image->delay/MagickMax( 15755 display_image->ticks_per_second,1L); 15756 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15757 break; 15758 } 15759 if ((event.xexpose.window == windows->magnify.id) && 15760 IfMagickTrue(windows->magnify.mapped)) 15761 { 15762 XMakeMagnifyImage(display,windows,exception); 15763 break; 15764 } 15765 if (event.xexpose.window == windows->pan.id) 15766 { 15767 XDrawPanRectangle(display,windows); 15768 break; 15769 } 15770 if (event.xexpose.window == windows->icon.id) 15771 { 15772 XRefreshWindow(display,&windows->icon,&event); 15773 break; 15774 } 15775 break; 15776 } 15777 case KeyPress: 15778 { 15779 int 15780 length; 15781 15782 /* 15783 Respond to a user key press. 15784 */ 15785 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15786 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15787 *(command+length)='\0'; 15788 if (IfMagickTrue(display_image->debug) ) 15789 (void) LogMagickEvent(X11Event,GetMagickModule(), 15790 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15791 key_symbol,command); 15792 if (event.xkey.window == windows->image.id) 15793 { 15794 command_type=XImageWindowCommand(display,resource_info,windows, 15795 event.xkey.state,key_symbol,&display_image,exception); 15796 if (command_type != NullCommand) 15797 nexus=XMagickCommand(display,resource_info,windows,command_type, 15798 &display_image,exception); 15799 } 15800 if (event.xkey.window == windows->magnify.id) 15801 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol, 15802 exception); 15803 if (event.xkey.window == windows->pan.id) 15804 { 15805 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15806 (void) XWithdrawWindow(display,windows->pan.id, 15807 windows->pan.screen); 15808 else 15809 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15810 XTextViewWidget(display,resource_info,windows,MagickFalse, 15811 "Help Viewer - Image Pan",ImagePanHelp); 15812 else 15813 XTranslateImage(display,windows,*image,key_symbol); 15814 } 15815 delay=display_image->delay/MagickMax( 15816 display_image->ticks_per_second,1L); 15817 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15818 break; 15819 } 15820 case KeyRelease: 15821 { 15822 /* 15823 Respond to a user key release. 15824 */ 15825 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15826 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15827 if (IfMagickTrue(display_image->debug) ) 15828 (void) LogMagickEvent(X11Event,GetMagickModule(), 15829 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15830 break; 15831 } 15832 case LeaveNotify: 15833 { 15834 /* 15835 Selectively uninstall colormap. 15836 */ 15837 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15838 if (event.xcrossing.mode != NotifyUngrab) 15839 XUninstallColormap(display,map_info->colormap); 15840 break; 15841 } 15842 case MapNotify: 15843 { 15844 if (IfMagickTrue(display_image->debug) ) 15845 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15846 event.xmap.window); 15847 if (event.xmap.window == windows->backdrop.id) 15848 { 15849 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15850 CurrentTime); 15851 windows->backdrop.mapped=MagickTrue; 15852 break; 15853 } 15854 if (event.xmap.window == windows->image.id) 15855 { 15856 if (windows->backdrop.id != (Window) NULL) 15857 (void) XInstallColormap(display,map_info->colormap); 15858 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15859 { 15860 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15861 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15862 } 15863 if (((int) windows->image.width < windows->image.ximage->width) || 15864 ((int) windows->image.height < windows->image.ximage->height)) 15865 (void) XMapRaised(display,windows->pan.id); 15866 windows->image.mapped=MagickTrue; 15867 break; 15868 } 15869 if (event.xmap.window == windows->magnify.id) 15870 { 15871 XMakeMagnifyImage(display,windows,exception); 15872 windows->magnify.mapped=MagickTrue; 15873 (void) XWithdrawWindow(display,windows->info.id, 15874 windows->info.screen); 15875 break; 15876 } 15877 if (event.xmap.window == windows->pan.id) 15878 { 15879 XMakePanImage(display,resource_info,windows,display_image, 15880 exception); 15881 windows->pan.mapped=MagickTrue; 15882 break; 15883 } 15884 if (event.xmap.window == windows->info.id) 15885 { 15886 windows->info.mapped=MagickTrue; 15887 break; 15888 } 15889 if (event.xmap.window == windows->icon.id) 15890 { 15891 MagickBooleanType 15892 taint; 15893 15894 /* 15895 Create an icon image. 15896 */ 15897 taint=display_image->taint; 15898 XMakeStandardColormap(display,icon_visual,icon_resources, 15899 display_image,icon_map,icon_pixel,exception); 15900 (void) XMakeImage(display,icon_resources,&windows->icon, 15901 display_image,windows->icon.width,windows->icon.height, 15902 exception); 15903 display_image->taint=taint; 15904 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15905 windows->icon.pixmap); 15906 (void) XClearWindow(display,windows->icon.id); 15907 (void) XWithdrawWindow(display,windows->info.id, 15908 windows->info.screen); 15909 windows->icon.mapped=MagickTrue; 15910 break; 15911 } 15912 if (event.xmap.window == windows->command.id) 15913 { 15914 windows->command.mapped=MagickTrue; 15915 break; 15916 } 15917 if (event.xmap.window == windows->popup.id) 15918 { 15919 windows->popup.mapped=MagickTrue; 15920 break; 15921 } 15922 if (event.xmap.window == windows->widget.id) 15923 { 15924 windows->widget.mapped=MagickTrue; 15925 break; 15926 } 15927 break; 15928 } 15929 case MappingNotify: 15930 { 15931 (void) XRefreshKeyboardMapping(&event.xmapping); 15932 break; 15933 } 15934 case NoExpose: 15935 break; 15936 case PropertyNotify: 15937 { 15938 Atom 15939 type; 15940 15941 int 15942 format, 15943 status; 15944 15945 unsigned char 15946 *data; 15947 15948 unsigned long 15949 after, 15950 length; 15951 15952 if (IfMagickTrue(display_image->debug) ) 15953 (void) LogMagickEvent(X11Event,GetMagickModule(), 15954 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15955 event.xproperty.atom,event.xproperty.state); 15956 if (event.xproperty.atom != windows->im_remote_command) 15957 break; 15958 /* 15959 Display image named by the remote command protocol. 15960 */ 15961 status=XGetWindowProperty(display,event.xproperty.window, 15962 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom) 15963 AnyPropertyType,&type,&format,&length,&after,&data); 15964 if ((status != Success) || (length == 0)) 15965 break; 15966 if (LocaleCompare((char *) data,"-quit") == 0) 15967 { 15968 XClientMessage(display,windows->image.id,windows->im_protocols, 15969 windows->im_exit,CurrentTime); 15970 (void) XFree((void *) data); 15971 break; 15972 } 15973 (void) CopyMagickString(resource_info->image_info->filename, 15974 (char *) data,MaxTextExtent); 15975 (void) XFree((void *) data); 15976 nexus=ReadImage(resource_info->image_info,exception); 15977 CatchException(exception); 15978 if (nexus != (Image *) NULL) 15979 *state|=NextImageState | ExitState; 15980 break; 15981 } 15982 case ReparentNotify: 15983 { 15984 if (IfMagickTrue(display_image->debug) ) 15985 (void) LogMagickEvent(X11Event,GetMagickModule(), 15986 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 15987 event.xreparent.window); 15988 break; 15989 } 15990 case UnmapNotify: 15991 { 15992 if (IfMagickTrue(display_image->debug) ) 15993 (void) LogMagickEvent(X11Event,GetMagickModule(), 15994 "Unmap Notify: 0x%lx",event.xunmap.window); 15995 if (event.xunmap.window == windows->backdrop.id) 15996 { 15997 windows->backdrop.mapped=MagickFalse; 15998 break; 15999 } 16000 if (event.xunmap.window == windows->image.id) 16001 { 16002 windows->image.mapped=MagickFalse; 16003 break; 16004 } 16005 if (event.xunmap.window == windows->magnify.id) 16006 { 16007 windows->magnify.mapped=MagickFalse; 16008 break; 16009 } 16010 if (event.xunmap.window == windows->pan.id) 16011 { 16012 windows->pan.mapped=MagickFalse; 16013 break; 16014 } 16015 if (event.xunmap.window == windows->info.id) 16016 { 16017 windows->info.mapped=MagickFalse; 16018 break; 16019 } 16020 if (event.xunmap.window == windows->icon.id) 16021 { 16022 if (map_info->colormap == icon_map->colormap) 16023 XConfigureImageColormap(display,resource_info,windows, 16024 display_image,exception); 16025 (void) XFreeStandardColormap(display,icon_visual,icon_map, 16026 icon_pixel); 16027 windows->icon.mapped=MagickFalse; 16028 break; 16029 } 16030 if (event.xunmap.window == windows->command.id) 16031 { 16032 windows->command.mapped=MagickFalse; 16033 break; 16034 } 16035 if (event.xunmap.window == windows->popup.id) 16036 { 16037 if (windows->backdrop.id != (Window) NULL) 16038 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16039 CurrentTime); 16040 windows->popup.mapped=MagickFalse; 16041 break; 16042 } 16043 if (event.xunmap.window == windows->widget.id) 16044 { 16045 if (windows->backdrop.id != (Window) NULL) 16046 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16047 CurrentTime); 16048 windows->widget.mapped=MagickFalse; 16049 break; 16050 } 16051 break; 16052 } 16053 default: 16054 { 16055 if (IfMagickTrue(display_image->debug) ) 16056 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 16057 event.type); 16058 break; 16059 } 16060 } 16061 } while (!(*state & ExitState)); 16062 if ((*state & ExitState) == 0) 16063 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 16064 &display_image,exception); 16065 else 16066 if (IfMagickTrue(resource_info->confirm_edit) ) 16067 { 16068 /* 16069 Query user if image has changed. 16070 */ 16071 if (IfMagickFalse(resource_info->immutable) && 16072 IfMagickTrue(display_image->taint)) 16073 { 16074 int 16075 status; 16076 16077 status=XConfirmWidget(display,windows,"Your image changed.", 16078 "Do you want to save it"); 16079 if (status == 0) 16080 *state&=(~ExitState); 16081 else 16082 if (status > 0) 16083 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 16084 &display_image,exception); 16085 } 16086 } 16087 if ((windows->visual_info->klass == GrayScale) || 16088 (windows->visual_info->klass == PseudoColor) || 16089 (windows->visual_info->klass == DirectColor)) 16090 { 16091 /* 16092 Withdraw pan and Magnify window. 16093 */ 16094 if (IfMagickTrue(windows->info.mapped) ) 16095 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 16096 if (IfMagickTrue(windows->magnify.mapped) ) 16097 (void) XWithdrawWindow(display,windows->magnify.id, 16098 windows->magnify.screen); 16099 if (IfMagickTrue(windows->command.mapped) ) 16100 (void) XWithdrawWindow(display,windows->command.id, 16101 windows->command.screen); 16102 } 16103 if (IfMagickTrue(windows->pan.mapped) ) 16104 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 16105 if (IfMagickFalse(resource_info->backdrop) ) 16106 if (windows->backdrop.mapped) 16107 { 16108 (void) XWithdrawWindow(display,windows->backdrop.id, 16109 windows->backdrop.screen); 16110 (void) XDestroyWindow(display,windows->backdrop.id); 16111 windows->backdrop.id=(Window) NULL; 16112 (void) XWithdrawWindow(display,windows->image.id, 16113 windows->image.screen); 16114 (void) XDestroyWindow(display,windows->image.id); 16115 windows->image.id=(Window) NULL; 16116 } 16117 XSetCursorState(display,windows,MagickTrue); 16118 XCheckRefreshWindows(display,windows); 16119 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 16120 *state&=(~ExitState); 16121 if (*state & ExitState) 16122 { 16123 /* 16124 Free Standard Colormap. 16125 */ 16126 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 16127 if (resource_info->map_type == (char *) NULL) 16128 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 16129 /* 16130 Free X resources. 16131 */ 16132 if (resource_info->copy_image != (Image *) NULL) 16133 { 16134 resource_info->copy_image=DestroyImage(resource_info->copy_image); 16135 resource_info->copy_image=NewImageList(); 16136 } 16137 DestroyXResources(); 16138 } 16139 (void) XSync(display,MagickFalse); 16140 /* 16141 Restore our progress monitor and warning handlers. 16142 */ 16143 (void) SetErrorHandler(warning_handler); 16144 (void) SetWarningHandler(warning_handler); 16145 /* 16146 Change to home directory. 16147 */ 16148 directory=getcwd(working_directory,MaxTextExtent); 16149 (void) directory; 16150 { 16151 int 16152 status; 16153 16154 if (*resource_info->home_directory == '\0') 16155 (void) CopyMagickString(resource_info->home_directory,".",MaxTextExtent); 16156 status=chdir(resource_info->home_directory); 16157 if (status == -1) 16158 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 16159 "UnableToOpenFile","%s",resource_info->home_directory); 16160 } 16161 *image=display_image; 16162 return(nexus); 16163} 16164#else 16165 16166/* 16167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16168% % 16169% % 16170% % 16171+ D i s p l a y I m a g e s % 16172% % 16173% % 16174% % 16175%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16176% 16177% DisplayImages() displays an image sequence to any X window screen. It 16178% returns a value other than 0 if successful. Check the exception member 16179% of image to determine the reason for any failure. 16180% 16181% The format of the DisplayImages method is: 16182% 16183% MagickBooleanType DisplayImages(const ImageInfo *image_info, 16184% Image *images,ExceptionInfo *exception) 16185% 16186% A description of each parameter follows: 16187% 16188% o image_info: the image info. 16189% 16190% o image: the image. 16191% 16192% o exception: return any errors or warnings in this structure. 16193% 16194*/ 16195MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16196 Image *image,ExceptionInfo *exception) 16197{ 16198 assert(image_info != (const ImageInfo *) NULL); 16199 assert(image_info->signature == MagickSignature); 16200 assert(image != (Image *) NULL); 16201 assert(image->signature == MagickSignature); 16202 (void) image_info; 16203 if (IfMagickTrue(image->debug) ) 16204 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16205 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16206 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image->filename); 16207 return(MagickFalse); 16208} 16209 16210/* 16211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16212% % 16213% % 16214% % 16215+ R e m o t e D i s p l a y C o m m a n d % 16216% % 16217% % 16218% % 16219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16220% 16221% RemoteDisplayCommand() encourages a remote display program to display the 16222% specified image filename. 16223% 16224% The format of the RemoteDisplayCommand method is: 16225% 16226% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16227% const char *window,const char *filename,ExceptionInfo *exception) 16228% 16229% A description of each parameter follows: 16230% 16231% o image_info: the image info. 16232% 16233% o window: Specifies the name or id of an X window. 16234% 16235% o filename: the name of the image filename to display. 16236% 16237% o exception: return any errors or warnings in this structure. 16238% 16239*/ 16240MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16241 const char *window,const char *filename,ExceptionInfo *exception) 16242{ 16243 assert(image_info != (const ImageInfo *) NULL); 16244 assert(image_info->signature == MagickSignature); 16245 assert(filename != (char *) NULL); 16246 (void) window; 16247 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16248 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16249 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image_info->filename); 16250 return(MagickFalse); 16251} 16252#endif 16253