display.c revision badc7524fff0d4d412aaeae28a65ea73a0451c8d
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-2015 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/nt-base-private.h" 76#include "MagickCore/option.h" 77#include "MagickCore/paint.h" 78#include "MagickCore/pixel.h" 79#include "MagickCore/pixel-accessor.h" 80#include "MagickCore/PreRvIcccm.h" 81#include "MagickCore/property.h" 82#include "MagickCore/quantum.h" 83#include "MagickCore/quantum-private.h" 84#include "MagickCore/resize.h" 85#include "MagickCore/resource_.h" 86#include "MagickCore/shear.h" 87#include "MagickCore/segment.h" 88#include "MagickCore/statistic.h" 89#include "MagickCore/string_.h" 90#include "MagickCore/string-private.h" 91#include "MagickCore/transform.h" 92#include "MagickCore/threshold.h" 93#include "MagickCore/utility.h" 94#include "MagickCore/utility-private.h" 95#include "MagickCore/version.h" 96#include "MagickCore/widget.h" 97#include "MagickCore/widget-private.h" 98#include "MagickCore/xwindow.h" 99#include "MagickCore/xwindow-private.h" 100 101#if defined(MAGICKCORE_X11_DELEGATE) 102/* 103 Define declarations. 104*/ 105#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L) 106 107/* 108 Constant declarations. 109*/ 110static const unsigned char 111 HighlightBitmap[8] = 112 { 113 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 114 }, 115 OpaqueBitmap[8] = 116 { 117 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 118 }, 119 ShadowBitmap[8] = 120 { 121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 122 }; 123 124static const char 125 *PageSizes[] = 126 { 127 "Letter", 128 "Tabloid", 129 "Ledger", 130 "Legal", 131 "Statement", 132 "Executive", 133 "A3", 134 "A4", 135 "A5", 136 "B4", 137 "B5", 138 "Folio", 139 "Quarto", 140 "10x14", 141 (char *) NULL 142 }; 143 144/* 145 Help widget declarations. 146*/ 147static const char 148 *ImageAnnotateHelp[] = 149 { 150 "In annotate mode, the Command widget has these options:", 151 "", 152 " Font Name", 153 " fixed", 154 " variable", 155 " 5x8", 156 " 6x10", 157 " 7x13bold", 158 " 8x13bold", 159 " 9x15bold", 160 " 10x20", 161 " 12x24", 162 " Browser...", 163 " Font Color", 164 " black", 165 " blue", 166 " cyan", 167 " green", 168 " gray", 169 " red", 170 " magenta", 171 " yellow", 172 " white", 173 " transparent", 174 " Browser...", 175 " Font Color", 176 " black", 177 " blue", 178 " cyan", 179 " green", 180 " gray", 181 " red", 182 " magenta", 183 " yellow", 184 " white", 185 " transparent", 186 " Browser...", 187 " Rotate Text", 188 " -90", 189 " -45", 190 " -30", 191 " 0", 192 " 30", 193 " 45", 194 " 90", 195 " 180", 196 " Dialog...", 197 " Help", 198 " Dismiss", 199 "", 200 "Choose a font name from the Font Name sub-menu. Additional", 201 "font names can be specified with the font browser. You can", 202 "change the menu names by setting the X resources font1", 203 "through font9.", 204 "", 205 "Choose a font color from the Font Color sub-menu.", 206 "Additional font colors can be specified with the color", 207 "browser. You can change the menu colors by setting the X", 208 "resources pen1 through pen9.", 209 "", 210 "If you select the color browser and press Grab, you can", 211 "choose the font color by moving the pointer to the desired", 212 "color on the screen and press any button.", 213 "", 214 "If you choose to rotate the text, choose Rotate Text from the", 215 "menu and select an angle. Typically you will only want to", 216 "rotate one line of text at a time. Depending on the angle you", 217 "choose, subsequent lines may end up overwriting each other.", 218 "", 219 "Choosing a font and its color is optional. The default font", 220 "is fixed and the default color is black. However, you must", 221 "choose a location to begin entering text and press button 1.", 222 "An underscore character will appear at the location of the", 223 "pointer. The cursor changes to a pencil to indicate you are", 224 "in text mode. To exit immediately, press Dismiss.", 225 "", 226 "In text mode, any key presses will display the character at", 227 "the location of the underscore and advance the underscore", 228 "cursor. Enter your text and once completed press Apply to", 229 "finish your image annotation. To correct errors press BACK", 230 "SPACE. To delete an entire line of text, press DELETE. Any", 231 "text that exceeds the boundaries of the image window is", 232 "automagically continued onto the next line.", 233 "", 234 "The actual color you request for the font is saved in the", 235 "image. However, the color that appears in your image window", 236 "may be different. For example, on a monochrome screen the", 237 "text will appear black or white even if you choose the color", 238 "red as the font color. However, the image saved to a file", 239 "with -write is written with red lettering. To assure the", 240 "correct color text in the final image, any PseudoClass image", 241 "is promoted to DirectClass (see miff(5)). To force a", 242 "PseudoClass image to remain PseudoClass, use -colors.", 243 (char *) NULL, 244 }, 245 *ImageChopHelp[] = 246 { 247 "In chop mode, the Command widget has these options:", 248 "", 249 " Direction", 250 " horizontal", 251 " vertical", 252 " Help", 253 " Dismiss", 254 "", 255 "If the you choose the horizontal direction (this the", 256 "default), the area of the image between the two horizontal", 257 "endpoints of the chop line is removed. Otherwise, the area", 258 "of the image between the two vertical endpoints of the chop", 259 "line is removed.", 260 "", 261 "Select a location within the image window to begin your chop,", 262 "press and hold any button. Next, move the pointer to", 263 "another location in the image. As you move a line will", 264 "connect the initial location and the pointer. When you", 265 "release the button, the area within the image to chop is", 266 "determined by which direction you choose from the Command", 267 "widget.", 268 "", 269 "To cancel the image chopping, move the pointer back to the", 270 "starting point of the line and release the button.", 271 (char *) NULL, 272 }, 273 *ImageColorEditHelp[] = 274 { 275 "In color edit mode, the Command widget has these options:", 276 "", 277 " Method", 278 " point", 279 " replace", 280 " floodfill", 281 " filltoborder", 282 " reset", 283 " Pixel Color", 284 " black", 285 " blue", 286 " cyan", 287 " green", 288 " gray", 289 " red", 290 " magenta", 291 " yellow", 292 " white", 293 " Browser...", 294 " Border Color", 295 " black", 296 " blue", 297 " cyan", 298 " green", 299 " gray", 300 " red", 301 " magenta", 302 " yellow", 303 " white", 304 " Browser...", 305 " Fuzz", 306 " 0%", 307 " 2%", 308 " 5%", 309 " 10%", 310 " 15%", 311 " Dialog...", 312 " Undo", 313 " Help", 314 " Dismiss", 315 "", 316 "Choose a color editing method from the Method sub-menu", 317 "of the Command widget. The point method recolors any pixel", 318 "selected with the pointer until the button is released. The", 319 "replace method recolors any pixel that matches the color of", 320 "the pixel you select with a button press. Floodfill recolors", 321 "any pixel that matches the color of the pixel you select with", 322 "a button press and is a neighbor. Whereas filltoborder recolors", 323 "any neighbor pixel that is not the border color. Finally reset", 324 "changes the entire image to the designated color.", 325 "", 326 "Next, choose a pixel color from the Pixel Color sub-menu.", 327 "Additional pixel colors can be specified with the color", 328 "browser. You can change the menu colors by setting the X", 329 "resources pen1 through pen9.", 330 "", 331 "Now press button 1 to select a pixel within the image window", 332 "to change its color. Additional pixels may be recolored as", 333 "prescribed by the method you choose.", 334 "", 335 "If the Magnify widget is mapped, it can be helpful in positioning", 336 "your pointer within the image (refer to button 2).", 337 "", 338 "The actual color you request for the pixels is saved in the", 339 "image. However, the color that appears in your image window", 340 "may be different. For example, on a monochrome screen the", 341 "pixel will appear black or white even if you choose the", 342 "color red as the pixel color. However, the image saved to a", 343 "file with -write is written with red pixels. To assure the", 344 "correct color text in the final image, any PseudoClass image", 345 "is promoted to DirectClass (see miff(5)). To force a", 346 "PseudoClass image to remain PseudoClass, use -colors.", 347 (char *) NULL, 348 }, 349 *ImageCompositeHelp[] = 350 { 351 "First a widget window is displayed requesting you to enter an", 352 "image name. Press Composite, Grab or type a file name.", 353 "Press Cancel if you choose not to create a composite image.", 354 "When you choose Grab, move the pointer to the desired window", 355 "and press any button.", 356 "", 357 "If the Composite image does not have any matte information,", 358 "you are informed and the file browser is displayed again.", 359 "Enter the name of a mask image. The image is typically", 360 "grayscale and the same size as the composite image. If the", 361 "image is not grayscale, it is converted to grayscale and the", 362 "resulting intensities are used as matte information.", 363 "", 364 "A small window appears showing the location of the cursor in", 365 "the image window. You are now in composite mode. To exit", 366 "immediately, press Dismiss. In composite mode, the Command", 367 "widget has these options:", 368 "", 369 " Operators", 370 " Over", 371 " In", 372 " Out", 373 " Atop", 374 " Xor", 375 " Plus", 376 " Minus", 377 " Add", 378 " Subtract", 379 " Difference", 380 " Multiply", 381 " Bumpmap", 382 " Copy", 383 " CopyRed", 384 " CopyGreen", 385 " CopyBlue", 386 " CopyOpacity", 387 " Clear", 388 " Dissolve", 389 " Displace", 390 " Help", 391 " Dismiss", 392 "", 393 "Choose a composite operation from the Operators sub-menu of", 394 "the Command widget. How each operator behaves is described", 395 "below. Image window is the image currently displayed on", 396 "your X server and image is the image obtained with the File", 397 "Browser widget.", 398 "", 399 "Over The result is the union of the two image shapes,", 400 " with image obscuring image window in the region of", 401 " overlap.", 402 "", 403 "In The result is simply image cut by the shape of", 404 " image window. None of the image data of image", 405 " window is in the result.", 406 "", 407 "Out The resulting image is image with the shape of", 408 " image window cut out.", 409 "", 410 "Atop The result is the same shape as image image window,", 411 " with image obscuring image window where the image", 412 " shapes overlap. Note this differs from over", 413 " because the portion of image outside image window's", 414 " shape does not appear in the result.", 415 "", 416 "Xor The result is the image data from both image and", 417 " image window that is outside the overlap region.", 418 " The overlap region is blank.", 419 "", 420 "Plus The result is just the sum of the image data.", 421 " Output values are cropped to QuantumRange (no overflow).", 422 "", 423 "Minus The result of image - image window, with underflow", 424 " cropped to zero.", 425 "", 426 "Add The result of image + image window, with overflow", 427 " wrapping around (mod 256).", 428 "", 429 "Subtract The result of image - image window, with underflow", 430 " wrapping around (mod 256). The add and subtract", 431 " operators can be used to perform reversible", 432 " transformations.", 433 "", 434 "Difference", 435 " The result of abs(image - image window). This", 436 " useful for comparing two very similar images.", 437 "", 438 "Multiply", 439 " The result of image * image window. This", 440 " useful for the creation of drop-shadows.", 441 "", 442 "Bumpmap The result of surface normals from image * image", 443 " window.", 444 "", 445 "Copy The resulting image is image window replaced with", 446 " image. Here the matte information is ignored.", 447 "", 448 "CopyRed The red layer of the image window is replace with", 449 " the red layer of the image. The other layers are", 450 " untouched.", 451 "", 452 "CopyGreen", 453 " The green layer of the image window is replace with", 454 " the green layer of the image. The other layers are", 455 " untouched.", 456 "", 457 "CopyBlue The blue layer of the image window is replace with", 458 " the blue layer of the image. The other layers are", 459 " untouched.", 460 "", 461 "CopyOpacity", 462 " The matte layer of the image window is replace with", 463 " the matte layer of the image. The other layers are", 464 " untouched.", 465 "", 466 "The image compositor requires a matte, or alpha channel in", 467 "the image for some operations. This extra channel usually", 468 "defines a mask which represents a sort of a cookie-cutter", 469 "for the image. This the case when matte is opaque (full", 470 "coverage) for pixels inside the shape, zero outside, and", 471 "between 0 and QuantumRange on the boundary. If image does not", 472 "have a matte channel, it is initialized with 0 for any pixel", 473 "matching in color to pixel location (0,0), otherwise QuantumRange.", 474 "", 475 "If you choose Dissolve, the composite operator becomes Over. The", 476 "image matte channel percent transparency is initialized to factor.", 477 "The image window is initialized to (100-factor). Where factor is the", 478 "value you specify in the Dialog widget.", 479 "", 480 "Displace shifts the image pixels as defined by a displacement", 481 "map. With this option, image is used as a displacement map.", 482 "Black, within the displacement map, is a maximum positive", 483 "displacement. White is a maximum negative displacement and", 484 "middle gray is neutral. The displacement is scaled to determine", 485 "the pixel shift. By default, the displacement applies in both the", 486 "horizontal and vertical directions. However, if you specify a mask,", 487 "image is the horizontal X displacement and mask the vertical Y", 488 "displacement.", 489 "", 490 "Note that matte information for image window is not retained", 491 "for colormapped X server visuals (e.g. StaticColor,", 492 "StaticColor, GrayScale, PseudoColor). Correct compositing", 493 "behavior may require a TrueColor or DirectColor visual or a", 494 "Standard Colormap.", 495 "", 496 "Choosing a composite operator is optional. The default", 497 "operator is replace. However, you must choose a location to", 498 "composite your image and press button 1. Press and hold the", 499 "button before releasing and an outline of the image will", 500 "appear to help you identify your location.", 501 "", 502 "The actual colors of the composite image is saved. However,", 503 "the color that appears in image window may be different.", 504 "For example, on a monochrome screen image window will appear", 505 "black or white even though your composited image may have", 506 "many colors. If the image is saved to a file it is written", 507 "with the correct colors. To assure the correct colors are", 508 "saved in the final image, any PseudoClass image is promoted", 509 "to DirectClass (see miff(5)). To force a PseudoClass image", 510 "to remain PseudoClass, use -colors.", 511 (char *) NULL, 512 }, 513 *ImageCutHelp[] = 514 { 515 "In cut mode, the Command widget has these options:", 516 "", 517 " Help", 518 " Dismiss", 519 "", 520 "To define a cut region, press button 1 and drag. The", 521 "cut region is defined by a highlighted rectangle that", 522 "expands or contracts as it follows the pointer. Once you", 523 "are satisfied with the cut region, release the button.", 524 "You are now in rectify mode. In rectify mode, the Command", 525 "widget has these options:", 526 "", 527 " Cut", 528 " Help", 529 " Dismiss", 530 "", 531 "You can make adjustments by moving the pointer to one of the", 532 "cut rectangle corners, pressing a button, and dragging.", 533 "Finally, press Cut to commit your copy region. To", 534 "exit without cutting the image, press Dismiss.", 535 (char *) NULL, 536 }, 537 *ImageCopyHelp[] = 538 { 539 "In copy mode, the Command widget has these options:", 540 "", 541 " Help", 542 " Dismiss", 543 "", 544 "To define a copy region, press button 1 and drag. The", 545 "copy region is defined by a highlighted rectangle that", 546 "expands or contracts as it follows the pointer. Once you", 547 "are satisfied with the copy region, release the button.", 548 "You are now in rectify mode. In rectify mode, the Command", 549 "widget has these options:", 550 "", 551 " Copy", 552 " Help", 553 " Dismiss", 554 "", 555 "You can make adjustments by moving the pointer to one of the", 556 "copy rectangle corners, pressing a button, and dragging.", 557 "Finally, press Copy to commit your copy region. To", 558 "exit without copying the image, press Dismiss.", 559 (char *) NULL, 560 }, 561 *ImageCropHelp[] = 562 { 563 "In crop mode, the Command widget has these options:", 564 "", 565 " Help", 566 " Dismiss", 567 "", 568 "To define a cropping region, press button 1 and drag. The", 569 "cropping region is defined by a highlighted rectangle that", 570 "expands or contracts as it follows the pointer. Once you", 571 "are satisfied with the cropping region, release the button.", 572 "You are now in rectify mode. In rectify mode, the Command", 573 "widget has these options:", 574 "", 575 " Crop", 576 " Help", 577 " Dismiss", 578 "", 579 "You can make adjustments by moving the pointer to one of the", 580 "cropping rectangle corners, pressing a button, and dragging.", 581 "Finally, press Crop to commit your cropping region. To", 582 "exit without cropping the image, press Dismiss.", 583 (char *) NULL, 584 }, 585 *ImageDrawHelp[] = 586 { 587 "The cursor changes to a crosshair to indicate you are in", 588 "draw mode. To exit immediately, press Dismiss. In draw mode,", 589 "the Command widget has these options:", 590 "", 591 " Element", 592 " point", 593 " line", 594 " rectangle", 595 " fill rectangle", 596 " circle", 597 " fill circle", 598 " ellipse", 599 " fill ellipse", 600 " polygon", 601 " fill polygon", 602 " Color", 603 " black", 604 " blue", 605 " cyan", 606 " green", 607 " gray", 608 " red", 609 " magenta", 610 " yellow", 611 " white", 612 " transparent", 613 " Browser...", 614 " Stipple", 615 " Brick", 616 " Diagonal", 617 " Scales", 618 " Vertical", 619 " Wavy", 620 " Translucent", 621 " Opaque", 622 " Open...", 623 " Width", 624 " 1", 625 " 2", 626 " 4", 627 " 8", 628 " 16", 629 " Dialog...", 630 " Undo", 631 " Help", 632 " Dismiss", 633 "", 634 "Choose a drawing primitive from the Element sub-menu.", 635 "", 636 "Choose a color from the Color sub-menu. Additional", 637 "colors can be specified with the color browser.", 638 "", 639 "If you choose the color browser and press Grab, you can", 640 "select the color by moving the pointer to the desired", 641 "color on the screen and press any button. The transparent", 642 "color updates the image matte channel and is useful for", 643 "image compositing.", 644 "", 645 "Choose a stipple, if appropriate, from the Stipple sub-menu.", 646 "Additional stipples can be specified with the file browser.", 647 "Stipples obtained from the file browser must be on disk in the", 648 "X11 bitmap format.", 649 "", 650 "Choose a width, if appropriate, from the Width sub-menu. To", 651 "choose a specific width select the Dialog widget.", 652 "", 653 "Choose a point in the Image window and press button 1 and", 654 "hold. Next, move the pointer to another location in the", 655 "image. As you move, a line connects the initial location and", 656 "the pointer. When you release the button, the image is", 657 "updated with the primitive you just drew. For polygons, the", 658 "image is updated when you press and release the button without", 659 "moving the pointer.", 660 "", 661 "To cancel image drawing, move the pointer back to the", 662 "starting point of the line and release the button.", 663 (char *) NULL, 664 }, 665 *DisplayHelp[] = 666 { 667 "BUTTONS", 668 " The effects of each button press is described below. Three", 669 " buttons are required. If you have a two button mouse,", 670 " button 1 and 3 are returned. Press ALT and button 3 to", 671 " simulate button 2.", 672 "", 673 " 1 Press this button to map or unmap the Command widget.", 674 "", 675 " 2 Press and drag to define a region of the image to", 676 " magnify.", 677 "", 678 " 3 Press and drag to choose from a select set of commands.", 679 " This button behaves differently if the image being", 680 " displayed is a visual image directory. Here, choose a", 681 " particular tile of the directory and press this button and", 682 " drag to select a command from a pop-up menu. Choose from", 683 " these menu items:", 684 "", 685 " Open", 686 " Next", 687 " Former", 688 " Delete", 689 " Update", 690 "", 691 " If you choose Open, the image represented by the tile is", 692 " displayed. To return to the visual image directory, choose", 693 " Next from the Command widget. Next and Former moves to the", 694 " next or former image respectively. Choose Delete to delete", 695 " a particular image tile. Finally, choose Update to", 696 " synchronize all the image tiles with their respective", 697 " images.", 698 "", 699 "COMMAND WIDGET", 700 " The Command widget lists a number of sub-menus and commands.", 701 " They are", 702 "", 703 " File", 704 " Open...", 705 " Next", 706 " Former", 707 " Select...", 708 " Save...", 709 " Print...", 710 " Delete...", 711 " New...", 712 " Visual Directory...", 713 " Quit", 714 " Edit", 715 " Undo", 716 " Redo", 717 " Cut", 718 " Copy", 719 " Paste", 720 " View", 721 " Half Size", 722 " Original Size", 723 " Double Size", 724 " Resize...", 725 " Apply", 726 " Refresh", 727 " Restore", 728 " Transform", 729 " Crop", 730 " Chop", 731 " Flop", 732 " Flip", 733 " Rotate Right", 734 " Rotate Left", 735 " Rotate...", 736 " Shear...", 737 " Roll...", 738 " Trim Edges", 739 " Enhance", 740 " Brightness...", 741 " Saturation...", 742 " Hue...", 743 " Gamma...", 744 " Sharpen...", 745 " Dull", 746 " Contrast Stretch...", 747 " Sigmoidal Contrast...", 748 " Normalize", 749 " Equalize", 750 " Negate", 751 " Grayscale", 752 " Map...", 753 " Quantize...", 754 " Effects", 755 " Despeckle", 756 " Emboss", 757 " Reduce Noise", 758 " Add Noise", 759 " Sharpen...", 760 " Blur...", 761 " Threshold...", 762 " Edge Detect...", 763 " Spread...", 764 " Shade...", 765 " Painting...", 766 " Segment...", 767 " F/X", 768 " Solarize...", 769 " Sepia Tone...", 770 " Swirl...", 771 " Implode...", 772 " Vignette...", 773 " Wave...", 774 " Oil Painting...", 775 " Charcoal Drawing...", 776 " Image Edit", 777 " Annotate...", 778 " Draw...", 779 " Color...", 780 " Matte...", 781 " Composite...", 782 " Add Border...", 783 " Add Frame...", 784 " Comment...", 785 " Launch...", 786 " Region of Interest...", 787 " Miscellany", 788 " Image Info", 789 " Zoom Image", 790 " Show Preview...", 791 " Show Histogram", 792 " Show Matte", 793 " Background...", 794 " Slide Show", 795 " Preferences...", 796 " Help", 797 " Overview", 798 " Browse Documentation", 799 " About Display", 800 "", 801 " Menu items with a indented triangle have a sub-menu. They", 802 " are represented above as the indented items. To access a", 803 " sub-menu item, move the pointer to the appropriate menu and", 804 " press a button and drag. When you find the desired sub-menu", 805 " item, release the button and the command is executed. Move", 806 " the pointer away from the sub-menu if you decide not to", 807 " execute a particular command.", 808 "", 809 "KEYBOARD ACCELERATORS", 810 " Accelerators are one or two key presses that effect a", 811 " particular command. The keyboard accelerators that", 812 " display(1) understands is:", 813 "", 814 " Ctl+O Press to open an image from a file.", 815 "", 816 " space Press to display the next image.", 817 "", 818 " If the image is a multi-paged document such as a Postscript", 819 " document, you can skip ahead several pages by preceding", 820 " this command with a number. For example to display the", 821 " third page beyond the current page, press 3<space>.", 822 "", 823 " backspace Press to display the former image.", 824 "", 825 " If the image is a multi-paged document such as a Postscript", 826 " document, you can skip behind several pages by preceding", 827 " this command with a number. For example to display the", 828 " third page preceding the current page, press 3<backspace>.", 829 "", 830 " Ctl+S Press to write the image to a file.", 831 "", 832 " Ctl+P Press to print the image to a Postscript printer.", 833 "", 834 " Ctl+D Press to delete an image file.", 835 "", 836 " Ctl+N Press to create a blank canvas.", 837 "", 838 " Ctl+Q Press to discard all images and exit program.", 839 "", 840 " Ctl+Z Press to undo last image transformation.", 841 "", 842 " Ctl+R Press to redo last image transformation.", 843 "", 844 " Ctl+X Press to cut a region of the image.", 845 "", 846 " Ctl+C Press to copy a region of the image.", 847 "", 848 " Ctl+V Press to paste a region to the image.", 849 "", 850 " < Press to half the image size.", 851 "", 852 " - Press to return to the original image size.", 853 "", 854 " > Press to double the image size.", 855 "", 856 " % Press to resize the image to a width and height you", 857 " specify.", 858 "", 859 "Cmd-A Press to make any image transformations permanent." 860 "", 861 " By default, any image size transformations are applied", 862 " to the original image to create the image displayed on", 863 " the X server. However, the transformations are not", 864 " permanent (i.e. the original image does not change", 865 " size only the X image does). For example, if you", 866 " press > the X image will appear to double in size,", 867 " but the original image will in fact remain the same size.", 868 " To force the original image to double in size, press >", 869 " followed by Cmd-A.", 870 "", 871 " @ Press to refresh the image window.", 872 "", 873 " C Press to cut out a rectangular region of the image.", 874 "", 875 " [ Press to chop the image.", 876 "", 877 " H Press to flop image in the horizontal direction.", 878 "", 879 " V Press to flip image in the vertical direction.", 880 "", 881 " / Press to rotate the image 90 degrees clockwise.", 882 "", 883 " \\ Press to rotate the image 90 degrees counter-clockwise.", 884 "", 885 " * Press to rotate the image the number of degrees you", 886 " specify.", 887 "", 888 " S Press to shear the image the number of degrees you", 889 " specify.", 890 "", 891 " R Press to roll the image.", 892 "", 893 " T Press to trim the image edges.", 894 "", 895 " Shft-H Press to vary the image hue.", 896 "", 897 " Shft-S Press to vary the color saturation.", 898 "", 899 " Shft-L Press to vary the color brightness.", 900 "", 901 " Shft-G Press to gamma correct the image.", 902 "", 903 " Shft-C Press to sharpen the image contrast.", 904 "", 905 " Shft-Z Press to dull the image contrast.", 906 "", 907 " = Press to perform histogram equalization on the image.", 908 "", 909 " Shft-N Press to perform histogram normalization on the image.", 910 "", 911 " Shft-~ Press to negate the colors of the image.", 912 "", 913 " . Press to convert the image colors to gray.", 914 "", 915 " Shft-# Press to set the maximum number of unique colors in the", 916 " image.", 917 "", 918 " F2 Press to reduce the speckles in an image.", 919 "", 920 " F3 Press to eliminate peak noise from an image.", 921 "", 922 " F4 Press to add noise to an image.", 923 "", 924 " F5 Press to sharpen an image.", 925 "", 926 " F6 Press to delete an image file.", 927 "", 928 " F7 Press to threshold the image.", 929 "", 930 " F8 Press to detect edges within an image.", 931 "", 932 " F9 Press to emboss an image.", 933 "", 934 " F10 Press to displace pixels by a random amount.", 935 "", 936 " F11 Press to negate all pixels above the threshold level.", 937 "", 938 " F12 Press to shade the image using a distant light source.", 939 "", 940 " F13 Press to lighten or darken image edges to create a 3-D effect.", 941 "", 942 " F14 Press to segment the image by color.", 943 "", 944 " Meta-S Press to swirl image pixels about the center.", 945 "", 946 " Meta-I Press to implode image pixels about the center.", 947 "", 948 " Meta-W Press to alter an image along a sine wave.", 949 "", 950 " Meta-P Press to simulate an oil painting.", 951 "", 952 " Meta-C Press to simulate a charcoal drawing.", 953 "", 954 " Alt-A Press to annotate the image with text.", 955 "", 956 " Alt-D Press to draw on an image.", 957 "", 958 " Alt-P Press to edit an image pixel color.", 959 "", 960 " Alt-M Press to edit the image matte information.", 961 "", 962 " Alt-V Press to composite the image with another.", 963 "", 964 " Alt-B Press to add a border to the image.", 965 "", 966 " Alt-F Press to add an ornamental border to the image.", 967 "", 968 " Alt-Shft-!", 969 " Press to add an image comment.", 970 "", 971 " Ctl-A Press to apply image processing techniques to a region", 972 " of interest.", 973 "", 974 " Shft-? Press to display information about the image.", 975 "", 976 " Shft-+ Press to map the zoom image window.", 977 "", 978 " Shft-P Press to preview an image enhancement, effect, or f/x.", 979 "", 980 " F1 Press to display helpful information about display(1).", 981 "", 982 " Find Press to browse documentation about ImageMagick.", 983 "", 984 " 1-9 Press to change the level of magnification.", 985 "", 986 " Use the arrow keys to move the image one pixel up, down,", 987 " left, or right within the magnify window. Be sure to first", 988 " map the magnify window by pressing button 2.", 989 "", 990 " Press ALT and one of the arrow keys to trim off one pixel", 991 " from any side of the image.", 992 (char *) NULL, 993 }, 994 *ImageMatteEditHelp[] = 995 { 996 "Matte information within an image is useful for some", 997 "operations such as image compositing (See IMAGE", 998 "COMPOSITING). This extra channel usually defines a mask", 999 "which represents a sort of a cookie-cutter for the image.", 1000 "This the case when matte is opaque (full coverage) for", 1001 "pixels inside the shape, zero outside, and between 0 and", 1002 "QuantumRange on the boundary.", 1003 "", 1004 "A small window appears showing the location of the cursor in", 1005 "the image window. You are now in matte edit mode. To exit", 1006 "immediately, press Dismiss. In matte edit mode, the Command", 1007 "widget has these options:", 1008 "", 1009 " Method", 1010 " point", 1011 " replace", 1012 " floodfill", 1013 " filltoborder", 1014 " reset", 1015 " Border Color", 1016 " black", 1017 " blue", 1018 " cyan", 1019 " green", 1020 " gray", 1021 " red", 1022 " magenta", 1023 " yellow", 1024 " white", 1025 " Browser...", 1026 " Fuzz", 1027 " 0%", 1028 " 2%", 1029 " 5%", 1030 " 10%", 1031 " 15%", 1032 " Dialog...", 1033 " Matte", 1034 " Opaque", 1035 " Transparent", 1036 " Dialog...", 1037 " Undo", 1038 " Help", 1039 " Dismiss", 1040 "", 1041 "Choose a matte editing method from the Method sub-menu of", 1042 "the Command widget. The point method changes the matte value", 1043 "of any pixel selected with the pointer until the button is", 1044 "is released. The replace method changes the matte value of", 1045 "any pixel that matches the color of the pixel you select with", 1046 "a button press. Floodfill changes the matte value of any pixel", 1047 "that matches the color of the pixel you select with a button", 1048 "press and is a neighbor. Whereas filltoborder changes the matte", 1049 "value any neighbor pixel that is not the border color. Finally", 1050 "reset changes the entire image to the designated matte value.", 1051 "", 1052 "Choose Matte Value and pick Opaque or Transarent. For other values", 1053 "select the Dialog entry. Here a dialog appears requesting a matte", 1054 "value. The value you select is assigned as the opacity value of the", 1055 "selected pixel or pixels.", 1056 "", 1057 "Now, press any button to select a pixel within the image", 1058 "window to change its matte value.", 1059 "", 1060 "If the Magnify widget is mapped, it can be helpful in positioning", 1061 "your pointer within the image (refer to button 2).", 1062 "", 1063 "Matte information is only valid in a DirectClass image.", 1064 "Therefore, any PseudoClass image is promoted to DirectClass", 1065 "(see miff(5)). Note that matte information for PseudoClass", 1066 "is not retained for colormapped X server visuals (e.g.", 1067 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you", 1068 "immediately save your image to a file (refer to Write).", 1069 "Correct matte editing behavior may require a TrueColor or", 1070 "DirectColor visual or a Standard Colormap.", 1071 (char *) NULL, 1072 }, 1073 *ImagePanHelp[] = 1074 { 1075 "When an image exceeds the width or height of the X server", 1076 "screen, display maps a small panning icon. The rectangle", 1077 "within the panning icon shows the area that is currently", 1078 "displayed in the image window. To pan about the image,", 1079 "press any button and drag the pointer within the panning", 1080 "icon. The pan rectangle moves with the pointer and the", 1081 "image window is updated to reflect the location of the", 1082 "rectangle within the panning icon. When you have selected", 1083 "the area of the image you wish to view, release the button.", 1084 "", 1085 "Use the arrow keys to pan the image one pixel up, down,", 1086 "left, or right within the image window.", 1087 "", 1088 "The panning icon is withdrawn if the image becomes smaller", 1089 "than the dimensions of the X server screen.", 1090 (char *) NULL, 1091 }, 1092 *ImagePasteHelp[] = 1093 { 1094 "A small window appears showing the location of the cursor in", 1095 "the image window. You are now in paste mode. To exit", 1096 "immediately, press Dismiss. In paste mode, the Command", 1097 "widget has these options:", 1098 "", 1099 " Operators", 1100 " over", 1101 " in", 1102 " out", 1103 " atop", 1104 " xor", 1105 " plus", 1106 " minus", 1107 " add", 1108 " subtract", 1109 " difference", 1110 " replace", 1111 " Help", 1112 " Dismiss", 1113 "", 1114 "Choose a composite operation from the Operators sub-menu of", 1115 "the Command widget. How each operator behaves is described", 1116 "below. Image window is the image currently displayed on", 1117 "your X server and image is the image obtained with the File", 1118 "Browser widget.", 1119 "", 1120 "Over The result is the union of the two image shapes,", 1121 " with image obscuring image window in the region of", 1122 " overlap.", 1123 "", 1124 "In The result is simply image cut by the shape of", 1125 " image window. None of the image data of image", 1126 " window is in the result.", 1127 "", 1128 "Out The resulting image is image with the shape of", 1129 " image window cut out.", 1130 "", 1131 "Atop The result is the same shape as image image window,", 1132 " with image obscuring image window where the image", 1133 " shapes overlap. Note this differs from over", 1134 " because the portion of image outside image window's", 1135 " shape does not appear in the result.", 1136 "", 1137 "Xor The result is the image data from both image and", 1138 " image window that is outside the overlap region.", 1139 " The overlap region is blank.", 1140 "", 1141 "Plus The result is just the sum of the image data.", 1142 " Output values are cropped to QuantumRange (no overflow).", 1143 " This operation is independent of the matte", 1144 " channels.", 1145 "", 1146 "Minus The result of image - image window, with underflow", 1147 " cropped to zero.", 1148 "", 1149 "Add The result of image + image window, with overflow", 1150 " wrapping around (mod 256).", 1151 "", 1152 "Subtract The result of image - image window, with underflow", 1153 " wrapping around (mod 256). The add and subtract", 1154 " operators can be used to perform reversible", 1155 " transformations.", 1156 "", 1157 "Difference", 1158 " The result of abs(image - image window). This", 1159 " useful for comparing two very similar images.", 1160 "", 1161 "Copy The resulting image is image window replaced with", 1162 " image. Here the matte information is ignored.", 1163 "", 1164 "CopyRed The red layer of the image window is replace with", 1165 " the red layer of the image. The other layers are", 1166 " untouched.", 1167 "", 1168 "CopyGreen", 1169 " The green layer of the image window is replace with", 1170 " the green layer of the image. The other layers are", 1171 " untouched.", 1172 "", 1173 "CopyBlue The blue layer of the image window is replace with", 1174 " the blue layer of the image. The other layers are", 1175 " untouched.", 1176 "", 1177 "CopyOpacity", 1178 " The matte layer of the image window is replace with", 1179 " the matte layer of the image. The other layers are", 1180 " untouched.", 1181 "", 1182 "The image compositor requires a matte, or alpha channel in", 1183 "the image for some operations. This extra channel usually", 1184 "defines a mask which represents a sort of a cookie-cutter", 1185 "for the image. This the case when matte is opaque (full", 1186 "coverage) for pixels inside the shape, zero outside, and", 1187 "between 0 and QuantumRange on the boundary. If image does not", 1188 "have a matte channel, it is initialized with 0 for any pixel", 1189 "matching in color to pixel location (0,0), otherwise QuantumRange.", 1190 "", 1191 "Note that matte information for image window is not retained", 1192 "for colormapped X server visuals (e.g. StaticColor,", 1193 "StaticColor, GrayScale, PseudoColor). Correct compositing", 1194 "behavior may require a TrueColor or DirectColor visual or a", 1195 "Standard Colormap.", 1196 "", 1197 "Choosing a composite operator is optional. The default", 1198 "operator is replace. However, you must choose a location to", 1199 "paste your image and press button 1. Press and hold the", 1200 "button before releasing and an outline of the image will", 1201 "appear to help you identify your location.", 1202 "", 1203 "The actual colors of the pasted image is saved. However,", 1204 "the color that appears in image window may be different.", 1205 "For example, on a monochrome screen image window will appear", 1206 "black or white even though your pasted image may have", 1207 "many colors. If the image is saved to a file it is written", 1208 "with the correct colors. To assure the correct colors are", 1209 "saved in the final image, any PseudoClass image is promoted", 1210 "to DirectClass (see miff(5)). To force a PseudoClass image", 1211 "to remain PseudoClass, use -colors.", 1212 (char *) NULL, 1213 }, 1214 *ImageROIHelp[] = 1215 { 1216 "In region of interest mode, the Command widget has these", 1217 "options:", 1218 "", 1219 " Help", 1220 " Dismiss", 1221 "", 1222 "To define a region of interest, press button 1 and drag.", 1223 "The region of interest is defined by a highlighted rectangle", 1224 "that expands or contracts as it follows the pointer. Once", 1225 "you are satisfied with the region of interest, release the", 1226 "button. You are now in apply mode. In apply mode the", 1227 "Command widget has these options:", 1228 "", 1229 " File", 1230 " Save...", 1231 " Print...", 1232 " Edit", 1233 " Undo", 1234 " Redo", 1235 " Transform", 1236 " Flop", 1237 " Flip", 1238 " Rotate Right", 1239 " Rotate Left", 1240 " Enhance", 1241 " Hue...", 1242 " Saturation...", 1243 " Brightness...", 1244 " Gamma...", 1245 " Spiff", 1246 " Dull", 1247 " Contrast Stretch", 1248 " Sigmoidal Contrast...", 1249 " Normalize", 1250 " Equalize", 1251 " Negate", 1252 " Grayscale", 1253 " Map...", 1254 " Quantize...", 1255 " Effects", 1256 " Despeckle", 1257 " Emboss", 1258 " Reduce Noise", 1259 " Sharpen...", 1260 " Blur...", 1261 " Threshold...", 1262 " Edge Detect...", 1263 " Spread...", 1264 " Shade...", 1265 " Raise...", 1266 " Segment...", 1267 " F/X", 1268 " Solarize...", 1269 " Sepia Tone...", 1270 " Swirl...", 1271 " Implode...", 1272 " Vignette...", 1273 " Wave...", 1274 " Oil Painting...", 1275 " Charcoal Drawing...", 1276 " Miscellany", 1277 " Image Info", 1278 " Zoom Image", 1279 " Show Preview...", 1280 " Show Histogram", 1281 " Show Matte", 1282 " Help", 1283 " Dismiss", 1284 "", 1285 "You can make adjustments to the region of interest by moving", 1286 "the pointer to one of the rectangle corners, pressing a", 1287 "button, and dragging. Finally, choose an image processing", 1288 "technique from the Command widget. You can choose more than", 1289 "one image processing technique to apply to an area.", 1290 "Alternatively, you can move the region of interest before", 1291 "applying another image processing technique. To exit, press", 1292 "Dismiss.", 1293 (char *) NULL, 1294 }, 1295 *ImageRotateHelp[] = 1296 { 1297 "In rotate mode, the Command widget has these options:", 1298 "", 1299 " Pixel Color", 1300 " black", 1301 " blue", 1302 " cyan", 1303 " green", 1304 " gray", 1305 " red", 1306 " magenta", 1307 " yellow", 1308 " white", 1309 " Browser...", 1310 " Direction", 1311 " horizontal", 1312 " vertical", 1313 " Help", 1314 " Dismiss", 1315 "", 1316 "Choose a background color from the Pixel Color sub-menu.", 1317 "Additional background colors can be specified with the color", 1318 "browser. You can change the menu colors by setting the X", 1319 "resources pen1 through pen9.", 1320 "", 1321 "If you choose the color browser and press Grab, you can", 1322 "select the background color by moving the pointer to the", 1323 "desired color on the screen and press any button.", 1324 "", 1325 "Choose a point in the image window and press this button and", 1326 "hold. Next, move the pointer to another location in the", 1327 "image. As you move a line connects the initial location and", 1328 "the pointer. When you release the button, the degree of", 1329 "image rotation is determined by the slope of the line you", 1330 "just drew. The slope is relative to the direction you", 1331 "choose from the Direction sub-menu of the Command widget.", 1332 "", 1333 "To cancel the image rotation, move the pointer back to the", 1334 "starting point of the line and release the button.", 1335 (char *) NULL, 1336 }; 1337 1338/* 1339 Enumeration declarations. 1340*/ 1341typedef enum 1342{ 1343 CopyMode, 1344 CropMode, 1345 CutMode 1346} ClipboardMode; 1347 1348typedef enum 1349{ 1350 OpenCommand, 1351 NextCommand, 1352 FormerCommand, 1353 SelectCommand, 1354 SaveCommand, 1355 PrintCommand, 1356 DeleteCommand, 1357 NewCommand, 1358 VisualDirectoryCommand, 1359 QuitCommand, 1360 UndoCommand, 1361 RedoCommand, 1362 CutCommand, 1363 CopyCommand, 1364 PasteCommand, 1365 HalfSizeCommand, 1366 OriginalSizeCommand, 1367 DoubleSizeCommand, 1368 ResizeCommand, 1369 ApplyCommand, 1370 RefreshCommand, 1371 RestoreCommand, 1372 CropCommand, 1373 ChopCommand, 1374 FlopCommand, 1375 FlipCommand, 1376 RotateRightCommand, 1377 RotateLeftCommand, 1378 RotateCommand, 1379 ShearCommand, 1380 RollCommand, 1381 TrimCommand, 1382 HueCommand, 1383 SaturationCommand, 1384 BrightnessCommand, 1385 GammaCommand, 1386 SpiffCommand, 1387 DullCommand, 1388 ContrastStretchCommand, 1389 SigmoidalContrastCommand, 1390 NormalizeCommand, 1391 EqualizeCommand, 1392 NegateCommand, 1393 GrayscaleCommand, 1394 MapCommand, 1395 QuantizeCommand, 1396 DespeckleCommand, 1397 EmbossCommand, 1398 ReduceNoiseCommand, 1399 AddNoiseCommand, 1400 SharpenCommand, 1401 BlurCommand, 1402 ThresholdCommand, 1403 EdgeDetectCommand, 1404 SpreadCommand, 1405 ShadeCommand, 1406 RaiseCommand, 1407 SegmentCommand, 1408 SolarizeCommand, 1409 SepiaToneCommand, 1410 SwirlCommand, 1411 ImplodeCommand, 1412 VignetteCommand, 1413 WaveCommand, 1414 OilPaintCommand, 1415 CharcoalDrawCommand, 1416 AnnotateCommand, 1417 DrawCommand, 1418 ColorCommand, 1419 MatteCommand, 1420 CompositeCommand, 1421 AddBorderCommand, 1422 AddFrameCommand, 1423 CommentCommand, 1424 LaunchCommand, 1425 RegionofInterestCommand, 1426 ROIHelpCommand, 1427 ROIDismissCommand, 1428 InfoCommand, 1429 ZoomCommand, 1430 ShowPreviewCommand, 1431 ShowHistogramCommand, 1432 ShowMatteCommand, 1433 BackgroundCommand, 1434 SlideShowCommand, 1435 PreferencesCommand, 1436 HelpCommand, 1437 BrowseDocumentationCommand, 1438 VersionCommand, 1439 SaveToUndoBufferCommand, 1440 FreeBuffersCommand, 1441 NullCommand 1442} CommandType; 1443 1444typedef enum 1445{ 1446 AnnotateNameCommand, 1447 AnnotateFontColorCommand, 1448 AnnotateBackgroundColorCommand, 1449 AnnotateRotateCommand, 1450 AnnotateHelpCommand, 1451 AnnotateDismissCommand, 1452 TextHelpCommand, 1453 TextApplyCommand, 1454 ChopDirectionCommand, 1455 ChopHelpCommand, 1456 ChopDismissCommand, 1457 HorizontalChopCommand, 1458 VerticalChopCommand, 1459 ColorEditMethodCommand, 1460 ColorEditColorCommand, 1461 ColorEditBorderCommand, 1462 ColorEditFuzzCommand, 1463 ColorEditUndoCommand, 1464 ColorEditHelpCommand, 1465 ColorEditDismissCommand, 1466 CompositeOperatorsCommand, 1467 CompositeDissolveCommand, 1468 CompositeDisplaceCommand, 1469 CompositeHelpCommand, 1470 CompositeDismissCommand, 1471 CropHelpCommand, 1472 CropDismissCommand, 1473 RectifyCopyCommand, 1474 RectifyHelpCommand, 1475 RectifyDismissCommand, 1476 DrawElementCommand, 1477 DrawColorCommand, 1478 DrawStippleCommand, 1479 DrawWidthCommand, 1480 DrawUndoCommand, 1481 DrawHelpCommand, 1482 DrawDismissCommand, 1483 MatteEditMethod, 1484 MatteEditBorderCommand, 1485 MatteEditFuzzCommand, 1486 MatteEditValueCommand, 1487 MatteEditUndoCommand, 1488 MatteEditHelpCommand, 1489 MatteEditDismissCommand, 1490 PasteOperatorsCommand, 1491 PasteHelpCommand, 1492 PasteDismissCommand, 1493 RotateColorCommand, 1494 RotateDirectionCommand, 1495 RotateCropCommand, 1496 RotateSharpenCommand, 1497 RotateHelpCommand, 1498 RotateDismissCommand, 1499 HorizontalRotateCommand, 1500 VerticalRotateCommand, 1501 TileLoadCommand, 1502 TileNextCommand, 1503 TileFormerCommand, 1504 TileDeleteCommand, 1505 TileUpdateCommand 1506} ModeType; 1507 1508/* 1509 Stipples. 1510*/ 1511#define BricksWidth 20 1512#define BricksHeight 20 1513#define DiagonalWidth 16 1514#define DiagonalHeight 16 1515#define HighlightWidth 8 1516#define HighlightHeight 8 1517#define OpaqueWidth 8 1518#define OpaqueHeight 8 1519#define ScalesWidth 16 1520#define ScalesHeight 16 1521#define ShadowWidth 8 1522#define ShadowHeight 8 1523#define VerticalWidth 16 1524#define VerticalHeight 16 1525#define WavyWidth 16 1526#define WavyHeight 16 1527 1528/* 1529 Constant declaration. 1530*/ 1531static const int 1532 RoiDelta = 8; 1533 1534static const unsigned char 1535 BricksBitmap[] = 1536 { 1537 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 1538 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 1539 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 1540 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 1541 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01 1542 }, 1543 DiagonalBitmap[] = 1544 { 1545 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 1546 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 1547 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22 1548 }, 1549 ScalesBitmap[] = 1550 { 1551 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80, 1552 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 1553 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e 1554 }, 1555 VerticalBitmap[] = 1556 { 1557 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1558 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1559 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 1560 }, 1561 WavyBitmap[] = 1562 { 1563 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff, 1564 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf, 1565 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f 1566 }; 1567 1568/* 1569 Function prototypes. 1570*/ 1571static CommandType 1572 XImageWindowCommand(Display *,XResourceInfo *,XWindows *, 1573 const MagickStatusType,KeySym,Image **,ExceptionInfo *); 1574 1575static Image 1576 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType, 1577 Image **,ExceptionInfo *), 1578 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType), 1579 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *, 1580 ExceptionInfo *), 1581 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *, 1582 ExceptionInfo *); 1583 1584static MagickBooleanType 1585 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *, 1586 ExceptionInfo *), 1587 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **, 1588 ExceptionInfo *), 1589 XChopImage(Display *,XResourceInfo *,XWindows *,Image **, 1590 ExceptionInfo *), 1591 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode, 1592 ExceptionInfo *), 1593 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1594 ExceptionInfo *), 1595 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *, 1596 ExceptionInfo *), 1597 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1598 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1599 ExceptionInfo *), 1600 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1601 ExceptionInfo *), 1602 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1603 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1604 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **, 1605 ExceptionInfo *), 1606 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *), 1607 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1608 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *); 1609 1610static void 1611 XDrawPanRectangle(Display *,XWindows *), 1612 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **, 1613 ExceptionInfo *), 1614 XMagnifyImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1615 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1616 XPanImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1617 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType, 1618 const KeySym,ExceptionInfo *), 1619 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *), 1620 XScreenEvent(Display *,XWindows *,XEvent *,ExceptionInfo *), 1621 XTranslateImage(Display *,XWindows *,Image *,const KeySym); 1622 1623/* 1624%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1625% % 1626% % 1627% % 1628% D i s p l a y I m a g e s % 1629% % 1630% % 1631% % 1632%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1633% 1634% DisplayImages() displays an image sequence to any X window screen. It 1635% returns a value other than 0 if successful. Check the exception member 1636% of image to determine the reason for any failure. 1637% 1638% The format of the DisplayImages method is: 1639% 1640% MagickBooleanType DisplayImages(const ImageInfo *image_info, 1641% Image *images,ExceptionInfo *exception) 1642% 1643% A description of each parameter follows: 1644% 1645% o image_info: the image info. 1646% 1647% o image: the image. 1648% 1649% o exception: return any errors or warnings in this structure. 1650% 1651*/ 1652MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 1653 Image *images,ExceptionInfo *exception) 1654{ 1655 char 1656 *argv[1]; 1657 1658 Display 1659 *display; 1660 1661 Image 1662 *image; 1663 1664 register ssize_t 1665 i; 1666 1667 size_t 1668 state; 1669 1670 XrmDatabase 1671 resource_database; 1672 1673 XResourceInfo 1674 resource_info; 1675 1676 assert(image_info != (const ImageInfo *) NULL); 1677 assert(image_info->signature == MagickSignature); 1678 assert(images != (Image *) NULL); 1679 assert(images->signature == MagickSignature); 1680 if (IfMagickTrue(images->debug) ) 1681 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 1682 display=XOpenDisplay(image_info->server_name); 1683 if (display == (Display *) NULL) 1684 { 1685 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1686 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1687 return(MagickFalse); 1688 } 1689 if (exception->severity != UndefinedException) 1690 CatchException(exception); 1691 (void) XSetErrorHandler(XError); 1692 resource_database=XGetResourceDatabase(display,GetClientName()); 1693 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info)); 1694 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info); 1695 if (image_info->page != (char *) NULL) 1696 resource_info.image_geometry=AcquireString(image_info->page); 1697 resource_info.immutable=MagickTrue; 1698 argv[0]=AcquireString(GetClientName()); 1699 state=DefaultState; 1700 for (i=0; (state & ExitState) == 0; i++) 1701 { 1702 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations)) 1703 break; 1704 image=GetImageFromList(images,i % GetImageListLength(images)); 1705 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception); 1706 } 1707 (void) SetErrorHandler((ErrorHandler) NULL); 1708 (void) SetWarningHandler((WarningHandler) NULL); 1709 argv[0]=DestroyString(argv[0]); 1710 (void) XCloseDisplay(display); 1711 XDestroyResourceInfo(&resource_info); 1712 if (exception->severity != UndefinedException) 1713 return(MagickFalse); 1714 return(MagickTrue); 1715} 1716 1717/* 1718%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1719% % 1720% % 1721% % 1722% R e m o t e D i s p l a y C o m m a n d % 1723% % 1724% % 1725% % 1726%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1727% 1728% RemoteDisplayCommand() encourages a remote display program to display the 1729% specified image filename. 1730% 1731% The format of the RemoteDisplayCommand method is: 1732% 1733% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1734% const char *window,const char *filename,ExceptionInfo *exception) 1735% 1736% A description of each parameter follows: 1737% 1738% o image_info: the image info. 1739% 1740% o window: Specifies the name or id of an X window. 1741% 1742% o filename: the name of the image filename to display. 1743% 1744% o exception: return any errors or warnings in this structure. 1745% 1746*/ 1747MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1748 const char *window,const char *filename,ExceptionInfo *exception) 1749{ 1750 Display 1751 *display; 1752 1753 MagickStatusType 1754 status; 1755 1756 assert(image_info != (const ImageInfo *) NULL); 1757 assert(image_info->signature == MagickSignature); 1758 assert(filename != (char *) NULL); 1759 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 1760 display=XOpenDisplay(image_info->server_name); 1761 if (display == (Display *) NULL) 1762 { 1763 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1764 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1765 return(MagickFalse); 1766 } 1767 (void) XSetErrorHandler(XError); 1768 status=XRemoteCommand(display,window,filename); 1769 (void) XCloseDisplay(display); 1770 return(IsMagickTrue(status)); 1771} 1772 1773/* 1774%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1775% % 1776% % 1777% % 1778+ X A n n o t a t e E d i t I m a g e % 1779% % 1780% % 1781% % 1782%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1783% 1784% XAnnotateEditImage() annotates the image with text. 1785% 1786% The format of the XAnnotateEditImage method is: 1787% 1788% MagickBooleanType XAnnotateEditImage(Display *display, 1789% XResourceInfo *resource_info,XWindows *windows,Image *image, 1790% ExceptionInfo *exception) 1791% 1792% A description of each parameter follows: 1793% 1794% o display: Specifies a connection to an X server; returned from 1795% XOpenDisplay. 1796% 1797% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 1798% 1799% o windows: Specifies a pointer to a XWindows structure. 1800% 1801% o image: the image; returned from ReadImage. 1802% 1803*/ 1804 1805static MagickBooleanType XAnnotateEditImage(Display *display, 1806 XResourceInfo *resource_info,XWindows *windows,Image *image, 1807 ExceptionInfo *exception) 1808{ 1809 static const char 1810 *AnnotateMenu[] = 1811 { 1812 "Font Name", 1813 "Font Color", 1814 "Box Color", 1815 "Rotate Text", 1816 "Help", 1817 "Dismiss", 1818 (char *) NULL 1819 }, 1820 *TextMenu[] = 1821 { 1822 "Help", 1823 "Apply", 1824 (char *) NULL 1825 }; 1826 1827 static const ModeType 1828 AnnotateCommands[] = 1829 { 1830 AnnotateNameCommand, 1831 AnnotateFontColorCommand, 1832 AnnotateBackgroundColorCommand, 1833 AnnotateRotateCommand, 1834 AnnotateHelpCommand, 1835 AnnotateDismissCommand 1836 }, 1837 TextCommands[] = 1838 { 1839 TextHelpCommand, 1840 TextApplyCommand 1841 }; 1842 1843 static MagickBooleanType 1844 transparent_box = MagickTrue, 1845 transparent_pen = MagickFalse; 1846 1847 static double 1848 degrees = 0.0; 1849 1850 static unsigned int 1851 box_id = MaxNumberPens-2, 1852 font_id = 0, 1853 pen_id = 0; 1854 1855 char 1856 command[MaxTextExtent], 1857 text[MaxTextExtent]; 1858 1859 const char 1860 *ColorMenu[MaxNumberPens+1]; 1861 1862 Cursor 1863 cursor; 1864 1865 GC 1866 annotate_context; 1867 1868 int 1869 id, 1870 pen_number, 1871 status, 1872 x, 1873 y; 1874 1875 KeySym 1876 key_symbol; 1877 1878 register char 1879 *p; 1880 1881 register ssize_t 1882 i; 1883 1884 unsigned int 1885 height, 1886 width; 1887 1888 size_t 1889 state; 1890 1891 XAnnotateInfo 1892 *annotate_info, 1893 *previous_info; 1894 1895 XColor 1896 color; 1897 1898 XFontStruct 1899 *font_info; 1900 1901 XEvent 1902 event, 1903 text_event; 1904 1905 /* 1906 Map Command widget. 1907 */ 1908 (void) CloneString(&windows->command.name,"Annotate"); 1909 windows->command.data=4; 1910 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL); 1911 (void) XMapRaised(display,windows->command.id); 1912 XClientMessage(display,windows->image.id,windows->im_protocols, 1913 windows->im_update_widget,CurrentTime); 1914 /* 1915 Track pointer until button 1 is pressed. 1916 */ 1917 XQueryPosition(display,windows->image.id,&x,&y); 1918 (void) XSelectInput(display,windows->image.id, 1919 windows->image.attributes.event_mask | PointerMotionMask); 1920 cursor=XCreateFontCursor(display,XC_left_side); 1921 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1922 state=DefaultState; 1923 do 1924 { 1925 if (IfMagickTrue(windows->info.mapped) ) 1926 { 1927 /* 1928 Display pointer position. 1929 */ 1930 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 1931 x+windows->image.x,y+windows->image.y); 1932 XInfoWidget(display,windows,text); 1933 } 1934 /* 1935 Wait for next event. 1936 */ 1937 XScreenEvent(display,windows,&event,exception); 1938 if (event.xany.window == windows->command.id) 1939 { 1940 /* 1941 Select a command from the Command widget. 1942 */ 1943 id=XCommandWidget(display,windows,AnnotateMenu,&event); 1944 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1945 if (id < 0) 1946 continue; 1947 switch (AnnotateCommands[id]) 1948 { 1949 case AnnotateNameCommand: 1950 { 1951 const char 1952 *FontMenu[MaxNumberFonts]; 1953 1954 int 1955 font_number; 1956 1957 /* 1958 Initialize menu selections. 1959 */ 1960 for (i=0; i < MaxNumberFonts; i++) 1961 FontMenu[i]=resource_info->font_name[i]; 1962 FontMenu[MaxNumberFonts-2]="Browser..."; 1963 FontMenu[MaxNumberFonts-1]=(const char *) NULL; 1964 /* 1965 Select a font name from the pop-up menu. 1966 */ 1967 font_number=XMenuWidget(display,windows,AnnotateMenu[id], 1968 (const char **) FontMenu,command); 1969 if (font_number < 0) 1970 break; 1971 if (font_number == (MaxNumberFonts-2)) 1972 { 1973 static char 1974 font_name[MaxTextExtent] = "fixed"; 1975 1976 /* 1977 Select a font name from a browser. 1978 */ 1979 resource_info->font_name[font_number]=font_name; 1980 XFontBrowserWidget(display,windows,"Select",font_name); 1981 if (*font_name == '\0') 1982 break; 1983 } 1984 /* 1985 Initialize font info. 1986 */ 1987 font_info=XLoadQueryFont(display,resource_info->font_name[ 1988 font_number]); 1989 if (font_info == (XFontStruct *) NULL) 1990 { 1991 XNoticeWidget(display,windows,"Unable to load font:", 1992 resource_info->font_name[font_number]); 1993 break; 1994 } 1995 font_id=(unsigned int) font_number; 1996 (void) XFreeFont(display,font_info); 1997 break; 1998 } 1999 case AnnotateFontColorCommand: 2000 { 2001 /* 2002 Initialize menu selections. 2003 */ 2004 for (i=0; i < (int) (MaxNumberPens-2); i++) 2005 ColorMenu[i]=resource_info->pen_colors[i]; 2006 ColorMenu[MaxNumberPens-2]="transparent"; 2007 ColorMenu[MaxNumberPens-1]="Browser..."; 2008 ColorMenu[MaxNumberPens]=(const char *) NULL; 2009 /* 2010 Select a pen color from the pop-up menu. 2011 */ 2012 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2013 (const char **) ColorMenu,command); 2014 if (pen_number < 0) 2015 break; 2016 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue : 2017 MagickFalse; 2018 if (IfMagickTrue(transparent_pen) ) 2019 break; 2020 if (pen_number == (MaxNumberPens-1)) 2021 { 2022 static char 2023 color_name[MaxTextExtent] = "gray"; 2024 2025 /* 2026 Select a pen color from a dialog. 2027 */ 2028 resource_info->pen_colors[pen_number]=color_name; 2029 XColorBrowserWidget(display,windows,"Select",color_name); 2030 if (*color_name == '\0') 2031 break; 2032 } 2033 /* 2034 Set pen color. 2035 */ 2036 (void) XParseColor(display,windows->map_info->colormap, 2037 resource_info->pen_colors[pen_number],&color); 2038 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2039 (unsigned int) MaxColors,&color); 2040 windows->pixel_info->pen_colors[pen_number]=color; 2041 pen_id=(unsigned int) pen_number; 2042 break; 2043 } 2044 case AnnotateBackgroundColorCommand: 2045 { 2046 /* 2047 Initialize menu selections. 2048 */ 2049 for (i=0; i < (int) (MaxNumberPens-2); i++) 2050 ColorMenu[i]=resource_info->pen_colors[i]; 2051 ColorMenu[MaxNumberPens-2]="transparent"; 2052 ColorMenu[MaxNumberPens-1]="Browser..."; 2053 ColorMenu[MaxNumberPens]=(const char *) NULL; 2054 /* 2055 Select a pen color from the pop-up menu. 2056 */ 2057 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2058 (const char **) ColorMenu,command); 2059 if (pen_number < 0) 2060 break; 2061 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue : 2062 MagickFalse; 2063 if (IfMagickTrue(transparent_box) ) 2064 break; 2065 if (pen_number == (MaxNumberPens-1)) 2066 { 2067 static char 2068 color_name[MaxTextExtent] = "gray"; 2069 2070 /* 2071 Select a pen color from a dialog. 2072 */ 2073 resource_info->pen_colors[pen_number]=color_name; 2074 XColorBrowserWidget(display,windows,"Select",color_name); 2075 if (*color_name == '\0') 2076 break; 2077 } 2078 /* 2079 Set pen color. 2080 */ 2081 (void) XParseColor(display,windows->map_info->colormap, 2082 resource_info->pen_colors[pen_number],&color); 2083 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2084 (unsigned int) MaxColors,&color); 2085 windows->pixel_info->pen_colors[pen_number]=color; 2086 box_id=(unsigned int) pen_number; 2087 break; 2088 } 2089 case AnnotateRotateCommand: 2090 { 2091 int 2092 entry; 2093 2094 static char 2095 angle[MaxTextExtent] = "30.0"; 2096 2097 static const char 2098 *RotateMenu[] = 2099 { 2100 "-90", 2101 "-45", 2102 "-30", 2103 "0", 2104 "30", 2105 "45", 2106 "90", 2107 "180", 2108 "Dialog...", 2109 (char *) NULL, 2110 }; 2111 2112 /* 2113 Select a command from the pop-up menu. 2114 */ 2115 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu, 2116 command); 2117 if (entry < 0) 2118 break; 2119 if (entry != 8) 2120 { 2121 degrees=StringToDouble(RotateMenu[entry],(char **) NULL); 2122 break; 2123 } 2124 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:", 2125 angle); 2126 if (*angle == '\0') 2127 break; 2128 degrees=StringToDouble(angle,(char **) NULL); 2129 break; 2130 } 2131 case AnnotateHelpCommand: 2132 { 2133 XTextViewWidget(display,resource_info,windows,MagickFalse, 2134 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2135 break; 2136 } 2137 case AnnotateDismissCommand: 2138 { 2139 /* 2140 Prematurely exit. 2141 */ 2142 state|=EscapeState; 2143 state|=ExitState; 2144 break; 2145 } 2146 default: 2147 break; 2148 } 2149 continue; 2150 } 2151 switch (event.type) 2152 { 2153 case ButtonPress: 2154 { 2155 if (event.xbutton.button != Button1) 2156 break; 2157 if (event.xbutton.window != windows->image.id) 2158 break; 2159 /* 2160 Change to text entering mode. 2161 */ 2162 x=event.xbutton.x; 2163 y=event.xbutton.y; 2164 state|=ExitState; 2165 break; 2166 } 2167 case ButtonRelease: 2168 break; 2169 case Expose: 2170 break; 2171 case KeyPress: 2172 { 2173 if (event.xkey.window != windows->image.id) 2174 break; 2175 /* 2176 Respond to a user key press. 2177 */ 2178 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2179 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2180 switch ((int) key_symbol) 2181 { 2182 case XK_Escape: 2183 case XK_F20: 2184 { 2185 /* 2186 Prematurely exit. 2187 */ 2188 state|=EscapeState; 2189 state|=ExitState; 2190 break; 2191 } 2192 case XK_F1: 2193 case XK_Help: 2194 { 2195 XTextViewWidget(display,resource_info,windows,MagickFalse, 2196 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2197 break; 2198 } 2199 default: 2200 { 2201 (void) XBell(display,0); 2202 break; 2203 } 2204 } 2205 break; 2206 } 2207 case MotionNotify: 2208 { 2209 /* 2210 Map and unmap Info widget as cursor crosses its boundaries. 2211 */ 2212 x=event.xmotion.x; 2213 y=event.xmotion.y; 2214 if (IfMagickTrue(windows->info.mapped) ) 2215 { 2216 if ((x < (int) (windows->info.x+windows->info.width)) && 2217 (y < (int) (windows->info.y+windows->info.height))) 2218 (void) XWithdrawWindow(display,windows->info.id, 2219 windows->info.screen); 2220 } 2221 else 2222 if ((x > (int) (windows->info.x+windows->info.width)) || 2223 (y > (int) (windows->info.y+windows->info.height))) 2224 (void) XMapWindow(display,windows->info.id); 2225 break; 2226 } 2227 default: 2228 break; 2229 } 2230 } while ((state & ExitState) == 0); 2231 (void) XSelectInput(display,windows->image.id, 2232 windows->image.attributes.event_mask); 2233 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 2234 if ((state & EscapeState) != 0) 2235 return(MagickTrue); 2236 /* 2237 Set font info and check boundary conditions. 2238 */ 2239 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]); 2240 if (font_info == (XFontStruct *) NULL) 2241 { 2242 XNoticeWidget(display,windows,"Unable to load font:", 2243 resource_info->font_name[font_id]); 2244 font_info=windows->font_info; 2245 } 2246 if ((x+font_info->max_bounds.width) >= (int) windows->image.width) 2247 x=(int) windows->image.width-font_info->max_bounds.width; 2248 if (y < (int) (font_info->ascent+font_info->descent)) 2249 y=(int) font_info->ascent+font_info->descent; 2250 if (((int) font_info->max_bounds.width > (int) windows->image.width) || 2251 ((font_info->ascent+font_info->descent) >= (int) windows->image.height)) 2252 return(MagickFalse); 2253 /* 2254 Initialize annotate structure. 2255 */ 2256 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info)); 2257 if (annotate_info == (XAnnotateInfo *) NULL) 2258 return(MagickFalse); 2259 XGetAnnotateInfo(annotate_info); 2260 annotate_info->x=x; 2261 annotate_info->y=y; 2262 if (IfMagickFalse(transparent_box) && IfMagickFalse(transparent_pen)) 2263 annotate_info->stencil=OpaqueStencil; 2264 else 2265 if (IfMagickFalse(transparent_box) ) 2266 annotate_info->stencil=BackgroundStencil; 2267 else 2268 annotate_info->stencil=ForegroundStencil; 2269 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent; 2270 annotate_info->degrees=degrees; 2271 annotate_info->font_info=font_info; 2272 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2273 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL, 2274 sizeof(*annotate_info->text)); 2275 if (annotate_info->text == (char *) NULL) 2276 return(MagickFalse); 2277 /* 2278 Create cursor and set graphic context. 2279 */ 2280 cursor=XCreateFontCursor(display,XC_pencil); 2281 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2282 annotate_context=windows->image.annotate_context; 2283 (void) XSetFont(display,annotate_context,font_info->fid); 2284 (void) XSetBackground(display,annotate_context, 2285 windows->pixel_info->pen_colors[box_id].pixel); 2286 (void) XSetForeground(display,annotate_context, 2287 windows->pixel_info->pen_colors[pen_id].pixel); 2288 /* 2289 Begin annotating the image with text. 2290 */ 2291 (void) CloneString(&windows->command.name,"Text"); 2292 windows->command.data=0; 2293 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL); 2294 state=DefaultState; 2295 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2296 text_event.xexpose.width=(int) font_info->max_bounds.width; 2297 text_event.xexpose.height=font_info->max_bounds.ascent+ 2298 font_info->max_bounds.descent; 2299 p=annotate_info->text; 2300 do 2301 { 2302 /* 2303 Display text cursor. 2304 */ 2305 *p='\0'; 2306 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2307 /* 2308 Wait for next event. 2309 */ 2310 XScreenEvent(display,windows,&event,exception); 2311 if (event.xany.window == windows->command.id) 2312 { 2313 /* 2314 Select a command from the Command widget. 2315 */ 2316 (void) XSetBackground(display,annotate_context, 2317 windows->pixel_info->background_color.pixel); 2318 (void) XSetForeground(display,annotate_context, 2319 windows->pixel_info->foreground_color.pixel); 2320 id=XCommandWidget(display,windows,AnnotateMenu,&event); 2321 (void) XSetBackground(display,annotate_context, 2322 windows->pixel_info->pen_colors[box_id].pixel); 2323 (void) XSetForeground(display,annotate_context, 2324 windows->pixel_info->pen_colors[pen_id].pixel); 2325 if (id < 0) 2326 continue; 2327 switch (TextCommands[id]) 2328 { 2329 case TextHelpCommand: 2330 { 2331 XTextViewWidget(display,resource_info,windows,MagickFalse, 2332 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2333 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2334 break; 2335 } 2336 case TextApplyCommand: 2337 { 2338 /* 2339 Finished annotating. 2340 */ 2341 annotate_info->width=(unsigned int) XTextWidth(font_info, 2342 annotate_info->text,(int) strlen(annotate_info->text)); 2343 XRefreshWindow(display,&windows->image,&text_event); 2344 state|=ExitState; 2345 break; 2346 } 2347 default: 2348 break; 2349 } 2350 continue; 2351 } 2352 /* 2353 Erase text cursor. 2354 */ 2355 text_event.xexpose.x=x; 2356 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2357 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y, 2358 (unsigned int) text_event.xexpose.width,(unsigned int) 2359 text_event.xexpose.height,MagickFalse); 2360 XRefreshWindow(display,&windows->image,&text_event); 2361 switch (event.type) 2362 { 2363 case ButtonPress: 2364 { 2365 if (event.xbutton.window != windows->image.id) 2366 break; 2367 if (event.xbutton.button == Button2) 2368 { 2369 /* 2370 Request primary selection. 2371 */ 2372 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, 2373 windows->image.id,CurrentTime); 2374 break; 2375 } 2376 break; 2377 } 2378 case Expose: 2379 { 2380 if (event.xexpose.count == 0) 2381 { 2382 XAnnotateInfo 2383 *text_info; 2384 2385 /* 2386 Refresh Image window. 2387 */ 2388 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 2389 text_info=annotate_info; 2390 while (text_info != (XAnnotateInfo *) NULL) 2391 { 2392 if (annotate_info->stencil == ForegroundStencil) 2393 (void) XDrawString(display,windows->image.id,annotate_context, 2394 text_info->x,text_info->y,text_info->text, 2395 (int) strlen(text_info->text)); 2396 else 2397 (void) XDrawImageString(display,windows->image.id, 2398 annotate_context,text_info->x,text_info->y,text_info->text, 2399 (int) strlen(text_info->text)); 2400 text_info=text_info->previous; 2401 } 2402 (void) XDrawString(display,windows->image.id,annotate_context, 2403 x,y,"_",1); 2404 } 2405 break; 2406 } 2407 case KeyPress: 2408 { 2409 int 2410 length; 2411 2412 if (event.xkey.window != windows->image.id) 2413 break; 2414 /* 2415 Respond to a user key press. 2416 */ 2417 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 2418 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2419 *(command+length)='\0'; 2420 if (((event.xkey.state & ControlMask) != 0) || 2421 ((event.xkey.state & Mod1Mask) != 0)) 2422 state|=ModifierState; 2423 if ((state & ModifierState) != 0) 2424 switch ((int) key_symbol) 2425 { 2426 case XK_u: 2427 case XK_U: 2428 { 2429 key_symbol=DeleteCommand; 2430 break; 2431 } 2432 default: 2433 break; 2434 } 2435 switch ((int) key_symbol) 2436 { 2437 case XK_BackSpace: 2438 { 2439 /* 2440 Erase one character. 2441 */ 2442 if (p == annotate_info->text) 2443 { 2444 if (annotate_info->previous == (XAnnotateInfo *) NULL) 2445 break; 2446 else 2447 { 2448 /* 2449 Go to end of the previous line of text. 2450 */ 2451 annotate_info=annotate_info->previous; 2452 p=annotate_info->text; 2453 x=annotate_info->x+annotate_info->width; 2454 y=annotate_info->y; 2455 if (annotate_info->width != 0) 2456 p+=strlen(annotate_info->text); 2457 break; 2458 } 2459 } 2460 p--; 2461 x-=XTextWidth(font_info,p,1); 2462 text_event.xexpose.x=x; 2463 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2464 XRefreshWindow(display,&windows->image,&text_event); 2465 break; 2466 } 2467 case XK_bracketleft: 2468 { 2469 key_symbol=XK_Escape; 2470 break; 2471 } 2472 case DeleteCommand: 2473 { 2474 /* 2475 Erase the entire line of text. 2476 */ 2477 while (p != annotate_info->text) 2478 { 2479 p--; 2480 x-=XTextWidth(font_info,p,1); 2481 text_event.xexpose.x=x; 2482 XRefreshWindow(display,&windows->image,&text_event); 2483 } 2484 break; 2485 } 2486 case XK_Escape: 2487 case XK_F20: 2488 { 2489 /* 2490 Finished annotating. 2491 */ 2492 annotate_info->width=(unsigned int) XTextWidth(font_info, 2493 annotate_info->text,(int) strlen(annotate_info->text)); 2494 XRefreshWindow(display,&windows->image,&text_event); 2495 state|=ExitState; 2496 break; 2497 } 2498 default: 2499 { 2500 /* 2501 Draw a single character on the Image window. 2502 */ 2503 if ((state & ModifierState) != 0) 2504 break; 2505 if (*command == '\0') 2506 break; 2507 *p=(*command); 2508 if (annotate_info->stencil == ForegroundStencil) 2509 (void) XDrawString(display,windows->image.id,annotate_context, 2510 x,y,p,1); 2511 else 2512 (void) XDrawImageString(display,windows->image.id, 2513 annotate_context,x,y,p,1); 2514 x+=XTextWidth(font_info,p,1); 2515 p++; 2516 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2517 break; 2518 } 2519 case XK_Return: 2520 case XK_KP_Enter: 2521 { 2522 /* 2523 Advance to the next line of text. 2524 */ 2525 *p='\0'; 2526 annotate_info->width=(unsigned int) XTextWidth(font_info, 2527 annotate_info->text,(int) strlen(annotate_info->text)); 2528 if (annotate_info->next != (XAnnotateInfo *) NULL) 2529 { 2530 /* 2531 Line of text already exists. 2532 */ 2533 annotate_info=annotate_info->next; 2534 x=annotate_info->x; 2535 y=annotate_info->y; 2536 p=annotate_info->text; 2537 break; 2538 } 2539 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2540 sizeof(*annotate_info->next)); 2541 if (annotate_info->next == (XAnnotateInfo *) NULL) 2542 return(MagickFalse); 2543 *annotate_info->next=(*annotate_info); 2544 annotate_info->next->previous=annotate_info; 2545 annotate_info=annotate_info->next; 2546 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2547 windows->image.width/MagickMax((ssize_t) 2548 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2549 if (annotate_info->text == (char *) NULL) 2550 return(MagickFalse); 2551 annotate_info->y+=annotate_info->height; 2552 if (annotate_info->y > (int) windows->image.height) 2553 annotate_info->y=(int) annotate_info->height; 2554 annotate_info->next=(XAnnotateInfo *) NULL; 2555 x=annotate_info->x; 2556 y=annotate_info->y; 2557 p=annotate_info->text; 2558 break; 2559 } 2560 } 2561 break; 2562 } 2563 case KeyRelease: 2564 { 2565 /* 2566 Respond to a user key release. 2567 */ 2568 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2569 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2570 state&=(~ModifierState); 2571 break; 2572 } 2573 case SelectionNotify: 2574 { 2575 Atom 2576 type; 2577 2578 int 2579 format; 2580 2581 unsigned char 2582 *data; 2583 2584 unsigned long 2585 after, 2586 length; 2587 2588 /* 2589 Obtain response from primary selection. 2590 */ 2591 if (event.xselection.property == (Atom) None) 2592 break; 2593 status=XGetWindowProperty(display,event.xselection.requestor, 2594 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING, 2595 &type,&format,&length,&after,&data); 2596 if ((status != Success) || (type != XA_STRING) || (format == 32) || 2597 (length == 0)) 2598 break; 2599 /* 2600 Annotate Image window with primary selection. 2601 */ 2602 for (i=0; i < (ssize_t) length; i++) 2603 { 2604 if ((char) data[i] != '\n') 2605 { 2606 /* 2607 Draw a single character on the Image window. 2608 */ 2609 *p=(char) data[i]; 2610 (void) XDrawString(display,windows->image.id,annotate_context, 2611 x,y,p,1); 2612 x+=XTextWidth(font_info,p,1); 2613 p++; 2614 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2615 continue; 2616 } 2617 /* 2618 Advance to the next line of text. 2619 */ 2620 *p='\0'; 2621 annotate_info->width=(unsigned int) XTextWidth(font_info, 2622 annotate_info->text,(int) strlen(annotate_info->text)); 2623 if (annotate_info->next != (XAnnotateInfo *) NULL) 2624 { 2625 /* 2626 Line of text already exists. 2627 */ 2628 annotate_info=annotate_info->next; 2629 x=annotate_info->x; 2630 y=annotate_info->y; 2631 p=annotate_info->text; 2632 continue; 2633 } 2634 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2635 sizeof(*annotate_info->next)); 2636 if (annotate_info->next == (XAnnotateInfo *) NULL) 2637 return(MagickFalse); 2638 *annotate_info->next=(*annotate_info); 2639 annotate_info->next->previous=annotate_info; 2640 annotate_info=annotate_info->next; 2641 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2642 windows->image.width/MagickMax((ssize_t) 2643 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2644 if (annotate_info->text == (char *) NULL) 2645 return(MagickFalse); 2646 annotate_info->y+=annotate_info->height; 2647 if (annotate_info->y > (int) windows->image.height) 2648 annotate_info->y=(int) annotate_info->height; 2649 annotate_info->next=(XAnnotateInfo *) NULL; 2650 x=annotate_info->x; 2651 y=annotate_info->y; 2652 p=annotate_info->text; 2653 } 2654 (void) XFree((void *) data); 2655 break; 2656 } 2657 default: 2658 break; 2659 } 2660 } while ((state & ExitState) == 0); 2661 (void) XFreeCursor(display,cursor); 2662 /* 2663 Annotation is relative to image configuration. 2664 */ 2665 width=(unsigned int) image->columns; 2666 height=(unsigned int) image->rows; 2667 x=0; 2668 y=0; 2669 if (windows->image.crop_geometry != (char *) NULL) 2670 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 2671 /* 2672 Initialize annotated image. 2673 */ 2674 XSetCursorState(display,windows,MagickTrue); 2675 XCheckRefreshWindows(display,windows); 2676 while (annotate_info != (XAnnotateInfo *) NULL) 2677 { 2678 if (annotate_info->width == 0) 2679 { 2680 /* 2681 No text on this line-- go to the next line of text. 2682 */ 2683 previous_info=annotate_info->previous; 2684 annotate_info->text=(char *) 2685 RelinquishMagickMemory(annotate_info->text); 2686 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2687 annotate_info=previous_info; 2688 continue; 2689 } 2690 /* 2691 Determine pixel index for box and pen color. 2692 */ 2693 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id]; 2694 if (windows->pixel_info->colors != 0) 2695 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2696 if (windows->pixel_info->pixels[i] == 2697 windows->pixel_info->pen_colors[box_id].pixel) 2698 { 2699 windows->pixel_info->box_index=(unsigned short) i; 2700 break; 2701 } 2702 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 2703 if (windows->pixel_info->colors != 0) 2704 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2705 if (windows->pixel_info->pixels[i] == 2706 windows->pixel_info->pen_colors[pen_id].pixel) 2707 { 2708 windows->pixel_info->pen_index=(unsigned short) i; 2709 break; 2710 } 2711 /* 2712 Define the annotate geometry string. 2713 */ 2714 annotate_info->x=(int) 2715 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width; 2716 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+ 2717 windows->image.y)/windows->image.ximage->height; 2718 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent, 2719 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width, 2720 height*annotate_info->height/windows->image.ximage->height, 2721 annotate_info->x+x,annotate_info->y+y); 2722 /* 2723 Annotate image with text. 2724 */ 2725 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image, 2726 exception); 2727 if (status == 0) 2728 return(MagickFalse); 2729 /* 2730 Free up memory. 2731 */ 2732 previous_info=annotate_info->previous; 2733 annotate_info->text=DestroyString(annotate_info->text); 2734 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2735 annotate_info=previous_info; 2736 } 2737 (void) XSetForeground(display,annotate_context, 2738 windows->pixel_info->foreground_color.pixel); 2739 (void) XSetBackground(display,annotate_context, 2740 windows->pixel_info->background_color.pixel); 2741 (void) XSetFont(display,annotate_context,windows->font_info->fid); 2742 XSetCursorState(display,windows,MagickFalse); 2743 (void) XFreeFont(display,font_info); 2744 /* 2745 Update image configuration. 2746 */ 2747 XConfigureImageColormap(display,resource_info,windows,image,exception); 2748 (void) XConfigureImage(display,resource_info,windows,image,exception); 2749 return(MagickTrue); 2750} 2751 2752/* 2753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2754% % 2755% % 2756% % 2757+ X B a c k g r o u n d I m a g e % 2758% % 2759% % 2760% % 2761%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2762% 2763% XBackgroundImage() displays the image in the background of a window. 2764% 2765% The format of the XBackgroundImage method is: 2766% 2767% MagickBooleanType XBackgroundImage(Display *display, 2768% XResourceInfo *resource_info,XWindows *windows,Image **image, 2769% ExceptionInfo *exception) 2770% 2771% A description of each parameter follows: 2772% 2773% o display: Specifies a connection to an X server; returned from 2774% XOpenDisplay. 2775% 2776% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2777% 2778% o windows: Specifies a pointer to a XWindows structure. 2779% 2780% o image: the image. 2781% 2782% o exception: return any errors or warnings in this structure. 2783% 2784*/ 2785static MagickBooleanType XBackgroundImage(Display *display, 2786 XResourceInfo *resource_info,XWindows *windows,Image **image, 2787 ExceptionInfo *exception) 2788{ 2789#define BackgroundImageTag "Background/Image" 2790 2791 int 2792 status; 2793 2794 static char 2795 window_id[MaxTextExtent] = "root"; 2796 2797 XResourceInfo 2798 background_resources; 2799 2800 /* 2801 Put image in background. 2802 */ 2803 status=XDialogWidget(display,windows,"Background", 2804 "Enter window id (id 0x00 selects window with pointer):",window_id); 2805 if (*window_id == '\0') 2806 return(MagickFalse); 2807 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 2808 exception); 2809 XInfoWidget(display,windows,BackgroundImageTag); 2810 XSetCursorState(display,windows,MagickTrue); 2811 XCheckRefreshWindows(display,windows); 2812 background_resources=(*resource_info); 2813 background_resources.window_id=window_id; 2814 background_resources.backdrop=IsMagickTrue(status); 2815 status=XDisplayBackgroundImage(display,&background_resources,*image, 2816 exception); 2817 if (IfMagickTrue(status)) 2818 XClientMessage(display,windows->image.id,windows->im_protocols, 2819 windows->im_retain_colors,CurrentTime); 2820 XSetCursorState(display,windows,MagickFalse); 2821 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image, 2822 exception); 2823 return(MagickTrue); 2824} 2825 2826/* 2827%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2828% % 2829% % 2830% % 2831+ X C h o p I m a g e % 2832% % 2833% % 2834% % 2835%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2836% 2837% XChopImage() chops the X image. 2838% 2839% The format of the XChopImage method is: 2840% 2841% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info, 2842% XWindows *windows,Image **image,ExceptionInfo *exception) 2843% 2844% A description of each parameter follows: 2845% 2846% o display: Specifies a connection to an X server; returned from 2847% XOpenDisplay. 2848% 2849% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2850% 2851% o windows: Specifies a pointer to a XWindows structure. 2852% 2853% o image: the image. 2854% 2855% o exception: return any errors or warnings in this structure. 2856% 2857*/ 2858static MagickBooleanType XChopImage(Display *display, 2859 XResourceInfo *resource_info,XWindows *windows,Image **image, 2860 ExceptionInfo *exception) 2861{ 2862 static const char 2863 *ChopMenu[] = 2864 { 2865 "Direction", 2866 "Help", 2867 "Dismiss", 2868 (char *) NULL 2869 }; 2870 2871 static ModeType 2872 direction = HorizontalChopCommand; 2873 2874 static const ModeType 2875 ChopCommands[] = 2876 { 2877 ChopDirectionCommand, 2878 ChopHelpCommand, 2879 ChopDismissCommand 2880 }, 2881 DirectionCommands[] = 2882 { 2883 HorizontalChopCommand, 2884 VerticalChopCommand 2885 }; 2886 2887 char 2888 text[MaxTextExtent]; 2889 2890 Image 2891 *chop_image; 2892 2893 int 2894 id, 2895 x, 2896 y; 2897 2898 double 2899 scale_factor; 2900 2901 RectangleInfo 2902 chop_info; 2903 2904 unsigned int 2905 distance, 2906 height, 2907 width; 2908 2909 size_t 2910 state; 2911 2912 XEvent 2913 event; 2914 2915 XSegment 2916 segment_info; 2917 2918 /* 2919 Map Command widget. 2920 */ 2921 (void) CloneString(&windows->command.name,"Chop"); 2922 windows->command.data=1; 2923 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL); 2924 (void) XMapRaised(display,windows->command.id); 2925 XClientMessage(display,windows->image.id,windows->im_protocols, 2926 windows->im_update_widget,CurrentTime); 2927 /* 2928 Track pointer until button 1 is pressed. 2929 */ 2930 XQueryPosition(display,windows->image.id,&x,&y); 2931 (void) XSelectInput(display,windows->image.id, 2932 windows->image.attributes.event_mask | PointerMotionMask); 2933 state=DefaultState; 2934 do 2935 { 2936 if (IfMagickTrue(windows->info.mapped) ) 2937 { 2938 /* 2939 Display pointer position. 2940 */ 2941 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 2942 x+windows->image.x,y+windows->image.y); 2943 XInfoWidget(display,windows,text); 2944 } 2945 /* 2946 Wait for next event. 2947 */ 2948 XScreenEvent(display,windows,&event,exception); 2949 if (event.xany.window == windows->command.id) 2950 { 2951 /* 2952 Select a command from the Command widget. 2953 */ 2954 id=XCommandWidget(display,windows,ChopMenu,&event); 2955 if (id < 0) 2956 continue; 2957 switch (ChopCommands[id]) 2958 { 2959 case ChopDirectionCommand: 2960 { 2961 char 2962 command[MaxTextExtent]; 2963 2964 static const char 2965 *Directions[] = 2966 { 2967 "horizontal", 2968 "vertical", 2969 (char *) NULL, 2970 }; 2971 2972 /* 2973 Select a command from the pop-up menu. 2974 */ 2975 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 2976 if (id >= 0) 2977 direction=DirectionCommands[id]; 2978 break; 2979 } 2980 case ChopHelpCommand: 2981 { 2982 XTextViewWidget(display,resource_info,windows,MagickFalse, 2983 "Help Viewer - Image Chop",ImageChopHelp); 2984 break; 2985 } 2986 case ChopDismissCommand: 2987 { 2988 /* 2989 Prematurely exit. 2990 */ 2991 state|=EscapeState; 2992 state|=ExitState; 2993 break; 2994 } 2995 default: 2996 break; 2997 } 2998 continue; 2999 } 3000 switch (event.type) 3001 { 3002 case ButtonPress: 3003 { 3004 if (event.xbutton.button != Button1) 3005 break; 3006 if (event.xbutton.window != windows->image.id) 3007 break; 3008 /* 3009 User has committed to start point of chopping line. 3010 */ 3011 segment_info.x1=(short int) event.xbutton.x; 3012 segment_info.x2=(short int) event.xbutton.x; 3013 segment_info.y1=(short int) event.xbutton.y; 3014 segment_info.y2=(short int) event.xbutton.y; 3015 state|=ExitState; 3016 break; 3017 } 3018 case ButtonRelease: 3019 break; 3020 case Expose: 3021 break; 3022 case KeyPress: 3023 { 3024 char 3025 command[MaxTextExtent]; 3026 3027 KeySym 3028 key_symbol; 3029 3030 if (event.xkey.window != windows->image.id) 3031 break; 3032 /* 3033 Respond to a user key press. 3034 */ 3035 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3036 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3037 switch ((int) key_symbol) 3038 { 3039 case XK_Escape: 3040 case XK_F20: 3041 { 3042 /* 3043 Prematurely exit. 3044 */ 3045 state|=EscapeState; 3046 state|=ExitState; 3047 break; 3048 } 3049 case XK_F1: 3050 case XK_Help: 3051 { 3052 (void) XSetFunction(display,windows->image.highlight_context, 3053 GXcopy); 3054 XTextViewWidget(display,resource_info,windows,MagickFalse, 3055 "Help Viewer - Image Chop",ImageChopHelp); 3056 (void) XSetFunction(display,windows->image.highlight_context, 3057 GXinvert); 3058 break; 3059 } 3060 default: 3061 { 3062 (void) XBell(display,0); 3063 break; 3064 } 3065 } 3066 break; 3067 } 3068 case MotionNotify: 3069 { 3070 /* 3071 Map and unmap Info widget as text cursor crosses its boundaries. 3072 */ 3073 x=event.xmotion.x; 3074 y=event.xmotion.y; 3075 if (IfMagickTrue(windows->info.mapped) ) 3076 { 3077 if ((x < (int) (windows->info.x+windows->info.width)) && 3078 (y < (int) (windows->info.y+windows->info.height))) 3079 (void) XWithdrawWindow(display,windows->info.id, 3080 windows->info.screen); 3081 } 3082 else 3083 if ((x > (int) (windows->info.x+windows->info.width)) || 3084 (y > (int) (windows->info.y+windows->info.height))) 3085 (void) XMapWindow(display,windows->info.id); 3086 } 3087 } 3088 } while ((state & ExitState) == 0); 3089 (void) XSelectInput(display,windows->image.id, 3090 windows->image.attributes.event_mask); 3091 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3092 if ((state & EscapeState) != 0) 3093 return(MagickTrue); 3094 /* 3095 Draw line as pointer moves until the mouse button is released. 3096 */ 3097 chop_info.width=0; 3098 chop_info.height=0; 3099 chop_info.x=0; 3100 chop_info.y=0; 3101 distance=0; 3102 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3103 state=DefaultState; 3104 do 3105 { 3106 if (distance > 9) 3107 { 3108 /* 3109 Display info and draw chopping line. 3110 */ 3111 if (IfMagickFalse(windows->info.mapped) ) 3112 (void) XMapWindow(display,windows->info.id); 3113 (void) FormatLocaleString(text,MaxTextExtent, 3114 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 3115 chop_info.height,(double) chop_info.x,(double) chop_info.y); 3116 XInfoWidget(display,windows,text); 3117 XHighlightLine(display,windows->image.id, 3118 windows->image.highlight_context,&segment_info); 3119 } 3120 else 3121 if (IfMagickTrue(windows->info.mapped) ) 3122 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3123 /* 3124 Wait for next event. 3125 */ 3126 XScreenEvent(display,windows,&event,exception); 3127 if (distance > 9) 3128 XHighlightLine(display,windows->image.id, 3129 windows->image.highlight_context,&segment_info); 3130 switch (event.type) 3131 { 3132 case ButtonPress: 3133 { 3134 segment_info.x2=(short int) event.xmotion.x; 3135 segment_info.y2=(short int) event.xmotion.y; 3136 break; 3137 } 3138 case ButtonRelease: 3139 { 3140 /* 3141 User has committed to chopping line. 3142 */ 3143 segment_info.x2=(short int) event.xbutton.x; 3144 segment_info.y2=(short int) event.xbutton.y; 3145 state|=ExitState; 3146 break; 3147 } 3148 case Expose: 3149 break; 3150 case MotionNotify: 3151 { 3152 segment_info.x2=(short int) event.xmotion.x; 3153 segment_info.y2=(short int) event.xmotion.y; 3154 } 3155 default: 3156 break; 3157 } 3158 /* 3159 Check boundary conditions. 3160 */ 3161 if (segment_info.x2 < 0) 3162 segment_info.x2=0; 3163 else 3164 if (segment_info.x2 > windows->image.ximage->width) 3165 segment_info.x2=windows->image.ximage->width; 3166 if (segment_info.y2 < 0) 3167 segment_info.y2=0; 3168 else 3169 if (segment_info.y2 > windows->image.ximage->height) 3170 segment_info.y2=windows->image.ximage->height; 3171 distance=(unsigned int) 3172 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 3173 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 3174 /* 3175 Compute chopping geometry. 3176 */ 3177 if (direction == HorizontalChopCommand) 3178 { 3179 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 3180 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 3181 chop_info.height=0; 3182 chop_info.y=0; 3183 if (segment_info.x1 > (int) segment_info.x2) 3184 { 3185 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 3186 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 3187 } 3188 } 3189 else 3190 { 3191 chop_info.width=0; 3192 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 3193 chop_info.x=0; 3194 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 3195 if (segment_info.y1 > segment_info.y2) 3196 { 3197 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 3198 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 3199 } 3200 } 3201 } while ((state & ExitState) == 0); 3202 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 3203 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3204 if (distance <= 9) 3205 return(MagickTrue); 3206 /* 3207 Image chopping is relative to image configuration. 3208 */ 3209 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 3210 exception); 3211 XSetCursorState(display,windows,MagickTrue); 3212 XCheckRefreshWindows(display,windows); 3213 windows->image.window_changes.width=windows->image.ximage->width- 3214 (unsigned int) chop_info.width; 3215 windows->image.window_changes.height=windows->image.ximage->height- 3216 (unsigned int) chop_info.height; 3217 width=(unsigned int) (*image)->columns; 3218 height=(unsigned int) (*image)->rows; 3219 x=0; 3220 y=0; 3221 if (windows->image.crop_geometry != (char *) NULL) 3222 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 3223 scale_factor=(double) width/windows->image.ximage->width; 3224 chop_info.x+=x; 3225 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 3226 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 3227 scale_factor=(double) height/windows->image.ximage->height; 3228 chop_info.y+=y; 3229 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 3230 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 3231 /* 3232 Chop image. 3233 */ 3234 chop_image=ChopImage(*image,&chop_info,exception); 3235 XSetCursorState(display,windows,MagickFalse); 3236 if (chop_image == (Image *) NULL) 3237 return(MagickFalse); 3238 *image=DestroyImage(*image); 3239 *image=chop_image; 3240 /* 3241 Update image configuration. 3242 */ 3243 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3244 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3245 return(MagickTrue); 3246} 3247 3248/* 3249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3250% % 3251% % 3252% % 3253+ X C o l o r E d i t I m a g e % 3254% % 3255% % 3256% % 3257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3258% 3259% XColorEditImage() allows the user to interactively change the color of one 3260% pixel for a DirectColor image or one colormap entry for a PseudoClass image. 3261% 3262% The format of the XColorEditImage method is: 3263% 3264% MagickBooleanType XColorEditImage(Display *display, 3265% XResourceInfo *resource_info,XWindows *windows,Image **image, 3266% ExceptionInfo *exception) 3267% 3268% A description of each parameter follows: 3269% 3270% o display: Specifies a connection to an X server; returned from 3271% XOpenDisplay. 3272% 3273% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3274% 3275% o windows: Specifies a pointer to a XWindows structure. 3276% 3277% o image: the image; returned from ReadImage. 3278% 3279% o exception: return any errors or warnings in this structure. 3280% 3281*/ 3282static MagickBooleanType XColorEditImage(Display *display, 3283 XResourceInfo *resource_info,XWindows *windows,Image **image, 3284 ExceptionInfo *exception) 3285{ 3286 static const char 3287 *ColorEditMenu[] = 3288 { 3289 "Method", 3290 "Pixel Color", 3291 "Border Color", 3292 "Fuzz", 3293 "Undo", 3294 "Help", 3295 "Dismiss", 3296 (char *) NULL 3297 }; 3298 3299 static const ModeType 3300 ColorEditCommands[] = 3301 { 3302 ColorEditMethodCommand, 3303 ColorEditColorCommand, 3304 ColorEditBorderCommand, 3305 ColorEditFuzzCommand, 3306 ColorEditUndoCommand, 3307 ColorEditHelpCommand, 3308 ColorEditDismissCommand 3309 }; 3310 3311 static PaintMethod 3312 method = PointMethod; 3313 3314 static unsigned int 3315 pen_id = 0; 3316 3317 static XColor 3318 border_color = { 0, 0, 0, 0, 0, 0 }; 3319 3320 char 3321 command[MaxTextExtent], 3322 text[MaxTextExtent]; 3323 3324 Cursor 3325 cursor; 3326 3327 int 3328 entry, 3329 id, 3330 x, 3331 x_offset, 3332 y, 3333 y_offset; 3334 3335 register Quantum 3336 *q; 3337 3338 register ssize_t 3339 i; 3340 3341 unsigned int 3342 height, 3343 width; 3344 3345 size_t 3346 state; 3347 3348 XColor 3349 color; 3350 3351 XEvent 3352 event; 3353 3354 /* 3355 Map Command widget. 3356 */ 3357 (void) CloneString(&windows->command.name,"Color Edit"); 3358 windows->command.data=4; 3359 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 3360 (void) XMapRaised(display,windows->command.id); 3361 XClientMessage(display,windows->image.id,windows->im_protocols, 3362 windows->im_update_widget,CurrentTime); 3363 /* 3364 Make cursor. 3365 */ 3366 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 3367 resource_info->background_color,resource_info->foreground_color); 3368 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3369 /* 3370 Track pointer until button 1 is pressed. 3371 */ 3372 XQueryPosition(display,windows->image.id,&x,&y); 3373 (void) XSelectInput(display,windows->image.id, 3374 windows->image.attributes.event_mask | PointerMotionMask); 3375 state=DefaultState; 3376 do 3377 { 3378 if (IfMagickTrue(windows->info.mapped) ) 3379 { 3380 /* 3381 Display pointer position. 3382 */ 3383 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 3384 x+windows->image.x,y+windows->image.y); 3385 XInfoWidget(display,windows,text); 3386 } 3387 /* 3388 Wait for next event. 3389 */ 3390 XScreenEvent(display,windows,&event,exception); 3391 if (event.xany.window == windows->command.id) 3392 { 3393 /* 3394 Select a command from the Command widget. 3395 */ 3396 id=XCommandWidget(display,windows,ColorEditMenu,&event); 3397 if (id < 0) 3398 { 3399 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3400 continue; 3401 } 3402 switch (ColorEditCommands[id]) 3403 { 3404 case ColorEditMethodCommand: 3405 { 3406 char 3407 **methods; 3408 3409 /* 3410 Select a method from the pop-up menu. 3411 */ 3412 methods=(char **) GetCommandOptions(MagickMethodOptions); 3413 if (methods == (char **) NULL) 3414 break; 3415 entry=XMenuWidget(display,windows,ColorEditMenu[id], 3416 (const char **) methods,command); 3417 if (entry >= 0) 3418 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 3419 MagickFalse,methods[entry]); 3420 methods=DestroyStringList(methods); 3421 break; 3422 } 3423 case ColorEditColorCommand: 3424 { 3425 const char 3426 *ColorMenu[MaxNumberPens]; 3427 3428 int 3429 pen_number; 3430 3431 /* 3432 Initialize menu selections. 3433 */ 3434 for (i=0; i < (int) (MaxNumberPens-2); i++) 3435 ColorMenu[i]=resource_info->pen_colors[i]; 3436 ColorMenu[MaxNumberPens-2]="Browser..."; 3437 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3438 /* 3439 Select a pen color from the pop-up menu. 3440 */ 3441 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3442 (const char **) ColorMenu,command); 3443 if (pen_number < 0) 3444 break; 3445 if (pen_number == (MaxNumberPens-2)) 3446 { 3447 static char 3448 color_name[MaxTextExtent] = "gray"; 3449 3450 /* 3451 Select a pen color from a dialog. 3452 */ 3453 resource_info->pen_colors[pen_number]=color_name; 3454 XColorBrowserWidget(display,windows,"Select",color_name); 3455 if (*color_name == '\0') 3456 break; 3457 } 3458 /* 3459 Set pen color. 3460 */ 3461 (void) XParseColor(display,windows->map_info->colormap, 3462 resource_info->pen_colors[pen_number],&color); 3463 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 3464 (unsigned int) MaxColors,&color); 3465 windows->pixel_info->pen_colors[pen_number]=color; 3466 pen_id=(unsigned int) pen_number; 3467 break; 3468 } 3469 case ColorEditBorderCommand: 3470 { 3471 const char 3472 *ColorMenu[MaxNumberPens]; 3473 3474 int 3475 pen_number; 3476 3477 /* 3478 Initialize menu selections. 3479 */ 3480 for (i=0; i < (int) (MaxNumberPens-2); i++) 3481 ColorMenu[i]=resource_info->pen_colors[i]; 3482 ColorMenu[MaxNumberPens-2]="Browser..."; 3483 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3484 /* 3485 Select a pen color from the pop-up menu. 3486 */ 3487 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3488 (const char **) ColorMenu,command); 3489 if (pen_number < 0) 3490 break; 3491 if (pen_number == (MaxNumberPens-2)) 3492 { 3493 static char 3494 color_name[MaxTextExtent] = "gray"; 3495 3496 /* 3497 Select a pen color from a dialog. 3498 */ 3499 resource_info->pen_colors[pen_number]=color_name; 3500 XColorBrowserWidget(display,windows,"Select",color_name); 3501 if (*color_name == '\0') 3502 break; 3503 } 3504 /* 3505 Set border color. 3506 */ 3507 (void) XParseColor(display,windows->map_info->colormap, 3508 resource_info->pen_colors[pen_number],&border_color); 3509 break; 3510 } 3511 case ColorEditFuzzCommand: 3512 { 3513 static char 3514 fuzz[MaxTextExtent]; 3515 3516 static const char 3517 *FuzzMenu[] = 3518 { 3519 "0%", 3520 "2%", 3521 "5%", 3522 "10%", 3523 "15%", 3524 "Dialog...", 3525 (char *) NULL, 3526 }; 3527 3528 /* 3529 Select a command from the pop-up menu. 3530 */ 3531 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 3532 command); 3533 if (entry < 0) 3534 break; 3535 if (entry != 5) 3536 { 3537 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 3538 QuantumRange+1.0); 3539 break; 3540 } 3541 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 3542 (void) XDialogWidget(display,windows,"Ok", 3543 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 3544 if (*fuzz == '\0') 3545 break; 3546 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 3547 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 3548 1.0); 3549 break; 3550 } 3551 case ColorEditUndoCommand: 3552 { 3553 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 3554 image,exception); 3555 break; 3556 } 3557 case ColorEditHelpCommand: 3558 default: 3559 { 3560 XTextViewWidget(display,resource_info,windows,MagickFalse, 3561 "Help Viewer - Image Annotation",ImageColorEditHelp); 3562 break; 3563 } 3564 case ColorEditDismissCommand: 3565 { 3566 /* 3567 Prematurely exit. 3568 */ 3569 state|=EscapeState; 3570 state|=ExitState; 3571 break; 3572 } 3573 } 3574 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3575 continue; 3576 } 3577 switch (event.type) 3578 { 3579 case ButtonPress: 3580 { 3581 if (event.xbutton.button != Button1) 3582 break; 3583 if ((event.xbutton.window != windows->image.id) && 3584 (event.xbutton.window != windows->magnify.id)) 3585 break; 3586 /* 3587 exit loop. 3588 */ 3589 x=event.xbutton.x; 3590 y=event.xbutton.y; 3591 (void) XMagickCommand(display,resource_info,windows, 3592 SaveToUndoBufferCommand,image,exception); 3593 state|=UpdateConfigurationState; 3594 break; 3595 } 3596 case ButtonRelease: 3597 { 3598 if (event.xbutton.button != Button1) 3599 break; 3600 if ((event.xbutton.window != windows->image.id) && 3601 (event.xbutton.window != windows->magnify.id)) 3602 break; 3603 /* 3604 Update colormap information. 3605 */ 3606 x=event.xbutton.x; 3607 y=event.xbutton.y; 3608 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3609 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3610 XInfoWidget(display,windows,text); 3611 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3612 state&=(~UpdateConfigurationState); 3613 break; 3614 } 3615 case Expose: 3616 break; 3617 case KeyPress: 3618 { 3619 KeySym 3620 key_symbol; 3621 3622 if (event.xkey.window == windows->magnify.id) 3623 { 3624 Window 3625 window; 3626 3627 window=windows->magnify.id; 3628 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 3629 } 3630 if (event.xkey.window != windows->image.id) 3631 break; 3632 /* 3633 Respond to a user key press. 3634 */ 3635 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3636 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3637 switch ((int) key_symbol) 3638 { 3639 case XK_Escape: 3640 case XK_F20: 3641 { 3642 /* 3643 Prematurely exit. 3644 */ 3645 state|=ExitState; 3646 break; 3647 } 3648 case XK_F1: 3649 case XK_Help: 3650 { 3651 XTextViewWidget(display,resource_info,windows,MagickFalse, 3652 "Help Viewer - Image Annotation",ImageColorEditHelp); 3653 break; 3654 } 3655 default: 3656 { 3657 (void) XBell(display,0); 3658 break; 3659 } 3660 } 3661 break; 3662 } 3663 case MotionNotify: 3664 { 3665 /* 3666 Map and unmap Info widget as cursor crosses its boundaries. 3667 */ 3668 x=event.xmotion.x; 3669 y=event.xmotion.y; 3670 if (IfMagickTrue(windows->info.mapped) ) 3671 { 3672 if ((x < (int) (windows->info.x+windows->info.width)) && 3673 (y < (int) (windows->info.y+windows->info.height))) 3674 (void) XWithdrawWindow(display,windows->info.id, 3675 windows->info.screen); 3676 } 3677 else 3678 if ((x > (int) (windows->info.x+windows->info.width)) || 3679 (y > (int) (windows->info.y+windows->info.height))) 3680 (void) XMapWindow(display,windows->info.id); 3681 break; 3682 } 3683 default: 3684 break; 3685 } 3686 if (event.xany.window == windows->magnify.id) 3687 { 3688 x=windows->magnify.x-windows->image.x; 3689 y=windows->magnify.y-windows->image.y; 3690 } 3691 x_offset=x; 3692 y_offset=y; 3693 if ((state & UpdateConfigurationState) != 0) 3694 { 3695 CacheView 3696 *image_view; 3697 3698 int 3699 x, 3700 y; 3701 3702 /* 3703 Pixel edit is relative to image configuration. 3704 */ 3705 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 3706 MagickTrue); 3707 color=windows->pixel_info->pen_colors[pen_id]; 3708 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 3709 width=(unsigned int) (*image)->columns; 3710 height=(unsigned int) (*image)->rows; 3711 x=0; 3712 y=0; 3713 if (windows->image.crop_geometry != (char *) NULL) 3714 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 3715 &width,&height); 3716 x_offset=(int) 3717 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 3718 y_offset=(int) 3719 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 3720 if ((x_offset < 0) || (y_offset < 0)) 3721 continue; 3722 if ((x_offset >= (int) (*image)->columns) || 3723 (y_offset >= (int) (*image)->rows)) 3724 continue; 3725 image_view=AcquireAuthenticCacheView(*image,exception); 3726 switch (method) 3727 { 3728 case PointMethod: 3729 default: 3730 { 3731 /* 3732 Update color information using point algorithm. 3733 */ 3734 if (IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) ) 3735 return(MagickFalse); 3736 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 3737 (ssize_t) y_offset,1,1,exception); 3738 if (q == (Quantum *) NULL) 3739 break; 3740 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3741 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3742 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3743 (void) SyncCacheViewAuthenticPixels(image_view,exception); 3744 break; 3745 } 3746 case ReplaceMethod: 3747 { 3748 PixelInfo 3749 pixel, 3750 target; 3751 3752 /* 3753 Update color information using replace algorithm. 3754 */ 3755 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t) 3756 x_offset,(ssize_t) y_offset,&target,exception); 3757 if ((*image)->storage_class == DirectClass) 3758 { 3759 for (y=0; y < (int) (*image)->rows; y++) 3760 { 3761 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3762 (*image)->columns,1,exception); 3763 if (q == (Quantum *) NULL) 3764 break; 3765 for (x=0; x < (int) (*image)->columns; x++) 3766 { 3767 GetPixelInfoPixel(*image,q,&pixel); 3768 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 3769 { 3770 SetPixelRed(*image,ScaleShortToQuantum( 3771 color.red),q); 3772 SetPixelGreen(*image,ScaleShortToQuantum( 3773 color.green),q); 3774 SetPixelBlue(*image,ScaleShortToQuantum( 3775 color.blue),q); 3776 } 3777 q+=GetPixelChannels(*image); 3778 } 3779 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 3780 break; 3781 } 3782 } 3783 else 3784 { 3785 for (i=0; i < (ssize_t) (*image)->colors; i++) 3786 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target)) 3787 { 3788 (*image)->colormap[i].red=(double) ScaleShortToQuantum( 3789 color.red); 3790 (*image)->colormap[i].green=(double) ScaleShortToQuantum( 3791 color.green); 3792 (*image)->colormap[i].blue=(double) ScaleShortToQuantum( 3793 color.blue); 3794 } 3795 (void) SyncImage(*image,exception); 3796 } 3797 break; 3798 } 3799 case FloodfillMethod: 3800 case FillToBorderMethod: 3801 { 3802 DrawInfo 3803 *draw_info; 3804 3805 PixelInfo 3806 target; 3807 3808 /* 3809 Update color information using floodfill algorithm. 3810 */ 3811 (void) GetOneVirtualPixelInfo(*image, 3812 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 3813 y_offset,&target,exception); 3814 if (method == FillToBorderMethod) 3815 { 3816 target.red=(double) 3817 ScaleShortToQuantum(border_color.red); 3818 target.green=(double) 3819 ScaleShortToQuantum(border_color.green); 3820 target.blue=(double) 3821 ScaleShortToQuantum(border_color.blue); 3822 } 3823 draw_info=CloneDrawInfo(resource_info->image_info, 3824 (DrawInfo *) NULL); 3825 (void) QueryColorCompliance(resource_info->pen_colors[pen_id], 3826 AllCompliance,&draw_info->fill,exception); 3827 (void) FloodfillPaintImage(*image,draw_info,&target, 3828 (ssize_t)x_offset,(ssize_t)y_offset, 3829 IsMagickFalse(method == FloodfillMethod),exception); 3830 draw_info=DestroyDrawInfo(draw_info); 3831 break; 3832 } 3833 case ResetMethod: 3834 { 3835 /* 3836 Update color information using reset algorithm. 3837 */ 3838 if (IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) ) 3839 return(MagickFalse); 3840 for (y=0; y < (int) (*image)->rows; y++) 3841 { 3842 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3843 (*image)->columns,1,exception); 3844 if (q == (Quantum *) NULL) 3845 break; 3846 for (x=0; x < (int) (*image)->columns; x++) 3847 { 3848 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3849 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3850 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3851 q+=GetPixelChannels(*image); 3852 } 3853 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 3854 break; 3855 } 3856 break; 3857 } 3858 } 3859 image_view=DestroyCacheView(image_view); 3860 state&=(~UpdateConfigurationState); 3861 } 3862 } while ((state & ExitState) == 0); 3863 (void) XSelectInput(display,windows->image.id, 3864 windows->image.attributes.event_mask); 3865 XSetCursorState(display,windows,MagickFalse); 3866 (void) XFreeCursor(display,cursor); 3867 return(MagickTrue); 3868} 3869 3870/* 3871%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3872% % 3873% % 3874% % 3875+ X C o m p o s i t e I m a g e % 3876% % 3877% % 3878% % 3879%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3880% 3881% XCompositeImage() requests an image name from the user, reads the image and 3882% composites it with the X window image at a location the user chooses with 3883% the pointer. 3884% 3885% The format of the XCompositeImage method is: 3886% 3887% MagickBooleanType XCompositeImage(Display *display, 3888% XResourceInfo *resource_info,XWindows *windows,Image *image, 3889% ExceptionInfo *exception) 3890% 3891% A description of each parameter follows: 3892% 3893% o display: Specifies a connection to an X server; returned from 3894% XOpenDisplay. 3895% 3896% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3897% 3898% o windows: Specifies a pointer to a XWindows structure. 3899% 3900% o image: the image; returned from ReadImage. 3901% 3902% o exception: return any errors or warnings in this structure. 3903% 3904*/ 3905static MagickBooleanType XCompositeImage(Display *display, 3906 XResourceInfo *resource_info,XWindows *windows,Image *image, 3907 ExceptionInfo *exception) 3908{ 3909 static char 3910 displacement_geometry[MaxTextExtent] = "30x30", 3911 filename[MaxTextExtent] = "\0"; 3912 3913 static const char 3914 *CompositeMenu[] = 3915 { 3916 "Operators", 3917 "Dissolve", 3918 "Displace", 3919 "Help", 3920 "Dismiss", 3921 (char *) NULL 3922 }; 3923 3924 static CompositeOperator 3925 compose = CopyCompositeOp; 3926 3927 static const ModeType 3928 CompositeCommands[] = 3929 { 3930 CompositeOperatorsCommand, 3931 CompositeDissolveCommand, 3932 CompositeDisplaceCommand, 3933 CompositeHelpCommand, 3934 CompositeDismissCommand 3935 }; 3936 3937 char 3938 text[MaxTextExtent]; 3939 3940 Cursor 3941 cursor; 3942 3943 Image 3944 *composite_image; 3945 3946 int 3947 entry, 3948 id, 3949 x, 3950 y; 3951 3952 double 3953 blend, 3954 scale_factor; 3955 3956 RectangleInfo 3957 highlight_info, 3958 composite_info; 3959 3960 unsigned int 3961 height, 3962 width; 3963 3964 size_t 3965 state; 3966 3967 XEvent 3968 event; 3969 3970 /* 3971 Request image file name from user. 3972 */ 3973 XFileBrowserWidget(display,windows,"Composite",filename); 3974 if (*filename == '\0') 3975 return(MagickTrue); 3976 /* 3977 Read image. 3978 */ 3979 XSetCursorState(display,windows,MagickTrue); 3980 XCheckRefreshWindows(display,windows); 3981 (void) CopyMagickString(resource_info->image_info->filename,filename, 3982 MaxTextExtent); 3983 composite_image=ReadImage(resource_info->image_info,exception); 3984 CatchException(exception); 3985 XSetCursorState(display,windows,MagickFalse); 3986 if (composite_image == (Image *) NULL) 3987 return(MagickFalse); 3988 /* 3989 Map Command widget. 3990 */ 3991 (void) CloneString(&windows->command.name,"Composite"); 3992 windows->command.data=1; 3993 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 3994 (void) XMapRaised(display,windows->command.id); 3995 XClientMessage(display,windows->image.id,windows->im_protocols, 3996 windows->im_update_widget,CurrentTime); 3997 /* 3998 Track pointer until button 1 is pressed. 3999 */ 4000 XQueryPosition(display,windows->image.id,&x,&y); 4001 (void) XSelectInput(display,windows->image.id, 4002 windows->image.attributes.event_mask | PointerMotionMask); 4003 composite_info.x=(ssize_t) windows->image.x+x; 4004 composite_info.y=(ssize_t) windows->image.y+y; 4005 composite_info.width=0; 4006 composite_info.height=0; 4007 cursor=XCreateFontCursor(display,XC_ul_angle); 4008 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4009 blend=0.0; 4010 state=DefaultState; 4011 do 4012 { 4013 if (IfMagickTrue(windows->info.mapped) ) 4014 { 4015 /* 4016 Display pointer position. 4017 */ 4018 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4019 (long) composite_info.x,(long) composite_info.y); 4020 XInfoWidget(display,windows,text); 4021 } 4022 highlight_info=composite_info; 4023 highlight_info.x=composite_info.x-windows->image.x; 4024 highlight_info.y=composite_info.y-windows->image.y; 4025 XHighlightRectangle(display,windows->image.id, 4026 windows->image.highlight_context,&highlight_info); 4027 /* 4028 Wait for next event. 4029 */ 4030 XScreenEvent(display,windows,&event,exception); 4031 XHighlightRectangle(display,windows->image.id, 4032 windows->image.highlight_context,&highlight_info); 4033 if (event.xany.window == windows->command.id) 4034 { 4035 /* 4036 Select a command from the Command widget. 4037 */ 4038 id=XCommandWidget(display,windows,CompositeMenu,&event); 4039 if (id < 0) 4040 continue; 4041 switch (CompositeCommands[id]) 4042 { 4043 case CompositeOperatorsCommand: 4044 { 4045 char 4046 command[MaxTextExtent], 4047 **operators; 4048 4049 /* 4050 Select a command from the pop-up menu. 4051 */ 4052 operators=GetCommandOptions(MagickComposeOptions); 4053 if (operators == (char **) NULL) 4054 break; 4055 entry=XMenuWidget(display,windows,CompositeMenu[id], 4056 (const char **) operators,command); 4057 if (entry >= 0) 4058 compose=(CompositeOperator) ParseCommandOption( 4059 MagickComposeOptions,MagickFalse,operators[entry]); 4060 operators=DestroyStringList(operators); 4061 break; 4062 } 4063 case CompositeDissolveCommand: 4064 { 4065 static char 4066 factor[MaxTextExtent] = "20.0"; 4067 4068 /* 4069 Dissolve the two images a given percent. 4070 */ 4071 (void) XSetFunction(display,windows->image.highlight_context, 4072 GXcopy); 4073 (void) XDialogWidget(display,windows,"Dissolve", 4074 "Enter the blend factor (0.0 - 99.9%):",factor); 4075 (void) XSetFunction(display,windows->image.highlight_context, 4076 GXinvert); 4077 if (*factor == '\0') 4078 break; 4079 blend=StringToDouble(factor,(char **) NULL); 4080 compose=DissolveCompositeOp; 4081 break; 4082 } 4083 case CompositeDisplaceCommand: 4084 { 4085 /* 4086 Get horizontal and vertical scale displacement geometry. 4087 */ 4088 (void) XSetFunction(display,windows->image.highlight_context, 4089 GXcopy); 4090 (void) XDialogWidget(display,windows,"Displace", 4091 "Enter the horizontal and vertical scale:",displacement_geometry); 4092 (void) XSetFunction(display,windows->image.highlight_context, 4093 GXinvert); 4094 if (*displacement_geometry == '\0') 4095 break; 4096 compose=DisplaceCompositeOp; 4097 break; 4098 } 4099 case CompositeHelpCommand: 4100 { 4101 (void) XSetFunction(display,windows->image.highlight_context, 4102 GXcopy); 4103 XTextViewWidget(display,resource_info,windows,MagickFalse, 4104 "Help Viewer - Image Composite",ImageCompositeHelp); 4105 (void) XSetFunction(display,windows->image.highlight_context, 4106 GXinvert); 4107 break; 4108 } 4109 case CompositeDismissCommand: 4110 { 4111 /* 4112 Prematurely exit. 4113 */ 4114 state|=EscapeState; 4115 state|=ExitState; 4116 break; 4117 } 4118 default: 4119 break; 4120 } 4121 continue; 4122 } 4123 switch (event.type) 4124 { 4125 case ButtonPress: 4126 { 4127 if (IfMagickTrue(image->debug) ) 4128 (void) LogMagickEvent(X11Event,GetMagickModule(), 4129 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 4130 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4131 if (event.xbutton.button != Button1) 4132 break; 4133 if (event.xbutton.window != windows->image.id) 4134 break; 4135 /* 4136 Change cursor. 4137 */ 4138 composite_info.width=composite_image->columns; 4139 composite_info.height=composite_image->rows; 4140 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4141 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4142 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4143 break; 4144 } 4145 case ButtonRelease: 4146 { 4147 if (IfMagickTrue(image->debug) ) 4148 (void) LogMagickEvent(X11Event,GetMagickModule(), 4149 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 4150 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4151 if (event.xbutton.button != Button1) 4152 break; 4153 if (event.xbutton.window != windows->image.id) 4154 break; 4155 if ((composite_info.width != 0) && (composite_info.height != 0)) 4156 { 4157 /* 4158 User has selected the location of the composite image. 4159 */ 4160 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4161 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4162 state|=ExitState; 4163 } 4164 break; 4165 } 4166 case Expose: 4167 break; 4168 case KeyPress: 4169 { 4170 char 4171 command[MaxTextExtent]; 4172 4173 KeySym 4174 key_symbol; 4175 4176 int 4177 length; 4178 4179 if (event.xkey.window != windows->image.id) 4180 break; 4181 /* 4182 Respond to a user key press. 4183 */ 4184 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 4185 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4186 *(command+length)='\0'; 4187 if (IfMagickTrue(image->debug) ) 4188 (void) LogMagickEvent(X11Event,GetMagickModule(), 4189 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 4190 switch ((int) key_symbol) 4191 { 4192 case XK_Escape: 4193 case XK_F20: 4194 { 4195 /* 4196 Prematurely exit. 4197 */ 4198 composite_image=DestroyImage(composite_image); 4199 state|=EscapeState; 4200 state|=ExitState; 4201 break; 4202 } 4203 case XK_F1: 4204 case XK_Help: 4205 { 4206 (void) XSetFunction(display,windows->image.highlight_context, 4207 GXcopy); 4208 XTextViewWidget(display,resource_info,windows,MagickFalse, 4209 "Help Viewer - Image Composite",ImageCompositeHelp); 4210 (void) XSetFunction(display,windows->image.highlight_context, 4211 GXinvert); 4212 break; 4213 } 4214 default: 4215 { 4216 (void) XBell(display,0); 4217 break; 4218 } 4219 } 4220 break; 4221 } 4222 case MotionNotify: 4223 { 4224 /* 4225 Map and unmap Info widget as text cursor crosses its boundaries. 4226 */ 4227 x=event.xmotion.x; 4228 y=event.xmotion.y; 4229 if (IfMagickTrue(windows->info.mapped) ) 4230 { 4231 if ((x < (int) (windows->info.x+windows->info.width)) && 4232 (y < (int) (windows->info.y+windows->info.height))) 4233 (void) XWithdrawWindow(display,windows->info.id, 4234 windows->info.screen); 4235 } 4236 else 4237 if ((x > (int) (windows->info.x+windows->info.width)) || 4238 (y > (int) (windows->info.y+windows->info.height))) 4239 (void) XMapWindow(display,windows->info.id); 4240 composite_info.x=(ssize_t) windows->image.x+x; 4241 composite_info.y=(ssize_t) windows->image.y+y; 4242 break; 4243 } 4244 default: 4245 { 4246 if (IfMagickTrue(image->debug) ) 4247 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 4248 event.type); 4249 break; 4250 } 4251 } 4252 } while ((state & ExitState) == 0); 4253 (void) XSelectInput(display,windows->image.id, 4254 windows->image.attributes.event_mask); 4255 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4256 XSetCursorState(display,windows,MagickFalse); 4257 (void) XFreeCursor(display,cursor); 4258 if ((state & EscapeState) != 0) 4259 return(MagickTrue); 4260 /* 4261 Image compositing is relative to image configuration. 4262 */ 4263 XSetCursorState(display,windows,MagickTrue); 4264 XCheckRefreshWindows(display,windows); 4265 width=(unsigned int) image->columns; 4266 height=(unsigned int) image->rows; 4267 x=0; 4268 y=0; 4269 if (windows->image.crop_geometry != (char *) NULL) 4270 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 4271 scale_factor=(double) width/windows->image.ximage->width; 4272 composite_info.x+=x; 4273 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 4274 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 4275 scale_factor=(double) height/windows->image.ximage->height; 4276 composite_info.y+=y; 4277 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 4278 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 4279 if ((composite_info.width != composite_image->columns) || 4280 (composite_info.height != composite_image->rows)) 4281 { 4282 Image 4283 *resize_image; 4284 4285 /* 4286 Scale composite image. 4287 */ 4288 resize_image=ResizeImage(composite_image,composite_info.width, 4289 composite_info.height,composite_image->filter,exception); 4290 composite_image=DestroyImage(composite_image); 4291 if (resize_image == (Image *) NULL) 4292 { 4293 XSetCursorState(display,windows,MagickFalse); 4294 return(MagickFalse); 4295 } 4296 composite_image=resize_image; 4297 } 4298 if (compose == DisplaceCompositeOp) 4299 (void) SetImageArtifact(composite_image,"compose:args", 4300 displacement_geometry); 4301 if (blend != 0.0) 4302 { 4303 CacheView 4304 *image_view; 4305 4306 int 4307 y; 4308 4309 Quantum 4310 opacity; 4311 4312 register int 4313 x; 4314 4315 register Quantum 4316 *q; 4317 4318 /* 4319 Create mattes for blending. 4320 */ 4321 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception); 4322 opacity=(Quantum) (ScaleQuantumToChar(QuantumRange)- 4323 ((ssize_t) ScaleQuantumToChar(QuantumRange)*blend)/100); 4324 if (IfMagickFalse(SetImageStorageClass(image,DirectClass,exception)) ) 4325 return(MagickFalse); 4326 image->alpha_trait=BlendPixelTrait; 4327 image_view=AcquireAuthenticCacheView(image,exception); 4328 for (y=0; y < (int) image->rows; y++) 4329 { 4330 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 4331 exception); 4332 if (q == (Quantum *) NULL) 4333 break; 4334 for (x=0; x < (int) image->columns; x++) 4335 { 4336 SetPixelAlpha(image,opacity,q); 4337 q+=GetPixelChannels(image); 4338 } 4339 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 4340 break; 4341 } 4342 image_view=DestroyCacheView(image_view); 4343 } 4344 /* 4345 Composite image with X Image window. 4346 */ 4347 (void) CompositeImage(image,composite_image,compose,MagickTrue, 4348 composite_info.x,composite_info.y,exception); 4349 composite_image=DestroyImage(composite_image); 4350 XSetCursorState(display,windows,MagickFalse); 4351 /* 4352 Update image configuration. 4353 */ 4354 XConfigureImageColormap(display,resource_info,windows,image,exception); 4355 (void) XConfigureImage(display,resource_info,windows,image,exception); 4356 return(MagickTrue); 4357} 4358 4359/* 4360%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4361% % 4362% % 4363% % 4364+ X C o n f i g u r e I m a g e % 4365% % 4366% % 4367% % 4368%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4369% 4370% XConfigureImage() creates a new X image. It also notifies the window 4371% manager of the new image size and configures the transient widows. 4372% 4373% The format of the XConfigureImage method is: 4374% 4375% MagickBooleanType XConfigureImage(Display *display, 4376% XResourceInfo *resource_info,XWindows *windows,Image *image, 4377% ExceptionInfo *exception) 4378% 4379% A description of each parameter follows: 4380% 4381% o display: Specifies a connection to an X server; returned from 4382% XOpenDisplay. 4383% 4384% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4385% 4386% o windows: Specifies a pointer to a XWindows structure. 4387% 4388% o image: the image. 4389% 4390% o exception: return any errors or warnings in this structure. 4391% 4392% o exception: return any errors or warnings in this structure. 4393% 4394*/ 4395static MagickBooleanType XConfigureImage(Display *display, 4396 XResourceInfo *resource_info,XWindows *windows,Image *image, 4397 ExceptionInfo *exception) 4398{ 4399 char 4400 geometry[MaxTextExtent]; 4401 4402 MagickStatusType 4403 status; 4404 4405 size_t 4406 mask, 4407 height, 4408 width; 4409 4410 ssize_t 4411 x, 4412 y; 4413 4414 XSizeHints 4415 *size_hints; 4416 4417 XWindowChanges 4418 window_changes; 4419 4420 /* 4421 Dismiss if window dimensions are zero. 4422 */ 4423 width=(unsigned int) windows->image.window_changes.width; 4424 height=(unsigned int) windows->image.window_changes.height; 4425 if (IfMagickTrue(image->debug) ) 4426 (void) LogMagickEvent(X11Event,GetMagickModule(), 4427 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 4428 windows->image.ximage->height,(double) width,(double) height); 4429 if ((width*height) == 0) 4430 return(MagickTrue); 4431 x=0; 4432 y=0; 4433 /* 4434 Resize image to fit Image window dimensions. 4435 */ 4436 XSetCursorState(display,windows,MagickTrue); 4437 (void) XFlush(display); 4438 if (((int) width != windows->image.ximage->width) || 4439 ((int) height != windows->image.ximage->height)) 4440 image->taint=MagickTrue; 4441 windows->magnify.x=(int) 4442 width*windows->magnify.x/windows->image.ximage->width; 4443 windows->magnify.y=(int) 4444 height*windows->magnify.y/windows->image.ximage->height; 4445 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 4446 windows->image.y=(int) 4447 (height*windows->image.y/windows->image.ximage->height); 4448 status=XMakeImage(display,resource_info,&windows->image,image, 4449 (unsigned int) width,(unsigned int) height,exception); 4450 if (IfMagickFalse(status) ) 4451 XNoticeWidget(display,windows,"Unable to configure X image:", 4452 windows->image.name); 4453 /* 4454 Notify window manager of the new configuration. 4455 */ 4456 if (resource_info->image_geometry != (char *) NULL) 4457 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!", 4458 resource_info->image_geometry); 4459 else 4460 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 4461 XDisplayWidth(display,windows->image.screen), 4462 XDisplayHeight(display,windows->image.screen)); 4463 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 4464 window_changes.width=(int) width; 4465 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 4466 window_changes.width=XDisplayWidth(display,windows->image.screen); 4467 window_changes.height=(int) height; 4468 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 4469 window_changes.height=XDisplayHeight(display,windows->image.screen); 4470 mask=(size_t) (CWWidth | CWHeight); 4471 if (resource_info->backdrop) 4472 { 4473 mask|=CWX | CWY; 4474 window_changes.x=(int) 4475 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 4476 window_changes.y=(int) 4477 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 4478 } 4479 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 4480 (unsigned int) mask,&window_changes); 4481 (void) XClearWindow(display,windows->image.id); 4482 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 4483 /* 4484 Update Magnify window configuration. 4485 */ 4486 if (IfMagickTrue(windows->magnify.mapped) ) 4487 XMakeMagnifyImage(display,windows,exception); 4488 windows->pan.crop_geometry=windows->image.crop_geometry; 4489 XBestIconSize(display,&windows->pan,image); 4490 while (((windows->pan.width << 1) < MaxIconSize) && 4491 ((windows->pan.height << 1) < MaxIconSize)) 4492 { 4493 windows->pan.width<<=1; 4494 windows->pan.height<<=1; 4495 } 4496 if (windows->pan.geometry != (char *) NULL) 4497 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 4498 &windows->pan.width,&windows->pan.height); 4499 window_changes.width=(int) windows->pan.width; 4500 window_changes.height=(int) windows->pan.height; 4501 size_hints=XAllocSizeHints(); 4502 if (size_hints != (XSizeHints *) NULL) 4503 { 4504 /* 4505 Set new size hints. 4506 */ 4507 size_hints->flags=PSize | PMinSize | PMaxSize; 4508 size_hints->width=window_changes.width; 4509 size_hints->height=window_changes.height; 4510 size_hints->min_width=size_hints->width; 4511 size_hints->min_height=size_hints->height; 4512 size_hints->max_width=size_hints->width; 4513 size_hints->max_height=size_hints->height; 4514 (void) XSetNormalHints(display,windows->pan.id,size_hints); 4515 (void) XFree((void *) size_hints); 4516 } 4517 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 4518 (unsigned int) (CWWidth | CWHeight),&window_changes); 4519 /* 4520 Update icon window configuration. 4521 */ 4522 windows->icon.crop_geometry=windows->image.crop_geometry; 4523 XBestIconSize(display,&windows->icon,image); 4524 window_changes.width=(int) windows->icon.width; 4525 window_changes.height=(int) windows->icon.height; 4526 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 4527 (unsigned int) (CWWidth | CWHeight),&window_changes); 4528 XSetCursorState(display,windows,MagickFalse); 4529 return(IsMagickTrue(status)); 4530} 4531 4532/* 4533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4534% % 4535% % 4536% % 4537+ X C r o p I m a g e % 4538% % 4539% % 4540% % 4541%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4542% 4543% XCropImage() allows the user to select a region of the image and crop, copy, 4544% or cut it. For copy or cut, the image can subsequently be composited onto 4545% the image with XPasteImage. 4546% 4547% The format of the XCropImage method is: 4548% 4549% MagickBooleanType XCropImage(Display *display, 4550% XResourceInfo *resource_info,XWindows *windows,Image *image, 4551% const ClipboardMode mode,ExceptionInfo *exception) 4552% 4553% A description of each parameter follows: 4554% 4555% o display: Specifies a connection to an X server; returned from 4556% XOpenDisplay. 4557% 4558% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4559% 4560% o windows: Specifies a pointer to a XWindows structure. 4561% 4562% o image: the image; returned from ReadImage. 4563% 4564% o mode: This unsigned value specified whether the image should be 4565% cropped, copied, or cut. 4566% 4567% o exception: return any errors or warnings in this structure. 4568% 4569*/ 4570static MagickBooleanType XCropImage(Display *display, 4571 XResourceInfo *resource_info,XWindows *windows,Image *image, 4572 const ClipboardMode mode,ExceptionInfo *exception) 4573{ 4574 static const char 4575 *CropModeMenu[] = 4576 { 4577 "Help", 4578 "Dismiss", 4579 (char *) NULL 4580 }, 4581 *RectifyModeMenu[] = 4582 { 4583 "Crop", 4584 "Help", 4585 "Dismiss", 4586 (char *) NULL 4587 }; 4588 4589 static const ModeType 4590 CropCommands[] = 4591 { 4592 CropHelpCommand, 4593 CropDismissCommand 4594 }, 4595 RectifyCommands[] = 4596 { 4597 RectifyCopyCommand, 4598 RectifyHelpCommand, 4599 RectifyDismissCommand 4600 }; 4601 4602 CacheView 4603 *image_view; 4604 4605 char 4606 command[MaxTextExtent], 4607 text[MaxTextExtent]; 4608 4609 Cursor 4610 cursor; 4611 4612 int 4613 id, 4614 x, 4615 y; 4616 4617 KeySym 4618 key_symbol; 4619 4620 Image 4621 *crop_image; 4622 4623 double 4624 scale_factor; 4625 4626 RectangleInfo 4627 crop_info, 4628 highlight_info; 4629 4630 register Quantum 4631 *q; 4632 4633 unsigned int 4634 height, 4635 width; 4636 4637 size_t 4638 state; 4639 4640 XEvent 4641 event; 4642 4643 /* 4644 Map Command widget. 4645 */ 4646 switch (mode) 4647 { 4648 case CopyMode: 4649 { 4650 (void) CloneString(&windows->command.name,"Copy"); 4651 break; 4652 } 4653 case CropMode: 4654 { 4655 (void) CloneString(&windows->command.name,"Crop"); 4656 break; 4657 } 4658 case CutMode: 4659 { 4660 (void) CloneString(&windows->command.name,"Cut"); 4661 break; 4662 } 4663 } 4664 RectifyModeMenu[0]=windows->command.name; 4665 windows->command.data=0; 4666 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 4667 (void) XMapRaised(display,windows->command.id); 4668 XClientMessage(display,windows->image.id,windows->im_protocols, 4669 windows->im_update_widget,CurrentTime); 4670 /* 4671 Track pointer until button 1 is pressed. 4672 */ 4673 XQueryPosition(display,windows->image.id,&x,&y); 4674 (void) XSelectInput(display,windows->image.id, 4675 windows->image.attributes.event_mask | PointerMotionMask); 4676 crop_info.x=(ssize_t) windows->image.x+x; 4677 crop_info.y=(ssize_t) windows->image.y+y; 4678 crop_info.width=0; 4679 crop_info.height=0; 4680 cursor=XCreateFontCursor(display,XC_fleur); 4681 state=DefaultState; 4682 do 4683 { 4684 if (IfMagickTrue(windows->info.mapped) ) 4685 { 4686 /* 4687 Display pointer position. 4688 */ 4689 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4690 (long) crop_info.x,(long) crop_info.y); 4691 XInfoWidget(display,windows,text); 4692 } 4693 /* 4694 Wait for next event. 4695 */ 4696 XScreenEvent(display,windows,&event,exception); 4697 if (event.xany.window == windows->command.id) 4698 { 4699 /* 4700 Select a command from the Command widget. 4701 */ 4702 id=XCommandWidget(display,windows,CropModeMenu,&event); 4703 if (id < 0) 4704 continue; 4705 switch (CropCommands[id]) 4706 { 4707 case CropHelpCommand: 4708 { 4709 switch (mode) 4710 { 4711 case CopyMode: 4712 { 4713 XTextViewWidget(display,resource_info,windows,MagickFalse, 4714 "Help Viewer - Image Copy",ImageCopyHelp); 4715 break; 4716 } 4717 case CropMode: 4718 { 4719 XTextViewWidget(display,resource_info,windows,MagickFalse, 4720 "Help Viewer - Image Crop",ImageCropHelp); 4721 break; 4722 } 4723 case CutMode: 4724 { 4725 XTextViewWidget(display,resource_info,windows,MagickFalse, 4726 "Help Viewer - Image Cut",ImageCutHelp); 4727 break; 4728 } 4729 } 4730 break; 4731 } 4732 case CropDismissCommand: 4733 { 4734 /* 4735 Prematurely exit. 4736 */ 4737 state|=EscapeState; 4738 state|=ExitState; 4739 break; 4740 } 4741 default: 4742 break; 4743 } 4744 continue; 4745 } 4746 switch (event.type) 4747 { 4748 case ButtonPress: 4749 { 4750 if (event.xbutton.button != Button1) 4751 break; 4752 if (event.xbutton.window != windows->image.id) 4753 break; 4754 /* 4755 Note first corner of cropping rectangle-- exit loop. 4756 */ 4757 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4758 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4759 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4760 state|=ExitState; 4761 break; 4762 } 4763 case ButtonRelease: 4764 break; 4765 case Expose: 4766 break; 4767 case KeyPress: 4768 { 4769 if (event.xkey.window != windows->image.id) 4770 break; 4771 /* 4772 Respond to a user key press. 4773 */ 4774 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 4775 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4776 switch ((int) key_symbol) 4777 { 4778 case XK_Escape: 4779 case XK_F20: 4780 { 4781 /* 4782 Prematurely exit. 4783 */ 4784 state|=EscapeState; 4785 state|=ExitState; 4786 break; 4787 } 4788 case XK_F1: 4789 case XK_Help: 4790 { 4791 switch (mode) 4792 { 4793 case CopyMode: 4794 { 4795 XTextViewWidget(display,resource_info,windows,MagickFalse, 4796 "Help Viewer - Image Copy",ImageCopyHelp); 4797 break; 4798 } 4799 case CropMode: 4800 { 4801 XTextViewWidget(display,resource_info,windows,MagickFalse, 4802 "Help Viewer - Image Crop",ImageCropHelp); 4803 break; 4804 } 4805 case CutMode: 4806 { 4807 XTextViewWidget(display,resource_info,windows,MagickFalse, 4808 "Help Viewer - Image Cut",ImageCutHelp); 4809 break; 4810 } 4811 } 4812 break; 4813 } 4814 default: 4815 { 4816 (void) XBell(display,0); 4817 break; 4818 } 4819 } 4820 break; 4821 } 4822 case MotionNotify: 4823 { 4824 if (event.xmotion.window != windows->image.id) 4825 break; 4826 /* 4827 Map and unmap Info widget as text cursor crosses its boundaries. 4828 */ 4829 x=event.xmotion.x; 4830 y=event.xmotion.y; 4831 if (IfMagickTrue(windows->info.mapped) ) 4832 { 4833 if ((x < (int) (windows->info.x+windows->info.width)) && 4834 (y < (int) (windows->info.y+windows->info.height))) 4835 (void) XWithdrawWindow(display,windows->info.id, 4836 windows->info.screen); 4837 } 4838 else 4839 if ((x > (int) (windows->info.x+windows->info.width)) || 4840 (y > (int) (windows->info.y+windows->info.height))) 4841 (void) XMapWindow(display,windows->info.id); 4842 crop_info.x=(ssize_t) windows->image.x+x; 4843 crop_info.y=(ssize_t) windows->image.y+y; 4844 break; 4845 } 4846 default: 4847 break; 4848 } 4849 } while ((state & ExitState) == 0); 4850 (void) XSelectInput(display,windows->image.id, 4851 windows->image.attributes.event_mask); 4852 if ((state & EscapeState) != 0) 4853 { 4854 /* 4855 User want to exit without cropping. 4856 */ 4857 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4858 (void) XFreeCursor(display,cursor); 4859 return(MagickTrue); 4860 } 4861 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4862 do 4863 { 4864 /* 4865 Size rectangle as pointer moves until the mouse button is released. 4866 */ 4867 x=(int) crop_info.x; 4868 y=(int) crop_info.y; 4869 crop_info.width=0; 4870 crop_info.height=0; 4871 state=DefaultState; 4872 do 4873 { 4874 highlight_info=crop_info; 4875 highlight_info.x=crop_info.x-windows->image.x; 4876 highlight_info.y=crop_info.y-windows->image.y; 4877 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4878 { 4879 /* 4880 Display info and draw cropping rectangle. 4881 */ 4882 if (IfMagickFalse(windows->info.mapped) ) 4883 (void) XMapWindow(display,windows->info.id); 4884 (void) FormatLocaleString(text,MaxTextExtent, 4885 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4886 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4887 XInfoWidget(display,windows,text); 4888 XHighlightRectangle(display,windows->image.id, 4889 windows->image.highlight_context,&highlight_info); 4890 } 4891 else 4892 if (IfMagickTrue(windows->info.mapped) ) 4893 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4894 /* 4895 Wait for next event. 4896 */ 4897 XScreenEvent(display,windows,&event,exception); 4898 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4899 XHighlightRectangle(display,windows->image.id, 4900 windows->image.highlight_context,&highlight_info); 4901 switch (event.type) 4902 { 4903 case ButtonPress: 4904 { 4905 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4906 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4907 break; 4908 } 4909 case ButtonRelease: 4910 { 4911 /* 4912 User has committed to cropping rectangle. 4913 */ 4914 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4915 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4916 XSetCursorState(display,windows,MagickFalse); 4917 state|=ExitState; 4918 windows->command.data=0; 4919 (void) XCommandWidget(display,windows,RectifyModeMenu, 4920 (XEvent *) NULL); 4921 break; 4922 } 4923 case Expose: 4924 break; 4925 case MotionNotify: 4926 { 4927 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 4928 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 4929 } 4930 default: 4931 break; 4932 } 4933 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 4934 ((state & ExitState) != 0)) 4935 { 4936 /* 4937 Check boundary conditions. 4938 */ 4939 if (crop_info.x < 0) 4940 crop_info.x=0; 4941 else 4942 if (crop_info.x > (ssize_t) windows->image.ximage->width) 4943 crop_info.x=(ssize_t) windows->image.ximage->width; 4944 if ((int) crop_info.x < x) 4945 crop_info.width=(unsigned int) (x-crop_info.x); 4946 else 4947 { 4948 crop_info.width=(unsigned int) (crop_info.x-x); 4949 crop_info.x=(ssize_t) x; 4950 } 4951 if (crop_info.y < 0) 4952 crop_info.y=0; 4953 else 4954 if (crop_info.y > (ssize_t) windows->image.ximage->height) 4955 crop_info.y=(ssize_t) windows->image.ximage->height; 4956 if ((int) crop_info.y < y) 4957 crop_info.height=(unsigned int) (y-crop_info.y); 4958 else 4959 { 4960 crop_info.height=(unsigned int) (crop_info.y-y); 4961 crop_info.y=(ssize_t) y; 4962 } 4963 } 4964 } while ((state & ExitState) == 0); 4965 /* 4966 Wait for user to grab a corner of the rectangle or press return. 4967 */ 4968 state=DefaultState; 4969 (void) XMapWindow(display,windows->info.id); 4970 do 4971 { 4972 if (IfMagickTrue(windows->info.mapped) ) 4973 { 4974 /* 4975 Display pointer position. 4976 */ 4977 (void) FormatLocaleString(text,MaxTextExtent, 4978 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4979 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4980 XInfoWidget(display,windows,text); 4981 } 4982 highlight_info=crop_info; 4983 highlight_info.x=crop_info.x-windows->image.x; 4984 highlight_info.y=crop_info.y-windows->image.y; 4985 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 4986 { 4987 state|=EscapeState; 4988 state|=ExitState; 4989 break; 4990 } 4991 XHighlightRectangle(display,windows->image.id, 4992 windows->image.highlight_context,&highlight_info); 4993 XScreenEvent(display,windows,&event,exception); 4994 if (event.xany.window == windows->command.id) 4995 { 4996 /* 4997 Select a command from the Command widget. 4998 */ 4999 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5000 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 5001 (void) XSetFunction(display,windows->image.highlight_context, 5002 GXinvert); 5003 XHighlightRectangle(display,windows->image.id, 5004 windows->image.highlight_context,&highlight_info); 5005 if (id >= 0) 5006 switch (RectifyCommands[id]) 5007 { 5008 case RectifyCopyCommand: 5009 { 5010 state|=ExitState; 5011 break; 5012 } 5013 case RectifyHelpCommand: 5014 { 5015 (void) XSetFunction(display,windows->image.highlight_context, 5016 GXcopy); 5017 switch (mode) 5018 { 5019 case CopyMode: 5020 { 5021 XTextViewWidget(display,resource_info,windows,MagickFalse, 5022 "Help Viewer - Image Copy",ImageCopyHelp); 5023 break; 5024 } 5025 case CropMode: 5026 { 5027 XTextViewWidget(display,resource_info,windows,MagickFalse, 5028 "Help Viewer - Image Crop",ImageCropHelp); 5029 break; 5030 } 5031 case CutMode: 5032 { 5033 XTextViewWidget(display,resource_info,windows,MagickFalse, 5034 "Help Viewer - Image Cut",ImageCutHelp); 5035 break; 5036 } 5037 } 5038 (void) XSetFunction(display,windows->image.highlight_context, 5039 GXinvert); 5040 break; 5041 } 5042 case RectifyDismissCommand: 5043 { 5044 /* 5045 Prematurely exit. 5046 */ 5047 state|=EscapeState; 5048 state|=ExitState; 5049 break; 5050 } 5051 default: 5052 break; 5053 } 5054 continue; 5055 } 5056 XHighlightRectangle(display,windows->image.id, 5057 windows->image.highlight_context,&highlight_info); 5058 switch (event.type) 5059 { 5060 case ButtonPress: 5061 { 5062 if (event.xbutton.button != Button1) 5063 break; 5064 if (event.xbutton.window != windows->image.id) 5065 break; 5066 x=windows->image.x+event.xbutton.x; 5067 y=windows->image.y+event.xbutton.y; 5068 if ((x < (int) (crop_info.x+RoiDelta)) && 5069 (x > (int) (crop_info.x-RoiDelta)) && 5070 (y < (int) (crop_info.y+RoiDelta)) && 5071 (y > (int) (crop_info.y-RoiDelta))) 5072 { 5073 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5074 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5075 state|=UpdateConfigurationState; 5076 break; 5077 } 5078 if ((x < (int) (crop_info.x+RoiDelta)) && 5079 (x > (int) (crop_info.x-RoiDelta)) && 5080 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5081 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5082 { 5083 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5084 state|=UpdateConfigurationState; 5085 break; 5086 } 5087 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5088 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5089 (y < (int) (crop_info.y+RoiDelta)) && 5090 (y > (int) (crop_info.y-RoiDelta))) 5091 { 5092 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5093 state|=UpdateConfigurationState; 5094 break; 5095 } 5096 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5097 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5098 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5099 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5100 { 5101 state|=UpdateConfigurationState; 5102 break; 5103 } 5104 } 5105 case ButtonRelease: 5106 { 5107 if (event.xbutton.window == windows->pan.id) 5108 if ((highlight_info.x != crop_info.x-windows->image.x) || 5109 (highlight_info.y != crop_info.y-windows->image.y)) 5110 XHighlightRectangle(display,windows->image.id, 5111 windows->image.highlight_context,&highlight_info); 5112 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5113 event.xbutton.time); 5114 break; 5115 } 5116 case Expose: 5117 { 5118 if (event.xexpose.window == windows->image.id) 5119 if (event.xexpose.count == 0) 5120 { 5121 event.xexpose.x=(int) highlight_info.x; 5122 event.xexpose.y=(int) highlight_info.y; 5123 event.xexpose.width=(int) highlight_info.width; 5124 event.xexpose.height=(int) highlight_info.height; 5125 XRefreshWindow(display,&windows->image,&event); 5126 } 5127 if (event.xexpose.window == windows->info.id) 5128 if (event.xexpose.count == 0) 5129 XInfoWidget(display,windows,text); 5130 break; 5131 } 5132 case KeyPress: 5133 { 5134 if (event.xkey.window != windows->image.id) 5135 break; 5136 /* 5137 Respond to a user key press. 5138 */ 5139 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5140 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5141 switch ((int) key_symbol) 5142 { 5143 case XK_Escape: 5144 case XK_F20: 5145 state|=EscapeState; 5146 case XK_Return: 5147 { 5148 state|=ExitState; 5149 break; 5150 } 5151 case XK_Home: 5152 case XK_KP_Home: 5153 { 5154 crop_info.x=(ssize_t) (windows->image.width/2L- 5155 crop_info.width/2L); 5156 crop_info.y=(ssize_t) (windows->image.height/2L- 5157 crop_info.height/2L); 5158 break; 5159 } 5160 case XK_Left: 5161 case XK_KP_Left: 5162 { 5163 crop_info.x--; 5164 break; 5165 } 5166 case XK_Up: 5167 case XK_KP_Up: 5168 case XK_Next: 5169 { 5170 crop_info.y--; 5171 break; 5172 } 5173 case XK_Right: 5174 case XK_KP_Right: 5175 { 5176 crop_info.x++; 5177 break; 5178 } 5179 case XK_Prior: 5180 case XK_Down: 5181 case XK_KP_Down: 5182 { 5183 crop_info.y++; 5184 break; 5185 } 5186 case XK_F1: 5187 case XK_Help: 5188 { 5189 (void) XSetFunction(display,windows->image.highlight_context, 5190 GXcopy); 5191 switch (mode) 5192 { 5193 case CopyMode: 5194 { 5195 XTextViewWidget(display,resource_info,windows,MagickFalse, 5196 "Help Viewer - Image Copy",ImageCopyHelp); 5197 break; 5198 } 5199 case CropMode: 5200 { 5201 XTextViewWidget(display,resource_info,windows,MagickFalse, 5202 "Help Viewer - Image Cropg",ImageCropHelp); 5203 break; 5204 } 5205 case CutMode: 5206 { 5207 XTextViewWidget(display,resource_info,windows,MagickFalse, 5208 "Help Viewer - Image Cutg",ImageCutHelp); 5209 break; 5210 } 5211 } 5212 (void) XSetFunction(display,windows->image.highlight_context, 5213 GXinvert); 5214 break; 5215 } 5216 default: 5217 { 5218 (void) XBell(display,0); 5219 break; 5220 } 5221 } 5222 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5223 event.xkey.time); 5224 break; 5225 } 5226 case KeyRelease: 5227 break; 5228 case MotionNotify: 5229 { 5230 if (event.xmotion.window != windows->image.id) 5231 break; 5232 /* 5233 Map and unmap Info widget as text cursor crosses its boundaries. 5234 */ 5235 x=event.xmotion.x; 5236 y=event.xmotion.y; 5237 if (IfMagickTrue(windows->info.mapped) ) 5238 { 5239 if ((x < (int) (windows->info.x+windows->info.width)) && 5240 (y < (int) (windows->info.y+windows->info.height))) 5241 (void) XWithdrawWindow(display,windows->info.id, 5242 windows->info.screen); 5243 } 5244 else 5245 if ((x > (int) (windows->info.x+windows->info.width)) || 5246 (y > (int) (windows->info.y+windows->info.height))) 5247 (void) XMapWindow(display,windows->info.id); 5248 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 5249 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 5250 break; 5251 } 5252 case SelectionRequest: 5253 { 5254 XSelectionEvent 5255 notify; 5256 5257 XSelectionRequestEvent 5258 *request; 5259 5260 /* 5261 Set primary selection. 5262 */ 5263 (void) FormatLocaleString(text,MaxTextExtent, 5264 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 5265 crop_info.height,(double) crop_info.x,(double) crop_info.y); 5266 request=(&(event.xselectionrequest)); 5267 (void) XChangeProperty(request->display,request->requestor, 5268 request->property,request->target,8,PropModeReplace, 5269 (unsigned char *) text,(int) strlen(text)); 5270 notify.type=SelectionNotify; 5271 notify.display=request->display; 5272 notify.requestor=request->requestor; 5273 notify.selection=request->selection; 5274 notify.target=request->target; 5275 notify.time=request->time; 5276 if (request->property == None) 5277 notify.property=request->target; 5278 else 5279 notify.property=request->property; 5280 (void) XSendEvent(request->display,request->requestor,False,0, 5281 (XEvent *) ¬ify); 5282 } 5283 default: 5284 break; 5285 } 5286 if ((state & UpdateConfigurationState) != 0) 5287 { 5288 (void) XPutBackEvent(display,&event); 5289 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5290 break; 5291 } 5292 } while ((state & ExitState) == 0); 5293 } while ((state & ExitState) == 0); 5294 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5295 XSetCursorState(display,windows,MagickFalse); 5296 if ((state & EscapeState) != 0) 5297 return(MagickTrue); 5298 if (mode == CropMode) 5299 if (((int) crop_info.width != windows->image.ximage->width) || 5300 ((int) crop_info.height != windows->image.ximage->height)) 5301 { 5302 /* 5303 Reconfigure Image window as defined by cropping rectangle. 5304 */ 5305 XSetCropGeometry(display,windows,&crop_info,image); 5306 windows->image.window_changes.width=(int) crop_info.width; 5307 windows->image.window_changes.height=(int) crop_info.height; 5308 (void) XConfigureImage(display,resource_info,windows,image,exception); 5309 return(MagickTrue); 5310 } 5311 /* 5312 Copy image before applying image transforms. 5313 */ 5314 XSetCursorState(display,windows,MagickTrue); 5315 XCheckRefreshWindows(display,windows); 5316 width=(unsigned int) image->columns; 5317 height=(unsigned int) image->rows; 5318 x=0; 5319 y=0; 5320 if (windows->image.crop_geometry != (char *) NULL) 5321 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 5322 scale_factor=(double) width/windows->image.ximage->width; 5323 crop_info.x+=x; 5324 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 5325 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 5326 scale_factor=(double) height/windows->image.ximage->height; 5327 crop_info.y+=y; 5328 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 5329 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5); 5330 crop_image=CropImage(image,&crop_info,exception); 5331 XSetCursorState(display,windows,MagickFalse); 5332 if (crop_image == (Image *) NULL) 5333 return(MagickFalse); 5334 if (resource_info->copy_image != (Image *) NULL) 5335 resource_info->copy_image=DestroyImage(resource_info->copy_image); 5336 resource_info->copy_image=crop_image; 5337 if (mode == CopyMode) 5338 { 5339 (void) XConfigureImage(display,resource_info,windows,image,exception); 5340 return(MagickTrue); 5341 } 5342 /* 5343 Cut image. 5344 */ 5345 if (IfMagickFalse(SetImageStorageClass(image,DirectClass,exception)) ) 5346 return(MagickFalse); 5347 image->alpha_trait=BlendPixelTrait; 5348 image_view=AcquireAuthenticCacheView(image,exception); 5349 for (y=0; y < (int) crop_info.height; y++) 5350 { 5351 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y, 5352 crop_info.width,1,exception); 5353 if (q == (Quantum *) NULL) 5354 break; 5355 for (x=0; x < (int) crop_info.width; x++) 5356 { 5357 SetPixelAlpha(image,TransparentAlpha,q); 5358 q+=GetPixelChannels(image); 5359 } 5360 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 5361 break; 5362 } 5363 image_view=DestroyCacheView(image_view); 5364 /* 5365 Update image configuration. 5366 */ 5367 XConfigureImageColormap(display,resource_info,windows,image,exception); 5368 (void) XConfigureImage(display,resource_info,windows,image,exception); 5369 return(MagickTrue); 5370} 5371 5372/* 5373%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5374% % 5375% % 5376% % 5377+ X D r a w I m a g e % 5378% % 5379% % 5380% % 5381%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5382% 5383% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on 5384% the image. 5385% 5386% The format of the XDrawEditImage method is: 5387% 5388% MagickBooleanType XDrawEditImage(Display *display, 5389% XResourceInfo *resource_info,XWindows *windows,Image **image, 5390% ExceptionInfo *exception) 5391% 5392% A description of each parameter follows: 5393% 5394% o display: Specifies a connection to an X server; returned from 5395% XOpenDisplay. 5396% 5397% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 5398% 5399% o windows: Specifies a pointer to a XWindows structure. 5400% 5401% o image: the image. 5402% 5403% o exception: return any errors or warnings in this structure. 5404% 5405*/ 5406static MagickBooleanType XDrawEditImage(Display *display, 5407 XResourceInfo *resource_info,XWindows *windows,Image **image, 5408 ExceptionInfo *exception) 5409{ 5410 static const char 5411 *DrawMenu[] = 5412 { 5413 "Element", 5414 "Color", 5415 "Stipple", 5416 "Width", 5417 "Undo", 5418 "Help", 5419 "Dismiss", 5420 (char *) NULL 5421 }; 5422 5423 static ElementType 5424 element = PointElement; 5425 5426 static const ModeType 5427 DrawCommands[] = 5428 { 5429 DrawElementCommand, 5430 DrawColorCommand, 5431 DrawStippleCommand, 5432 DrawWidthCommand, 5433 DrawUndoCommand, 5434 DrawHelpCommand, 5435 DrawDismissCommand 5436 }; 5437 5438 static Pixmap 5439 stipple = (Pixmap) NULL; 5440 5441 static unsigned int 5442 pen_id = 0, 5443 line_width = 1; 5444 5445 char 5446 command[MaxTextExtent], 5447 text[MaxTextExtent]; 5448 5449 Cursor 5450 cursor; 5451 5452 int 5453 entry, 5454 id, 5455 number_coordinates, 5456 x, 5457 y; 5458 5459 double 5460 degrees; 5461 5462 MagickStatusType 5463 status; 5464 5465 RectangleInfo 5466 rectangle_info; 5467 5468 register int 5469 i; 5470 5471 unsigned int 5472 distance, 5473 height, 5474 max_coordinates, 5475 width; 5476 5477 size_t 5478 state; 5479 5480 Window 5481 root_window; 5482 5483 XDrawInfo 5484 draw_info; 5485 5486 XEvent 5487 event; 5488 5489 XPoint 5490 *coordinate_info; 5491 5492 XSegment 5493 line_info; 5494 5495 /* 5496 Allocate polygon info. 5497 */ 5498 max_coordinates=2048; 5499 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates, 5500 sizeof(*coordinate_info)); 5501 if (coordinate_info == (XPoint *) NULL) 5502 { 5503 (void) ThrowMagickException(exception,GetMagickModule(), 5504 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 5505 return(MagickFalse); 5506 } 5507 /* 5508 Map Command widget. 5509 */ 5510 (void) CloneString(&windows->command.name,"Draw"); 5511 windows->command.data=4; 5512 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL); 5513 (void) XMapRaised(display,windows->command.id); 5514 XClientMessage(display,windows->image.id,windows->im_protocols, 5515 windows->im_update_widget,CurrentTime); 5516 /* 5517 Wait for first button press. 5518 */ 5519 root_window=XRootWindow(display,XDefaultScreen(display)); 5520 draw_info.stencil=OpaqueStencil; 5521 status=MagickTrue; 5522 cursor=XCreateFontCursor(display,XC_tcross); 5523 for ( ; ; ) 5524 { 5525 XQueryPosition(display,windows->image.id,&x,&y); 5526 (void) XSelectInput(display,windows->image.id, 5527 windows->image.attributes.event_mask | PointerMotionMask); 5528 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5529 state=DefaultState; 5530 do 5531 { 5532 if (IfMagickTrue(windows->info.mapped) ) 5533 { 5534 /* 5535 Display pointer position. 5536 */ 5537 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 5538 x+windows->image.x,y+windows->image.y); 5539 XInfoWidget(display,windows,text); 5540 } 5541 /* 5542 Wait for next event. 5543 */ 5544 XScreenEvent(display,windows,&event,exception); 5545 if (event.xany.window == windows->command.id) 5546 { 5547 /* 5548 Select a command from the Command widget. 5549 */ 5550 id=XCommandWidget(display,windows,DrawMenu,&event); 5551 if (id < 0) 5552 continue; 5553 switch (DrawCommands[id]) 5554 { 5555 case DrawElementCommand: 5556 { 5557 static const char 5558 *Elements[] = 5559 { 5560 "point", 5561 "line", 5562 "rectangle", 5563 "fill rectangle", 5564 "circle", 5565 "fill circle", 5566 "ellipse", 5567 "fill ellipse", 5568 "polygon", 5569 "fill polygon", 5570 (char *) NULL, 5571 }; 5572 5573 /* 5574 Select a command from the pop-up menu. 5575 */ 5576 element=(ElementType) (XMenuWidget(display,windows, 5577 DrawMenu[id],Elements,command)+1); 5578 break; 5579 } 5580 case DrawColorCommand: 5581 { 5582 const char 5583 *ColorMenu[MaxNumberPens+1]; 5584 5585 int 5586 pen_number; 5587 5588 MagickBooleanType 5589 transparent; 5590 5591 XColor 5592 color; 5593 5594 /* 5595 Initialize menu selections. 5596 */ 5597 for (i=0; i < (int) (MaxNumberPens-2); i++) 5598 ColorMenu[i]=resource_info->pen_colors[i]; 5599 ColorMenu[MaxNumberPens-2]="transparent"; 5600 ColorMenu[MaxNumberPens-1]="Browser..."; 5601 ColorMenu[MaxNumberPens]=(char *) NULL; 5602 /* 5603 Select a pen color from the pop-up menu. 5604 */ 5605 pen_number=XMenuWidget(display,windows,DrawMenu[id], 5606 (const char **) ColorMenu,command); 5607 if (pen_number < 0) 5608 break; 5609 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue : 5610 MagickFalse; 5611 if (IfMagickTrue(transparent) ) 5612 { 5613 draw_info.stencil=TransparentStencil; 5614 break; 5615 } 5616 if (pen_number == (MaxNumberPens-1)) 5617 { 5618 static char 5619 color_name[MaxTextExtent] = "gray"; 5620 5621 /* 5622 Select a pen color from a dialog. 5623 */ 5624 resource_info->pen_colors[pen_number]=color_name; 5625 XColorBrowserWidget(display,windows,"Select",color_name); 5626 if (*color_name == '\0') 5627 break; 5628 } 5629 /* 5630 Set pen color. 5631 */ 5632 (void) XParseColor(display,windows->map_info->colormap, 5633 resource_info->pen_colors[pen_number],&color); 5634 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 5635 (unsigned int) MaxColors,&color); 5636 windows->pixel_info->pen_colors[pen_number]=color; 5637 pen_id=(unsigned int) pen_number; 5638 draw_info.stencil=OpaqueStencil; 5639 break; 5640 } 5641 case DrawStippleCommand: 5642 { 5643 Image 5644 *stipple_image; 5645 5646 ImageInfo 5647 *image_info; 5648 5649 int 5650 status; 5651 5652 static char 5653 filename[MaxTextExtent] = "\0"; 5654 5655 static const char 5656 *StipplesMenu[] = 5657 { 5658 "Brick", 5659 "Diagonal", 5660 "Scales", 5661 "Vertical", 5662 "Wavy", 5663 "Translucent", 5664 "Opaque", 5665 (char *) NULL, 5666 (char *) NULL, 5667 }; 5668 5669 /* 5670 Select a command from the pop-up menu. 5671 */ 5672 StipplesMenu[7]="Open..."; 5673 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu, 5674 command); 5675 if (entry < 0) 5676 break; 5677 if (stipple != (Pixmap) NULL) 5678 (void) XFreePixmap(display,stipple); 5679 stipple=(Pixmap) NULL; 5680 if (entry != 7) 5681 { 5682 switch (entry) 5683 { 5684 case 0: 5685 { 5686 stipple=XCreateBitmapFromData(display,root_window, 5687 (char *) BricksBitmap,BricksWidth,BricksHeight); 5688 break; 5689 } 5690 case 1: 5691 { 5692 stipple=XCreateBitmapFromData(display,root_window, 5693 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight); 5694 break; 5695 } 5696 case 2: 5697 { 5698 stipple=XCreateBitmapFromData(display,root_window, 5699 (char *) ScalesBitmap,ScalesWidth,ScalesHeight); 5700 break; 5701 } 5702 case 3: 5703 { 5704 stipple=XCreateBitmapFromData(display,root_window, 5705 (char *) VerticalBitmap,VerticalWidth,VerticalHeight); 5706 break; 5707 } 5708 case 4: 5709 { 5710 stipple=XCreateBitmapFromData(display,root_window, 5711 (char *) WavyBitmap,WavyWidth,WavyHeight); 5712 break; 5713 } 5714 case 5: 5715 { 5716 stipple=XCreateBitmapFromData(display,root_window, 5717 (char *) HighlightBitmap,HighlightWidth, 5718 HighlightHeight); 5719 break; 5720 } 5721 case 6: 5722 default: 5723 { 5724 stipple=XCreateBitmapFromData(display,root_window, 5725 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight); 5726 break; 5727 } 5728 } 5729 break; 5730 } 5731 XFileBrowserWidget(display,windows,"Stipple",filename); 5732 if (*filename == '\0') 5733 break; 5734 /* 5735 Read image. 5736 */ 5737 XSetCursorState(display,windows,MagickTrue); 5738 XCheckRefreshWindows(display,windows); 5739 image_info=AcquireImageInfo(); 5740 (void) CopyMagickString(image_info->filename,filename, 5741 MaxTextExtent); 5742 stipple_image=ReadImage(image_info,exception); 5743 CatchException(exception); 5744 XSetCursorState(display,windows,MagickFalse); 5745 if (stipple_image == (Image *) NULL) 5746 break; 5747 (void) AcquireUniqueFileResource(filename); 5748 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent, 5749 "xbm:%s",filename); 5750 (void) WriteImage(image_info,stipple_image,exception); 5751 stipple_image=DestroyImage(stipple_image); 5752 image_info=DestroyImageInfo(image_info); 5753 status=XReadBitmapFile(display,root_window,filename,&width, 5754 &height,&stipple,&x,&y); 5755 (void) RelinquishUniqueFileResource(filename); 5756 if ((status != BitmapSuccess) != 0) 5757 XNoticeWidget(display,windows,"Unable to read X bitmap image:", 5758 filename); 5759 break; 5760 } 5761 case DrawWidthCommand: 5762 { 5763 static char 5764 width[MaxTextExtent] = "0"; 5765 5766 static const char 5767 *WidthsMenu[] = 5768 { 5769 "1", 5770 "2", 5771 "4", 5772 "8", 5773 "16", 5774 "Dialog...", 5775 (char *) NULL, 5776 }; 5777 5778 /* 5779 Select a command from the pop-up menu. 5780 */ 5781 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu, 5782 command); 5783 if (entry < 0) 5784 break; 5785 if (entry != 5) 5786 { 5787 line_width=(unsigned int) StringToUnsignedLong( 5788 WidthsMenu[entry]); 5789 break; 5790 } 5791 (void) XDialogWidget(display,windows,"Ok","Enter line width:", 5792 width); 5793 if (*width == '\0') 5794 break; 5795 line_width=(unsigned int) StringToUnsignedLong(width); 5796 break; 5797 } 5798 case DrawUndoCommand: 5799 { 5800 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 5801 image,exception); 5802 break; 5803 } 5804 case DrawHelpCommand: 5805 { 5806 XTextViewWidget(display,resource_info,windows,MagickFalse, 5807 "Help Viewer - Image Rotation",ImageDrawHelp); 5808 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5809 break; 5810 } 5811 case DrawDismissCommand: 5812 { 5813 /* 5814 Prematurely exit. 5815 */ 5816 state|=EscapeState; 5817 state|=ExitState; 5818 break; 5819 } 5820 default: 5821 break; 5822 } 5823 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5824 continue; 5825 } 5826 switch (event.type) 5827 { 5828 case ButtonPress: 5829 { 5830 if (event.xbutton.button != Button1) 5831 break; 5832 if (event.xbutton.window != windows->image.id) 5833 break; 5834 /* 5835 exit loop. 5836 */ 5837 x=event.xbutton.x; 5838 y=event.xbutton.y; 5839 state|=ExitState; 5840 break; 5841 } 5842 case ButtonRelease: 5843 break; 5844 case Expose: 5845 break; 5846 case KeyPress: 5847 { 5848 KeySym 5849 key_symbol; 5850 5851 if (event.xkey.window != windows->image.id) 5852 break; 5853 /* 5854 Respond to a user key press. 5855 */ 5856 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5857 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5858 switch ((int) key_symbol) 5859 { 5860 case XK_Escape: 5861 case XK_F20: 5862 { 5863 /* 5864 Prematurely exit. 5865 */ 5866 state|=EscapeState; 5867 state|=ExitState; 5868 break; 5869 } 5870 case XK_F1: 5871 case XK_Help: 5872 { 5873 XTextViewWidget(display,resource_info,windows,MagickFalse, 5874 "Help Viewer - Image Rotation",ImageDrawHelp); 5875 break; 5876 } 5877 default: 5878 { 5879 (void) XBell(display,0); 5880 break; 5881 } 5882 } 5883 break; 5884 } 5885 case MotionNotify: 5886 { 5887 /* 5888 Map and unmap Info widget as text cursor crosses its boundaries. 5889 */ 5890 x=event.xmotion.x; 5891 y=event.xmotion.y; 5892 if (IfMagickTrue(windows->info.mapped) ) 5893 { 5894 if ((x < (int) (windows->info.x+windows->info.width)) && 5895 (y < (int) (windows->info.y+windows->info.height))) 5896 (void) XWithdrawWindow(display,windows->info.id, 5897 windows->info.screen); 5898 } 5899 else 5900 if ((x > (int) (windows->info.x+windows->info.width)) || 5901 (y > (int) (windows->info.y+windows->info.height))) 5902 (void) XMapWindow(display,windows->info.id); 5903 break; 5904 } 5905 } 5906 } while ((state & ExitState) == 0); 5907 (void) XSelectInput(display,windows->image.id, 5908 windows->image.attributes.event_mask); 5909 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 5910 if ((state & EscapeState) != 0) 5911 break; 5912 /* 5913 Draw element as pointer moves until the button is released. 5914 */ 5915 distance=0; 5916 degrees=0.0; 5917 line_info.x1=x; 5918 line_info.y1=y; 5919 line_info.x2=x; 5920 line_info.y2=y; 5921 rectangle_info.x=(ssize_t) x; 5922 rectangle_info.y=(ssize_t) y; 5923 rectangle_info.width=0; 5924 rectangle_info.height=0; 5925 number_coordinates=1; 5926 coordinate_info->x=x; 5927 coordinate_info->y=y; 5928 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 5929 state=DefaultState; 5930 do 5931 { 5932 switch (element) 5933 { 5934 case PointElement: 5935 default: 5936 { 5937 if (number_coordinates > 1) 5938 { 5939 (void) XDrawLines(display,windows->image.id, 5940 windows->image.highlight_context,coordinate_info, 5941 number_coordinates,CoordModeOrigin); 5942 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d", 5943 coordinate_info[number_coordinates-1].x, 5944 coordinate_info[number_coordinates-1].y); 5945 XInfoWidget(display,windows,text); 5946 } 5947 break; 5948 } 5949 case LineElement: 5950 { 5951 if (distance > 9) 5952 { 5953 /* 5954 Display angle of the line. 5955 */ 5956 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 5957 line_info.y1),(double) (line_info.x2-line_info.x1))); 5958 (void) FormatLocaleString(text,MaxTextExtent," %g", 5959 (double) degrees); 5960 XInfoWidget(display,windows,text); 5961 XHighlightLine(display,windows->image.id, 5962 windows->image.highlight_context,&line_info); 5963 } 5964 else 5965 if (IfMagickTrue(windows->info.mapped) ) 5966 (void) XWithdrawWindow(display,windows->info.id, 5967 windows->info.screen); 5968 break; 5969 } 5970 case RectangleElement: 5971 case FillRectangleElement: 5972 { 5973 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5974 { 5975 /* 5976 Display info and draw drawing rectangle. 5977 */ 5978 (void) FormatLocaleString(text,MaxTextExtent, 5979 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5980 (double) rectangle_info.height,(double) rectangle_info.x, 5981 (double) rectangle_info.y); 5982 XInfoWidget(display,windows,text); 5983 XHighlightRectangle(display,windows->image.id, 5984 windows->image.highlight_context,&rectangle_info); 5985 } 5986 else 5987 if (IfMagickTrue(windows->info.mapped) ) 5988 (void) XWithdrawWindow(display,windows->info.id, 5989 windows->info.screen); 5990 break; 5991 } 5992 case CircleElement: 5993 case FillCircleElement: 5994 case EllipseElement: 5995 case FillEllipseElement: 5996 { 5997 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5998 { 5999 /* 6000 Display info and draw drawing rectangle. 6001 */ 6002 (void) FormatLocaleString(text,MaxTextExtent, 6003 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 6004 (double) rectangle_info.height,(double) rectangle_info.x, 6005 (double) rectangle_info.y); 6006 XInfoWidget(display,windows,text); 6007 XHighlightEllipse(display,windows->image.id, 6008 windows->image.highlight_context,&rectangle_info); 6009 } 6010 else 6011 if (IfMagickTrue(windows->info.mapped) ) 6012 (void) XWithdrawWindow(display,windows->info.id, 6013 windows->info.screen); 6014 break; 6015 } 6016 case PolygonElement: 6017 case FillPolygonElement: 6018 { 6019 if (number_coordinates > 1) 6020 (void) XDrawLines(display,windows->image.id, 6021 windows->image.highlight_context,coordinate_info, 6022 number_coordinates,CoordModeOrigin); 6023 if (distance > 9) 6024 { 6025 /* 6026 Display angle of the line. 6027 */ 6028 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 6029 line_info.y1),(double) (line_info.x2-line_info.x1))); 6030 (void) FormatLocaleString(text,MaxTextExtent," %g", 6031 (double) degrees); 6032 XInfoWidget(display,windows,text); 6033 XHighlightLine(display,windows->image.id, 6034 windows->image.highlight_context,&line_info); 6035 } 6036 else 6037 if (IfMagickTrue(windows->info.mapped) ) 6038 (void) XWithdrawWindow(display,windows->info.id, 6039 windows->info.screen); 6040 break; 6041 } 6042 } 6043 /* 6044 Wait for next event. 6045 */ 6046 XScreenEvent(display,windows,&event,exception); 6047 switch (element) 6048 { 6049 case PointElement: 6050 default: 6051 { 6052 if (number_coordinates > 1) 6053 (void) XDrawLines(display,windows->image.id, 6054 windows->image.highlight_context,coordinate_info, 6055 number_coordinates,CoordModeOrigin); 6056 break; 6057 } 6058 case LineElement: 6059 { 6060 if (distance > 9) 6061 XHighlightLine(display,windows->image.id, 6062 windows->image.highlight_context,&line_info); 6063 break; 6064 } 6065 case RectangleElement: 6066 case FillRectangleElement: 6067 { 6068 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6069 XHighlightRectangle(display,windows->image.id, 6070 windows->image.highlight_context,&rectangle_info); 6071 break; 6072 } 6073 case CircleElement: 6074 case FillCircleElement: 6075 case EllipseElement: 6076 case FillEllipseElement: 6077 { 6078 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6079 XHighlightEllipse(display,windows->image.id, 6080 windows->image.highlight_context,&rectangle_info); 6081 break; 6082 } 6083 case PolygonElement: 6084 case FillPolygonElement: 6085 { 6086 if (number_coordinates > 1) 6087 (void) XDrawLines(display,windows->image.id, 6088 windows->image.highlight_context,coordinate_info, 6089 number_coordinates,CoordModeOrigin); 6090 if (distance > 9) 6091 XHighlightLine(display,windows->image.id, 6092 windows->image.highlight_context,&line_info); 6093 break; 6094 } 6095 } 6096 switch (event.type) 6097 { 6098 case ButtonPress: 6099 break; 6100 case ButtonRelease: 6101 { 6102 /* 6103 User has committed to element. 6104 */ 6105 line_info.x2=event.xbutton.x; 6106 line_info.y2=event.xbutton.y; 6107 rectangle_info.x=(ssize_t) event.xbutton.x; 6108 rectangle_info.y=(ssize_t) event.xbutton.y; 6109 coordinate_info[number_coordinates].x=event.xbutton.x; 6110 coordinate_info[number_coordinates].y=event.xbutton.y; 6111 if (((element != PolygonElement) && 6112 (element != FillPolygonElement)) || (distance <= 9)) 6113 { 6114 state|=ExitState; 6115 break; 6116 } 6117 number_coordinates++; 6118 if (number_coordinates < (int) max_coordinates) 6119 { 6120 line_info.x1=event.xbutton.x; 6121 line_info.y1=event.xbutton.y; 6122 break; 6123 } 6124 max_coordinates<<=1; 6125 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6126 max_coordinates,sizeof(*coordinate_info)); 6127 if (coordinate_info == (XPoint *) NULL) 6128 (void) ThrowMagickException(exception,GetMagickModule(), 6129 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6130 break; 6131 } 6132 case Expose: 6133 break; 6134 case MotionNotify: 6135 { 6136 if (event.xmotion.window != windows->image.id) 6137 break; 6138 if (element != PointElement) 6139 { 6140 line_info.x2=event.xmotion.x; 6141 line_info.y2=event.xmotion.y; 6142 rectangle_info.x=(ssize_t) event.xmotion.x; 6143 rectangle_info.y=(ssize_t) event.xmotion.y; 6144 break; 6145 } 6146 coordinate_info[number_coordinates].x=event.xbutton.x; 6147 coordinate_info[number_coordinates].y=event.xbutton.y; 6148 number_coordinates++; 6149 if (number_coordinates < (int) max_coordinates) 6150 break; 6151 max_coordinates<<=1; 6152 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6153 max_coordinates,sizeof(*coordinate_info)); 6154 if (coordinate_info == (XPoint *) NULL) 6155 (void) ThrowMagickException(exception,GetMagickModule(), 6156 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6157 break; 6158 } 6159 default: 6160 break; 6161 } 6162 /* 6163 Check boundary conditions. 6164 */ 6165 if (line_info.x2 < 0) 6166 line_info.x2=0; 6167 else 6168 if (line_info.x2 > (int) windows->image.width) 6169 line_info.x2=(short) windows->image.width; 6170 if (line_info.y2 < 0) 6171 line_info.y2=0; 6172 else 6173 if (line_info.y2 > (int) windows->image.height) 6174 line_info.y2=(short) windows->image.height; 6175 distance=(unsigned int) 6176 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+ 6177 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1))); 6178 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) || 6179 ((state & ExitState) != 0)) 6180 { 6181 if (rectangle_info.x < 0) 6182 rectangle_info.x=0; 6183 else 6184 if (rectangle_info.x > (ssize_t) windows->image.width) 6185 rectangle_info.x=(ssize_t) windows->image.width; 6186 if ((int) rectangle_info.x < x) 6187 rectangle_info.width=(unsigned int) (x-rectangle_info.x); 6188 else 6189 { 6190 rectangle_info.width=(unsigned int) (rectangle_info.x-x); 6191 rectangle_info.x=(ssize_t) x; 6192 } 6193 if (rectangle_info.y < 0) 6194 rectangle_info.y=0; 6195 else 6196 if (rectangle_info.y > (ssize_t) windows->image.height) 6197 rectangle_info.y=(ssize_t) windows->image.height; 6198 if ((int) rectangle_info.y < y) 6199 rectangle_info.height=(unsigned int) (y-rectangle_info.y); 6200 else 6201 { 6202 rectangle_info.height=(unsigned int) (rectangle_info.y-y); 6203 rectangle_info.y=(ssize_t) y; 6204 } 6205 } 6206 } while ((state & ExitState) == 0); 6207 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 6208 if ((element == PointElement) || (element == PolygonElement) || 6209 (element == FillPolygonElement)) 6210 { 6211 /* 6212 Determine polygon bounding box. 6213 */ 6214 rectangle_info.x=(ssize_t) coordinate_info->x; 6215 rectangle_info.y=(ssize_t) coordinate_info->y; 6216 x=coordinate_info->x; 6217 y=coordinate_info->y; 6218 for (i=1; i < number_coordinates; i++) 6219 { 6220 if (coordinate_info[i].x > x) 6221 x=coordinate_info[i].x; 6222 if (coordinate_info[i].y > y) 6223 y=coordinate_info[i].y; 6224 if ((ssize_t) coordinate_info[i].x < rectangle_info.x) 6225 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0); 6226 if ((ssize_t) coordinate_info[i].y < rectangle_info.y) 6227 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0); 6228 } 6229 rectangle_info.width=(size_t) (x-rectangle_info.x); 6230 rectangle_info.height=(size_t) (y-rectangle_info.y); 6231 for (i=0; i < number_coordinates; i++) 6232 { 6233 coordinate_info[i].x-=rectangle_info.x; 6234 coordinate_info[i].y-=rectangle_info.y; 6235 } 6236 } 6237 else 6238 if (distance <= 9) 6239 continue; 6240 else 6241 if ((element == RectangleElement) || 6242 (element == CircleElement) || (element == EllipseElement)) 6243 { 6244 rectangle_info.width--; 6245 rectangle_info.height--; 6246 } 6247 /* 6248 Drawing is relative to image configuration. 6249 */ 6250 draw_info.x=(int) rectangle_info.x; 6251 draw_info.y=(int) rectangle_info.y; 6252 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand, 6253 image,exception); 6254 width=(unsigned int) (*image)->columns; 6255 height=(unsigned int) (*image)->rows; 6256 x=0; 6257 y=0; 6258 if (windows->image.crop_geometry != (char *) NULL) 6259 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 6260 draw_info.x+=windows->image.x-(line_width/2); 6261 if (draw_info.x < 0) 6262 draw_info.x=0; 6263 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width); 6264 draw_info.y+=windows->image.y-(line_width/2); 6265 if (draw_info.y < 0) 6266 draw_info.y=0; 6267 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height; 6268 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1); 6269 if (draw_info.width > (unsigned int) (*image)->columns) 6270 draw_info.width=(unsigned int) (*image)->columns; 6271 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1); 6272 if (draw_info.height > (unsigned int) (*image)->rows) 6273 draw_info.height=(unsigned int) (*image)->rows; 6274 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d", 6275 width*draw_info.width/windows->image.ximage->width, 6276 height*draw_info.height/windows->image.ximage->height, 6277 draw_info.x+x,draw_info.y+y); 6278 /* 6279 Initialize drawing attributes. 6280 */ 6281 draw_info.degrees=0.0; 6282 draw_info.element=element; 6283 draw_info.stipple=stipple; 6284 draw_info.line_width=line_width; 6285 draw_info.line_info=line_info; 6286 if (line_info.x1 > (int) (line_width/2)) 6287 draw_info.line_info.x1=(short) line_width/2; 6288 if (line_info.y1 > (int) (line_width/2)) 6289 draw_info.line_info.y1=(short) line_width/2; 6290 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2)); 6291 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2)); 6292 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0)) 6293 { 6294 draw_info.line_info.x2=(-draw_info.line_info.x2); 6295 draw_info.line_info.y2=(-draw_info.line_info.y2); 6296 } 6297 if (draw_info.line_info.x2 < 0) 6298 { 6299 draw_info.line_info.x2=(-draw_info.line_info.x2); 6300 Swap(draw_info.line_info.x1,draw_info.line_info.x2); 6301 } 6302 if (draw_info.line_info.y2 < 0) 6303 { 6304 draw_info.line_info.y2=(-draw_info.line_info.y2); 6305 Swap(draw_info.line_info.y1,draw_info.line_info.y2); 6306 } 6307 draw_info.rectangle_info=rectangle_info; 6308 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2)) 6309 draw_info.rectangle_info.x=(ssize_t) line_width/2; 6310 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2)) 6311 draw_info.rectangle_info.y=(ssize_t) line_width/2; 6312 draw_info.number_coordinates=(unsigned int) number_coordinates; 6313 draw_info.coordinate_info=coordinate_info; 6314 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 6315 /* 6316 Draw element on image. 6317 */ 6318 XSetCursorState(display,windows,MagickTrue); 6319 XCheckRefreshWindows(display,windows); 6320 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception); 6321 XSetCursorState(display,windows,MagickFalse); 6322 /* 6323 Update image colormap and return to image drawing. 6324 */ 6325 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6326 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6327 } 6328 XSetCursorState(display,windows,MagickFalse); 6329 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info); 6330 return(IsMagickTrue(status)); 6331} 6332 6333/* 6334%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6335% % 6336% % 6337% % 6338+ X D r a w P a n R e c t a n g l e % 6339% % 6340% % 6341% % 6342%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6343% 6344% XDrawPanRectangle() draws a rectangle in the pan window. The pan window 6345% displays a zoom image and the rectangle shows which portion of the image is 6346% displayed in the Image window. 6347% 6348% The format of the XDrawPanRectangle method is: 6349% 6350% XDrawPanRectangle(Display *display,XWindows *windows) 6351% 6352% A description of each parameter follows: 6353% 6354% o display: Specifies a connection to an X server; returned from 6355% XOpenDisplay. 6356% 6357% o windows: Specifies a pointer to a XWindows structure. 6358% 6359*/ 6360static void XDrawPanRectangle(Display *display,XWindows *windows) 6361{ 6362 double 6363 scale_factor; 6364 6365 RectangleInfo 6366 highlight_info; 6367 6368 /* 6369 Determine dimensions of the panning rectangle. 6370 */ 6371 scale_factor=(double) windows->pan.width/windows->image.ximage->width; 6372 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5); 6373 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5); 6374 scale_factor=(double) 6375 windows->pan.height/windows->image.ximage->height; 6376 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5); 6377 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5); 6378 /* 6379 Display the panning rectangle. 6380 */ 6381 (void) XClearWindow(display,windows->pan.id); 6382 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context, 6383 &highlight_info); 6384} 6385 6386/* 6387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6388% % 6389% % 6390% % 6391+ X I m a g e C a c h e % 6392% % 6393% % 6394% % 6395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6396% 6397% XImageCache() handles the creation, manipulation, and destruction of the 6398% image cache (undo and redo buffers). 6399% 6400% The format of the XImageCache method is: 6401% 6402% void XImageCache(Display *display,XResourceInfo *resource_info, 6403% XWindows *windows,const CommandType command,Image **image, 6404% ExceptionInfo *exception) 6405% 6406% A description of each parameter follows: 6407% 6408% o display: Specifies a connection to an X server; returned from 6409% XOpenDisplay. 6410% 6411% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6412% 6413% o windows: Specifies a pointer to a XWindows structure. 6414% 6415% o command: Specifies a command to perform. 6416% 6417% o image: the image; XImageCache may transform the image and return a new 6418% image pointer. 6419% 6420% o exception: return any errors or warnings in this structure. 6421% 6422*/ 6423static void XImageCache(Display *display,XResourceInfo *resource_info, 6424 XWindows *windows,const CommandType command,Image **image, 6425 ExceptionInfo *exception) 6426{ 6427 Image 6428 *cache_image; 6429 6430 static Image 6431 *redo_image = (Image *) NULL, 6432 *undo_image = (Image *) NULL; 6433 6434 switch (command) 6435 { 6436 case FreeBuffersCommand: 6437 { 6438 /* 6439 Free memory from the undo and redo cache. 6440 */ 6441 while (undo_image != (Image *) NULL) 6442 { 6443 cache_image=undo_image; 6444 undo_image=GetPreviousImageInList(undo_image); 6445 cache_image->list=DestroyImage(cache_image->list); 6446 cache_image=DestroyImage(cache_image); 6447 } 6448 undo_image=NewImageList(); 6449 if (redo_image != (Image *) NULL) 6450 redo_image=DestroyImage(redo_image); 6451 redo_image=NewImageList(); 6452 return; 6453 } 6454 case UndoCommand: 6455 { 6456 char 6457 image_geometry[MaxTextExtent]; 6458 6459 /* 6460 Undo the last image transformation. 6461 */ 6462 if (undo_image == (Image *) NULL) 6463 { 6464 (void) XBell(display,0); 6465 return; 6466 } 6467 cache_image=undo_image; 6468 undo_image=GetPreviousImageInList(undo_image); 6469 windows->image.window_changes.width=(int) cache_image->columns; 6470 windows->image.window_changes.height=(int) cache_image->rows; 6471 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 6472 windows->image.ximage->width,windows->image.ximage->height); 6473 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 6474 exception); 6475 if (windows->image.crop_geometry != (char *) NULL) 6476 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 6477 windows->image.crop_geometry); 6478 windows->image.crop_geometry=cache_image->geometry; 6479 if (redo_image != (Image *) NULL) 6480 redo_image=DestroyImage(redo_image); 6481 redo_image=(*image); 6482 *image=cache_image->list; 6483 cache_image=DestroyImage(cache_image); 6484 if (IfMagickTrue(windows->image.orphan) ) 6485 return; 6486 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6487 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6488 return; 6489 } 6490 case CutCommand: 6491 case PasteCommand: 6492 case ApplyCommand: 6493 case HalfSizeCommand: 6494 case OriginalSizeCommand: 6495 case DoubleSizeCommand: 6496 case ResizeCommand: 6497 case TrimCommand: 6498 case CropCommand: 6499 case ChopCommand: 6500 case FlipCommand: 6501 case FlopCommand: 6502 case RotateRightCommand: 6503 case RotateLeftCommand: 6504 case RotateCommand: 6505 case ShearCommand: 6506 case RollCommand: 6507 case NegateCommand: 6508 case ContrastStretchCommand: 6509 case SigmoidalContrastCommand: 6510 case NormalizeCommand: 6511 case EqualizeCommand: 6512 case HueCommand: 6513 case SaturationCommand: 6514 case BrightnessCommand: 6515 case GammaCommand: 6516 case SpiffCommand: 6517 case DullCommand: 6518 case GrayscaleCommand: 6519 case MapCommand: 6520 case QuantizeCommand: 6521 case DespeckleCommand: 6522 case EmbossCommand: 6523 case ReduceNoiseCommand: 6524 case AddNoiseCommand: 6525 case SharpenCommand: 6526 case BlurCommand: 6527 case ThresholdCommand: 6528 case EdgeDetectCommand: 6529 case SpreadCommand: 6530 case ShadeCommand: 6531 case RaiseCommand: 6532 case SegmentCommand: 6533 case SolarizeCommand: 6534 case SepiaToneCommand: 6535 case SwirlCommand: 6536 case ImplodeCommand: 6537 case VignetteCommand: 6538 case WaveCommand: 6539 case OilPaintCommand: 6540 case CharcoalDrawCommand: 6541 case AnnotateCommand: 6542 case AddBorderCommand: 6543 case AddFrameCommand: 6544 case CompositeCommand: 6545 case CommentCommand: 6546 case LaunchCommand: 6547 case RegionofInterestCommand: 6548 case SaveToUndoBufferCommand: 6549 case RedoCommand: 6550 { 6551 Image 6552 *previous_image; 6553 6554 ssize_t 6555 bytes; 6556 6557 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo)); 6558 if (undo_image != (Image *) NULL) 6559 { 6560 /* 6561 Ensure the undo cache has enough memory available. 6562 */ 6563 previous_image=undo_image; 6564 while (previous_image != (Image *) NULL) 6565 { 6566 bytes+=previous_image->list->columns*previous_image->list->rows* 6567 sizeof(PixelInfo); 6568 if (bytes <= (ssize_t) (resource_info->undo_cache << 20)) 6569 { 6570 previous_image=GetPreviousImageInList(previous_image); 6571 continue; 6572 } 6573 bytes-=previous_image->list->columns*previous_image->list->rows* 6574 sizeof(PixelInfo); 6575 if (previous_image == undo_image) 6576 undo_image=NewImageList(); 6577 else 6578 previous_image->next->previous=NewImageList(); 6579 break; 6580 } 6581 while (previous_image != (Image *) NULL) 6582 { 6583 /* 6584 Delete any excess memory from undo cache. 6585 */ 6586 cache_image=previous_image; 6587 previous_image=GetPreviousImageInList(previous_image); 6588 cache_image->list=DestroyImage(cache_image->list); 6589 cache_image=DestroyImage(cache_image); 6590 } 6591 } 6592 if (bytes > (ssize_t) (resource_info->undo_cache << 20)) 6593 break; 6594 /* 6595 Save image before transformations are applied. 6596 */ 6597 cache_image=AcquireImage((ImageInfo *) NULL,exception); 6598 if (cache_image == (Image *) NULL) 6599 break; 6600 XSetCursorState(display,windows,MagickTrue); 6601 XCheckRefreshWindows(display,windows); 6602 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception); 6603 XSetCursorState(display,windows,MagickFalse); 6604 if (cache_image->list == (Image *) NULL) 6605 { 6606 cache_image=DestroyImage(cache_image); 6607 break; 6608 } 6609 cache_image->columns=(size_t) windows->image.ximage->width; 6610 cache_image->rows=(size_t) windows->image.ximage->height; 6611 cache_image->geometry=windows->image.crop_geometry; 6612 if (windows->image.crop_geometry != (char *) NULL) 6613 { 6614 cache_image->geometry=AcquireString((char *) NULL); 6615 (void) CopyMagickString(cache_image->geometry, 6616 windows->image.crop_geometry,MaxTextExtent); 6617 } 6618 if (undo_image == (Image *) NULL) 6619 { 6620 undo_image=cache_image; 6621 break; 6622 } 6623 undo_image->next=cache_image; 6624 undo_image->next->previous=undo_image; 6625 undo_image=undo_image->next; 6626 break; 6627 } 6628 default: 6629 break; 6630 } 6631 if (command == RedoCommand) 6632 { 6633 /* 6634 Redo the last image transformation. 6635 */ 6636 if (redo_image == (Image *) NULL) 6637 { 6638 (void) XBell(display,0); 6639 return; 6640 } 6641 windows->image.window_changes.width=(int) redo_image->columns; 6642 windows->image.window_changes.height=(int) redo_image->rows; 6643 if (windows->image.crop_geometry != (char *) NULL) 6644 windows->image.crop_geometry=(char *) 6645 RelinquishMagickMemory(windows->image.crop_geometry); 6646 windows->image.crop_geometry=redo_image->geometry; 6647 *image=DestroyImage(*image); 6648 *image=redo_image; 6649 redo_image=NewImageList(); 6650 if (IfMagickTrue(windows->image.orphan) ) 6651 return; 6652 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6653 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6654 return; 6655 } 6656 if (command != InfoCommand) 6657 return; 6658 /* 6659 Display image info. 6660 */ 6661 XSetCursorState(display,windows,MagickTrue); 6662 XCheckRefreshWindows(display,windows); 6663 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception); 6664 XSetCursorState(display,windows,MagickFalse); 6665} 6666 6667/* 6668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6669% % 6670% % 6671% % 6672+ X I m a g e W i n d o w C o m m a n d % 6673% % 6674% % 6675% % 6676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6677% 6678% XImageWindowCommand() makes a transform to the image or Image window as 6679% specified by a user menu button or keyboard command. 6680% 6681% The format of the XImageWindowCommand method is: 6682% 6683% CommandType XImageWindowCommand(Display *display, 6684% XResourceInfo *resource_info,XWindows *windows, 6685% const MagickStatusType state,KeySym key_symbol,Image **image, 6686% ExceptionInfo *exception) 6687% 6688% A description of each parameter follows: 6689% 6690% o nexus: Method XImageWindowCommand returns an image when the 6691% user chooses 'Open Image' from the command menu. Otherwise a null 6692% image is returned. 6693% 6694% o display: Specifies a connection to an X server; returned from 6695% XOpenDisplay. 6696% 6697% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6698% 6699% o windows: Specifies a pointer to a XWindows structure. 6700% 6701% o state: key mask. 6702% 6703% o key_symbol: Specifies a command to perform. 6704% 6705% o image: the image; XImageWIndowCommand may transform the image and 6706% return a new image pointer. 6707% 6708% o exception: return any errors or warnings in this structure. 6709% 6710*/ 6711static CommandType XImageWindowCommand(Display *display, 6712 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state, 6713 KeySym key_symbol,Image **image,ExceptionInfo *exception) 6714{ 6715 static char 6716 delta[MaxTextExtent] = ""; 6717 6718 static const char 6719 Digits[] = "01234567890"; 6720 6721 static KeySym 6722 last_symbol = XK_0; 6723 6724 if ((key_symbol >= XK_0) && (key_symbol <= XK_9)) 6725 { 6726 if (((last_symbol < XK_0) || (last_symbol > XK_9))) 6727 { 6728 *delta='\0'; 6729 resource_info->quantum=1; 6730 } 6731 last_symbol=key_symbol; 6732 delta[strlen(delta)+1]='\0'; 6733 delta[strlen(delta)]=Digits[key_symbol-XK_0]; 6734 resource_info->quantum=StringToLong(delta); 6735 return(NullCommand); 6736 } 6737 last_symbol=key_symbol; 6738 if (resource_info->immutable) 6739 { 6740 /* 6741 Virtual image window has a restricted command set. 6742 */ 6743 switch (key_symbol) 6744 { 6745 case XK_question: 6746 return(InfoCommand); 6747 case XK_p: 6748 case XK_Print: 6749 return(PrintCommand); 6750 case XK_space: 6751 return(NextCommand); 6752 case XK_q: 6753 case XK_Escape: 6754 return(QuitCommand); 6755 default: 6756 break; 6757 } 6758 return(NullCommand); 6759 } 6760 switch ((int) key_symbol) 6761 { 6762 case XK_o: 6763 { 6764 if ((state & ControlMask) == 0) 6765 break; 6766 return(OpenCommand); 6767 } 6768 case XK_space: 6769 return(NextCommand); 6770 case XK_BackSpace: 6771 return(FormerCommand); 6772 case XK_s: 6773 { 6774 if ((state & Mod1Mask) != 0) 6775 return(SwirlCommand); 6776 if ((state & ControlMask) == 0) 6777 return(ShearCommand); 6778 return(SaveCommand); 6779 } 6780 case XK_p: 6781 case XK_Print: 6782 { 6783 if ((state & Mod1Mask) != 0) 6784 return(OilPaintCommand); 6785 if ((state & Mod4Mask) != 0) 6786 return(ColorCommand); 6787 if ((state & ControlMask) == 0) 6788 return(NullCommand); 6789 return(PrintCommand); 6790 } 6791 case XK_d: 6792 { 6793 if ((state & Mod4Mask) != 0) 6794 return(DrawCommand); 6795 if ((state & ControlMask) == 0) 6796 return(NullCommand); 6797 return(DeleteCommand); 6798 } 6799 case XK_Select: 6800 { 6801 if ((state & ControlMask) == 0) 6802 return(NullCommand); 6803 return(SelectCommand); 6804 } 6805 case XK_n: 6806 { 6807 if ((state & ControlMask) == 0) 6808 return(NullCommand); 6809 return(NewCommand); 6810 } 6811 case XK_q: 6812 case XK_Escape: 6813 return(QuitCommand); 6814 case XK_z: 6815 case XK_Undo: 6816 { 6817 if ((state & ControlMask) == 0) 6818 return(NullCommand); 6819 return(UndoCommand); 6820 } 6821 case XK_r: 6822 case XK_Redo: 6823 { 6824 if ((state & ControlMask) == 0) 6825 return(RollCommand); 6826 return(RedoCommand); 6827 } 6828 case XK_x: 6829 { 6830 if ((state & ControlMask) == 0) 6831 return(NullCommand); 6832 return(CutCommand); 6833 } 6834 case XK_c: 6835 { 6836 if ((state & Mod1Mask) != 0) 6837 return(CharcoalDrawCommand); 6838 if ((state & ControlMask) == 0) 6839 return(CropCommand); 6840 return(CopyCommand); 6841 } 6842 case XK_v: 6843 case XK_Insert: 6844 { 6845 if ((state & Mod4Mask) != 0) 6846 return(CompositeCommand); 6847 if ((state & ControlMask) == 0) 6848 return(FlipCommand); 6849 return(PasteCommand); 6850 } 6851 case XK_less: 6852 return(HalfSizeCommand); 6853 case XK_minus: 6854 return(OriginalSizeCommand); 6855 case XK_greater: 6856 return(DoubleSizeCommand); 6857 case XK_percent: 6858 return(ResizeCommand); 6859 case XK_at: 6860 return(RefreshCommand); 6861 case XK_bracketleft: 6862 return(ChopCommand); 6863 case XK_h: 6864 return(FlopCommand); 6865 case XK_slash: 6866 return(RotateRightCommand); 6867 case XK_backslash: 6868 return(RotateLeftCommand); 6869 case XK_asterisk: 6870 return(RotateCommand); 6871 case XK_t: 6872 return(TrimCommand); 6873 case XK_H: 6874 return(HueCommand); 6875 case XK_S: 6876 return(SaturationCommand); 6877 case XK_L: 6878 return(BrightnessCommand); 6879 case XK_G: 6880 return(GammaCommand); 6881 case XK_C: 6882 return(SpiffCommand); 6883 case XK_Z: 6884 return(DullCommand); 6885 case XK_N: 6886 return(NormalizeCommand); 6887 case XK_equal: 6888 return(EqualizeCommand); 6889 case XK_asciitilde: 6890 return(NegateCommand); 6891 case XK_period: 6892 return(GrayscaleCommand); 6893 case XK_numbersign: 6894 return(QuantizeCommand); 6895 case XK_F2: 6896 return(DespeckleCommand); 6897 case XK_F3: 6898 return(EmbossCommand); 6899 case XK_F4: 6900 return(ReduceNoiseCommand); 6901 case XK_F5: 6902 return(AddNoiseCommand); 6903 case XK_F6: 6904 return(SharpenCommand); 6905 case XK_F7: 6906 return(BlurCommand); 6907 case XK_F8: 6908 return(ThresholdCommand); 6909 case XK_F9: 6910 return(EdgeDetectCommand); 6911 case XK_F10: 6912 return(SpreadCommand); 6913 case XK_F11: 6914 return(ShadeCommand); 6915 case XK_F12: 6916 return(RaiseCommand); 6917 case XK_F13: 6918 return(SegmentCommand); 6919 case XK_i: 6920 { 6921 if ((state & Mod1Mask) == 0) 6922 return(NullCommand); 6923 return(ImplodeCommand); 6924 } 6925 case XK_w: 6926 { 6927 if ((state & Mod1Mask) == 0) 6928 return(NullCommand); 6929 return(WaveCommand); 6930 } 6931 case XK_m: 6932 { 6933 if ((state & Mod4Mask) == 0) 6934 return(NullCommand); 6935 return(MatteCommand); 6936 } 6937 case XK_b: 6938 { 6939 if ((state & Mod4Mask) == 0) 6940 return(NullCommand); 6941 return(AddBorderCommand); 6942 } 6943 case XK_f: 6944 { 6945 if ((state & Mod4Mask) == 0) 6946 return(NullCommand); 6947 return(AddFrameCommand); 6948 } 6949 case XK_exclam: 6950 { 6951 if ((state & Mod4Mask) == 0) 6952 return(NullCommand); 6953 return(CommentCommand); 6954 } 6955 case XK_a: 6956 { 6957 if ((state & Mod1Mask) != 0) 6958 return(ApplyCommand); 6959 if ((state & Mod4Mask) != 0) 6960 return(AnnotateCommand); 6961 if ((state & ControlMask) == 0) 6962 return(NullCommand); 6963 return(RegionofInterestCommand); 6964 } 6965 case XK_question: 6966 return(InfoCommand); 6967 case XK_plus: 6968 return(ZoomCommand); 6969 case XK_P: 6970 { 6971 if ((state & ShiftMask) == 0) 6972 return(NullCommand); 6973 return(ShowPreviewCommand); 6974 } 6975 case XK_Execute: 6976 return(LaunchCommand); 6977 case XK_F1: 6978 return(HelpCommand); 6979 case XK_Find: 6980 return(BrowseDocumentationCommand); 6981 case XK_Menu: 6982 { 6983 (void) XMapRaised(display,windows->command.id); 6984 return(NullCommand); 6985 } 6986 case XK_Next: 6987 case XK_Prior: 6988 case XK_Home: 6989 case XK_KP_Home: 6990 { 6991 XTranslateImage(display,windows,*image,key_symbol); 6992 return(NullCommand); 6993 } 6994 case XK_Up: 6995 case XK_KP_Up: 6996 case XK_Down: 6997 case XK_KP_Down: 6998 case XK_Left: 6999 case XK_KP_Left: 7000 case XK_Right: 7001 case XK_KP_Right: 7002 { 7003 if ((state & Mod1Mask) != 0) 7004 { 7005 RectangleInfo 7006 crop_info; 7007 7008 /* 7009 Trim one pixel from edge of image. 7010 */ 7011 crop_info.x=0; 7012 crop_info.y=0; 7013 crop_info.width=(size_t) windows->image.ximage->width; 7014 crop_info.height=(size_t) windows->image.ximage->height; 7015 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up)) 7016 { 7017 if (resource_info->quantum >= (int) crop_info.height) 7018 resource_info->quantum=(int) crop_info.height-1; 7019 crop_info.height-=resource_info->quantum; 7020 } 7021 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down)) 7022 { 7023 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y)) 7024 resource_info->quantum=(int) (crop_info.height-crop_info.y-1); 7025 crop_info.y+=resource_info->quantum; 7026 crop_info.height-=resource_info->quantum; 7027 } 7028 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left)) 7029 { 7030 if (resource_info->quantum >= (int) crop_info.width) 7031 resource_info->quantum=(int) crop_info.width-1; 7032 crop_info.width-=resource_info->quantum; 7033 } 7034 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right)) 7035 { 7036 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x)) 7037 resource_info->quantum=(int) (crop_info.width-crop_info.x-1); 7038 crop_info.x+=resource_info->quantum; 7039 crop_info.width-=resource_info->quantum; 7040 } 7041 if ((int) (windows->image.x+windows->image.width) > 7042 (int) crop_info.width) 7043 windows->image.x=(int) (crop_info.width-windows->image.width); 7044 if ((int) (windows->image.y+windows->image.height) > 7045 (int) crop_info.height) 7046 windows->image.y=(int) (crop_info.height-windows->image.height); 7047 XSetCropGeometry(display,windows,&crop_info,*image); 7048 windows->image.window_changes.width=(int) crop_info.width; 7049 windows->image.window_changes.height=(int) crop_info.height; 7050 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None); 7051 (void) XConfigureImage(display,resource_info,windows,*image, 7052 exception); 7053 return(NullCommand); 7054 } 7055 XTranslateImage(display,windows,*image,key_symbol); 7056 return(NullCommand); 7057 } 7058 default: 7059 return(NullCommand); 7060 } 7061 return(NullCommand); 7062} 7063 7064/* 7065%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7066% % 7067% % 7068% % 7069+ X M a g i c k C o m m a n d % 7070% % 7071% % 7072% % 7073%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7074% 7075% XMagickCommand() makes a transform to the image or Image window as 7076% specified by a user menu button or keyboard command. 7077% 7078% The format of the XMagickCommand method is: 7079% 7080% Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7081% XWindows *windows,const CommandType command,Image **image, 7082% ExceptionInfo *exception) 7083% 7084% A description of each parameter follows: 7085% 7086% o display: Specifies a connection to an X server; returned from 7087% XOpenDisplay. 7088% 7089% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 7090% 7091% o windows: Specifies a pointer to a XWindows structure. 7092% 7093% o command: Specifies a command to perform. 7094% 7095% o image: the image; XMagickCommand may transform the image and return a 7096% new image pointer. 7097% 7098% o exception: return any errors or warnings in this structure. 7099% 7100*/ 7101static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7102 XWindows *windows,const CommandType command,Image **image, 7103 ExceptionInfo *exception) 7104{ 7105 char 7106 filename[MaxTextExtent], 7107 geometry[MaxTextExtent], 7108 modulate_factors[MaxTextExtent]; 7109 7110 GeometryInfo 7111 geometry_info; 7112 7113 Image 7114 *nexus; 7115 7116 ImageInfo 7117 *image_info; 7118 7119 int 7120 x, 7121 y; 7122 7123 MagickStatusType 7124 flags, 7125 status; 7126 7127 QuantizeInfo 7128 quantize_info; 7129 7130 RectangleInfo 7131 page_geometry; 7132 7133 register int 7134 i; 7135 7136 static char 7137 color[MaxTextExtent] = "gray"; 7138 7139 unsigned int 7140 height, 7141 width; 7142 7143 /* 7144 Process user command. 7145 */ 7146 XCheckRefreshWindows(display,windows); 7147 XImageCache(display,resource_info,windows,command,image,exception); 7148 nexus=NewImageList(); 7149 windows->image.window_changes.width=windows->image.ximage->width; 7150 windows->image.window_changes.height=windows->image.ximage->height; 7151 image_info=CloneImageInfo(resource_info->image_info); 7152 SetGeometryInfo(&geometry_info); 7153 GetQuantizeInfo(&quantize_info); 7154 switch (command) 7155 { 7156 case OpenCommand: 7157 { 7158 /* 7159 Load image. 7160 */ 7161 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 7162 break; 7163 } 7164 case NextCommand: 7165 { 7166 /* 7167 Display next image. 7168 */ 7169 for (i=0; i < resource_info->quantum; i++) 7170 XClientMessage(display,windows->image.id,windows->im_protocols, 7171 windows->im_next_image,CurrentTime); 7172 break; 7173 } 7174 case FormerCommand: 7175 { 7176 /* 7177 Display former image. 7178 */ 7179 for (i=0; i < resource_info->quantum; i++) 7180 XClientMessage(display,windows->image.id,windows->im_protocols, 7181 windows->im_former_image,CurrentTime); 7182 break; 7183 } 7184 case SelectCommand: 7185 { 7186 int 7187 status; 7188 7189 /* 7190 Select image. 7191 */ 7192 if (*resource_info->home_directory == '\0') 7193 (void) CopyMagickString(resource_info->home_directory,".", 7194 MaxTextExtent); 7195 status=chdir(resource_info->home_directory); 7196 if (status == -1) 7197 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 7198 "UnableToOpenFile","%s",resource_info->home_directory); 7199 nexus=XOpenImage(display,resource_info,windows,MagickTrue); 7200 break; 7201 } 7202 case SaveCommand: 7203 { 7204 /* 7205 Save image. 7206 */ 7207 status=XSaveImage(display,resource_info,windows,*image,exception); 7208 if (IfMagickFalse(status) ) 7209 { 7210 char 7211 message[MaxTextExtent]; 7212 7213 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7214 exception->reason != (char *) NULL ? exception->reason : "", 7215 exception->description != (char *) NULL ? exception->description : 7216 ""); 7217 XNoticeWidget(display,windows,"Unable to save file:",message); 7218 break; 7219 } 7220 break; 7221 } 7222 case PrintCommand: 7223 { 7224 /* 7225 Print image. 7226 */ 7227 status=XPrintImage(display,resource_info,windows,*image,exception); 7228 if (IfMagickFalse(status) ) 7229 { 7230 char 7231 message[MaxTextExtent]; 7232 7233 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7234 exception->reason != (char *) NULL ? exception->reason : "", 7235 exception->description != (char *) NULL ? exception->description : 7236 ""); 7237 XNoticeWidget(display,windows,"Unable to print file:",message); 7238 break; 7239 } 7240 break; 7241 } 7242 case DeleteCommand: 7243 { 7244 static char 7245 filename[MaxTextExtent] = "\0"; 7246 7247 /* 7248 Delete image file. 7249 */ 7250 XFileBrowserWidget(display,windows,"Delete",filename); 7251 if (*filename == '\0') 7252 break; 7253 status=ShredFile(filename); 7254 if (IfMagickTrue(status) ) 7255 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7256 break; 7257 } 7258 case NewCommand: 7259 { 7260 int 7261 status; 7262 7263 static char 7264 color[MaxTextExtent] = "gray", 7265 geometry[MaxTextExtent] = "640x480"; 7266 7267 static const char 7268 *format = "gradient"; 7269 7270 /* 7271 Query user for canvas geometry. 7272 */ 7273 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7274 geometry); 7275 if (*geometry == '\0') 7276 break; 7277 if (status == 0) 7278 format="xc"; 7279 XColorBrowserWidget(display,windows,"Select",color); 7280 if (*color == '\0') 7281 break; 7282 /* 7283 Create canvas. 7284 */ 7285 (void) FormatLocaleString(image_info->filename,MaxTextExtent, 7286 "%s:%s",format,color); 7287 (void) CloneString(&image_info->size,geometry); 7288 nexus=ReadImage(image_info,exception); 7289 CatchException(exception); 7290 XClientMessage(display,windows->image.id,windows->im_protocols, 7291 windows->im_next_image,CurrentTime); 7292 break; 7293 } 7294 case VisualDirectoryCommand: 7295 { 7296 /* 7297 Visual Image directory. 7298 */ 7299 nexus=XVisualDirectoryImage(display,resource_info,windows,exception); 7300 break; 7301 } 7302 case QuitCommand: 7303 { 7304 /* 7305 exit program. 7306 */ 7307 if (IfMagickFalse(resource_info->confirm_exit) ) 7308 XClientMessage(display,windows->image.id,windows->im_protocols, 7309 windows->im_exit,CurrentTime); 7310 else 7311 { 7312 int 7313 status; 7314 7315 /* 7316 Confirm program exit. 7317 */ 7318 status=XConfirmWidget(display,windows,"Do you really want to exit", 7319 resource_info->client_name); 7320 if (status > 0) 7321 XClientMessage(display,windows->image.id,windows->im_protocols, 7322 windows->im_exit,CurrentTime); 7323 } 7324 break; 7325 } 7326 case CutCommand: 7327 { 7328 /* 7329 Cut image. 7330 */ 7331 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception); 7332 break; 7333 } 7334 case CopyCommand: 7335 { 7336 /* 7337 Copy image. 7338 */ 7339 (void) XCropImage(display,resource_info,windows,*image,CopyMode, 7340 exception); 7341 break; 7342 } 7343 case PasteCommand: 7344 { 7345 /* 7346 Paste image. 7347 */ 7348 status=XPasteImage(display,resource_info,windows,*image,exception); 7349 if (IfMagickFalse(status) ) 7350 { 7351 XNoticeWidget(display,windows,"Unable to paste X image", 7352 (*image)->filename); 7353 break; 7354 } 7355 break; 7356 } 7357 case HalfSizeCommand: 7358 { 7359 /* 7360 Half image size. 7361 */ 7362 windows->image.window_changes.width=windows->image.ximage->width/2; 7363 windows->image.window_changes.height=windows->image.ximage->height/2; 7364 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7365 break; 7366 } 7367 case OriginalSizeCommand: 7368 { 7369 /* 7370 Original image size. 7371 */ 7372 windows->image.window_changes.width=(int) (*image)->columns; 7373 windows->image.window_changes.height=(int) (*image)->rows; 7374 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7375 break; 7376 } 7377 case DoubleSizeCommand: 7378 { 7379 /* 7380 Double the image size. 7381 */ 7382 windows->image.window_changes.width=windows->image.ximage->width << 1; 7383 windows->image.window_changes.height=windows->image.ximage->height << 1; 7384 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7385 break; 7386 } 7387 case ResizeCommand: 7388 { 7389 int 7390 status; 7391 7392 size_t 7393 height, 7394 width; 7395 7396 ssize_t 7397 x, 7398 y; 7399 7400 /* 7401 Resize image. 7402 */ 7403 width=(size_t) windows->image.ximage->width; 7404 height=(size_t) windows->image.ximage->height; 7405 x=0; 7406 y=0; 7407 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0", 7408 (double) width,(double) height); 7409 status=XDialogWidget(display,windows,"Resize", 7410 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7411 if (*geometry == '\0') 7412 break; 7413 if (status == 0) 7414 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent); 7415 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7416 windows->image.window_changes.width=(int) width; 7417 windows->image.window_changes.height=(int) height; 7418 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7419 break; 7420 } 7421 case ApplyCommand: 7422 { 7423 char 7424 image_geometry[MaxTextExtent]; 7425 7426 if ((windows->image.crop_geometry == (char *) NULL) && 7427 ((int) (*image)->columns == windows->image.ximage->width) && 7428 ((int) (*image)->rows == windows->image.ximage->height)) 7429 break; 7430 /* 7431 Apply size transforms to image. 7432 */ 7433 XSetCursorState(display,windows,MagickTrue); 7434 XCheckRefreshWindows(display,windows); 7435 /* 7436 Crop and/or scale displayed image. 7437 */ 7438 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 7439 windows->image.ximage->width,windows->image.ximage->height); 7440 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 7441 exception); 7442 if (windows->image.crop_geometry != (char *) NULL) 7443 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 7444 windows->image.crop_geometry); 7445 windows->image.x=0; 7446 windows->image.y=0; 7447 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7448 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7449 break; 7450 } 7451 case RefreshCommand: 7452 { 7453 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7454 break; 7455 } 7456 case RestoreCommand: 7457 { 7458 /* 7459 Restore Image window to its original size. 7460 */ 7461 if ((windows->image.width == (unsigned int) (*image)->columns) && 7462 (windows->image.height == (unsigned int) (*image)->rows) && 7463 (windows->image.crop_geometry == (char *) NULL)) 7464 { 7465 (void) XBell(display,0); 7466 break; 7467 } 7468 windows->image.window_changes.width=(int) (*image)->columns; 7469 windows->image.window_changes.height=(int) (*image)->rows; 7470 if (windows->image.crop_geometry != (char *) NULL) 7471 { 7472 windows->image.crop_geometry=(char *) 7473 RelinquishMagickMemory(windows->image.crop_geometry); 7474 windows->image.crop_geometry=(char *) NULL; 7475 windows->image.x=0; 7476 windows->image.y=0; 7477 } 7478 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7479 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7480 break; 7481 } 7482 case CropCommand: 7483 { 7484 /* 7485 Crop image. 7486 */ 7487 (void) XCropImage(display,resource_info,windows,*image,CropMode, 7488 exception); 7489 break; 7490 } 7491 case ChopCommand: 7492 { 7493 /* 7494 Chop image. 7495 */ 7496 status=XChopImage(display,resource_info,windows,image,exception); 7497 if (IfMagickFalse(status) ) 7498 { 7499 XNoticeWidget(display,windows,"Unable to cut X image", 7500 (*image)->filename); 7501 break; 7502 } 7503 break; 7504 } 7505 case FlopCommand: 7506 { 7507 Image 7508 *flop_image; 7509 7510 /* 7511 Flop image scanlines. 7512 */ 7513 XSetCursorState(display,windows,MagickTrue); 7514 XCheckRefreshWindows(display,windows); 7515 flop_image=FlopImage(*image,exception); 7516 if (flop_image != (Image *) NULL) 7517 { 7518 *image=DestroyImage(*image); 7519 *image=flop_image; 7520 } 7521 CatchException(exception); 7522 XSetCursorState(display,windows,MagickFalse); 7523 if (windows->image.crop_geometry != (char *) NULL) 7524 { 7525 /* 7526 Flop crop geometry. 7527 */ 7528 width=(unsigned int) (*image)->columns; 7529 height=(unsigned int) (*image)->rows; 7530 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7531 &width,&height); 7532 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7533 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7534 } 7535 if (IfMagickTrue(windows->image.orphan) ) 7536 break; 7537 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7538 break; 7539 } 7540 case FlipCommand: 7541 { 7542 Image 7543 *flip_image; 7544 7545 /* 7546 Flip image scanlines. 7547 */ 7548 XSetCursorState(display,windows,MagickTrue); 7549 XCheckRefreshWindows(display,windows); 7550 flip_image=FlipImage(*image,exception); 7551 if (flip_image != (Image *) NULL) 7552 { 7553 *image=DestroyImage(*image); 7554 *image=flip_image; 7555 } 7556 CatchException(exception); 7557 XSetCursorState(display,windows,MagickFalse); 7558 if (windows->image.crop_geometry != (char *) NULL) 7559 { 7560 /* 7561 Flip crop geometry. 7562 */ 7563 width=(unsigned int) (*image)->columns; 7564 height=(unsigned int) (*image)->rows; 7565 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7566 &width,&height); 7567 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7568 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7569 } 7570 if (IfMagickTrue(windows->image.orphan) ) 7571 break; 7572 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7573 break; 7574 } 7575 case RotateRightCommand: 7576 { 7577 /* 7578 Rotate image 90 degrees clockwise. 7579 */ 7580 status=XRotateImage(display,resource_info,windows,90.0,image,exception); 7581 if (IfMagickFalse(status) ) 7582 { 7583 XNoticeWidget(display,windows,"Unable to rotate X image", 7584 (*image)->filename); 7585 break; 7586 } 7587 break; 7588 } 7589 case RotateLeftCommand: 7590 { 7591 /* 7592 Rotate image 90 degrees counter-clockwise. 7593 */ 7594 status=XRotateImage(display,resource_info,windows,-90.0,image,exception); 7595 if (IfMagickFalse(status) ) 7596 { 7597 XNoticeWidget(display,windows,"Unable to rotate X image", 7598 (*image)->filename); 7599 break; 7600 } 7601 break; 7602 } 7603 case RotateCommand: 7604 { 7605 /* 7606 Rotate image. 7607 */ 7608 status=XRotateImage(display,resource_info,windows,0.0,image,exception); 7609 if (IfMagickFalse(status) ) 7610 { 7611 XNoticeWidget(display,windows,"Unable to rotate X image", 7612 (*image)->filename); 7613 break; 7614 } 7615 break; 7616 } 7617 case ShearCommand: 7618 { 7619 Image 7620 *shear_image; 7621 7622 static char 7623 geometry[MaxTextExtent] = "45.0x45.0"; 7624 7625 /* 7626 Query user for shear color and geometry. 7627 */ 7628 XColorBrowserWidget(display,windows,"Select",color); 7629 if (*color == '\0') 7630 break; 7631 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7632 geometry); 7633 if (*geometry == '\0') 7634 break; 7635 /* 7636 Shear image. 7637 */ 7638 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7639 exception); 7640 XSetCursorState(display,windows,MagickTrue); 7641 XCheckRefreshWindows(display,windows); 7642 (void) QueryColorCompliance(color,AllCompliance, 7643 &(*image)->background_color,exception); 7644 flags=ParseGeometry(geometry,&geometry_info); 7645 if ((flags & SigmaValue) == 0) 7646 geometry_info.sigma=geometry_info.rho; 7647 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7648 exception); 7649 if (shear_image != (Image *) NULL) 7650 { 7651 *image=DestroyImage(*image); 7652 *image=shear_image; 7653 } 7654 CatchException(exception); 7655 XSetCursorState(display,windows,MagickFalse); 7656 if (IfMagickTrue(windows->image.orphan) ) 7657 break; 7658 windows->image.window_changes.width=(int) (*image)->columns; 7659 windows->image.window_changes.height=(int) (*image)->rows; 7660 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7661 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7662 break; 7663 } 7664 case RollCommand: 7665 { 7666 Image 7667 *roll_image; 7668 7669 static char 7670 geometry[MaxTextExtent] = "+2+2"; 7671 7672 /* 7673 Query user for the roll geometry. 7674 */ 7675 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7676 geometry); 7677 if (*geometry == '\0') 7678 break; 7679 /* 7680 Roll image. 7681 */ 7682 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7683 exception); 7684 XSetCursorState(display,windows,MagickTrue); 7685 XCheckRefreshWindows(display,windows); 7686 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7687 exception); 7688 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7689 exception); 7690 if (roll_image != (Image *) NULL) 7691 { 7692 *image=DestroyImage(*image); 7693 *image=roll_image; 7694 } 7695 CatchException(exception); 7696 XSetCursorState(display,windows,MagickFalse); 7697 if (IfMagickTrue(windows->image.orphan) ) 7698 break; 7699 windows->image.window_changes.width=(int) (*image)->columns; 7700 windows->image.window_changes.height=(int) (*image)->rows; 7701 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7702 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7703 break; 7704 } 7705 case TrimCommand: 7706 { 7707 static char 7708 fuzz[MaxTextExtent]; 7709 7710 /* 7711 Query user for the fuzz factor. 7712 */ 7713 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0* 7714 (*image)->fuzz/(QuantumRange+1.0)); 7715 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7716 if (*fuzz == '\0') 7717 break; 7718 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0); 7719 /* 7720 Trim image. 7721 */ 7722 status=XTrimImage(display,resource_info,windows,*image,exception); 7723 if (IfMagickFalse(status) ) 7724 { 7725 XNoticeWidget(display,windows,"Unable to trim X image", 7726 (*image)->filename); 7727 break; 7728 } 7729 break; 7730 } 7731 case HueCommand: 7732 { 7733 static char 7734 hue_percent[MaxTextExtent] = "110"; 7735 7736 /* 7737 Query user for percent hue change. 7738 */ 7739 (void) XDialogWidget(display,windows,"Apply", 7740 "Enter percent change in image hue (0-200):",hue_percent); 7741 if (*hue_percent == '\0') 7742 break; 7743 /* 7744 Vary the image hue. 7745 */ 7746 XSetCursorState(display,windows,MagickTrue); 7747 XCheckRefreshWindows(display,windows); 7748 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent); 7749 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7750 MaxTextExtent); 7751 (void) ModulateImage(*image,modulate_factors,exception); 7752 XSetCursorState(display,windows,MagickFalse); 7753 if (IfMagickTrue(windows->image.orphan) ) 7754 break; 7755 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7756 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7757 break; 7758 } 7759 case SaturationCommand: 7760 { 7761 static char 7762 saturation_percent[MaxTextExtent] = "110"; 7763 7764 /* 7765 Query user for percent saturation change. 7766 */ 7767 (void) XDialogWidget(display,windows,"Apply", 7768 "Enter percent change in color saturation (0-200):",saturation_percent); 7769 if (*saturation_percent == '\0') 7770 break; 7771 /* 7772 Vary color saturation. 7773 */ 7774 XSetCursorState(display,windows,MagickTrue); 7775 XCheckRefreshWindows(display,windows); 7776 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent); 7777 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7778 MaxTextExtent); 7779 (void) ModulateImage(*image,modulate_factors,exception); 7780 XSetCursorState(display,windows,MagickFalse); 7781 if (IfMagickTrue(windows->image.orphan) ) 7782 break; 7783 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7784 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7785 break; 7786 } 7787 case BrightnessCommand: 7788 { 7789 static char 7790 brightness_percent[MaxTextExtent] = "110"; 7791 7792 /* 7793 Query user for percent brightness change. 7794 */ 7795 (void) XDialogWidget(display,windows,"Apply", 7796 "Enter percent change in color brightness (0-200):",brightness_percent); 7797 if (*brightness_percent == '\0') 7798 break; 7799 /* 7800 Vary the color brightness. 7801 */ 7802 XSetCursorState(display,windows,MagickTrue); 7803 XCheckRefreshWindows(display,windows); 7804 (void) CopyMagickString(modulate_factors,brightness_percent, 7805 MaxTextExtent); 7806 (void) ModulateImage(*image,modulate_factors,exception); 7807 XSetCursorState(display,windows,MagickFalse); 7808 if (IfMagickTrue(windows->image.orphan) ) 7809 break; 7810 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7811 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7812 break; 7813 } 7814 case GammaCommand: 7815 { 7816 static char 7817 factor[MaxTextExtent] = "1.6"; 7818 7819 /* 7820 Query user for gamma value. 7821 */ 7822 (void) XDialogWidget(display,windows,"Gamma", 7823 "Enter gamma value (e.g. 1.2):",factor); 7824 if (*factor == '\0') 7825 break; 7826 /* 7827 Gamma correct image. 7828 */ 7829 XSetCursorState(display,windows,MagickTrue); 7830 XCheckRefreshWindows(display,windows); 7831 (void) GammaImage(*image,atof(factor),exception); 7832 XSetCursorState(display,windows,MagickFalse); 7833 if (IfMagickTrue(windows->image.orphan) ) 7834 break; 7835 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7836 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7837 break; 7838 } 7839 case SpiffCommand: 7840 { 7841 /* 7842 Sharpen the image contrast. 7843 */ 7844 XSetCursorState(display,windows,MagickTrue); 7845 XCheckRefreshWindows(display,windows); 7846 (void) ContrastImage(*image,MagickTrue,exception); 7847 XSetCursorState(display,windows,MagickFalse); 7848 if (IfMagickTrue(windows->image.orphan) ) 7849 break; 7850 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7851 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7852 break; 7853 } 7854 case DullCommand: 7855 { 7856 /* 7857 Dull the image contrast. 7858 */ 7859 XSetCursorState(display,windows,MagickTrue); 7860 XCheckRefreshWindows(display,windows); 7861 (void) ContrastImage(*image,MagickFalse,exception); 7862 XSetCursorState(display,windows,MagickFalse); 7863 if (IfMagickTrue(windows->image.orphan) ) 7864 break; 7865 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7866 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7867 break; 7868 } 7869 case ContrastStretchCommand: 7870 { 7871 double 7872 black_point, 7873 white_point; 7874 7875 static char 7876 levels[MaxTextExtent] = "1%"; 7877 7878 /* 7879 Query user for gamma value. 7880 */ 7881 (void) XDialogWidget(display,windows,"Contrast Stretch", 7882 "Enter black and white points:",levels); 7883 if (*levels == '\0') 7884 break; 7885 /* 7886 Contrast stretch image. 7887 */ 7888 XSetCursorState(display,windows,MagickTrue); 7889 XCheckRefreshWindows(display,windows); 7890 flags=ParseGeometry(levels,&geometry_info); 7891 black_point=geometry_info.rho; 7892 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7893 if ((flags & PercentValue) != 0) 7894 { 7895 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7896 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7897 } 7898 white_point=(double) (*image)->columns*(*image)->rows-white_point; 7899 (void) ContrastStretchImage(*image,black_point,white_point, 7900 exception); 7901 XSetCursorState(display,windows,MagickFalse); 7902 if (IfMagickTrue(windows->image.orphan) ) 7903 break; 7904 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7905 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7906 break; 7907 } 7908 case SigmoidalContrastCommand: 7909 { 7910 GeometryInfo 7911 geometry_info; 7912 7913 MagickStatusType 7914 flags; 7915 7916 static char 7917 levels[MaxTextExtent] = "3x50%"; 7918 7919 /* 7920 Query user for gamma value. 7921 */ 7922 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7923 "Enter contrast and midpoint:",levels); 7924 if (*levels == '\0') 7925 break; 7926 /* 7927 Contrast stretch image. 7928 */ 7929 XSetCursorState(display,windows,MagickTrue); 7930 XCheckRefreshWindows(display,windows); 7931 flags=ParseGeometry(levels,&geometry_info); 7932 if ((flags & SigmaValue) == 0) 7933 geometry_info.sigma=1.0*QuantumRange/2.0; 7934 if ((flags & PercentValue) != 0) 7935 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0; 7936 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho, 7937 geometry_info.sigma,exception); 7938 XSetCursorState(display,windows,MagickFalse); 7939 if (IfMagickTrue(windows->image.orphan) ) 7940 break; 7941 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7942 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7943 break; 7944 } 7945 case NormalizeCommand: 7946 { 7947 /* 7948 Perform histogram normalization on the image. 7949 */ 7950 XSetCursorState(display,windows,MagickTrue); 7951 XCheckRefreshWindows(display,windows); 7952 (void) NormalizeImage(*image,exception); 7953 XSetCursorState(display,windows,MagickFalse); 7954 if (IfMagickTrue(windows->image.orphan) ) 7955 break; 7956 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7957 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7958 break; 7959 } 7960 case EqualizeCommand: 7961 { 7962 /* 7963 Perform histogram equalization on the image. 7964 */ 7965 XSetCursorState(display,windows,MagickTrue); 7966 XCheckRefreshWindows(display,windows); 7967 (void) EqualizeImage(*image,exception); 7968 XSetCursorState(display,windows,MagickFalse); 7969 if (IfMagickTrue(windows->image.orphan) ) 7970 break; 7971 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7972 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7973 break; 7974 } 7975 case NegateCommand: 7976 { 7977 /* 7978 Negate colors in image. 7979 */ 7980 XSetCursorState(display,windows,MagickTrue); 7981 XCheckRefreshWindows(display,windows); 7982 (void) NegateImage(*image,MagickFalse,exception); 7983 XSetCursorState(display,windows,MagickFalse); 7984 if (IfMagickTrue(windows->image.orphan) ) 7985 break; 7986 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7987 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7988 break; 7989 } 7990 case GrayscaleCommand: 7991 { 7992 /* 7993 Convert image to grayscale. 7994 */ 7995 XSetCursorState(display,windows,MagickTrue); 7996 XCheckRefreshWindows(display,windows); 7997 (void) SetImageType(*image,(*image)->alpha_trait == UndefinedPixelTrait ? 7998 GrayscaleType : GrayscaleMatteType,exception); 7999 XSetCursorState(display,windows,MagickFalse); 8000 if (IfMagickTrue(windows->image.orphan) ) 8001 break; 8002 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8003 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8004 break; 8005 } 8006 case MapCommand: 8007 { 8008 Image 8009 *affinity_image; 8010 8011 static char 8012 filename[MaxTextExtent] = "\0"; 8013 8014 /* 8015 Request image file name from user. 8016 */ 8017 XFileBrowserWidget(display,windows,"Map",filename); 8018 if (*filename == '\0') 8019 break; 8020 /* 8021 Map image. 8022 */ 8023 XSetCursorState(display,windows,MagickTrue); 8024 XCheckRefreshWindows(display,windows); 8025 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 8026 affinity_image=ReadImage(image_info,exception); 8027 if (affinity_image != (Image *) NULL) 8028 { 8029 (void) RemapImage(&quantize_info,*image,affinity_image,exception); 8030 affinity_image=DestroyImage(affinity_image); 8031 } 8032 CatchException(exception); 8033 XSetCursorState(display,windows,MagickFalse); 8034 if (IfMagickTrue(windows->image.orphan) ) 8035 break; 8036 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8037 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8038 break; 8039 } 8040 case QuantizeCommand: 8041 { 8042 int 8043 status; 8044 8045 static char 8046 colors[MaxTextExtent] = "256"; 8047 8048 /* 8049 Query user for maximum number of colors. 8050 */ 8051 status=XDialogWidget(display,windows,"Quantize", 8052 "Maximum number of colors:",colors); 8053 if (*colors == '\0') 8054 break; 8055 /* 8056 Color reduce the image. 8057 */ 8058 XSetCursorState(display,windows,MagickTrue); 8059 XCheckRefreshWindows(display,windows); 8060 quantize_info.number_colors=StringToUnsignedLong(colors); 8061 quantize_info.dither_method=status != 0 ? RiemersmaDitherMethod : 8062 NoDitherMethod; 8063 (void) QuantizeImage(&quantize_info,*image,exception); 8064 XSetCursorState(display,windows,MagickFalse); 8065 if (IfMagickTrue(windows->image.orphan) ) 8066 break; 8067 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8068 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8069 break; 8070 } 8071 case DespeckleCommand: 8072 { 8073 Image 8074 *despeckle_image; 8075 8076 /* 8077 Despeckle image. 8078 */ 8079 XSetCursorState(display,windows,MagickTrue); 8080 XCheckRefreshWindows(display,windows); 8081 despeckle_image=DespeckleImage(*image,exception); 8082 if (despeckle_image != (Image *) NULL) 8083 { 8084 *image=DestroyImage(*image); 8085 *image=despeckle_image; 8086 } 8087 CatchException(exception); 8088 XSetCursorState(display,windows,MagickFalse); 8089 if (IfMagickTrue(windows->image.orphan) ) 8090 break; 8091 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8092 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8093 break; 8094 } 8095 case EmbossCommand: 8096 { 8097 Image 8098 *emboss_image; 8099 8100 static char 8101 radius[MaxTextExtent] = "0.0x1.0"; 8102 8103 /* 8104 Query user for emboss radius. 8105 */ 8106 (void) XDialogWidget(display,windows,"Emboss", 8107 "Enter the emboss radius and standard deviation:",radius); 8108 if (*radius == '\0') 8109 break; 8110 /* 8111 Reduce noise in the image. 8112 */ 8113 XSetCursorState(display,windows,MagickTrue); 8114 XCheckRefreshWindows(display,windows); 8115 flags=ParseGeometry(radius,&geometry_info); 8116 if ((flags & SigmaValue) == 0) 8117 geometry_info.sigma=1.0; 8118 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma, 8119 exception); 8120 if (emboss_image != (Image *) NULL) 8121 { 8122 *image=DestroyImage(*image); 8123 *image=emboss_image; 8124 } 8125 CatchException(exception); 8126 XSetCursorState(display,windows,MagickFalse); 8127 if (IfMagickTrue(windows->image.orphan) ) 8128 break; 8129 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8130 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8131 break; 8132 } 8133 case ReduceNoiseCommand: 8134 { 8135 Image 8136 *noise_image; 8137 8138 static char 8139 radius[MaxTextExtent] = "0"; 8140 8141 /* 8142 Query user for noise radius. 8143 */ 8144 (void) XDialogWidget(display,windows,"Reduce Noise", 8145 "Enter the noise radius:",radius); 8146 if (*radius == '\0') 8147 break; 8148 /* 8149 Reduce noise in the image. 8150 */ 8151 XSetCursorState(display,windows,MagickTrue); 8152 XCheckRefreshWindows(display,windows); 8153 flags=ParseGeometry(radius,&geometry_info); 8154 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t) 8155 geometry_info.rho,(size_t) geometry_info.rho,exception); 8156 if (noise_image != (Image *) NULL) 8157 { 8158 *image=DestroyImage(*image); 8159 *image=noise_image; 8160 } 8161 CatchException(exception); 8162 XSetCursorState(display,windows,MagickFalse); 8163 if (IfMagickTrue(windows->image.orphan) ) 8164 break; 8165 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8166 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8167 break; 8168 } 8169 case AddNoiseCommand: 8170 { 8171 char 8172 **noises; 8173 8174 Image 8175 *noise_image; 8176 8177 static char 8178 noise_type[MaxTextExtent] = "Gaussian"; 8179 8180 /* 8181 Add noise to the image. 8182 */ 8183 noises=GetCommandOptions(MagickNoiseOptions); 8184 if (noises == (char **) NULL) 8185 break; 8186 XListBrowserWidget(display,windows,&windows->widget, 8187 (const char **) noises,"Add Noise", 8188 "Select a type of noise to add to your image:",noise_type); 8189 noises=DestroyStringList(noises); 8190 if (*noise_type == '\0') 8191 break; 8192 XSetCursorState(display,windows,MagickTrue); 8193 XCheckRefreshWindows(display,windows); 8194 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption( 8195 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception); 8196 if (noise_image != (Image *) NULL) 8197 { 8198 *image=DestroyImage(*image); 8199 *image=noise_image; 8200 } 8201 CatchException(exception); 8202 XSetCursorState(display,windows,MagickFalse); 8203 if (IfMagickTrue(windows->image.orphan) ) 8204 break; 8205 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8206 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8207 break; 8208 } 8209 case SharpenCommand: 8210 { 8211 Image 8212 *sharp_image; 8213 8214 static char 8215 radius[MaxTextExtent] = "0.0x1.0"; 8216 8217 /* 8218 Query user for sharpen radius. 8219 */ 8220 (void) XDialogWidget(display,windows,"Sharpen", 8221 "Enter the sharpen radius and standard deviation:",radius); 8222 if (*radius == '\0') 8223 break; 8224 /* 8225 Sharpen image scanlines. 8226 */ 8227 XSetCursorState(display,windows,MagickTrue); 8228 XCheckRefreshWindows(display,windows); 8229 flags=ParseGeometry(radius,&geometry_info); 8230 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma, 8231 exception); 8232 if (sharp_image != (Image *) NULL) 8233 { 8234 *image=DestroyImage(*image); 8235 *image=sharp_image; 8236 } 8237 CatchException(exception); 8238 XSetCursorState(display,windows,MagickFalse); 8239 if (IfMagickTrue(windows->image.orphan) ) 8240 break; 8241 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8242 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8243 break; 8244 } 8245 case BlurCommand: 8246 { 8247 Image 8248 *blur_image; 8249 8250 static char 8251 radius[MaxTextExtent] = "0.0x1.0"; 8252 8253 /* 8254 Query user for blur radius. 8255 */ 8256 (void) XDialogWidget(display,windows,"Blur", 8257 "Enter the blur radius and standard deviation:",radius); 8258 if (*radius == '\0') 8259 break; 8260 /* 8261 Blur an image. 8262 */ 8263 XSetCursorState(display,windows,MagickTrue); 8264 XCheckRefreshWindows(display,windows); 8265 flags=ParseGeometry(radius,&geometry_info); 8266 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma, 8267 exception); 8268 if (blur_image != (Image *) NULL) 8269 { 8270 *image=DestroyImage(*image); 8271 *image=blur_image; 8272 } 8273 CatchException(exception); 8274 XSetCursorState(display,windows,MagickFalse); 8275 if (IfMagickTrue(windows->image.orphan) ) 8276 break; 8277 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8278 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8279 break; 8280 } 8281 case ThresholdCommand: 8282 { 8283 double 8284 threshold; 8285 8286 static char 8287 factor[MaxTextExtent] = "128"; 8288 8289 /* 8290 Query user for threshold value. 8291 */ 8292 (void) XDialogWidget(display,windows,"Threshold", 8293 "Enter threshold value:",factor); 8294 if (*factor == '\0') 8295 break; 8296 /* 8297 Gamma correct image. 8298 */ 8299 XSetCursorState(display,windows,MagickTrue); 8300 XCheckRefreshWindows(display,windows); 8301 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8302 (void) BilevelImage(*image,threshold,exception); 8303 XSetCursorState(display,windows,MagickFalse); 8304 if (IfMagickTrue(windows->image.orphan) ) 8305 break; 8306 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8307 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8308 break; 8309 } 8310 case EdgeDetectCommand: 8311 { 8312 Image 8313 *edge_image; 8314 8315 static char 8316 radius[MaxTextExtent] = "0"; 8317 8318 /* 8319 Query user for edge factor. 8320 */ 8321 (void) XDialogWidget(display,windows,"Detect Edges", 8322 "Enter the edge detect radius:",radius); 8323 if (*radius == '\0') 8324 break; 8325 /* 8326 Detect edge in image. 8327 */ 8328 XSetCursorState(display,windows,MagickTrue); 8329 XCheckRefreshWindows(display,windows); 8330 flags=ParseGeometry(radius,&geometry_info); 8331 edge_image=EdgeImage(*image,geometry_info.rho,exception); 8332 if (edge_image != (Image *) NULL) 8333 { 8334 *image=DestroyImage(*image); 8335 *image=edge_image; 8336 } 8337 CatchException(exception); 8338 XSetCursorState(display,windows,MagickFalse); 8339 if (IfMagickTrue(windows->image.orphan) ) 8340 break; 8341 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8342 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8343 break; 8344 } 8345 case SpreadCommand: 8346 { 8347 Image 8348 *spread_image; 8349 8350 static char 8351 amount[MaxTextExtent] = "2"; 8352 8353 /* 8354 Query user for spread amount. 8355 */ 8356 (void) XDialogWidget(display,windows,"Spread", 8357 "Enter the displacement amount:",amount); 8358 if (*amount == '\0') 8359 break; 8360 /* 8361 Displace image pixels by a random amount. 8362 */ 8363 XSetCursorState(display,windows,MagickTrue); 8364 XCheckRefreshWindows(display,windows); 8365 flags=ParseGeometry(amount,&geometry_info); 8366 spread_image=EdgeImage(*image,geometry_info.rho,exception); 8367 if (spread_image != (Image *) NULL) 8368 { 8369 *image=DestroyImage(*image); 8370 *image=spread_image; 8371 } 8372 CatchException(exception); 8373 XSetCursorState(display,windows,MagickFalse); 8374 if (IfMagickTrue(windows->image.orphan) ) 8375 break; 8376 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8377 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8378 break; 8379 } 8380 case ShadeCommand: 8381 { 8382 Image 8383 *shade_image; 8384 8385 int 8386 status; 8387 8388 static char 8389 geometry[MaxTextExtent] = "30x30"; 8390 8391 /* 8392 Query user for the shade geometry. 8393 */ 8394 status=XDialogWidget(display,windows,"Shade", 8395 "Enter the azimuth and elevation of the light source:",geometry); 8396 if (*geometry == '\0') 8397 break; 8398 /* 8399 Shade image pixels. 8400 */ 8401 XSetCursorState(display,windows,MagickTrue); 8402 XCheckRefreshWindows(display,windows); 8403 flags=ParseGeometry(geometry,&geometry_info); 8404 if ((flags & SigmaValue) == 0) 8405 geometry_info.sigma=1.0; 8406 shade_image=ShadeImage(*image,IsMagickTrue(status), 8407 geometry_info.rho,geometry_info.sigma,exception); 8408 if (shade_image != (Image *) NULL) 8409 { 8410 *image=DestroyImage(*image); 8411 *image=shade_image; 8412 } 8413 CatchException(exception); 8414 XSetCursorState(display,windows,MagickFalse); 8415 if (IfMagickTrue(windows->image.orphan) ) 8416 break; 8417 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8418 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8419 break; 8420 } 8421 case RaiseCommand: 8422 { 8423 static char 8424 bevel_width[MaxTextExtent] = "10"; 8425 8426 /* 8427 Query user for bevel width. 8428 */ 8429 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8430 if (*bevel_width == '\0') 8431 break; 8432 /* 8433 Raise an image. 8434 */ 8435 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8436 exception); 8437 XSetCursorState(display,windows,MagickTrue); 8438 XCheckRefreshWindows(display,windows); 8439 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8440 exception); 8441 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception); 8442 XSetCursorState(display,windows,MagickFalse); 8443 if (IfMagickTrue(windows->image.orphan) ) 8444 break; 8445 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8446 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8447 break; 8448 } 8449 case SegmentCommand: 8450 { 8451 static char 8452 threshold[MaxTextExtent] = "1.0x1.5"; 8453 8454 /* 8455 Query user for smoothing threshold. 8456 */ 8457 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8458 threshold); 8459 if (*threshold == '\0') 8460 break; 8461 /* 8462 Segment an image. 8463 */ 8464 XSetCursorState(display,windows,MagickTrue); 8465 XCheckRefreshWindows(display,windows); 8466 flags=ParseGeometry(threshold,&geometry_info); 8467 if ((flags & SigmaValue) == 0) 8468 geometry_info.sigma=1.0; 8469 (void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho, 8470 geometry_info.sigma,exception); 8471 XSetCursorState(display,windows,MagickFalse); 8472 if (IfMagickTrue(windows->image.orphan) ) 8473 break; 8474 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8475 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8476 break; 8477 } 8478 case SepiaToneCommand: 8479 { 8480 double 8481 threshold; 8482 8483 Image 8484 *sepia_image; 8485 8486 static char 8487 factor[MaxTextExtent] = "80%"; 8488 8489 /* 8490 Query user for sepia-tone factor. 8491 */ 8492 (void) XDialogWidget(display,windows,"Sepia Tone", 8493 "Enter the sepia tone factor (0 - 99.9%):",factor); 8494 if (*factor == '\0') 8495 break; 8496 /* 8497 Sepia tone image pixels. 8498 */ 8499 XSetCursorState(display,windows,MagickTrue); 8500 XCheckRefreshWindows(display,windows); 8501 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8502 sepia_image=SepiaToneImage(*image,threshold,exception); 8503 if (sepia_image != (Image *) NULL) 8504 { 8505 *image=DestroyImage(*image); 8506 *image=sepia_image; 8507 } 8508 CatchException(exception); 8509 XSetCursorState(display,windows,MagickFalse); 8510 if (IfMagickTrue(windows->image.orphan) ) 8511 break; 8512 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8513 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8514 break; 8515 } 8516 case SolarizeCommand: 8517 { 8518 double 8519 threshold; 8520 8521 static char 8522 factor[MaxTextExtent] = "60%"; 8523 8524 /* 8525 Query user for solarize factor. 8526 */ 8527 (void) XDialogWidget(display,windows,"Solarize", 8528 "Enter the solarize factor (0 - 99.9%):",factor); 8529 if (*factor == '\0') 8530 break; 8531 /* 8532 Solarize image pixels. 8533 */ 8534 XSetCursorState(display,windows,MagickTrue); 8535 XCheckRefreshWindows(display,windows); 8536 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8537 (void) SolarizeImage(*image,threshold,exception); 8538 XSetCursorState(display,windows,MagickFalse); 8539 if (IfMagickTrue(windows->image.orphan) ) 8540 break; 8541 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8542 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8543 break; 8544 } 8545 case SwirlCommand: 8546 { 8547 Image 8548 *swirl_image; 8549 8550 static char 8551 degrees[MaxTextExtent] = "60"; 8552 8553 /* 8554 Query user for swirl angle. 8555 */ 8556 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8557 degrees); 8558 if (*degrees == '\0') 8559 break; 8560 /* 8561 Swirl image pixels about the center. 8562 */ 8563 XSetCursorState(display,windows,MagickTrue); 8564 XCheckRefreshWindows(display,windows); 8565 flags=ParseGeometry(degrees,&geometry_info); 8566 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate, 8567 exception); 8568 if (swirl_image != (Image *) NULL) 8569 { 8570 *image=DestroyImage(*image); 8571 *image=swirl_image; 8572 } 8573 CatchException(exception); 8574 XSetCursorState(display,windows,MagickFalse); 8575 if (IfMagickTrue(windows->image.orphan) ) 8576 break; 8577 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8578 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8579 break; 8580 } 8581 case ImplodeCommand: 8582 { 8583 Image 8584 *implode_image; 8585 8586 static char 8587 factor[MaxTextExtent] = "0.3"; 8588 8589 /* 8590 Query user for implode factor. 8591 */ 8592 (void) XDialogWidget(display,windows,"Implode", 8593 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8594 if (*factor == '\0') 8595 break; 8596 /* 8597 Implode image pixels about the center. 8598 */ 8599 XSetCursorState(display,windows,MagickTrue); 8600 XCheckRefreshWindows(display,windows); 8601 flags=ParseGeometry(factor,&geometry_info); 8602 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate, 8603 exception); 8604 if (implode_image != (Image *) NULL) 8605 { 8606 *image=DestroyImage(*image); 8607 *image=implode_image; 8608 } 8609 CatchException(exception); 8610 XSetCursorState(display,windows,MagickFalse); 8611 if (IfMagickTrue(windows->image.orphan) ) 8612 break; 8613 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8614 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8615 break; 8616 } 8617 case VignetteCommand: 8618 { 8619 Image 8620 *vignette_image; 8621 8622 static char 8623 geometry[MaxTextExtent] = "0x20"; 8624 8625 /* 8626 Query user for the vignette geometry. 8627 */ 8628 (void) XDialogWidget(display,windows,"Vignette", 8629 "Enter the radius, sigma, and x and y offsets:",geometry); 8630 if (*geometry == '\0') 8631 break; 8632 /* 8633 Soften the edges of the image in vignette style 8634 */ 8635 XSetCursorState(display,windows,MagickTrue); 8636 XCheckRefreshWindows(display,windows); 8637 flags=ParseGeometry(geometry,&geometry_info); 8638 if ((flags & SigmaValue) == 0) 8639 geometry_info.sigma=1.0; 8640 if ((flags & XiValue) == 0) 8641 geometry_info.xi=0.1*(*image)->columns; 8642 if ((flags & PsiValue) == 0) 8643 geometry_info.psi=0.1*(*image)->rows; 8644 vignette_image=VignetteImage(*image,geometry_info.rho,0.0,(ssize_t) 8645 ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5), 8646 exception); 8647 if (vignette_image != (Image *) NULL) 8648 { 8649 *image=DestroyImage(*image); 8650 *image=vignette_image; 8651 } 8652 CatchException(exception); 8653 XSetCursorState(display,windows,MagickFalse); 8654 if (IfMagickTrue(windows->image.orphan) ) 8655 break; 8656 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8657 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8658 break; 8659 } 8660 case WaveCommand: 8661 { 8662 Image 8663 *wave_image; 8664 8665 static char 8666 geometry[MaxTextExtent] = "25x150"; 8667 8668 /* 8669 Query user for the wave geometry. 8670 */ 8671 (void) XDialogWidget(display,windows,"Wave", 8672 "Enter the amplitude and length of the wave:",geometry); 8673 if (*geometry == '\0') 8674 break; 8675 /* 8676 Alter an image along a sine wave. 8677 */ 8678 XSetCursorState(display,windows,MagickTrue); 8679 XCheckRefreshWindows(display,windows); 8680 flags=ParseGeometry(geometry,&geometry_info); 8681 if ((flags & SigmaValue) == 0) 8682 geometry_info.sigma=1.0; 8683 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8684 (*image)->interpolate,exception); 8685 if (wave_image != (Image *) NULL) 8686 { 8687 *image=DestroyImage(*image); 8688 *image=wave_image; 8689 } 8690 CatchException(exception); 8691 XSetCursorState(display,windows,MagickFalse); 8692 if (IfMagickTrue(windows->image.orphan) ) 8693 break; 8694 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8695 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8696 break; 8697 } 8698 case OilPaintCommand: 8699 { 8700 Image 8701 *paint_image; 8702 8703 static char 8704 radius[MaxTextExtent] = "0"; 8705 8706 /* 8707 Query user for circular neighborhood radius. 8708 */ 8709 (void) XDialogWidget(display,windows,"Oil Paint", 8710 "Enter the mask radius:",radius); 8711 if (*radius == '\0') 8712 break; 8713 /* 8714 OilPaint image scanlines. 8715 */ 8716 XSetCursorState(display,windows,MagickTrue); 8717 XCheckRefreshWindows(display,windows); 8718 flags=ParseGeometry(radius,&geometry_info); 8719 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma, 8720 exception); 8721 if (paint_image != (Image *) NULL) 8722 { 8723 *image=DestroyImage(*image); 8724 *image=paint_image; 8725 } 8726 CatchException(exception); 8727 XSetCursorState(display,windows,MagickFalse); 8728 if (IfMagickTrue(windows->image.orphan) ) 8729 break; 8730 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8731 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8732 break; 8733 } 8734 case CharcoalDrawCommand: 8735 { 8736 Image 8737 *charcoal_image; 8738 8739 static char 8740 radius[MaxTextExtent] = "0x1"; 8741 8742 /* 8743 Query user for charcoal radius. 8744 */ 8745 (void) XDialogWidget(display,windows,"Charcoal Draw", 8746 "Enter the charcoal radius and sigma:",radius); 8747 if (*radius == '\0') 8748 break; 8749 /* 8750 Charcoal the image. 8751 */ 8752 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8753 exception); 8754 XSetCursorState(display,windows,MagickTrue); 8755 XCheckRefreshWindows(display,windows); 8756 flags=ParseGeometry(radius,&geometry_info); 8757 if ((flags & SigmaValue) == 0) 8758 geometry_info.sigma=geometry_info.rho; 8759 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8760 exception); 8761 if (charcoal_image != (Image *) NULL) 8762 { 8763 *image=DestroyImage(*image); 8764 *image=charcoal_image; 8765 } 8766 CatchException(exception); 8767 XSetCursorState(display,windows,MagickFalse); 8768 if (IfMagickTrue(windows->image.orphan) ) 8769 break; 8770 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8771 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8772 break; 8773 } 8774 case AnnotateCommand: 8775 { 8776 /* 8777 Annotate the image with text. 8778 */ 8779 status=XAnnotateEditImage(display,resource_info,windows,*image,exception); 8780 if (IfMagickFalse(status) ) 8781 { 8782 XNoticeWidget(display,windows,"Unable to annotate X image", 8783 (*image)->filename); 8784 break; 8785 } 8786 break; 8787 } 8788 case DrawCommand: 8789 { 8790 /* 8791 Draw image. 8792 */ 8793 status=XDrawEditImage(display,resource_info,windows,image,exception); 8794 if (IfMagickFalse(status) ) 8795 { 8796 XNoticeWidget(display,windows,"Unable to draw on the X image", 8797 (*image)->filename); 8798 break; 8799 } 8800 break; 8801 } 8802 case ColorCommand: 8803 { 8804 /* 8805 Color edit. 8806 */ 8807 status=XColorEditImage(display,resource_info,windows,image,exception); 8808 if (IfMagickFalse(status) ) 8809 { 8810 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8811 (*image)->filename); 8812 break; 8813 } 8814 break; 8815 } 8816 case MatteCommand: 8817 { 8818 /* 8819 Matte edit. 8820 */ 8821 status=XMatteEditImage(display,resource_info,windows,image,exception); 8822 if (IfMagickFalse(status) ) 8823 { 8824 XNoticeWidget(display,windows,"Unable to matte edit X image", 8825 (*image)->filename); 8826 break; 8827 } 8828 break; 8829 } 8830 case CompositeCommand: 8831 { 8832 /* 8833 Composite image. 8834 */ 8835 status=XCompositeImage(display,resource_info,windows,*image, 8836 exception); 8837 if (IfMagickFalse(status) ) 8838 { 8839 XNoticeWidget(display,windows,"Unable to composite X image", 8840 (*image)->filename); 8841 break; 8842 } 8843 break; 8844 } 8845 case AddBorderCommand: 8846 { 8847 Image 8848 *border_image; 8849 8850 static char 8851 geometry[MaxTextExtent] = "6x6"; 8852 8853 /* 8854 Query user for border color and geometry. 8855 */ 8856 XColorBrowserWidget(display,windows,"Select",color); 8857 if (*color == '\0') 8858 break; 8859 (void) XDialogWidget(display,windows,"Add Border", 8860 "Enter border geometry:",geometry); 8861 if (*geometry == '\0') 8862 break; 8863 /* 8864 Add a border to the image. 8865 */ 8866 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8867 exception); 8868 XSetCursorState(display,windows,MagickTrue); 8869 XCheckRefreshWindows(display,windows); 8870 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color, 8871 exception); 8872 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8873 exception); 8874 border_image=BorderImage(*image,&page_geometry,(*image)->compose, 8875 exception); 8876 if (border_image != (Image *) NULL) 8877 { 8878 *image=DestroyImage(*image); 8879 *image=border_image; 8880 } 8881 CatchException(exception); 8882 XSetCursorState(display,windows,MagickFalse); 8883 if (IfMagickTrue(windows->image.orphan) ) 8884 break; 8885 windows->image.window_changes.width=(int) (*image)->columns; 8886 windows->image.window_changes.height=(int) (*image)->rows; 8887 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8888 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8889 break; 8890 } 8891 case AddFrameCommand: 8892 { 8893 FrameInfo 8894 frame_info; 8895 8896 Image 8897 *frame_image; 8898 8899 static char 8900 geometry[MaxTextExtent] = "6x6"; 8901 8902 /* 8903 Query user for frame color and geometry. 8904 */ 8905 XColorBrowserWidget(display,windows,"Select",color); 8906 if (*color == '\0') 8907 break; 8908 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8909 geometry); 8910 if (*geometry == '\0') 8911 break; 8912 /* 8913 Surround image with an ornamental border. 8914 */ 8915 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8916 exception); 8917 XSetCursorState(display,windows,MagickTrue); 8918 XCheckRefreshWindows(display,windows); 8919 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color, 8920 exception); 8921 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8922 exception); 8923 frame_info.width=page_geometry.width; 8924 frame_info.height=page_geometry.height; 8925 frame_info.outer_bevel=page_geometry.x; 8926 frame_info.inner_bevel=page_geometry.y; 8927 frame_info.x=(ssize_t) frame_info.width; 8928 frame_info.y=(ssize_t) frame_info.height; 8929 frame_info.width=(*image)->columns+2*frame_info.width; 8930 frame_info.height=(*image)->rows+2*frame_info.height; 8931 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception); 8932 if (frame_image != (Image *) NULL) 8933 { 8934 *image=DestroyImage(*image); 8935 *image=frame_image; 8936 } 8937 CatchException(exception); 8938 XSetCursorState(display,windows,MagickFalse); 8939 if (IfMagickTrue(windows->image.orphan) ) 8940 break; 8941 windows->image.window_changes.width=(int) (*image)->columns; 8942 windows->image.window_changes.height=(int) (*image)->rows; 8943 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8944 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8945 break; 8946 } 8947 case CommentCommand: 8948 { 8949 const char 8950 *value; 8951 8952 FILE 8953 *file; 8954 8955 int 8956 unique_file; 8957 8958 /* 8959 Edit image comment. 8960 */ 8961 unique_file=AcquireUniqueFileResource(image_info->filename); 8962 if (unique_file == -1) 8963 XNoticeWidget(display,windows,"Unable to edit image comment", 8964 image_info->filename); 8965 value=GetImageProperty(*image,"comment",exception); 8966 if (value == (char *) NULL) 8967 unique_file=close(unique_file)-1; 8968 else 8969 { 8970 register const char 8971 *p; 8972 8973 file=fdopen(unique_file,"w"); 8974 if (file == (FILE *) NULL) 8975 { 8976 XNoticeWidget(display,windows,"Unable to edit image comment", 8977 image_info->filename); 8978 break; 8979 } 8980 for (p=value; *p != '\0'; p++) 8981 (void) fputc((int) *p,file); 8982 (void) fputc('\n',file); 8983 (void) fclose(file); 8984 } 8985 XSetCursorState(display,windows,MagickTrue); 8986 XCheckRefreshWindows(display,windows); 8987 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 8988 exception); 8989 if (IfMagickFalse(status) ) 8990 XNoticeWidget(display,windows,"Unable to edit image comment", 8991 (char *) NULL); 8992 else 8993 { 8994 char 8995 *comment; 8996 8997 comment=FileToString(image_info->filename,~0UL,exception); 8998 if (comment != (char *) NULL) 8999 { 9000 (void) SetImageProperty(*image,"comment",comment,exception); 9001 (*image)->taint=MagickTrue; 9002 } 9003 } 9004 (void) RelinquishUniqueFileResource(image_info->filename); 9005 XSetCursorState(display,windows,MagickFalse); 9006 break; 9007 } 9008 case LaunchCommand: 9009 { 9010 /* 9011 Launch program. 9012 */ 9013 XSetCursorState(display,windows,MagickTrue); 9014 XCheckRefreshWindows(display,windows); 9015 (void) AcquireUniqueFilename(filename); 9016 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s", 9017 filename); 9018 status=WriteImage(image_info,*image,exception); 9019 if (IfMagickFalse(status) ) 9020 XNoticeWidget(display,windows,"Unable to launch image editor", 9021 (char *) NULL); 9022 else 9023 { 9024 nexus=ReadImage(resource_info->image_info,exception); 9025 CatchException(exception); 9026 XClientMessage(display,windows->image.id,windows->im_protocols, 9027 windows->im_next_image,CurrentTime); 9028 } 9029 (void) RelinquishUniqueFileResource(filename); 9030 XSetCursorState(display,windows,MagickFalse); 9031 break; 9032 } 9033 case RegionofInterestCommand: 9034 { 9035 /* 9036 Apply an image processing technique to a region of interest. 9037 */ 9038 (void) XROIImage(display,resource_info,windows,image,exception); 9039 break; 9040 } 9041 case InfoCommand: 9042 break; 9043 case ZoomCommand: 9044 { 9045 /* 9046 Zoom image. 9047 */ 9048 if (IfMagickTrue(windows->magnify.mapped) ) 9049 (void) XRaiseWindow(display,windows->magnify.id); 9050 else 9051 { 9052 /* 9053 Make magnify image. 9054 */ 9055 XSetCursorState(display,windows,MagickTrue); 9056 (void) XMapRaised(display,windows->magnify.id); 9057 XSetCursorState(display,windows,MagickFalse); 9058 } 9059 break; 9060 } 9061 case ShowPreviewCommand: 9062 { 9063 char 9064 **previews; 9065 9066 Image 9067 *preview_image; 9068 9069 static char 9070 preview_type[MaxTextExtent] = "Gamma"; 9071 9072 /* 9073 Select preview type from menu. 9074 */ 9075 previews=GetCommandOptions(MagickPreviewOptions); 9076 if (previews == (char **) NULL) 9077 break; 9078 XListBrowserWidget(display,windows,&windows->widget, 9079 (const char **) previews,"Preview", 9080 "Select an enhancement, effect, or F/X:",preview_type); 9081 previews=DestroyStringList(previews); 9082 if (*preview_type == '\0') 9083 break; 9084 /* 9085 Show image preview. 9086 */ 9087 XSetCursorState(display,windows,MagickTrue); 9088 XCheckRefreshWindows(display,windows); 9089 image_info->preview_type=(PreviewType) 9090 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type); 9091 image_info->group=(ssize_t) windows->image.id; 9092 (void) DeleteImageProperty(*image,"label"); 9093 (void) SetImageProperty(*image,"label","Preview",exception); 9094 (void) AcquireUniqueFilename(filename); 9095 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s", 9096 filename); 9097 status=WriteImage(image_info,*image,exception); 9098 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9099 preview_image=ReadImage(image_info,exception); 9100 (void) RelinquishUniqueFileResource(filename); 9101 if (preview_image == (Image *) NULL) 9102 break; 9103 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s", 9104 filename); 9105 status=WriteImage(image_info,preview_image,exception); 9106 preview_image=DestroyImage(preview_image); 9107 if (IfMagickFalse(status) ) 9108 XNoticeWidget(display,windows,"Unable to show image preview", 9109 (*image)->filename); 9110 XDelay(display,1500); 9111 XSetCursorState(display,windows,MagickFalse); 9112 break; 9113 } 9114 case ShowHistogramCommand: 9115 { 9116 Image 9117 *histogram_image; 9118 9119 /* 9120 Show image histogram. 9121 */ 9122 XSetCursorState(display,windows,MagickTrue); 9123 XCheckRefreshWindows(display,windows); 9124 image_info->group=(ssize_t) windows->image.id; 9125 (void) DeleteImageProperty(*image,"label"); 9126 (void) SetImageProperty(*image,"label","Histogram",exception); 9127 (void) AcquireUniqueFilename(filename); 9128 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s", 9129 filename); 9130 status=WriteImage(image_info,*image,exception); 9131 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9132 histogram_image=ReadImage(image_info,exception); 9133 (void) RelinquishUniqueFileResource(filename); 9134 if (histogram_image == (Image *) NULL) 9135 break; 9136 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent, 9137 "show:%s",filename); 9138 status=WriteImage(image_info,histogram_image,exception); 9139 histogram_image=DestroyImage(histogram_image); 9140 if (IfMagickFalse(status) ) 9141 XNoticeWidget(display,windows,"Unable to show histogram", 9142 (*image)->filename); 9143 XDelay(display,1500); 9144 XSetCursorState(display,windows,MagickFalse); 9145 break; 9146 } 9147 case ShowMatteCommand: 9148 { 9149 Image 9150 *matte_image; 9151 9152 if ((*image)->alpha_trait == UndefinedPixelTrait) 9153 { 9154 XNoticeWidget(display,windows, 9155 "Image does not have any matte information",(*image)->filename); 9156 break; 9157 } 9158 /* 9159 Show image matte. 9160 */ 9161 XSetCursorState(display,windows,MagickTrue); 9162 XCheckRefreshWindows(display,windows); 9163 image_info->group=(ssize_t) windows->image.id; 9164 (void) DeleteImageProperty(*image,"label"); 9165 (void) SetImageProperty(*image,"label","Matte",exception); 9166 (void) AcquireUniqueFilename(filename); 9167 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s", 9168 filename); 9169 status=WriteImage(image_info,*image,exception); 9170 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9171 matte_image=ReadImage(image_info,exception); 9172 (void) RelinquishUniqueFileResource(filename); 9173 if (matte_image == (Image *) NULL) 9174 break; 9175 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s", 9176 filename); 9177 status=WriteImage(image_info,matte_image,exception); 9178 matte_image=DestroyImage(matte_image); 9179 if (IfMagickFalse(status) ) 9180 XNoticeWidget(display,windows,"Unable to show matte", 9181 (*image)->filename); 9182 XDelay(display,1500); 9183 XSetCursorState(display,windows,MagickFalse); 9184 break; 9185 } 9186 case BackgroundCommand: 9187 { 9188 /* 9189 Background image. 9190 */ 9191 status=XBackgroundImage(display,resource_info,windows,image,exception); 9192 if (IfMagickFalse(status) ) 9193 break; 9194 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9195 if (nexus != (Image *) NULL) 9196 XClientMessage(display,windows->image.id,windows->im_protocols, 9197 windows->im_next_image,CurrentTime); 9198 break; 9199 } 9200 case SlideShowCommand: 9201 { 9202 static char 9203 delay[MaxTextExtent] = "5"; 9204 9205 /* 9206 Display next image after pausing. 9207 */ 9208 (void) XDialogWidget(display,windows,"Slide Show", 9209 "Pause how many 1/100ths of a second between images:",delay); 9210 if (*delay == '\0') 9211 break; 9212 resource_info->delay=StringToUnsignedLong(delay); 9213 XClientMessage(display,windows->image.id,windows->im_protocols, 9214 windows->im_next_image,CurrentTime); 9215 break; 9216 } 9217 case PreferencesCommand: 9218 { 9219 /* 9220 Set user preferences. 9221 */ 9222 status=XPreferencesWidget(display,resource_info,windows); 9223 if (IfMagickFalse(status) ) 9224 break; 9225 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9226 if (nexus != (Image *) NULL) 9227 XClientMessage(display,windows->image.id,windows->im_protocols, 9228 windows->im_next_image,CurrentTime); 9229 break; 9230 } 9231 case HelpCommand: 9232 { 9233 /* 9234 User requested help. 9235 */ 9236 XTextViewWidget(display,resource_info,windows,MagickFalse, 9237 "Help Viewer - Display",DisplayHelp); 9238 break; 9239 } 9240 case BrowseDocumentationCommand: 9241 { 9242 Atom 9243 mozilla_atom; 9244 9245 Window 9246 mozilla_window, 9247 root_window; 9248 9249 /* 9250 Browse the ImageMagick documentation. 9251 */ 9252 root_window=XRootWindow(display,XDefaultScreen(display)); 9253 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); 9254 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); 9255 if (mozilla_window != (Window) NULL) 9256 { 9257 char 9258 command[MaxTextExtent], 9259 *url; 9260 9261 /* 9262 Display documentation using Netscape remote control. 9263 */ 9264 url=GetMagickHomeURL(); 9265 (void) FormatLocaleString(command,MaxTextExtent, 9266 "openurl(%s,new-tab)",url); 9267 url=DestroyString(url); 9268 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); 9269 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING, 9270 8,PropModeReplace,(unsigned char *) command,(int) strlen(command)); 9271 XSetCursorState(display,windows,MagickFalse); 9272 break; 9273 } 9274 XSetCursorState(display,windows,MagickTrue); 9275 XCheckRefreshWindows(display,windows); 9276 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL, 9277 exception); 9278 if (IfMagickFalse(status) ) 9279 XNoticeWidget(display,windows,"Unable to browse documentation", 9280 (char *) NULL); 9281 XDelay(display,1500); 9282 XSetCursorState(display,windows,MagickFalse); 9283 break; 9284 } 9285 case VersionCommand: 9286 { 9287 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), 9288 GetMagickCopyright()); 9289 break; 9290 } 9291 case SaveToUndoBufferCommand: 9292 break; 9293 default: 9294 { 9295 (void) XBell(display,0); 9296 break; 9297 } 9298 } 9299 image_info=DestroyImageInfo(image_info); 9300 return(nexus); 9301} 9302 9303/* 9304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9305% % 9306% % 9307% % 9308+ X M a g n i f y I m a g e % 9309% % 9310% % 9311% % 9312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9313% 9314% XMagnifyImage() magnifies portions of the image as indicated by the pointer. 9315% The magnified portion is displayed in a separate window. 9316% 9317% The format of the XMagnifyImage method is: 9318% 9319% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9320% ExceptionInfo *exception) 9321% 9322% A description of each parameter follows: 9323% 9324% o display: Specifies a connection to an X server; returned from 9325% XOpenDisplay. 9326% 9327% o windows: Specifies a pointer to a XWindows structure. 9328% 9329% o event: Specifies a pointer to a XEvent structure. If it is NULL, 9330% the entire image is refreshed. 9331% 9332% o exception: return any errors or warnings in this structure. 9333% 9334*/ 9335static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9336 ExceptionInfo *exception) 9337{ 9338 char 9339 text[MaxTextExtent]; 9340 9341 register int 9342 x, 9343 y; 9344 9345 size_t 9346 state; 9347 9348 /* 9349 Update magnified image until the mouse button is released. 9350 */ 9351 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor); 9352 state=DefaultState; 9353 x=event->xbutton.x; 9354 y=event->xbutton.y; 9355 windows->magnify.x=(int) windows->image.x+x; 9356 windows->magnify.y=(int) windows->image.y+y; 9357 do 9358 { 9359 /* 9360 Map and unmap Info widget as text cursor crosses its boundaries. 9361 */ 9362 if (IfMagickTrue(windows->info.mapped) ) 9363 { 9364 if ((x < (int) (windows->info.x+windows->info.width)) && 9365 (y < (int) (windows->info.y+windows->info.height))) 9366 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 9367 } 9368 else 9369 if ((x > (int) (windows->info.x+windows->info.width)) || 9370 (y > (int) (windows->info.y+windows->info.height))) 9371 (void) XMapWindow(display,windows->info.id); 9372 if (IfMagickTrue(windows->info.mapped) ) 9373 { 9374 /* 9375 Display pointer position. 9376 */ 9377 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9378 windows->magnify.x,windows->magnify.y); 9379 XInfoWidget(display,windows,text); 9380 } 9381 /* 9382 Wait for next event. 9383 */ 9384 XScreenEvent(display,windows,event,exception); 9385 switch (event->type) 9386 { 9387 case ButtonPress: 9388 break; 9389 case ButtonRelease: 9390 { 9391 /* 9392 User has finished magnifying image. 9393 */ 9394 x=event->xbutton.x; 9395 y=event->xbutton.y; 9396 state|=ExitState; 9397 break; 9398 } 9399 case Expose: 9400 break; 9401 case MotionNotify: 9402 { 9403 x=event->xmotion.x; 9404 y=event->xmotion.y; 9405 break; 9406 } 9407 default: 9408 break; 9409 } 9410 /* 9411 Check boundary conditions. 9412 */ 9413 if (x < 0) 9414 x=0; 9415 else 9416 if (x >= (int) windows->image.width) 9417 x=(int) windows->image.width-1; 9418 if (y < 0) 9419 y=0; 9420 else 9421 if (y >= (int) windows->image.height) 9422 y=(int) windows->image.height-1; 9423 } while ((state & ExitState) == 0); 9424 /* 9425 Display magnified image. 9426 */ 9427 XSetCursorState(display,windows,MagickFalse); 9428} 9429 9430/* 9431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9432% % 9433% % 9434% % 9435+ X M a g n i f y W i n d o w C o m m a n d % 9436% % 9437% % 9438% % 9439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9440% 9441% XMagnifyWindowCommand() moves the image within an Magnify window by one 9442% pixel as specified by the key symbol. 9443% 9444% The format of the XMagnifyWindowCommand method is: 9445% 9446% void XMagnifyWindowCommand(Display *display,XWindows *windows, 9447% const MagickStatusType state,const KeySym key_symbol, 9448% ExceptionInfo *exception) 9449% 9450% A description of each parameter follows: 9451% 9452% o display: Specifies a connection to an X server; returned from 9453% XOpenDisplay. 9454% 9455% o windows: Specifies a pointer to a XWindows structure. 9456% 9457% o state: key mask. 9458% 9459% o key_symbol: Specifies a KeySym which indicates which side of the image 9460% to trim. 9461% 9462% o exception: return any errors or warnings in this structure. 9463% 9464*/ 9465static void XMagnifyWindowCommand(Display *display,XWindows *windows, 9466 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception) 9467{ 9468 unsigned int 9469 quantum; 9470 9471 /* 9472 User specified a magnify factor or position. 9473 */ 9474 quantum=1; 9475 if ((state & Mod1Mask) != 0) 9476 quantum=10; 9477 switch ((int) key_symbol) 9478 { 9479 case QuitCommand: 9480 { 9481 (void) XWithdrawWindow(display,windows->magnify.id, 9482 windows->magnify.screen); 9483 break; 9484 } 9485 case XK_Home: 9486 case XK_KP_Home: 9487 { 9488 windows->magnify.x=(int) windows->image.width/2; 9489 windows->magnify.y=(int) windows->image.height/2; 9490 break; 9491 } 9492 case XK_Left: 9493 case XK_KP_Left: 9494 { 9495 if (windows->magnify.x > 0) 9496 windows->magnify.x-=quantum; 9497 break; 9498 } 9499 case XK_Up: 9500 case XK_KP_Up: 9501 { 9502 if (windows->magnify.y > 0) 9503 windows->magnify.y-=quantum; 9504 break; 9505 } 9506 case XK_Right: 9507 case XK_KP_Right: 9508 { 9509 if (windows->magnify.x < (int) (windows->image.ximage->width-1)) 9510 windows->magnify.x+=quantum; 9511 break; 9512 } 9513 case XK_Down: 9514 case XK_KP_Down: 9515 { 9516 if (windows->magnify.y < (int) (windows->image.ximage->height-1)) 9517 windows->magnify.y+=quantum; 9518 break; 9519 } 9520 case XK_0: 9521 case XK_1: 9522 case XK_2: 9523 case XK_3: 9524 case XK_4: 9525 case XK_5: 9526 case XK_6: 9527 case XK_7: 9528 case XK_8: 9529 case XK_9: 9530 { 9531 windows->magnify.data=(key_symbol-XK_0); 9532 break; 9533 } 9534 case XK_KP_0: 9535 case XK_KP_1: 9536 case XK_KP_2: 9537 case XK_KP_3: 9538 case XK_KP_4: 9539 case XK_KP_5: 9540 case XK_KP_6: 9541 case XK_KP_7: 9542 case XK_KP_8: 9543 case XK_KP_9: 9544 { 9545 windows->magnify.data=(key_symbol-XK_KP_0); 9546 break; 9547 } 9548 default: 9549 break; 9550 } 9551 XMakeMagnifyImage(display,windows,exception); 9552} 9553 9554/* 9555%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9556% % 9557% % 9558% % 9559+ X M a k e P a n I m a g e % 9560% % 9561% % 9562% % 9563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9564% 9565% XMakePanImage() creates a thumbnail of the image and displays it in the Pan 9566% icon window. 9567% 9568% The format of the XMakePanImage method is: 9569% 9570% void XMakePanImage(Display *display,XResourceInfo *resource_info, 9571% XWindows *windows,Image *image,ExceptionInfo *exception) 9572% 9573% A description of each parameter follows: 9574% 9575% o display: Specifies a connection to an X server; returned from 9576% XOpenDisplay. 9577% 9578% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9579% 9580% o windows: Specifies a pointer to a XWindows structure. 9581% 9582% o image: the image. 9583% 9584% o exception: return any errors or warnings in this structure. 9585% 9586*/ 9587static void XMakePanImage(Display *display,XResourceInfo *resource_info, 9588 XWindows *windows,Image *image,ExceptionInfo *exception) 9589{ 9590 MagickStatusType 9591 status; 9592 9593 /* 9594 Create and display image for panning icon. 9595 */ 9596 XSetCursorState(display,windows,MagickTrue); 9597 XCheckRefreshWindows(display,windows); 9598 windows->pan.x=(int) windows->image.x; 9599 windows->pan.y=(int) windows->image.y; 9600 status=XMakeImage(display,resource_info,&windows->pan,image, 9601 windows->pan.width,windows->pan.height,exception); 9602 if (IfMagickFalse(status) ) 9603 ThrowXWindowException(ResourceLimitError, 9604 "MemoryAllocationFailed",image->filename); 9605 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 9606 windows->pan.pixmap); 9607 (void) XClearWindow(display,windows->pan.id); 9608 XDrawPanRectangle(display,windows); 9609 XSetCursorState(display,windows,MagickFalse); 9610} 9611 9612/* 9613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9614% % 9615% % 9616% % 9617+ X M a t t a E d i t I m a g e % 9618% % 9619% % 9620% % 9621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9622% 9623% XMatteEditImage() allows the user to interactively change the Matte channel 9624% of an image. If the image is PseudoClass it is promoted to DirectClass 9625% before the matte information is stored. 9626% 9627% The format of the XMatteEditImage method is: 9628% 9629% MagickBooleanType XMatteEditImage(Display *display, 9630% XResourceInfo *resource_info,XWindows *windows,Image **image, 9631% ExceptionInfo *exception) 9632% 9633% A description of each parameter follows: 9634% 9635% o display: Specifies a connection to an X server; returned from 9636% XOpenDisplay. 9637% 9638% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9639% 9640% o windows: Specifies a pointer to a XWindows structure. 9641% 9642% o image: the image; returned from ReadImage. 9643% 9644% o exception: return any errors or warnings in this structure. 9645% 9646*/ 9647static MagickBooleanType XMatteEditImage(Display *display, 9648 XResourceInfo *resource_info,XWindows *windows,Image **image, 9649 ExceptionInfo *exception) 9650{ 9651 static char 9652 matte[MaxTextExtent] = "0"; 9653 9654 static const char 9655 *MatteEditMenu[] = 9656 { 9657 "Method", 9658 "Border Color", 9659 "Fuzz", 9660 "Matte Value", 9661 "Undo", 9662 "Help", 9663 "Dismiss", 9664 (char *) NULL 9665 }; 9666 9667 static const ModeType 9668 MatteEditCommands[] = 9669 { 9670 MatteEditMethod, 9671 MatteEditBorderCommand, 9672 MatteEditFuzzCommand, 9673 MatteEditValueCommand, 9674 MatteEditUndoCommand, 9675 MatteEditHelpCommand, 9676 MatteEditDismissCommand 9677 }; 9678 9679 static PaintMethod 9680 method = PointMethod; 9681 9682 static XColor 9683 border_color = { 0, 0, 0, 0, 0, 0 }; 9684 9685 char 9686 command[MaxTextExtent], 9687 text[MaxTextExtent]; 9688 9689 Cursor 9690 cursor; 9691 9692 int 9693 entry, 9694 id, 9695 x, 9696 x_offset, 9697 y, 9698 y_offset; 9699 9700 register int 9701 i; 9702 9703 register Quantum 9704 *q; 9705 9706 unsigned int 9707 height, 9708 width; 9709 9710 size_t 9711 state; 9712 9713 XEvent 9714 event; 9715 9716 /* 9717 Map Command widget. 9718 */ 9719 (void) CloneString(&windows->command.name,"Matte Edit"); 9720 windows->command.data=4; 9721 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL); 9722 (void) XMapRaised(display,windows->command.id); 9723 XClientMessage(display,windows->image.id,windows->im_protocols, 9724 windows->im_update_widget,CurrentTime); 9725 /* 9726 Make cursor. 9727 */ 9728 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 9729 resource_info->background_color,resource_info->foreground_color); 9730 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9731 /* 9732 Track pointer until button 1 is pressed. 9733 */ 9734 XQueryPosition(display,windows->image.id,&x,&y); 9735 (void) XSelectInput(display,windows->image.id, 9736 windows->image.attributes.event_mask | PointerMotionMask); 9737 state=DefaultState; 9738 do 9739 { 9740 if (IfMagickTrue(windows->info.mapped) ) 9741 { 9742 /* 9743 Display pointer position. 9744 */ 9745 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9746 x+windows->image.x,y+windows->image.y); 9747 XInfoWidget(display,windows,text); 9748 } 9749 /* 9750 Wait for next event. 9751 */ 9752 XScreenEvent(display,windows,&event,exception); 9753 if (event.xany.window == windows->command.id) 9754 { 9755 /* 9756 Select a command from the Command widget. 9757 */ 9758 id=XCommandWidget(display,windows,MatteEditMenu,&event); 9759 if (id < 0) 9760 { 9761 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9762 continue; 9763 } 9764 switch (MatteEditCommands[id]) 9765 { 9766 case MatteEditMethod: 9767 { 9768 char 9769 **methods; 9770 9771 /* 9772 Select a method from the pop-up menu. 9773 */ 9774 methods=GetCommandOptions(MagickMethodOptions); 9775 if (methods == (char **) NULL) 9776 break; 9777 entry=XMenuWidget(display,windows,MatteEditMenu[id], 9778 (const char **) methods,command); 9779 if (entry >= 0) 9780 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 9781 MagickFalse,methods[entry]); 9782 methods=DestroyStringList(methods); 9783 break; 9784 } 9785 case MatteEditBorderCommand: 9786 { 9787 const char 9788 *ColorMenu[MaxNumberPens]; 9789 9790 int 9791 pen_number; 9792 9793 /* 9794 Initialize menu selections. 9795 */ 9796 for (i=0; i < (int) (MaxNumberPens-2); i++) 9797 ColorMenu[i]=resource_info->pen_colors[i]; 9798 ColorMenu[MaxNumberPens-2]="Browser..."; 9799 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 9800 /* 9801 Select a pen color from the pop-up menu. 9802 */ 9803 pen_number=XMenuWidget(display,windows,MatteEditMenu[id], 9804 (const char **) ColorMenu,command); 9805 if (pen_number < 0) 9806 break; 9807 if (pen_number == (MaxNumberPens-2)) 9808 { 9809 static char 9810 color_name[MaxTextExtent] = "gray"; 9811 9812 /* 9813 Select a pen color from a dialog. 9814 */ 9815 resource_info->pen_colors[pen_number]=color_name; 9816 XColorBrowserWidget(display,windows,"Select",color_name); 9817 if (*color_name == '\0') 9818 break; 9819 } 9820 /* 9821 Set border color. 9822 */ 9823 (void) XParseColor(display,windows->map_info->colormap, 9824 resource_info->pen_colors[pen_number],&border_color); 9825 break; 9826 } 9827 case MatteEditFuzzCommand: 9828 { 9829 static char 9830 fuzz[MaxTextExtent]; 9831 9832 static const char 9833 *FuzzMenu[] = 9834 { 9835 "0%", 9836 "2%", 9837 "5%", 9838 "10%", 9839 "15%", 9840 "Dialog...", 9841 (char *) NULL, 9842 }; 9843 9844 /* 9845 Select a command from the pop-up menu. 9846 */ 9847 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu, 9848 command); 9849 if (entry < 0) 9850 break; 9851 if (entry != 5) 9852 { 9853 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 9854 QuantumRange+1.0); 9855 break; 9856 } 9857 (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 9858 (void) XDialogWidget(display,windows,"Ok", 9859 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 9860 if (*fuzz == '\0') 9861 break; 9862 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 9863 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 9864 1.0); 9865 break; 9866 } 9867 case MatteEditValueCommand: 9868 { 9869 static char 9870 message[MaxTextExtent]; 9871 9872 static const char 9873 *MatteMenu[] = 9874 { 9875 "Opaque", 9876 "Transparent", 9877 "Dialog...", 9878 (char *) NULL, 9879 }; 9880 9881 /* 9882 Select a command from the pop-up menu. 9883 */ 9884 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu, 9885 command); 9886 if (entry < 0) 9887 break; 9888 if (entry != 2) 9889 { 9890 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9891 OpaqueAlpha); 9892 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9893 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9894 (Quantum) TransparentAlpha); 9895 break; 9896 } 9897 (void) FormatLocaleString(message,MaxTextExtent, 9898 "Enter matte value (0 - " QuantumFormat "):",(Quantum) 9899 QuantumRange); 9900 (void) XDialogWidget(display,windows,"Matte",message,matte); 9901 if (*matte == '\0') 9902 break; 9903 break; 9904 } 9905 case MatteEditUndoCommand: 9906 { 9907 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 9908 image,exception); 9909 break; 9910 } 9911 case MatteEditHelpCommand: 9912 { 9913 XTextViewWidget(display,resource_info,windows,MagickFalse, 9914 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9915 break; 9916 } 9917 case MatteEditDismissCommand: 9918 { 9919 /* 9920 Prematurely exit. 9921 */ 9922 state|=EscapeState; 9923 state|=ExitState; 9924 break; 9925 } 9926 default: 9927 break; 9928 } 9929 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9930 continue; 9931 } 9932 switch (event.type) 9933 { 9934 case ButtonPress: 9935 { 9936 if (event.xbutton.button != Button1) 9937 break; 9938 if ((event.xbutton.window != windows->image.id) && 9939 (event.xbutton.window != windows->magnify.id)) 9940 break; 9941 /* 9942 Update matte data. 9943 */ 9944 x=event.xbutton.x; 9945 y=event.xbutton.y; 9946 (void) XMagickCommand(display,resource_info,windows, 9947 SaveToUndoBufferCommand,image,exception); 9948 state|=UpdateConfigurationState; 9949 break; 9950 } 9951 case ButtonRelease: 9952 { 9953 if (event.xbutton.button != Button1) 9954 break; 9955 if ((event.xbutton.window != windows->image.id) && 9956 (event.xbutton.window != windows->magnify.id)) 9957 break; 9958 /* 9959 Update colormap information. 9960 */ 9961 x=event.xbutton.x; 9962 y=event.xbutton.y; 9963 XConfigureImageColormap(display,resource_info,windows,*image,exception); 9964 (void) XConfigureImage(display,resource_info,windows,*image,exception); 9965 XInfoWidget(display,windows,text); 9966 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9967 state&=(~UpdateConfigurationState); 9968 break; 9969 } 9970 case Expose: 9971 break; 9972 case KeyPress: 9973 { 9974 char 9975 command[MaxTextExtent]; 9976 9977 KeySym 9978 key_symbol; 9979 9980 if (event.xkey.window == windows->magnify.id) 9981 { 9982 Window 9983 window; 9984 9985 window=windows->magnify.id; 9986 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 9987 } 9988 if (event.xkey.window != windows->image.id) 9989 break; 9990 /* 9991 Respond to a user key press. 9992 */ 9993 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 9994 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 9995 switch ((int) key_symbol) 9996 { 9997 case XK_Escape: 9998 case XK_F20: 9999 { 10000 /* 10001 Prematurely exit. 10002 */ 10003 state|=ExitState; 10004 break; 10005 } 10006 case XK_F1: 10007 case XK_Help: 10008 { 10009 XTextViewWidget(display,resource_info,windows,MagickFalse, 10010 "Help Viewer - Matte Edit",ImageMatteEditHelp); 10011 break; 10012 } 10013 default: 10014 { 10015 (void) XBell(display,0); 10016 break; 10017 } 10018 } 10019 break; 10020 } 10021 case MotionNotify: 10022 { 10023 /* 10024 Map and unmap Info widget as cursor crosses its boundaries. 10025 */ 10026 x=event.xmotion.x; 10027 y=event.xmotion.y; 10028 if (IfMagickTrue(windows->info.mapped) ) 10029 { 10030 if ((x < (int) (windows->info.x+windows->info.width)) && 10031 (y < (int) (windows->info.y+windows->info.height))) 10032 (void) XWithdrawWindow(display,windows->info.id, 10033 windows->info.screen); 10034 } 10035 else 10036 if ((x > (int) (windows->info.x+windows->info.width)) || 10037 (y > (int) (windows->info.y+windows->info.height))) 10038 (void) XMapWindow(display,windows->info.id); 10039 break; 10040 } 10041 default: 10042 break; 10043 } 10044 if (event.xany.window == windows->magnify.id) 10045 { 10046 x=windows->magnify.x-windows->image.x; 10047 y=windows->magnify.y-windows->image.y; 10048 } 10049 x_offset=x; 10050 y_offset=y; 10051 if ((state & UpdateConfigurationState) != 0) 10052 { 10053 CacheView 10054 *image_view; 10055 10056 int 10057 x, 10058 y; 10059 10060 /* 10061 Matte edit is relative to image configuration. 10062 */ 10063 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 10064 MagickTrue); 10065 XPutPixel(windows->image.ximage,x_offset,y_offset, 10066 windows->pixel_info->background_color.pixel); 10067 width=(unsigned int) (*image)->columns; 10068 height=(unsigned int) (*image)->rows; 10069 x=0; 10070 y=0; 10071 if (windows->image.crop_geometry != (char *) NULL) 10072 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width, 10073 &height); 10074 x_offset=(int) (width*(windows->image.x+x_offset)/ 10075 windows->image.ximage->width+x); 10076 y_offset=(int) (height*(windows->image.y+y_offset)/ 10077 windows->image.ximage->height+y); 10078 if ((x_offset < 0) || (y_offset < 0)) 10079 continue; 10080 if ((x_offset >= (int) (*image)->columns) || 10081 (y_offset >= (int) (*image)->rows)) 10082 continue; 10083 if (IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) ) 10084 return(MagickFalse); 10085 if ((*image)->alpha_trait == UndefinedPixelTrait) 10086 (void) SetImageAlphaChannel(*image,OpaqueAlphaChannel,exception); 10087 image_view=AcquireAuthenticCacheView(*image,exception); 10088 switch (method) 10089 { 10090 case PointMethod: 10091 default: 10092 { 10093 /* 10094 Update matte information using point algorithm. 10095 */ 10096 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset, 10097 (ssize_t) y_offset,1,1,exception); 10098 if (q == (Quantum *) NULL) 10099 break; 10100 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10101 (void) SyncCacheViewAuthenticPixels(image_view,exception); 10102 break; 10103 } 10104 case ReplaceMethod: 10105 { 10106 PixelInfo 10107 pixel, 10108 target; 10109 10110 /* 10111 Update matte information using replace algorithm. 10112 */ 10113 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t) 10114 x_offset,(ssize_t) y_offset,&target,exception); 10115 for (y=0; y < (int) (*image)->rows; y++) 10116 { 10117 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10118 (*image)->columns,1,exception); 10119 if (q == (Quantum *) NULL) 10120 break; 10121 for (x=0; x < (int) (*image)->columns; x++) 10122 { 10123 GetPixelInfoPixel(*image,q,&pixel); 10124 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 10125 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10126 q+=GetPixelChannels(*image); 10127 } 10128 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 10129 break; 10130 } 10131 break; 10132 } 10133 case FloodfillMethod: 10134 case FillToBorderMethod: 10135 { 10136 ChannelType 10137 channel_mask; 10138 10139 DrawInfo 10140 *draw_info; 10141 10142 PixelInfo 10143 target; 10144 10145 /* 10146 Update matte information using floodfill algorithm. 10147 */ 10148 (void) GetOneVirtualPixelInfo(*image, 10149 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 10150 y_offset,&target,exception); 10151 if (method == FillToBorderMethod) 10152 { 10153 target.red=(double) ScaleShortToQuantum( 10154 border_color.red); 10155 target.green=(double) ScaleShortToQuantum( 10156 border_color.green); 10157 target.blue=(double) ScaleShortToQuantum( 10158 border_color.blue); 10159 } 10160 draw_info=CloneDrawInfo(resource_info->image_info, 10161 (DrawInfo *) NULL); 10162 draw_info->fill.alpha=(double) ClampToQuantum( 10163 StringToDouble(matte,(char **) NULL)); 10164 channel_mask=SetImageChannelMask(*image,AlphaChannel); 10165 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 10166 x_offset,(ssize_t) y_offset, 10167 IsMagickFalse(method == FloodfillMethod),exception); 10168 (void) SetPixelChannelMask(*image,channel_mask); 10169 draw_info=DestroyDrawInfo(draw_info); 10170 break; 10171 } 10172 case ResetMethod: 10173 { 10174 /* 10175 Update matte information using reset algorithm. 10176 */ 10177 if (IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) ) 10178 return(MagickFalse); 10179 for (y=0; y < (int) (*image)->rows; y++) 10180 { 10181 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10182 (*image)->columns,1,exception); 10183 if (q == (Quantum *) NULL) 10184 break; 10185 for (x=0; x < (int) (*image)->columns; x++) 10186 { 10187 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10188 q+=GetPixelChannels(*image); 10189 } 10190 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 10191 break; 10192 } 10193 if (StringToLong(matte) == (long) OpaqueAlpha) 10194 (*image)->alpha_trait=UndefinedPixelTrait; 10195 break; 10196 } 10197 } 10198 image_view=DestroyCacheView(image_view); 10199 state&=(~UpdateConfigurationState); 10200 } 10201 } while ((state & ExitState) == 0); 10202 (void) XSelectInput(display,windows->image.id, 10203 windows->image.attributes.event_mask); 10204 XSetCursorState(display,windows,MagickFalse); 10205 (void) XFreeCursor(display,cursor); 10206 return(MagickTrue); 10207} 10208 10209/* 10210%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10211% % 10212% % 10213% % 10214+ X O p e n I m a g e % 10215% % 10216% % 10217% % 10218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10219% 10220% XOpenImage() loads an image from a file. 10221% 10222% The format of the XOpenImage method is: 10223% 10224% Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10225% XWindows *windows,const unsigned int command) 10226% 10227% A description of each parameter follows: 10228% 10229% o display: Specifies a connection to an X server; returned from 10230% XOpenDisplay. 10231% 10232% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10233% 10234% o windows: Specifies a pointer to a XWindows structure. 10235% 10236% o command: A value other than zero indicates that the file is selected 10237% from the command line argument list. 10238% 10239*/ 10240static Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10241 XWindows *windows,const MagickBooleanType command) 10242{ 10243 const MagickInfo 10244 *magick_info; 10245 10246 ExceptionInfo 10247 *exception; 10248 10249 Image 10250 *nexus; 10251 10252 ImageInfo 10253 *image_info; 10254 10255 static char 10256 filename[MaxTextExtent] = "\0"; 10257 10258 /* 10259 Request file name from user. 10260 */ 10261 if (IfMagickFalse(command) ) 10262 XFileBrowserWidget(display,windows,"Open",filename); 10263 else 10264 { 10265 char 10266 **filelist, 10267 **files; 10268 10269 int 10270 count, 10271 status; 10272 10273 register int 10274 i, 10275 j; 10276 10277 /* 10278 Select next image from the command line. 10279 */ 10280 status=XGetCommand(display,windows->image.id,&files,&count); 10281 if (status == 0) 10282 { 10283 ThrowXWindowException(XServerError,"UnableToGetProperty","..."); 10284 return((Image *) NULL); 10285 } 10286 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10287 if (filelist == (char **) NULL) 10288 { 10289 ThrowXWindowException(ResourceLimitError, 10290 "MemoryAllocationFailed","..."); 10291 (void) XFreeStringList(files); 10292 return((Image *) NULL); 10293 } 10294 j=0; 10295 for (i=1; i < count; i++) 10296 if (*files[i] != '-') 10297 filelist[j++]=files[i]; 10298 filelist[j]=(char *) NULL; 10299 XListBrowserWidget(display,windows,&windows->widget, 10300 (const char **) filelist,"Load","Select Image to Load:",filename); 10301 filelist=(char **) RelinquishMagickMemory(filelist); 10302 (void) XFreeStringList(files); 10303 } 10304 if (*filename == '\0') 10305 return((Image *) NULL); 10306 image_info=CloneImageInfo(resource_info->image_info); 10307 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL, 10308 (void *) NULL); 10309 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10310 exception=AcquireExceptionInfo(); 10311 (void) SetImageInfo(image_info,0,exception); 10312 if (LocaleCompare(image_info->magick,"X") == 0) 10313 { 10314 char 10315 seconds[MaxTextExtent]; 10316 10317 /* 10318 User may want to delay the X server screen grab. 10319 */ 10320 (void) CopyMagickString(seconds,"0",MaxTextExtent); 10321 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:", 10322 seconds); 10323 if (*seconds == '\0') 10324 return((Image *) NULL); 10325 XDelay(display,(size_t) (1000*StringToLong(seconds))); 10326 } 10327 magick_info=GetMagickInfo(image_info->magick,exception); 10328 if ((magick_info != (const MagickInfo *) NULL) && 10329 IfMagickTrue(magick_info->raw)) 10330 { 10331 char 10332 geometry[MaxTextExtent]; 10333 10334 /* 10335 Request image size from the user. 10336 */ 10337 (void) CopyMagickString(geometry,"512x512",MaxTextExtent); 10338 if (image_info->size != (char *) NULL) 10339 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent); 10340 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:", 10341 geometry); 10342 (void) CloneString(&image_info->size,geometry); 10343 } 10344 /* 10345 Load the image. 10346 */ 10347 XSetCursorState(display,windows,MagickTrue); 10348 XCheckRefreshWindows(display,windows); 10349 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10350 nexus=ReadImage(image_info,exception); 10351 CatchException(exception); 10352 XSetCursorState(display,windows,MagickFalse); 10353 if (nexus != (Image *) NULL) 10354 XClientMessage(display,windows->image.id,windows->im_protocols, 10355 windows->im_next_image,CurrentTime); 10356 else 10357 { 10358 char 10359 *text, 10360 **textlist; 10361 10362 /* 10363 Unknown image format. 10364 */ 10365 text=FileToString(filename,~0UL,exception); 10366 if (text == (char *) NULL) 10367 return((Image *) NULL); 10368 textlist=StringToList(text); 10369 if (textlist != (char **) NULL) 10370 { 10371 char 10372 title[MaxTextExtent]; 10373 10374 register int 10375 i; 10376 10377 (void) FormatLocaleString(title,MaxTextExtent, 10378 "Unknown format: %s",filename); 10379 XTextViewWidget(display,resource_info,windows,MagickTrue,title, 10380 (const char **) textlist); 10381 for (i=0; textlist[i] != (char *) NULL; i++) 10382 textlist[i]=DestroyString(textlist[i]); 10383 textlist=(char **) RelinquishMagickMemory(textlist); 10384 } 10385 text=DestroyString(text); 10386 } 10387 exception=DestroyExceptionInfo(exception); 10388 image_info=DestroyImageInfo(image_info); 10389 return(nexus); 10390} 10391 10392/* 10393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10394% % 10395% % 10396% % 10397+ X P a n I m a g e % 10398% % 10399% % 10400% % 10401%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10402% 10403% XPanImage() pans the image until the mouse button is released. 10404% 10405% The format of the XPanImage method is: 10406% 10407% void XPanImage(Display *display,XWindows *windows,XEvent *event, 10408% ExceptionInfo *exception) 10409% 10410% A description of each parameter follows: 10411% 10412% o display: Specifies a connection to an X server; returned from 10413% XOpenDisplay. 10414% 10415% o windows: Specifies a pointer to a XWindows structure. 10416% 10417% o event: Specifies a pointer to a XEvent structure. If it is NULL, 10418% the entire image is refreshed. 10419% 10420% o exception: return any errors or warnings in this structure. 10421% 10422*/ 10423static void XPanImage(Display *display,XWindows *windows,XEvent *event, 10424 ExceptionInfo *exception) 10425{ 10426 char 10427 text[MaxTextExtent]; 10428 10429 Cursor 10430 cursor; 10431 10432 double 10433 x_factor, 10434 y_factor; 10435 10436 RectangleInfo 10437 pan_info; 10438 10439 size_t 10440 state; 10441 10442 /* 10443 Define cursor. 10444 */ 10445 if ((windows->image.ximage->width > (int) windows->image.width) && 10446 (windows->image.ximage->height > (int) windows->image.height)) 10447 cursor=XCreateFontCursor(display,XC_fleur); 10448 else 10449 if (windows->image.ximage->width > (int) windows->image.width) 10450 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow); 10451 else 10452 if (windows->image.ximage->height > (int) windows->image.height) 10453 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow); 10454 else 10455 cursor=XCreateFontCursor(display,XC_arrow); 10456 (void) XCheckDefineCursor(display,windows->pan.id,cursor); 10457 /* 10458 Pan image as pointer moves until the mouse button is released. 10459 */ 10460 x_factor=(double) windows->image.ximage->width/windows->pan.width; 10461 y_factor=(double) windows->image.ximage->height/windows->pan.height; 10462 pan_info.width=windows->pan.width*windows->image.width/ 10463 windows->image.ximage->width; 10464 pan_info.height=windows->pan.height*windows->image.height/ 10465 windows->image.ximage->height; 10466 pan_info.x=0; 10467 pan_info.y=0; 10468 state=UpdateConfigurationState; 10469 do 10470 { 10471 switch (event->type) 10472 { 10473 case ButtonPress: 10474 { 10475 /* 10476 User choose an initial pan location. 10477 */ 10478 pan_info.x=(ssize_t) event->xbutton.x; 10479 pan_info.y=(ssize_t) event->xbutton.y; 10480 state|=UpdateConfigurationState; 10481 break; 10482 } 10483 case ButtonRelease: 10484 { 10485 /* 10486 User has finished panning the image. 10487 */ 10488 pan_info.x=(ssize_t) event->xbutton.x; 10489 pan_info.y=(ssize_t) event->xbutton.y; 10490 state|=UpdateConfigurationState | ExitState; 10491 break; 10492 } 10493 case MotionNotify: 10494 { 10495 pan_info.x=(ssize_t) event->xmotion.x; 10496 pan_info.y=(ssize_t) event->xmotion.y; 10497 state|=UpdateConfigurationState; 10498 } 10499 default: 10500 break; 10501 } 10502 if ((state & UpdateConfigurationState) != 0) 10503 { 10504 /* 10505 Check boundary conditions. 10506 */ 10507 if (pan_info.x < (ssize_t) (pan_info.width/2)) 10508 pan_info.x=0; 10509 else 10510 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2))); 10511 if (pan_info.x < 0) 10512 pan_info.x=0; 10513 else 10514 if ((int) (pan_info.x+windows->image.width) > 10515 windows->image.ximage->width) 10516 pan_info.x=(ssize_t) 10517 (windows->image.ximage->width-windows->image.width); 10518 if (pan_info.y < (ssize_t) (pan_info.height/2)) 10519 pan_info.y=0; 10520 else 10521 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2))); 10522 if (pan_info.y < 0) 10523 pan_info.y=0; 10524 else 10525 if ((int) (pan_info.y+windows->image.height) > 10526 windows->image.ximage->height) 10527 pan_info.y=(ssize_t) 10528 (windows->image.ximage->height-windows->image.height); 10529 if ((windows->image.x != (int) pan_info.x) || 10530 (windows->image.y != (int) pan_info.y)) 10531 { 10532 /* 10533 Display image pan offset. 10534 */ 10535 windows->image.x=(int) pan_info.x; 10536 windows->image.y=(int) pan_info.y; 10537 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 10538 windows->image.width,windows->image.height,windows->image.x, 10539 windows->image.y); 10540 XInfoWidget(display,windows,text); 10541 /* 10542 Refresh Image window. 10543 */ 10544 XDrawPanRectangle(display,windows); 10545 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 10546 } 10547 state&=(~UpdateConfigurationState); 10548 } 10549 /* 10550 Wait for next event. 10551 */ 10552 if ((state & ExitState) == 0) 10553 XScreenEvent(display,windows,event,exception); 10554 } while ((state & ExitState) == 0); 10555 /* 10556 Restore cursor. 10557 */ 10558 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor); 10559 (void) XFreeCursor(display,cursor); 10560 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 10561} 10562 10563/* 10564%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10565% % 10566% % 10567% % 10568+ X P a s t e I m a g e % 10569% % 10570% % 10571% % 10572%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10573% 10574% XPasteImage() pastes an image previously saved with XCropImage in the X 10575% window image at a location the user chooses with the pointer. 10576% 10577% The format of the XPasteImage method is: 10578% 10579% MagickBooleanType XPasteImage(Display *display, 10580% XResourceInfo *resource_info,XWindows *windows,Image *image, 10581% ExceptionInfo *exception) 10582% 10583% A description of each parameter follows: 10584% 10585% o display: Specifies a connection to an X server; returned from 10586% XOpenDisplay. 10587% 10588% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10589% 10590% o windows: Specifies a pointer to a XWindows structure. 10591% 10592% o image: the image; returned from ReadImage. 10593% 10594% o exception: return any errors or warnings in this structure. 10595% 10596*/ 10597static MagickBooleanType XPasteImage(Display *display, 10598 XResourceInfo *resource_info,XWindows *windows,Image *image, 10599 ExceptionInfo *exception) 10600{ 10601 static const char 10602 *PasteMenu[] = 10603 { 10604 "Operator", 10605 "Help", 10606 "Dismiss", 10607 (char *) NULL 10608 }; 10609 10610 static const ModeType 10611 PasteCommands[] = 10612 { 10613 PasteOperatorsCommand, 10614 PasteHelpCommand, 10615 PasteDismissCommand 10616 }; 10617 10618 static CompositeOperator 10619 compose = CopyCompositeOp; 10620 10621 char 10622 text[MaxTextExtent]; 10623 10624 Cursor 10625 cursor; 10626 10627 Image 10628 *paste_image; 10629 10630 int 10631 entry, 10632 id, 10633 x, 10634 y; 10635 10636 double 10637 scale_factor; 10638 10639 RectangleInfo 10640 highlight_info, 10641 paste_info; 10642 10643 unsigned int 10644 height, 10645 width; 10646 10647 size_t 10648 state; 10649 10650 XEvent 10651 event; 10652 10653 /* 10654 Copy image. 10655 */ 10656 if (resource_info->copy_image == (Image *) NULL) 10657 return(MagickFalse); 10658 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception); 10659 /* 10660 Map Command widget. 10661 */ 10662 (void) CloneString(&windows->command.name,"Paste"); 10663 windows->command.data=1; 10664 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL); 10665 (void) XMapRaised(display,windows->command.id); 10666 XClientMessage(display,windows->image.id,windows->im_protocols, 10667 windows->im_update_widget,CurrentTime); 10668 /* 10669 Track pointer until button 1 is pressed. 10670 */ 10671 XSetCursorState(display,windows,MagickFalse); 10672 XQueryPosition(display,windows->image.id,&x,&y); 10673 (void) XSelectInput(display,windows->image.id, 10674 windows->image.attributes.event_mask | PointerMotionMask); 10675 paste_info.x=(ssize_t) windows->image.x+x; 10676 paste_info.y=(ssize_t) windows->image.y+y; 10677 paste_info.width=0; 10678 paste_info.height=0; 10679 cursor=XCreateFontCursor(display,XC_ul_angle); 10680 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 10681 state=DefaultState; 10682 do 10683 { 10684 if (IfMagickTrue(windows->info.mapped) ) 10685 { 10686 /* 10687 Display pointer position. 10688 */ 10689 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 10690 (long) paste_info.x,(long) paste_info.y); 10691 XInfoWidget(display,windows,text); 10692 } 10693 highlight_info=paste_info; 10694 highlight_info.x=paste_info.x-windows->image.x; 10695 highlight_info.y=paste_info.y-windows->image.y; 10696 XHighlightRectangle(display,windows->image.id, 10697 windows->image.highlight_context,&highlight_info); 10698 /* 10699 Wait for next event. 10700 */ 10701 XScreenEvent(display,windows,&event,exception); 10702 XHighlightRectangle(display,windows->image.id, 10703 windows->image.highlight_context,&highlight_info); 10704 if (event.xany.window == windows->command.id) 10705 { 10706 /* 10707 Select a command from the Command widget. 10708 */ 10709 id=XCommandWidget(display,windows,PasteMenu,&event); 10710 if (id < 0) 10711 continue; 10712 switch (PasteCommands[id]) 10713 { 10714 case PasteOperatorsCommand: 10715 { 10716 char 10717 command[MaxTextExtent], 10718 **operators; 10719 10720 /* 10721 Select a command from the pop-up menu. 10722 */ 10723 operators=GetCommandOptions(MagickComposeOptions); 10724 if (operators == (char **) NULL) 10725 break; 10726 entry=XMenuWidget(display,windows,PasteMenu[id], 10727 (const char **) operators,command); 10728 if (entry >= 0) 10729 compose=(CompositeOperator) ParseCommandOption( 10730 MagickComposeOptions,MagickFalse,operators[entry]); 10731 operators=DestroyStringList(operators); 10732 break; 10733 } 10734 case PasteHelpCommand: 10735 { 10736 XTextViewWidget(display,resource_info,windows,MagickFalse, 10737 "Help Viewer - Image Composite",ImagePasteHelp); 10738 break; 10739 } 10740 case PasteDismissCommand: 10741 { 10742 /* 10743 Prematurely exit. 10744 */ 10745 state|=EscapeState; 10746 state|=ExitState; 10747 break; 10748 } 10749 default: 10750 break; 10751 } 10752 continue; 10753 } 10754 switch (event.type) 10755 { 10756 case ButtonPress: 10757 { 10758 if (IfMagickTrue(image->debug) ) 10759 (void) LogMagickEvent(X11Event,GetMagickModule(), 10760 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 10761 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10762 if (event.xbutton.button != Button1) 10763 break; 10764 if (event.xbutton.window != windows->image.id) 10765 break; 10766 /* 10767 Paste rectangle is relative to image configuration. 10768 */ 10769 width=(unsigned int) image->columns; 10770 height=(unsigned int) image->rows; 10771 x=0; 10772 y=0; 10773 if (windows->image.crop_geometry != (char *) NULL) 10774 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 10775 &width,&height); 10776 scale_factor=(double) windows->image.ximage->width/width; 10777 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5); 10778 scale_factor=(double) windows->image.ximage->height/height; 10779 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5); 10780 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10781 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10782 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10783 break; 10784 } 10785 case ButtonRelease: 10786 { 10787 if (IfMagickTrue(image->debug) ) 10788 (void) LogMagickEvent(X11Event,GetMagickModule(), 10789 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 10790 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10791 if (event.xbutton.button != Button1) 10792 break; 10793 if (event.xbutton.window != windows->image.id) 10794 break; 10795 if ((paste_info.width != 0) && (paste_info.height != 0)) 10796 { 10797 /* 10798 User has selected the location of the paste image. 10799 */ 10800 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10801 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10802 state|=ExitState; 10803 } 10804 break; 10805 } 10806 case Expose: 10807 break; 10808 case KeyPress: 10809 { 10810 char 10811 command[MaxTextExtent]; 10812 10813 KeySym 10814 key_symbol; 10815 10816 int 10817 length; 10818 10819 if (event.xkey.window != windows->image.id) 10820 break; 10821 /* 10822 Respond to a user key press. 10823 */ 10824 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 10825 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10826 *(command+length)='\0'; 10827 if (IfMagickTrue(image->debug) ) 10828 (void) LogMagickEvent(X11Event,GetMagickModule(), 10829 "Key press: 0x%lx (%s)",(long) key_symbol,command); 10830 switch ((int) key_symbol) 10831 { 10832 case XK_Escape: 10833 case XK_F20: 10834 { 10835 /* 10836 Prematurely exit. 10837 */ 10838 paste_image=DestroyImage(paste_image); 10839 state|=EscapeState; 10840 state|=ExitState; 10841 break; 10842 } 10843 case XK_F1: 10844 case XK_Help: 10845 { 10846 (void) XSetFunction(display,windows->image.highlight_context, 10847 GXcopy); 10848 XTextViewWidget(display,resource_info,windows,MagickFalse, 10849 "Help Viewer - Image Composite",ImagePasteHelp); 10850 (void) XSetFunction(display,windows->image.highlight_context, 10851 GXinvert); 10852 break; 10853 } 10854 default: 10855 { 10856 (void) XBell(display,0); 10857 break; 10858 } 10859 } 10860 break; 10861 } 10862 case MotionNotify: 10863 { 10864 /* 10865 Map and unmap Info widget as text cursor crosses its boundaries. 10866 */ 10867 x=event.xmotion.x; 10868 y=event.xmotion.y; 10869 if (IfMagickTrue(windows->info.mapped) ) 10870 { 10871 if ((x < (int) (windows->info.x+windows->info.width)) && 10872 (y < (int) (windows->info.y+windows->info.height))) 10873 (void) XWithdrawWindow(display,windows->info.id, 10874 windows->info.screen); 10875 } 10876 else 10877 if ((x > (int) (windows->info.x+windows->info.width)) || 10878 (y > (int) (windows->info.y+windows->info.height))) 10879 (void) XMapWindow(display,windows->info.id); 10880 paste_info.x=(ssize_t) windows->image.x+x; 10881 paste_info.y=(ssize_t) windows->image.y+y; 10882 break; 10883 } 10884 default: 10885 { 10886 if (IfMagickTrue(image->debug) ) 10887 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 10888 event.type); 10889 break; 10890 } 10891 } 10892 } while ((state & ExitState) == 0); 10893 (void) XSelectInput(display,windows->image.id, 10894 windows->image.attributes.event_mask); 10895 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 10896 XSetCursorState(display,windows,MagickFalse); 10897 (void) XFreeCursor(display,cursor); 10898 if ((state & EscapeState) != 0) 10899 return(MagickTrue); 10900 /* 10901 Image pasting is relative to image configuration. 10902 */ 10903 XSetCursorState(display,windows,MagickTrue); 10904 XCheckRefreshWindows(display,windows); 10905 width=(unsigned int) image->columns; 10906 height=(unsigned int) image->rows; 10907 x=0; 10908 y=0; 10909 if (windows->image.crop_geometry != (char *) NULL) 10910 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 10911 scale_factor=(double) width/windows->image.ximage->width; 10912 paste_info.x+=x; 10913 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5); 10914 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5); 10915 scale_factor=(double) height/windows->image.ximage->height; 10916 paste_info.y+=y; 10917 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5); 10918 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5); 10919 /* 10920 Paste image with X Image window. 10921 */ 10922 (void) CompositeImage(image,paste_image,compose,MagickTrue,paste_info.x, 10923 paste_info.y,exception); 10924 paste_image=DestroyImage(paste_image); 10925 XSetCursorState(display,windows,MagickFalse); 10926 /* 10927 Update image colormap. 10928 */ 10929 XConfigureImageColormap(display,resource_info,windows,image,exception); 10930 (void) XConfigureImage(display,resource_info,windows,image,exception); 10931 return(MagickTrue); 10932} 10933 10934/* 10935%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10936% % 10937% % 10938% % 10939+ X P r i n t I m a g e % 10940% % 10941% % 10942% % 10943%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10944% 10945% XPrintImage() prints an image to a Postscript printer. 10946% 10947% The format of the XPrintImage method is: 10948% 10949% MagickBooleanType XPrintImage(Display *display, 10950% XResourceInfo *resource_info,XWindows *windows,Image *image, 10951% ExceptionInfo *exception) 10952% 10953% A description of each parameter follows: 10954% 10955% o display: Specifies a connection to an X server; returned from 10956% XOpenDisplay. 10957% 10958% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10959% 10960% o windows: Specifies a pointer to a XWindows structure. 10961% 10962% o image: the image. 10963% 10964% o exception: return any errors or warnings in this structure. 10965% 10966*/ 10967static MagickBooleanType XPrintImage(Display *display, 10968 XResourceInfo *resource_info,XWindows *windows,Image *image, 10969 ExceptionInfo *exception) 10970{ 10971 char 10972 filename[MaxTextExtent], 10973 geometry[MaxTextExtent]; 10974 10975 Image 10976 *print_image; 10977 10978 ImageInfo 10979 *image_info; 10980 10981 MagickStatusType 10982 status; 10983 10984 /* 10985 Request Postscript page geometry from user. 10986 */ 10987 image_info=CloneImageInfo(resource_info->image_info); 10988 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter"); 10989 if (image_info->page != (char *) NULL) 10990 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 10991 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 10992 "Select Postscript Page Geometry:",geometry); 10993 if (*geometry == '\0') 10994 return(MagickTrue); 10995 image_info->page=GetPageGeometry(geometry); 10996 /* 10997 Apply image transforms. 10998 */ 10999 XSetCursorState(display,windows,MagickTrue); 11000 XCheckRefreshWindows(display,windows); 11001 print_image=CloneImage(image,0,0,MagickTrue,exception); 11002 if (print_image == (Image *) NULL) 11003 return(MagickFalse); 11004 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 11005 windows->image.ximage->width,windows->image.ximage->height); 11006 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry, 11007 exception); 11008 /* 11009 Print image. 11010 */ 11011 (void) AcquireUniqueFilename(filename); 11012 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s", 11013 filename); 11014 status=WriteImage(image_info,print_image,exception); 11015 (void) RelinquishUniqueFileResource(filename); 11016 print_image=DestroyImage(print_image); 11017 image_info=DestroyImageInfo(image_info); 11018 XSetCursorState(display,windows,MagickFalse); 11019 return(IsMagickTrue(status)); 11020} 11021 11022/* 11023%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11024% % 11025% % 11026% % 11027+ X R O I I m a g e % 11028% % 11029% % 11030% % 11031%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11032% 11033% XROIImage() applies an image processing technique to a region of interest. 11034% 11035% The format of the XROIImage method is: 11036% 11037% MagickBooleanType XROIImage(Display *display, 11038% XResourceInfo *resource_info,XWindows *windows,Image **image, 11039% ExceptionInfo *exception) 11040% 11041% A description of each parameter follows: 11042% 11043% o display: Specifies a connection to an X server; returned from 11044% XOpenDisplay. 11045% 11046% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11047% 11048% o windows: Specifies a pointer to a XWindows structure. 11049% 11050% o image: the image; returned from ReadImage. 11051% 11052% o exception: return any errors or warnings in this structure. 11053% 11054*/ 11055static MagickBooleanType XROIImage(Display *display, 11056 XResourceInfo *resource_info,XWindows *windows,Image **image, 11057 ExceptionInfo *exception) 11058{ 11059#define ApplyMenus 7 11060 11061 static const char 11062 *ROIMenu[] = 11063 { 11064 "Help", 11065 "Dismiss", 11066 (char *) NULL 11067 }, 11068 *ApplyMenu[] = 11069 { 11070 "File", 11071 "Edit", 11072 "Transform", 11073 "Enhance", 11074 "Effects", 11075 "F/X", 11076 "Miscellany", 11077 "Help", 11078 "Dismiss", 11079 (char *) NULL 11080 }, 11081 *FileMenu[] = 11082 { 11083 "Save...", 11084 "Print...", 11085 (char *) NULL 11086 }, 11087 *EditMenu[] = 11088 { 11089 "Undo", 11090 "Redo", 11091 (char *) NULL 11092 }, 11093 *TransformMenu[] = 11094 { 11095 "Flop", 11096 "Flip", 11097 "Rotate Right", 11098 "Rotate Left", 11099 (char *) NULL 11100 }, 11101 *EnhanceMenu[] = 11102 { 11103 "Hue...", 11104 "Saturation...", 11105 "Brightness...", 11106 "Gamma...", 11107 "Spiff", 11108 "Dull", 11109 "Contrast Stretch...", 11110 "Sigmoidal Contrast...", 11111 "Normalize", 11112 "Equalize", 11113 "Negate", 11114 "Grayscale", 11115 "Map...", 11116 "Quantize...", 11117 (char *) NULL 11118 }, 11119 *EffectsMenu[] = 11120 { 11121 "Despeckle", 11122 "Emboss", 11123 "Reduce Noise", 11124 "Add Noise", 11125 "Sharpen...", 11126 "Blur...", 11127 "Threshold...", 11128 "Edge Detect...", 11129 "Spread...", 11130 "Shade...", 11131 "Raise...", 11132 "Segment...", 11133 (char *) NULL 11134 }, 11135 *FXMenu[] = 11136 { 11137 "Solarize...", 11138 "Sepia Tone...", 11139 "Swirl...", 11140 "Implode...", 11141 "Vignette...", 11142 "Wave...", 11143 "Oil Paint...", 11144 "Charcoal Draw...", 11145 (char *) NULL 11146 }, 11147 *MiscellanyMenu[] = 11148 { 11149 "Image Info", 11150 "Zoom Image", 11151 "Show Preview...", 11152 "Show Histogram", 11153 "Show Matte", 11154 (char *) NULL 11155 }; 11156 11157 static const char 11158 **Menus[ApplyMenus] = 11159 { 11160 FileMenu, 11161 EditMenu, 11162 TransformMenu, 11163 EnhanceMenu, 11164 EffectsMenu, 11165 FXMenu, 11166 MiscellanyMenu 11167 }; 11168 11169 static const CommandType 11170 ApplyCommands[] = 11171 { 11172 NullCommand, 11173 NullCommand, 11174 NullCommand, 11175 NullCommand, 11176 NullCommand, 11177 NullCommand, 11178 NullCommand, 11179 HelpCommand, 11180 QuitCommand 11181 }, 11182 FileCommands[] = 11183 { 11184 SaveCommand, 11185 PrintCommand 11186 }, 11187 EditCommands[] = 11188 { 11189 UndoCommand, 11190 RedoCommand 11191 }, 11192 TransformCommands[] = 11193 { 11194 FlopCommand, 11195 FlipCommand, 11196 RotateRightCommand, 11197 RotateLeftCommand 11198 }, 11199 EnhanceCommands[] = 11200 { 11201 HueCommand, 11202 SaturationCommand, 11203 BrightnessCommand, 11204 GammaCommand, 11205 SpiffCommand, 11206 DullCommand, 11207 ContrastStretchCommand, 11208 SigmoidalContrastCommand, 11209 NormalizeCommand, 11210 EqualizeCommand, 11211 NegateCommand, 11212 GrayscaleCommand, 11213 MapCommand, 11214 QuantizeCommand 11215 }, 11216 EffectsCommands[] = 11217 { 11218 DespeckleCommand, 11219 EmbossCommand, 11220 ReduceNoiseCommand, 11221 AddNoiseCommand, 11222 SharpenCommand, 11223 BlurCommand, 11224 EdgeDetectCommand, 11225 SpreadCommand, 11226 ShadeCommand, 11227 RaiseCommand, 11228 SegmentCommand 11229 }, 11230 FXCommands[] = 11231 { 11232 SolarizeCommand, 11233 SepiaToneCommand, 11234 SwirlCommand, 11235 ImplodeCommand, 11236 VignetteCommand, 11237 WaveCommand, 11238 OilPaintCommand, 11239 CharcoalDrawCommand 11240 }, 11241 MiscellanyCommands[] = 11242 { 11243 InfoCommand, 11244 ZoomCommand, 11245 ShowPreviewCommand, 11246 ShowHistogramCommand, 11247 ShowMatteCommand 11248 }, 11249 ROICommands[] = 11250 { 11251 ROIHelpCommand, 11252 ROIDismissCommand 11253 }; 11254 11255 static const CommandType 11256 *Commands[ApplyMenus] = 11257 { 11258 FileCommands, 11259 EditCommands, 11260 TransformCommands, 11261 EnhanceCommands, 11262 EffectsCommands, 11263 FXCommands, 11264 MiscellanyCommands 11265 }; 11266 11267 char 11268 command[MaxTextExtent], 11269 text[MaxTextExtent]; 11270 11271 CommandType 11272 command_type; 11273 11274 Cursor 11275 cursor; 11276 11277 Image 11278 *roi_image; 11279 11280 int 11281 entry, 11282 id, 11283 x, 11284 y; 11285 11286 double 11287 scale_factor; 11288 11289 MagickProgressMonitor 11290 progress_monitor; 11291 11292 RectangleInfo 11293 crop_info, 11294 highlight_info, 11295 roi_info; 11296 11297 unsigned int 11298 height, 11299 width; 11300 11301 size_t 11302 state; 11303 11304 XEvent 11305 event; 11306 11307 /* 11308 Map Command widget. 11309 */ 11310 (void) CloneString(&windows->command.name,"ROI"); 11311 windows->command.data=0; 11312 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL); 11313 (void) XMapRaised(display,windows->command.id); 11314 XClientMessage(display,windows->image.id,windows->im_protocols, 11315 windows->im_update_widget,CurrentTime); 11316 /* 11317 Track pointer until button 1 is pressed. 11318 */ 11319 XQueryPosition(display,windows->image.id,&x,&y); 11320 (void) XSelectInput(display,windows->image.id, 11321 windows->image.attributes.event_mask | PointerMotionMask); 11322 roi_info.x=(ssize_t) windows->image.x+x; 11323 roi_info.y=(ssize_t) windows->image.y+y; 11324 roi_info.width=0; 11325 roi_info.height=0; 11326 cursor=XCreateFontCursor(display,XC_fleur); 11327 state=DefaultState; 11328 do 11329 { 11330 if (IfMagickTrue(windows->info.mapped) ) 11331 { 11332 /* 11333 Display pointer position. 11334 */ 11335 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 11336 (long) roi_info.x,(long) roi_info.y); 11337 XInfoWidget(display,windows,text); 11338 } 11339 /* 11340 Wait for next event. 11341 */ 11342 XScreenEvent(display,windows,&event,exception); 11343 if (event.xany.window == windows->command.id) 11344 { 11345 /* 11346 Select a command from the Command widget. 11347 */ 11348 id=XCommandWidget(display,windows,ROIMenu,&event); 11349 if (id < 0) 11350 continue; 11351 switch (ROICommands[id]) 11352 { 11353 case ROIHelpCommand: 11354 { 11355 XTextViewWidget(display,resource_info,windows,MagickFalse, 11356 "Help Viewer - Region of Interest",ImageROIHelp); 11357 break; 11358 } 11359 case ROIDismissCommand: 11360 { 11361 /* 11362 Prematurely exit. 11363 */ 11364 state|=EscapeState; 11365 state|=ExitState; 11366 break; 11367 } 11368 default: 11369 break; 11370 } 11371 continue; 11372 } 11373 switch (event.type) 11374 { 11375 case ButtonPress: 11376 { 11377 if (event.xbutton.button != Button1) 11378 break; 11379 if (event.xbutton.window != windows->image.id) 11380 break; 11381 /* 11382 Note first corner of region of interest rectangle-- exit loop. 11383 */ 11384 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11385 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11386 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11387 state|=ExitState; 11388 break; 11389 } 11390 case ButtonRelease: 11391 break; 11392 case Expose: 11393 break; 11394 case KeyPress: 11395 { 11396 KeySym 11397 key_symbol; 11398 11399 if (event.xkey.window != windows->image.id) 11400 break; 11401 /* 11402 Respond to a user key press. 11403 */ 11404 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11405 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11406 switch ((int) key_symbol) 11407 { 11408 case XK_Escape: 11409 case XK_F20: 11410 { 11411 /* 11412 Prematurely exit. 11413 */ 11414 state|=EscapeState; 11415 state|=ExitState; 11416 break; 11417 } 11418 case XK_F1: 11419 case XK_Help: 11420 { 11421 XTextViewWidget(display,resource_info,windows,MagickFalse, 11422 "Help Viewer - Region of Interest",ImageROIHelp); 11423 break; 11424 } 11425 default: 11426 { 11427 (void) XBell(display,0); 11428 break; 11429 } 11430 } 11431 break; 11432 } 11433 case MotionNotify: 11434 { 11435 /* 11436 Map and unmap Info widget as text cursor crosses its boundaries. 11437 */ 11438 x=event.xmotion.x; 11439 y=event.xmotion.y; 11440 if (IfMagickTrue(windows->info.mapped) ) 11441 { 11442 if ((x < (int) (windows->info.x+windows->info.width)) && 11443 (y < (int) (windows->info.y+windows->info.height))) 11444 (void) XWithdrawWindow(display,windows->info.id, 11445 windows->info.screen); 11446 } 11447 else 11448 if ((x > (int) (windows->info.x+windows->info.width)) || 11449 (y > (int) (windows->info.y+windows->info.height))) 11450 (void) XMapWindow(display,windows->info.id); 11451 roi_info.x=(ssize_t) windows->image.x+x; 11452 roi_info.y=(ssize_t) windows->image.y+y; 11453 break; 11454 } 11455 default: 11456 break; 11457 } 11458 } while ((state & ExitState) == 0); 11459 (void) XSelectInput(display,windows->image.id, 11460 windows->image.attributes.event_mask); 11461 if ((state & EscapeState) != 0) 11462 { 11463 /* 11464 User want to exit without region of interest. 11465 */ 11466 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11467 (void) XFreeCursor(display,cursor); 11468 return(MagickTrue); 11469 } 11470 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11471 do 11472 { 11473 /* 11474 Size rectangle as pointer moves until the mouse button is released. 11475 */ 11476 x=(int) roi_info.x; 11477 y=(int) roi_info.y; 11478 roi_info.width=0; 11479 roi_info.height=0; 11480 state=DefaultState; 11481 do 11482 { 11483 highlight_info=roi_info; 11484 highlight_info.x=roi_info.x-windows->image.x; 11485 highlight_info.y=roi_info.y-windows->image.y; 11486 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11487 { 11488 /* 11489 Display info and draw region of interest rectangle. 11490 */ 11491 if (IfMagickFalse(windows->info.mapped) ) 11492 (void) XMapWindow(display,windows->info.id); 11493 (void) FormatLocaleString(text,MaxTextExtent, 11494 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11495 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11496 XInfoWidget(display,windows,text); 11497 XHighlightRectangle(display,windows->image.id, 11498 windows->image.highlight_context,&highlight_info); 11499 } 11500 else 11501 if (IfMagickTrue(windows->info.mapped) ) 11502 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11503 /* 11504 Wait for next event. 11505 */ 11506 XScreenEvent(display,windows,&event,exception); 11507 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11508 XHighlightRectangle(display,windows->image.id, 11509 windows->image.highlight_context,&highlight_info); 11510 switch (event.type) 11511 { 11512 case ButtonPress: 11513 { 11514 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11515 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11516 break; 11517 } 11518 case ButtonRelease: 11519 { 11520 /* 11521 User has committed to region of interest rectangle. 11522 */ 11523 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11524 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11525 XSetCursorState(display,windows,MagickFalse); 11526 state|=ExitState; 11527 if (LocaleCompare(windows->command.name,"Apply") == 0) 11528 break; 11529 (void) CloneString(&windows->command.name,"Apply"); 11530 windows->command.data=ApplyMenus; 11531 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL); 11532 break; 11533 } 11534 case Expose: 11535 break; 11536 case MotionNotify: 11537 { 11538 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11539 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11540 } 11541 default: 11542 break; 11543 } 11544 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) || 11545 ((state & ExitState) != 0)) 11546 { 11547 /* 11548 Check boundary conditions. 11549 */ 11550 if (roi_info.x < 0) 11551 roi_info.x=0; 11552 else 11553 if (roi_info.x > (ssize_t) windows->image.ximage->width) 11554 roi_info.x=(ssize_t) windows->image.ximage->width; 11555 if ((int) roi_info.x < x) 11556 roi_info.width=(unsigned int) (x-roi_info.x); 11557 else 11558 { 11559 roi_info.width=(unsigned int) (roi_info.x-x); 11560 roi_info.x=(ssize_t) x; 11561 } 11562 if (roi_info.y < 0) 11563 roi_info.y=0; 11564 else 11565 if (roi_info.y > (ssize_t) windows->image.ximage->height) 11566 roi_info.y=(ssize_t) windows->image.ximage->height; 11567 if ((int) roi_info.y < y) 11568 roi_info.height=(unsigned int) (y-roi_info.y); 11569 else 11570 { 11571 roi_info.height=(unsigned int) (roi_info.y-y); 11572 roi_info.y=(ssize_t) y; 11573 } 11574 } 11575 } while ((state & ExitState) == 0); 11576 /* 11577 Wait for user to grab a corner of the rectangle or press return. 11578 */ 11579 state=DefaultState; 11580 command_type=NullCommand; 11581 crop_info.x=0; 11582 crop_info.y=0; 11583 (void) XMapWindow(display,windows->info.id); 11584 do 11585 { 11586 if (IfMagickTrue(windows->info.mapped) ) 11587 { 11588 /* 11589 Display pointer position. 11590 */ 11591 (void) FormatLocaleString(text,MaxTextExtent, 11592 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11593 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11594 XInfoWidget(display,windows,text); 11595 } 11596 highlight_info=roi_info; 11597 highlight_info.x=roi_info.x-windows->image.x; 11598 highlight_info.y=roi_info.y-windows->image.y; 11599 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11600 { 11601 state|=EscapeState; 11602 state|=ExitState; 11603 break; 11604 } 11605 if ((state & UpdateRegionState) != 0) 11606 { 11607 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11608 switch (command_type) 11609 { 11610 case UndoCommand: 11611 case RedoCommand: 11612 { 11613 (void) XMagickCommand(display,resource_info,windows,command_type, 11614 image,exception); 11615 break; 11616 } 11617 default: 11618 { 11619 /* 11620 Region of interest is relative to image configuration. 11621 */ 11622 progress_monitor=SetImageProgressMonitor(*image, 11623 (MagickProgressMonitor) NULL,(*image)->client_data); 11624 crop_info=roi_info; 11625 width=(unsigned int) (*image)->columns; 11626 height=(unsigned int) (*image)->rows; 11627 x=0; 11628 y=0; 11629 if (windows->image.crop_geometry != (char *) NULL) 11630 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11631 &width,&height); 11632 scale_factor=(double) width/windows->image.ximage->width; 11633 crop_info.x+=x; 11634 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11635 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11636 scale_factor=(double) 11637 height/windows->image.ximage->height; 11638 crop_info.y+=y; 11639 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11640 crop_info.height=(unsigned int) 11641 (scale_factor*crop_info.height+0.5); 11642 roi_image=CropImage(*image,&crop_info,exception); 11643 (void) SetImageProgressMonitor(*image,progress_monitor, 11644 (*image)->client_data); 11645 if (roi_image == (Image *) NULL) 11646 continue; 11647 /* 11648 Apply image processing technique to the region of interest. 11649 */ 11650 windows->image.orphan=MagickTrue; 11651 (void) XMagickCommand(display,resource_info,windows,command_type, 11652 &roi_image,exception); 11653 progress_monitor=SetImageProgressMonitor(*image, 11654 (MagickProgressMonitor) NULL,(*image)->client_data); 11655 (void) XMagickCommand(display,resource_info,windows, 11656 SaveToUndoBufferCommand,image,exception); 11657 windows->image.orphan=MagickFalse; 11658 (void) CompositeImage(*image,roi_image,CopyCompositeOp, 11659 MagickTrue,crop_info.x,crop_info.y,exception); 11660 roi_image=DestroyImage(roi_image); 11661 (void) SetImageProgressMonitor(*image,progress_monitor, 11662 (*image)->client_data); 11663 break; 11664 } 11665 } 11666 if (command_type != InfoCommand) 11667 { 11668 XConfigureImageColormap(display,resource_info,windows,*image, 11669 exception); 11670 (void) XConfigureImage(display,resource_info,windows,*image, 11671 exception); 11672 } 11673 XCheckRefreshWindows(display,windows); 11674 XInfoWidget(display,windows,text); 11675 (void) XSetFunction(display,windows->image.highlight_context, 11676 GXinvert); 11677 state&=(~UpdateRegionState); 11678 } 11679 XHighlightRectangle(display,windows->image.id, 11680 windows->image.highlight_context,&highlight_info); 11681 XScreenEvent(display,windows,&event,exception); 11682 if (event.xany.window == windows->command.id) 11683 { 11684 /* 11685 Select a command from the Command widget. 11686 */ 11687 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11688 command_type=NullCommand; 11689 id=XCommandWidget(display,windows,ApplyMenu,&event); 11690 if (id >= 0) 11691 { 11692 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent); 11693 command_type=ApplyCommands[id]; 11694 if (id < ApplyMenus) 11695 { 11696 /* 11697 Select a command from a pop-up menu. 11698 */ 11699 entry=XMenuWidget(display,windows,ApplyMenu[id], 11700 (const char **) Menus[id],command); 11701 if (entry >= 0) 11702 { 11703 (void) CopyMagickString(command,Menus[id][entry], 11704 MaxTextExtent); 11705 command_type=Commands[id][entry]; 11706 } 11707 } 11708 } 11709 (void) XSetFunction(display,windows->image.highlight_context, 11710 GXinvert); 11711 XHighlightRectangle(display,windows->image.id, 11712 windows->image.highlight_context,&highlight_info); 11713 if (command_type == HelpCommand) 11714 { 11715 (void) XSetFunction(display,windows->image.highlight_context, 11716 GXcopy); 11717 XTextViewWidget(display,resource_info,windows,MagickFalse, 11718 "Help Viewer - Region of Interest",ImageROIHelp); 11719 (void) XSetFunction(display,windows->image.highlight_context, 11720 GXinvert); 11721 continue; 11722 } 11723 if (command_type == QuitCommand) 11724 { 11725 /* 11726 exit. 11727 */ 11728 state|=EscapeState; 11729 state|=ExitState; 11730 continue; 11731 } 11732 if (command_type != NullCommand) 11733 state|=UpdateRegionState; 11734 continue; 11735 } 11736 XHighlightRectangle(display,windows->image.id, 11737 windows->image.highlight_context,&highlight_info); 11738 switch (event.type) 11739 { 11740 case ButtonPress: 11741 { 11742 x=windows->image.x; 11743 y=windows->image.y; 11744 if (event.xbutton.button != Button1) 11745 break; 11746 if (event.xbutton.window != windows->image.id) 11747 break; 11748 x=windows->image.x+event.xbutton.x; 11749 y=windows->image.y+event.xbutton.y; 11750 if ((x < (int) (roi_info.x+RoiDelta)) && 11751 (x > (int) (roi_info.x-RoiDelta)) && 11752 (y < (int) (roi_info.y+RoiDelta)) && 11753 (y > (int) (roi_info.y-RoiDelta))) 11754 { 11755 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11756 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11757 state|=UpdateConfigurationState; 11758 break; 11759 } 11760 if ((x < (int) (roi_info.x+RoiDelta)) && 11761 (x > (int) (roi_info.x-RoiDelta)) && 11762 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11763 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11764 { 11765 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11766 state|=UpdateConfigurationState; 11767 break; 11768 } 11769 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11770 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11771 (y < (int) (roi_info.y+RoiDelta)) && 11772 (y > (int) (roi_info.y-RoiDelta))) 11773 { 11774 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11775 state|=UpdateConfigurationState; 11776 break; 11777 } 11778 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11779 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11780 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11781 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11782 { 11783 state|=UpdateConfigurationState; 11784 break; 11785 } 11786 } 11787 case ButtonRelease: 11788 { 11789 if (event.xbutton.window == windows->pan.id) 11790 if ((highlight_info.x != crop_info.x-windows->image.x) || 11791 (highlight_info.y != crop_info.y-windows->image.y)) 11792 XHighlightRectangle(display,windows->image.id, 11793 windows->image.highlight_context,&highlight_info); 11794 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11795 event.xbutton.time); 11796 break; 11797 } 11798 case Expose: 11799 { 11800 if (event.xexpose.window == windows->image.id) 11801 if (event.xexpose.count == 0) 11802 { 11803 event.xexpose.x=(int) highlight_info.x; 11804 event.xexpose.y=(int) highlight_info.y; 11805 event.xexpose.width=(int) highlight_info.width; 11806 event.xexpose.height=(int) highlight_info.height; 11807 XRefreshWindow(display,&windows->image,&event); 11808 } 11809 if (event.xexpose.window == windows->info.id) 11810 if (event.xexpose.count == 0) 11811 XInfoWidget(display,windows,text); 11812 break; 11813 } 11814 case KeyPress: 11815 { 11816 KeySym 11817 key_symbol; 11818 11819 if (event.xkey.window != windows->image.id) 11820 break; 11821 /* 11822 Respond to a user key press. 11823 */ 11824 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11825 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11826 switch ((int) key_symbol) 11827 { 11828 case XK_Shift_L: 11829 case XK_Shift_R: 11830 break; 11831 case XK_Escape: 11832 case XK_F20: 11833 state|=EscapeState; 11834 case XK_Return: 11835 { 11836 state|=ExitState; 11837 break; 11838 } 11839 case XK_Home: 11840 case XK_KP_Home: 11841 { 11842 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11843 roi_info.y=(ssize_t) (windows->image.height/2L- 11844 roi_info.height/2L); 11845 break; 11846 } 11847 case XK_Left: 11848 case XK_KP_Left: 11849 { 11850 roi_info.x--; 11851 break; 11852 } 11853 case XK_Up: 11854 case XK_KP_Up: 11855 case XK_Next: 11856 { 11857 roi_info.y--; 11858 break; 11859 } 11860 case XK_Right: 11861 case XK_KP_Right: 11862 { 11863 roi_info.x++; 11864 break; 11865 } 11866 case XK_Prior: 11867 case XK_Down: 11868 case XK_KP_Down: 11869 { 11870 roi_info.y++; 11871 break; 11872 } 11873 case XK_F1: 11874 case XK_Help: 11875 { 11876 (void) XSetFunction(display,windows->image.highlight_context, 11877 GXcopy); 11878 XTextViewWidget(display,resource_info,windows,MagickFalse, 11879 "Help Viewer - Region of Interest",ImageROIHelp); 11880 (void) XSetFunction(display,windows->image.highlight_context, 11881 GXinvert); 11882 break; 11883 } 11884 default: 11885 { 11886 command_type=XImageWindowCommand(display,resource_info,windows, 11887 event.xkey.state,key_symbol,image,exception); 11888 if (command_type != NullCommand) 11889 state|=UpdateRegionState; 11890 break; 11891 } 11892 } 11893 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11894 event.xkey.time); 11895 break; 11896 } 11897 case KeyRelease: 11898 break; 11899 case MotionNotify: 11900 { 11901 if (event.xbutton.window != windows->image.id) 11902 break; 11903 /* 11904 Map and unmap Info widget as text cursor crosses its boundaries. 11905 */ 11906 x=event.xmotion.x; 11907 y=event.xmotion.y; 11908 if (IfMagickTrue(windows->info.mapped) ) 11909 { 11910 if ((x < (int) (windows->info.x+windows->info.width)) && 11911 (y < (int) (windows->info.y+windows->info.height))) 11912 (void) XWithdrawWindow(display,windows->info.id, 11913 windows->info.screen); 11914 } 11915 else 11916 if ((x > (int) (windows->info.x+windows->info.width)) || 11917 (y > (int) (windows->info.y+windows->info.height))) 11918 (void) XMapWindow(display,windows->info.id); 11919 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11920 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11921 break; 11922 } 11923 case SelectionRequest: 11924 { 11925 XSelectionEvent 11926 notify; 11927 11928 XSelectionRequestEvent 11929 *request; 11930 11931 /* 11932 Set primary selection. 11933 */ 11934 (void) FormatLocaleString(text,MaxTextExtent, 11935 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11936 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11937 request=(&(event.xselectionrequest)); 11938 (void) XChangeProperty(request->display,request->requestor, 11939 request->property,request->target,8,PropModeReplace, 11940 (unsigned char *) text,(int) strlen(text)); 11941 notify.type=SelectionNotify; 11942 notify.display=request->display; 11943 notify.requestor=request->requestor; 11944 notify.selection=request->selection; 11945 notify.target=request->target; 11946 notify.time=request->time; 11947 if (request->property == None) 11948 notify.property=request->target; 11949 else 11950 notify.property=request->property; 11951 (void) XSendEvent(request->display,request->requestor,False,0, 11952 (XEvent *) ¬ify); 11953 } 11954 default: 11955 break; 11956 } 11957 if ((state & UpdateConfigurationState) != 0) 11958 { 11959 (void) XPutBackEvent(display,&event); 11960 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11961 break; 11962 } 11963 } while ((state & ExitState) == 0); 11964 } while ((state & ExitState) == 0); 11965 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11966 XSetCursorState(display,windows,MagickFalse); 11967 if ((state & EscapeState) != 0) 11968 return(MagickTrue); 11969 return(MagickTrue); 11970} 11971 11972/* 11973%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11974% % 11975% % 11976% % 11977+ X R o t a t e I m a g e % 11978% % 11979% % 11980% % 11981%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11982% 11983% XRotateImage() rotates the X image. If the degrees parameter if zero, the 11984% rotation angle is computed from the slope of a line drawn by the user. 11985% 11986% The format of the XRotateImage method is: 11987% 11988% MagickBooleanType XRotateImage(Display *display, 11989% XResourceInfo *resource_info,XWindows *windows,double degrees, 11990% Image **image,ExceptionInfo *exception) 11991% 11992% A description of each parameter follows: 11993% 11994% o display: Specifies a connection to an X server; returned from 11995% XOpenDisplay. 11996% 11997% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11998% 11999% o windows: Specifies a pointer to a XWindows structure. 12000% 12001% o degrees: Specifies the number of degrees to rotate the image. 12002% 12003% o image: the image. 12004% 12005% o exception: return any errors or warnings in this structure. 12006% 12007*/ 12008static MagickBooleanType XRotateImage(Display *display, 12009 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image, 12010 ExceptionInfo *exception) 12011{ 12012 static const char 12013 *RotateMenu[] = 12014 { 12015 "Pixel Color", 12016 "Direction", 12017 "Help", 12018 "Dismiss", 12019 (char *) NULL 12020 }; 12021 12022 static ModeType 12023 direction = HorizontalRotateCommand; 12024 12025 static const ModeType 12026 DirectionCommands[] = 12027 { 12028 HorizontalRotateCommand, 12029 VerticalRotateCommand 12030 }, 12031 RotateCommands[] = 12032 { 12033 RotateColorCommand, 12034 RotateDirectionCommand, 12035 RotateHelpCommand, 12036 RotateDismissCommand 12037 }; 12038 12039 static unsigned int 12040 pen_id = 0; 12041 12042 char 12043 command[MaxTextExtent], 12044 text[MaxTextExtent]; 12045 12046 Image 12047 *rotate_image; 12048 12049 int 12050 id, 12051 x, 12052 y; 12053 12054 double 12055 normalized_degrees; 12056 12057 register int 12058 i; 12059 12060 unsigned int 12061 height, 12062 rotations, 12063 width; 12064 12065 if (degrees == 0.0) 12066 { 12067 unsigned int 12068 distance; 12069 12070 size_t 12071 state; 12072 12073 XEvent 12074 event; 12075 12076 XSegment 12077 rotate_info; 12078 12079 /* 12080 Map Command widget. 12081 */ 12082 (void) CloneString(&windows->command.name,"Rotate"); 12083 windows->command.data=2; 12084 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 12085 (void) XMapRaised(display,windows->command.id); 12086 XClientMessage(display,windows->image.id,windows->im_protocols, 12087 windows->im_update_widget,CurrentTime); 12088 /* 12089 Wait for first button press. 12090 */ 12091 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12092 XQueryPosition(display,windows->image.id,&x,&y); 12093 rotate_info.x1=x; 12094 rotate_info.y1=y; 12095 rotate_info.x2=x; 12096 rotate_info.y2=y; 12097 state=DefaultState; 12098 do 12099 { 12100 XHighlightLine(display,windows->image.id, 12101 windows->image.highlight_context,&rotate_info); 12102 /* 12103 Wait for next event. 12104 */ 12105 XScreenEvent(display,windows,&event,exception); 12106 XHighlightLine(display,windows->image.id, 12107 windows->image.highlight_context,&rotate_info); 12108 if (event.xany.window == windows->command.id) 12109 { 12110 /* 12111 Select a command from the Command widget. 12112 */ 12113 id=XCommandWidget(display,windows,RotateMenu,&event); 12114 if (id < 0) 12115 continue; 12116 (void) XSetFunction(display,windows->image.highlight_context, 12117 GXcopy); 12118 switch (RotateCommands[id]) 12119 { 12120 case RotateColorCommand: 12121 { 12122 const char 12123 *ColorMenu[MaxNumberPens]; 12124 12125 int 12126 pen_number; 12127 12128 XColor 12129 color; 12130 12131 /* 12132 Initialize menu selections. 12133 */ 12134 for (i=0; i < (int) (MaxNumberPens-2); i++) 12135 ColorMenu[i]=resource_info->pen_colors[i]; 12136 ColorMenu[MaxNumberPens-2]="Browser..."; 12137 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12138 /* 12139 Select a pen color from the pop-up menu. 12140 */ 12141 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12142 (const char **) ColorMenu,command); 12143 if (pen_number < 0) 12144 break; 12145 if (pen_number == (MaxNumberPens-2)) 12146 { 12147 static char 12148 color_name[MaxTextExtent] = "gray"; 12149 12150 /* 12151 Select a pen color from a dialog. 12152 */ 12153 resource_info->pen_colors[pen_number]=color_name; 12154 XColorBrowserWidget(display,windows,"Select",color_name); 12155 if (*color_name == '\0') 12156 break; 12157 } 12158 /* 12159 Set pen color. 12160 */ 12161 (void) XParseColor(display,windows->map_info->colormap, 12162 resource_info->pen_colors[pen_number],&color); 12163 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12164 (unsigned int) MaxColors,&color); 12165 windows->pixel_info->pen_colors[pen_number]=color; 12166 pen_id=(unsigned int) pen_number; 12167 break; 12168 } 12169 case RotateDirectionCommand: 12170 { 12171 static const char 12172 *Directions[] = 12173 { 12174 "horizontal", 12175 "vertical", 12176 (char *) NULL, 12177 }; 12178 12179 /* 12180 Select a command from the pop-up menu. 12181 */ 12182 id=XMenuWidget(display,windows,RotateMenu[id], 12183 Directions,command); 12184 if (id >= 0) 12185 direction=DirectionCommands[id]; 12186 break; 12187 } 12188 case RotateHelpCommand: 12189 { 12190 XTextViewWidget(display,resource_info,windows,MagickFalse, 12191 "Help Viewer - Image Rotation",ImageRotateHelp); 12192 break; 12193 } 12194 case RotateDismissCommand: 12195 { 12196 /* 12197 Prematurely exit. 12198 */ 12199 state|=EscapeState; 12200 state|=ExitState; 12201 break; 12202 } 12203 default: 12204 break; 12205 } 12206 (void) XSetFunction(display,windows->image.highlight_context, 12207 GXinvert); 12208 continue; 12209 } 12210 switch (event.type) 12211 { 12212 case ButtonPress: 12213 { 12214 if (event.xbutton.button != Button1) 12215 break; 12216 if (event.xbutton.window != windows->image.id) 12217 break; 12218 /* 12219 exit loop. 12220 */ 12221 (void) XSetFunction(display,windows->image.highlight_context, 12222 GXcopy); 12223 rotate_info.x1=event.xbutton.x; 12224 rotate_info.y1=event.xbutton.y; 12225 state|=ExitState; 12226 break; 12227 } 12228 case ButtonRelease: 12229 break; 12230 case Expose: 12231 break; 12232 case KeyPress: 12233 { 12234 char 12235 command[MaxTextExtent]; 12236 12237 KeySym 12238 key_symbol; 12239 12240 if (event.xkey.window != windows->image.id) 12241 break; 12242 /* 12243 Respond to a user key press. 12244 */ 12245 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12246 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12247 switch ((int) key_symbol) 12248 { 12249 case XK_Escape: 12250 case XK_F20: 12251 { 12252 /* 12253 Prematurely exit. 12254 */ 12255 state|=EscapeState; 12256 state|=ExitState; 12257 break; 12258 } 12259 case XK_F1: 12260 case XK_Help: 12261 { 12262 (void) XSetFunction(display,windows->image.highlight_context, 12263 GXcopy); 12264 XTextViewWidget(display,resource_info,windows,MagickFalse, 12265 "Help Viewer - Image Rotation",ImageRotateHelp); 12266 (void) XSetFunction(display,windows->image.highlight_context, 12267 GXinvert); 12268 break; 12269 } 12270 default: 12271 { 12272 (void) XBell(display,0); 12273 break; 12274 } 12275 } 12276 break; 12277 } 12278 case MotionNotify: 12279 { 12280 rotate_info.x1=event.xmotion.x; 12281 rotate_info.y1=event.xmotion.y; 12282 } 12283 } 12284 rotate_info.x2=rotate_info.x1; 12285 rotate_info.y2=rotate_info.y1; 12286 if (direction == HorizontalRotateCommand) 12287 rotate_info.x2+=32; 12288 else 12289 rotate_info.y2-=32; 12290 } while ((state & ExitState) == 0); 12291 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12292 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12293 if ((state & EscapeState) != 0) 12294 return(MagickTrue); 12295 /* 12296 Draw line as pointer moves until the mouse button is released. 12297 */ 12298 distance=0; 12299 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12300 state=DefaultState; 12301 do 12302 { 12303 if (distance > 9) 12304 { 12305 /* 12306 Display info and draw rotation line. 12307 */ 12308 if (IfMagickFalse(windows->info.mapped) ) 12309 (void) XMapWindow(display,windows->info.id); 12310 (void) FormatLocaleString(text,MaxTextExtent," %g", 12311 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12312 XInfoWidget(display,windows,text); 12313 XHighlightLine(display,windows->image.id, 12314 windows->image.highlight_context,&rotate_info); 12315 } 12316 else 12317 if (IfMagickTrue(windows->info.mapped) ) 12318 (void) XWithdrawWindow(display,windows->info.id, 12319 windows->info.screen); 12320 /* 12321 Wait for next event. 12322 */ 12323 XScreenEvent(display,windows,&event,exception); 12324 if (distance > 9) 12325 XHighlightLine(display,windows->image.id, 12326 windows->image.highlight_context,&rotate_info); 12327 switch (event.type) 12328 { 12329 case ButtonPress: 12330 break; 12331 case ButtonRelease: 12332 { 12333 /* 12334 User has committed to rotation line. 12335 */ 12336 rotate_info.x2=event.xbutton.x; 12337 rotate_info.y2=event.xbutton.y; 12338 state|=ExitState; 12339 break; 12340 } 12341 case Expose: 12342 break; 12343 case MotionNotify: 12344 { 12345 rotate_info.x2=event.xmotion.x; 12346 rotate_info.y2=event.xmotion.y; 12347 } 12348 default: 12349 break; 12350 } 12351 /* 12352 Check boundary conditions. 12353 */ 12354 if (rotate_info.x2 < 0) 12355 rotate_info.x2=0; 12356 else 12357 if (rotate_info.x2 > (int) windows->image.width) 12358 rotate_info.x2=(short) windows->image.width; 12359 if (rotate_info.y2 < 0) 12360 rotate_info.y2=0; 12361 else 12362 if (rotate_info.y2 > (int) windows->image.height) 12363 rotate_info.y2=(short) windows->image.height; 12364 /* 12365 Compute rotation angle from the slope of the line. 12366 */ 12367 degrees=0.0; 12368 distance=(unsigned int) 12369 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12370 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12371 if (distance > 9) 12372 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12373 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12374 } while ((state & ExitState) == 0); 12375 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12376 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12377 if (distance <= 9) 12378 return(MagickTrue); 12379 } 12380 if (direction == VerticalRotateCommand) 12381 degrees-=90.0; 12382 if (degrees == 0.0) 12383 return(MagickTrue); 12384 /* 12385 Rotate image. 12386 */ 12387 normalized_degrees=degrees; 12388 while (normalized_degrees < -45.0) 12389 normalized_degrees+=360.0; 12390 for (rotations=0; normalized_degrees > 45.0; rotations++) 12391 normalized_degrees-=90.0; 12392 if (normalized_degrees != 0.0) 12393 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 12394 exception); 12395 XSetCursorState(display,windows,MagickTrue); 12396 XCheckRefreshWindows(display,windows); 12397 (*image)->background_color.red=(double) ScaleShortToQuantum( 12398 windows->pixel_info->pen_colors[pen_id].red); 12399 (*image)->background_color.green=(double) ScaleShortToQuantum( 12400 windows->pixel_info->pen_colors[pen_id].green); 12401 (*image)->background_color.blue=(double) ScaleShortToQuantum( 12402 windows->pixel_info->pen_colors[pen_id].blue); 12403 rotate_image=RotateImage(*image,degrees,exception); 12404 XSetCursorState(display,windows,MagickFalse); 12405 if (rotate_image == (Image *) NULL) 12406 return(MagickFalse); 12407 *image=DestroyImage(*image); 12408 *image=rotate_image; 12409 if (windows->image.crop_geometry != (char *) NULL) 12410 { 12411 /* 12412 Rotate crop geometry. 12413 */ 12414 width=(unsigned int) (*image)->columns; 12415 height=(unsigned int) (*image)->rows; 12416 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12417 switch (rotations % 4) 12418 { 12419 default: 12420 case 0: 12421 break; 12422 case 1: 12423 { 12424 /* 12425 Rotate 90 degrees. 12426 */ 12427 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12428 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12429 (int) height-y,x); 12430 break; 12431 } 12432 case 2: 12433 { 12434 /* 12435 Rotate 180 degrees. 12436 */ 12437 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12438 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12439 break; 12440 } 12441 case 3: 12442 { 12443 /* 12444 Rotate 270 degrees. 12445 */ 12446 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12447 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12448 break; 12449 } 12450 } 12451 } 12452 if (IfMagickTrue(windows->image.orphan) ) 12453 return(MagickTrue); 12454 if (normalized_degrees != 0.0) 12455 { 12456 /* 12457 Update image colormap. 12458 */ 12459 windows->image.window_changes.width=(int) (*image)->columns; 12460 windows->image.window_changes.height=(int) (*image)->rows; 12461 if (windows->image.crop_geometry != (char *) NULL) 12462 { 12463 /* 12464 Obtain dimensions of image from crop geometry. 12465 */ 12466 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12467 &width,&height); 12468 windows->image.window_changes.width=(int) width; 12469 windows->image.window_changes.height=(int) height; 12470 } 12471 XConfigureImageColormap(display,resource_info,windows,*image,exception); 12472 } 12473 else 12474 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12475 { 12476 windows->image.window_changes.width=windows->image.ximage->height; 12477 windows->image.window_changes.height=windows->image.ximage->width; 12478 } 12479 /* 12480 Update image configuration. 12481 */ 12482 (void) XConfigureImage(display,resource_info,windows,*image,exception); 12483 return(MagickTrue); 12484} 12485 12486/* 12487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12488% % 12489% % 12490% % 12491+ X S a v e I m a g e % 12492% % 12493% % 12494% % 12495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12496% 12497% XSaveImage() saves an image to a file. 12498% 12499% The format of the XSaveImage method is: 12500% 12501% MagickBooleanType XSaveImage(Display *display, 12502% XResourceInfo *resource_info,XWindows *windows,Image *image, 12503% ExceptionInfo *exception) 12504% 12505% A description of each parameter follows: 12506% 12507% o display: Specifies a connection to an X server; returned from 12508% XOpenDisplay. 12509% 12510% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12511% 12512% o windows: Specifies a pointer to a XWindows structure. 12513% 12514% o image: the image. 12515% 12516% o exception: return any errors or warnings in this structure. 12517% 12518*/ 12519static MagickBooleanType XSaveImage(Display *display, 12520 XResourceInfo *resource_info,XWindows *windows,Image *image, 12521 ExceptionInfo *exception) 12522{ 12523 char 12524 filename[MaxTextExtent], 12525 geometry[MaxTextExtent]; 12526 12527 Image 12528 *save_image; 12529 12530 ImageInfo 12531 *image_info; 12532 12533 MagickStatusType 12534 status; 12535 12536 /* 12537 Request file name from user. 12538 */ 12539 if (resource_info->write_filename != (char *) NULL) 12540 (void) CopyMagickString(filename,resource_info->write_filename, 12541 MaxTextExtent); 12542 else 12543 { 12544 char 12545 path[MaxTextExtent]; 12546 12547 int 12548 status; 12549 12550 GetPathComponent(image->filename,HeadPath,path); 12551 GetPathComponent(image->filename,TailPath,filename); 12552 if (*path != '\0') 12553 { 12554 status=chdir(path); 12555 if (status == -1) 12556 (void) ThrowMagickException(exception,GetMagickModule(), 12557 FileOpenError,"UnableToOpenFile","%s",path); 12558 } 12559 } 12560 XFileBrowserWidget(display,windows,"Save",filename); 12561 if (*filename == '\0') 12562 return(MagickTrue); 12563 if (IfMagickTrue(IsPathAccessible(filename)) ) 12564 { 12565 int 12566 status; 12567 12568 /* 12569 File exists-- seek user's permission before overwriting. 12570 */ 12571 status=XConfirmWidget(display,windows,"Overwrite",filename); 12572 if (status <= 0) 12573 return(MagickTrue); 12574 } 12575 image_info=CloneImageInfo(resource_info->image_info); 12576 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 12577 (void) SetImageInfo(image_info,1,exception); 12578 if ((LocaleCompare(image_info->magick,"JPEG") == 0) || 12579 (LocaleCompare(image_info->magick,"JPG") == 0)) 12580 { 12581 char 12582 quality[MaxTextExtent]; 12583 12584 int 12585 status; 12586 12587 /* 12588 Request JPEG quality from user. 12589 */ 12590 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double) 12591 image->quality); 12592 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", 12593 quality); 12594 if (*quality == '\0') 12595 return(MagickTrue); 12596 image->quality=StringToUnsignedLong(quality); 12597 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace; 12598 } 12599 if ((LocaleCompare(image_info->magick,"EPS") == 0) || 12600 (LocaleCompare(image_info->magick,"PDF") == 0) || 12601 (LocaleCompare(image_info->magick,"PS") == 0) || 12602 (LocaleCompare(image_info->magick,"PS2") == 0)) 12603 { 12604 char 12605 geometry[MaxTextExtent]; 12606 12607 /* 12608 Request page geometry from user. 12609 */ 12610 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12611 if (LocaleCompare(image_info->magick,"PDF") == 0) 12612 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12613 if (image_info->page != (char *) NULL) 12614 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 12615 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 12616 "Select page geometry:",geometry); 12617 if (*geometry != '\0') 12618 image_info->page=GetPageGeometry(geometry); 12619 } 12620 /* 12621 Apply image transforms. 12622 */ 12623 XSetCursorState(display,windows,MagickTrue); 12624 XCheckRefreshWindows(display,windows); 12625 save_image=CloneImage(image,0,0,MagickTrue,exception); 12626 if (save_image == (Image *) NULL) 12627 return(MagickFalse); 12628 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 12629 windows->image.ximage->width,windows->image.ximage->height); 12630 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry, 12631 exception); 12632 /* 12633 Write image. 12634 */ 12635 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent); 12636 status=WriteImage(image_info,save_image,exception); 12637 if (IfMagickTrue(status) ) 12638 image->taint=MagickFalse; 12639 save_image=DestroyImage(save_image); 12640 image_info=DestroyImageInfo(image_info); 12641 XSetCursorState(display,windows,MagickFalse); 12642 return(IsMagickTrue(status)); 12643} 12644 12645/* 12646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12647% % 12648% % 12649% % 12650+ X S c r e e n E v e n t % 12651% % 12652% % 12653% % 12654%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12655% 12656% XScreenEvent() handles global events associated with the Pan and Magnify 12657% windows. 12658% 12659% The format of the XScreenEvent function is: 12660% 12661% void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12662% ExceptionInfo *exception) 12663% 12664% A description of each parameter follows: 12665% 12666% o display: Specifies a pointer to the Display structure; returned from 12667% XOpenDisplay. 12668% 12669% o windows: Specifies a pointer to a XWindows structure. 12670% 12671% o event: Specifies a pointer to a X11 XEvent structure. 12672% 12673% o exception: return any errors or warnings in this structure. 12674% 12675*/ 12676 12677#if defined(__cplusplus) || defined(c_plusplus) 12678extern "C" { 12679#endif 12680 12681static int XPredicate(Display *magick_unused(display),XEvent *event,char *data) 12682{ 12683 register XWindows 12684 *windows; 12685 12686 windows=(XWindows *) data; 12687 if ((event->type == ClientMessage) && 12688 (event->xclient.window == windows->image.id)) 12689 return(MagickFalse); 12690 return(MagickTrue); 12691} 12692 12693#if defined(__cplusplus) || defined(c_plusplus) 12694} 12695#endif 12696 12697static void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12698 ExceptionInfo *exception) 12699{ 12700 register int 12701 x, 12702 y; 12703 12704 (void) XIfEvent(display,event,XPredicate,(char *) windows); 12705 if (event->xany.window == windows->command.id) 12706 return; 12707 switch (event->type) 12708 { 12709 case ButtonPress: 12710 case ButtonRelease: 12711 { 12712 if ((event->xbutton.button == Button3) && 12713 (event->xbutton.state & Mod1Mask)) 12714 { 12715 /* 12716 Convert Alt-Button3 to Button2. 12717 */ 12718 event->xbutton.button=Button2; 12719 event->xbutton.state&=(~Mod1Mask); 12720 } 12721 if (event->xbutton.window == windows->backdrop.id) 12722 { 12723 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent, 12724 event->xbutton.time); 12725 break; 12726 } 12727 if (event->xbutton.window == windows->pan.id) 12728 { 12729 XPanImage(display,windows,event,exception); 12730 break; 12731 } 12732 if (event->xbutton.window == windows->image.id) 12733 if (event->xbutton.button == Button2) 12734 { 12735 /* 12736 Update magnified image. 12737 */ 12738 x=event->xbutton.x; 12739 y=event->xbutton.y; 12740 if (x < 0) 12741 x=0; 12742 else 12743 if (x >= (int) windows->image.width) 12744 x=(int) (windows->image.width-1); 12745 windows->magnify.x=(int) windows->image.x+x; 12746 if (y < 0) 12747 y=0; 12748 else 12749 if (y >= (int) windows->image.height) 12750 y=(int) (windows->image.height-1); 12751 windows->magnify.y=windows->image.y+y; 12752 if (IfMagickFalse(windows->magnify.mapped) ) 12753 (void) XMapRaised(display,windows->magnify.id); 12754 XMakeMagnifyImage(display,windows,exception); 12755 if (event->type == ButtonRelease) 12756 (void) XWithdrawWindow(display,windows->info.id, 12757 windows->info.screen); 12758 break; 12759 } 12760 break; 12761 } 12762 case ClientMessage: 12763 { 12764 /* 12765 If client window delete message, exit. 12766 */ 12767 if (event->xclient.message_type != windows->wm_protocols) 12768 break; 12769 if (*event->xclient.data.l != (long) windows->wm_delete_window) 12770 break; 12771 if (event->xclient.window == windows->magnify.id) 12772 { 12773 (void) XWithdrawWindow(display,windows->magnify.id, 12774 windows->magnify.screen); 12775 break; 12776 } 12777 break; 12778 } 12779 case ConfigureNotify: 12780 { 12781 if (event->xconfigure.window == windows->magnify.id) 12782 { 12783 unsigned int 12784 magnify; 12785 12786 /* 12787 Magnify window has a new configuration. 12788 */ 12789 windows->magnify.width=(unsigned int) event->xconfigure.width; 12790 windows->magnify.height=(unsigned int) event->xconfigure.height; 12791 if (IfMagickFalse(windows->magnify.mapped) ) 12792 break; 12793 magnify=1; 12794 while ((int) magnify <= event->xconfigure.width) 12795 magnify<<=1; 12796 while ((int) magnify <= event->xconfigure.height) 12797 magnify<<=1; 12798 magnify>>=1; 12799 if (((int) magnify != event->xconfigure.width) || 12800 ((int) magnify != event->xconfigure.height)) 12801 { 12802 XWindowChanges 12803 window_changes; 12804 12805 window_changes.width=(int) magnify; 12806 window_changes.height=(int) magnify; 12807 (void) XReconfigureWMWindow(display,windows->magnify.id, 12808 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 12809 &window_changes); 12810 break; 12811 } 12812 XMakeMagnifyImage(display,windows,exception); 12813 break; 12814 } 12815 break; 12816 } 12817 case Expose: 12818 { 12819 if (event->xexpose.window == windows->image.id) 12820 { 12821 XRefreshWindow(display,&windows->image,event); 12822 break; 12823 } 12824 if (event->xexpose.window == windows->pan.id) 12825 if (event->xexpose.count == 0) 12826 { 12827 XDrawPanRectangle(display,windows); 12828 break; 12829 } 12830 if (event->xexpose.window == windows->magnify.id) 12831 if (event->xexpose.count == 0) 12832 { 12833 XMakeMagnifyImage(display,windows,exception); 12834 break; 12835 } 12836 break; 12837 } 12838 case KeyPress: 12839 { 12840 char 12841 command[MaxTextExtent]; 12842 12843 KeySym 12844 key_symbol; 12845 12846 if (event->xkey.window != windows->magnify.id) 12847 break; 12848 /* 12849 Respond to a user key press. 12850 */ 12851 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int) 12852 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12853 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol, 12854 exception); 12855 break; 12856 } 12857 case MapNotify: 12858 { 12859 if (event->xmap.window == windows->magnify.id) 12860 { 12861 windows->magnify.mapped=MagickTrue; 12862 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12863 break; 12864 } 12865 if (event->xmap.window == windows->info.id) 12866 { 12867 windows->info.mapped=MagickTrue; 12868 break; 12869 } 12870 break; 12871 } 12872 case MotionNotify: 12873 { 12874 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; 12875 if (event->xmotion.window == windows->image.id) 12876 if (IfMagickTrue(windows->magnify.mapped) ) 12877 { 12878 /* 12879 Update magnified image. 12880 */ 12881 x=event->xmotion.x; 12882 y=event->xmotion.y; 12883 if (x < 0) 12884 x=0; 12885 else 12886 if (x >= (int) windows->image.width) 12887 x=(int) (windows->image.width-1); 12888 windows->magnify.x=(int) windows->image.x+x; 12889 if (y < 0) 12890 y=0; 12891 else 12892 if (y >= (int) windows->image.height) 12893 y=(int) (windows->image.height-1); 12894 windows->magnify.y=windows->image.y+y; 12895 XMakeMagnifyImage(display,windows,exception); 12896 } 12897 break; 12898 } 12899 case UnmapNotify: 12900 { 12901 if (event->xunmap.window == windows->magnify.id) 12902 { 12903 windows->magnify.mapped=MagickFalse; 12904 break; 12905 } 12906 if (event->xunmap.window == windows->info.id) 12907 { 12908 windows->info.mapped=MagickFalse; 12909 break; 12910 } 12911 break; 12912 } 12913 default: 12914 break; 12915 } 12916} 12917 12918/* 12919%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12920% % 12921% % 12922% % 12923+ X S e t C r o p G e o m e t r y % 12924% % 12925% % 12926% % 12927%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12928% 12929% XSetCropGeometry() accepts a cropping geometry relative to the Image window 12930% and translates it to a cropping geometry relative to the image. 12931% 12932% The format of the XSetCropGeometry method is: 12933% 12934% void XSetCropGeometry(Display *display,XWindows *windows, 12935% RectangleInfo *crop_info,Image *image) 12936% 12937% A description of each parameter follows: 12938% 12939% o display: Specifies a connection to an X server; returned from 12940% XOpenDisplay. 12941% 12942% o windows: Specifies a pointer to a XWindows structure. 12943% 12944% o crop_info: A pointer to a RectangleInfo that defines a region of the 12945% Image window to crop. 12946% 12947% o image: the image. 12948% 12949*/ 12950static void XSetCropGeometry(Display *display,XWindows *windows, 12951 RectangleInfo *crop_info,Image *image) 12952{ 12953 char 12954 text[MaxTextExtent]; 12955 12956 int 12957 x, 12958 y; 12959 12960 double 12961 scale_factor; 12962 12963 unsigned int 12964 height, 12965 width; 12966 12967 if (IfMagickTrue(windows->info.mapped) ) 12968 { 12969 /* 12970 Display info on cropping rectangle. 12971 */ 12972 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g", 12973 (double) crop_info->width,(double) crop_info->height,(double) 12974 crop_info->x,(double) crop_info->y); 12975 XInfoWidget(display,windows,text); 12976 } 12977 /* 12978 Cropping geometry is relative to any previous crop geometry. 12979 */ 12980 x=0; 12981 y=0; 12982 width=(unsigned int) image->columns; 12983 height=(unsigned int) image->rows; 12984 if (windows->image.crop_geometry != (char *) NULL) 12985 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12986 else 12987 windows->image.crop_geometry=AcquireString((char *) NULL); 12988 /* 12989 Define the crop geometry string from the cropping rectangle. 12990 */ 12991 scale_factor=(double) width/windows->image.ximage->width; 12992 if (crop_info->x > 0) 12993 x+=(int) (scale_factor*crop_info->x+0.5); 12994 width=(unsigned int) (scale_factor*crop_info->width+0.5); 12995 if (width == 0) 12996 width=1; 12997 scale_factor=(double) height/windows->image.ximage->height; 12998 if (crop_info->y > 0) 12999 y+=(int) (scale_factor*crop_info->y+0.5); 13000 height=(unsigned int) (scale_factor*crop_info->height+0.5); 13001 if (height == 0) 13002 height=1; 13003 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 13004 "%ux%u%+d%+d",width,height,x,y); 13005} 13006 13007/* 13008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13009% % 13010% % 13011% % 13012+ X T i l e I m a g e % 13013% % 13014% % 13015% % 13016%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13017% 13018% XTileImage() loads or deletes a selected tile from a visual image directory. 13019% The load or delete command is chosen from a menu. 13020% 13021% The format of the XTileImage method is: 13022% 13023% Image *XTileImage(Display *display,XResourceInfo *resource_info, 13024% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13025% 13026% A description of each parameter follows: 13027% 13028% o tile_image: XTileImage reads or deletes the tile image 13029% and returns it. A null image is returned if an error occurs. 13030% 13031% o display: Specifies a connection to an X server; returned from 13032% XOpenDisplay. 13033% 13034% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13035% 13036% o windows: Specifies a pointer to a XWindows structure. 13037% 13038% o image: the image; returned from ReadImage. 13039% 13040% o event: Specifies a pointer to a XEvent structure. If it is NULL, 13041% the entire image is refreshed. 13042% 13043% o exception: return any errors or warnings in this structure. 13044% 13045*/ 13046static Image *XTileImage(Display *display,XResourceInfo *resource_info, 13047 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13048{ 13049 static const char 13050 *VerbMenu[] = 13051 { 13052 "Load", 13053 "Next", 13054 "Former", 13055 "Delete", 13056 "Update", 13057 (char *) NULL, 13058 }; 13059 13060 static const ModeType 13061 TileCommands[] = 13062 { 13063 TileLoadCommand, 13064 TileNextCommand, 13065 TileFormerCommand, 13066 TileDeleteCommand, 13067 TileUpdateCommand 13068 }; 13069 13070 char 13071 command[MaxTextExtent], 13072 filename[MaxTextExtent]; 13073 13074 Image 13075 *tile_image; 13076 13077 int 13078 id, 13079 status, 13080 tile, 13081 x, 13082 y; 13083 13084 double 13085 scale_factor; 13086 13087 register char 13088 *p, 13089 *q; 13090 13091 register int 13092 i; 13093 13094 unsigned int 13095 height, 13096 width; 13097 13098 /* 13099 Tile image is relative to montage image configuration. 13100 */ 13101 x=0; 13102 y=0; 13103 width=(unsigned int) image->columns; 13104 height=(unsigned int) image->rows; 13105 if (windows->image.crop_geometry != (char *) NULL) 13106 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13107 scale_factor=(double) width/windows->image.ximage->width; 13108 event->xbutton.x+=windows->image.x; 13109 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5); 13110 scale_factor=(double) height/windows->image.ximage->height; 13111 event->xbutton.y+=windows->image.y; 13112 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5); 13113 /* 13114 Determine size and location of each tile in the visual image directory. 13115 */ 13116 width=(unsigned int) image->columns; 13117 height=(unsigned int) image->rows; 13118 x=0; 13119 y=0; 13120 (void) XParseGeometry(image->montage,&x,&y,&width,&height); 13121 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+ 13122 (event->xbutton.x-x)/width; 13123 if (tile < 0) 13124 { 13125 /* 13126 Button press is outside any tile. 13127 */ 13128 (void) XBell(display,0); 13129 return((Image *) NULL); 13130 } 13131 /* 13132 Determine file name from the tile directory. 13133 */ 13134 p=image->directory; 13135 for (i=tile; (i != 0) && (*p != '\0'); ) 13136 { 13137 if (*p == '\n') 13138 i--; 13139 p++; 13140 } 13141 if (*p == '\0') 13142 { 13143 /* 13144 Button press is outside any tile. 13145 */ 13146 (void) XBell(display,0); 13147 return((Image *) NULL); 13148 } 13149 /* 13150 Select a command from the pop-up menu. 13151 */ 13152 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command); 13153 if (id < 0) 13154 return((Image *) NULL); 13155 q=p; 13156 while ((*q != '\n') && (*q != '\0')) 13157 q++; 13158 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13159 /* 13160 Perform command for the selected tile. 13161 */ 13162 XSetCursorState(display,windows,MagickTrue); 13163 XCheckRefreshWindows(display,windows); 13164 tile_image=NewImageList(); 13165 switch (TileCommands[id]) 13166 { 13167 case TileLoadCommand: 13168 { 13169 /* 13170 Load tile image. 13171 */ 13172 XCheckRefreshWindows(display,windows); 13173 (void) CopyMagickString(resource_info->image_info->magick,"MIFF", 13174 MaxTextExtent); 13175 (void) CopyMagickString(resource_info->image_info->filename,filename, 13176 MaxTextExtent); 13177 tile_image=ReadImage(resource_info->image_info,exception); 13178 CatchException(exception); 13179 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13180 break; 13181 } 13182 case TileNextCommand: 13183 { 13184 /* 13185 Display next image. 13186 */ 13187 XClientMessage(display,windows->image.id,windows->im_protocols, 13188 windows->im_next_image,CurrentTime); 13189 break; 13190 } 13191 case TileFormerCommand: 13192 { 13193 /* 13194 Display former image. 13195 */ 13196 XClientMessage(display,windows->image.id,windows->im_protocols, 13197 windows->im_former_image,CurrentTime); 13198 break; 13199 } 13200 case TileDeleteCommand: 13201 { 13202 /* 13203 Delete tile image. 13204 */ 13205 if (IfMagickFalse(IsPathAccessible(filename)) ) 13206 { 13207 XNoticeWidget(display,windows,"Image file does not exist:",filename); 13208 break; 13209 } 13210 status=XConfirmWidget(display,windows,"Really delete tile",filename); 13211 if (status <= 0) 13212 break; 13213 status=ShredFile(filename); 13214 if (IfMagickTrue(status) ) 13215 { 13216 XNoticeWidget(display,windows,"Unable to delete image file:", 13217 filename); 13218 break; 13219 } 13220 } 13221 case TileUpdateCommand: 13222 { 13223 int 13224 x_offset, 13225 y_offset; 13226 13227 PixelInfo 13228 pixel; 13229 13230 register int 13231 j; 13232 13233 register Quantum 13234 *s; 13235 13236 /* 13237 Ensure all the images exist. 13238 */ 13239 tile=0; 13240 GetPixelInfo(image,&pixel); 13241 for (p=image->directory; *p != '\0'; p++) 13242 { 13243 CacheView 13244 *image_view; 13245 13246 q=p; 13247 while ((*q != '\n') && (*q != '\0')) 13248 q++; 13249 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13250 p=q; 13251 if (IfMagickTrue(IsPathAccessible(filename)) ) 13252 { 13253 tile++; 13254 continue; 13255 } 13256 /* 13257 Overwrite tile with background color. 13258 */ 13259 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x); 13260 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y); 13261 image_view=AcquireAuthenticCacheView(image,exception); 13262 (void) GetOneCacheViewVirtualPixelInfo(image_view,0,0,&pixel,exception); 13263 for (i=0; i < (int) height; i++) 13264 { 13265 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t) 13266 y_offset+i,width,1,exception); 13267 if (s == (Quantum *) NULL) 13268 break; 13269 for (j=0; j < (int) width; j++) 13270 { 13271 SetPixelInfoPixel(image,&pixel,s); 13272 s+=GetPixelChannels(image); 13273 } 13274 if (IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 13275 break; 13276 } 13277 image_view=DestroyCacheView(image_view); 13278 tile++; 13279 } 13280 windows->image.window_changes.width=(int) image->columns; 13281 windows->image.window_changes.height=(int) image->rows; 13282 XConfigureImageColormap(display,resource_info,windows,image,exception); 13283 (void) XConfigureImage(display,resource_info,windows,image,exception); 13284 break; 13285 } 13286 default: 13287 break; 13288 } 13289 XSetCursorState(display,windows,MagickFalse); 13290 return(tile_image); 13291} 13292 13293/* 13294%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13295% % 13296% % 13297% % 13298+ X T r a n s l a t e I m a g e % 13299% % 13300% % 13301% % 13302%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13303% 13304% XTranslateImage() translates the image within an Image window by one pixel 13305% as specified by the key symbol. If the image has a montage string the 13306% translation is respect to the width and height contained within the string. 13307% 13308% The format of the XTranslateImage method is: 13309% 13310% void XTranslateImage(Display *display,XWindows *windows, 13311% Image *image,const KeySym key_symbol) 13312% 13313% A description of each parameter follows: 13314% 13315% o display: Specifies a connection to an X server; returned from 13316% XOpenDisplay. 13317% 13318% o windows: Specifies a pointer to a XWindows structure. 13319% 13320% o image: the image. 13321% 13322% o key_symbol: Specifies a KeySym which indicates which side of the image 13323% to trim. 13324% 13325*/ 13326static void XTranslateImage(Display *display,XWindows *windows, 13327 Image *image,const KeySym key_symbol) 13328{ 13329 char 13330 text[MaxTextExtent]; 13331 13332 int 13333 x, 13334 y; 13335 13336 unsigned int 13337 x_offset, 13338 y_offset; 13339 13340 /* 13341 User specified a pan position offset. 13342 */ 13343 x_offset=windows->image.width; 13344 y_offset=windows->image.height; 13345 if (image->montage != (char *) NULL) 13346 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset); 13347 switch ((int) key_symbol) 13348 { 13349 case XK_Home: 13350 case XK_KP_Home: 13351 { 13352 windows->image.x=(int) windows->image.width/2; 13353 windows->image.y=(int) windows->image.height/2; 13354 break; 13355 } 13356 case XK_Left: 13357 case XK_KP_Left: 13358 { 13359 windows->image.x-=x_offset; 13360 break; 13361 } 13362 case XK_Next: 13363 case XK_Up: 13364 case XK_KP_Up: 13365 { 13366 windows->image.y-=y_offset; 13367 break; 13368 } 13369 case XK_Right: 13370 case XK_KP_Right: 13371 { 13372 windows->image.x+=x_offset; 13373 break; 13374 } 13375 case XK_Prior: 13376 case XK_Down: 13377 case XK_KP_Down: 13378 { 13379 windows->image.y+=y_offset; 13380 break; 13381 } 13382 default: 13383 return; 13384 } 13385 /* 13386 Check boundary conditions. 13387 */ 13388 if (windows->image.x < 0) 13389 windows->image.x=0; 13390 else 13391 if ((int) (windows->image.x+windows->image.width) > 13392 windows->image.ximage->width) 13393 windows->image.x=(int) windows->image.ximage->width-windows->image.width; 13394 if (windows->image.y < 0) 13395 windows->image.y=0; 13396 else 13397 if ((int) (windows->image.y+windows->image.height) > 13398 windows->image.ximage->height) 13399 windows->image.y=(int) windows->image.ximage->height-windows->image.height; 13400 /* 13401 Refresh Image window. 13402 */ 13403 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 13404 windows->image.width,windows->image.height,windows->image.x, 13405 windows->image.y); 13406 XInfoWidget(display,windows,text); 13407 XCheckRefreshWindows(display,windows); 13408 XDrawPanRectangle(display,windows); 13409 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 13410 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13411} 13412 13413/* 13414%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13415% % 13416% % 13417% % 13418+ X T r i m I m a g e % 13419% % 13420% % 13421% % 13422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13423% 13424% XTrimImage() trims the edges from the Image window. 13425% 13426% The format of the XTrimImage method is: 13427% 13428% MagickBooleanType XTrimImage(Display *display, 13429% XResourceInfo *resource_info,XWindows *windows,Image *image, 13430% ExceptionInfo *exception) 13431% 13432% A description of each parameter follows: 13433% 13434% o display: Specifies a connection to an X server; returned from 13435% XOpenDisplay. 13436% 13437% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13438% 13439% o windows: Specifies a pointer to a XWindows structure. 13440% 13441% o image: the image. 13442% 13443% o exception: return any errors or warnings in this structure. 13444% 13445*/ 13446static MagickBooleanType XTrimImage(Display *display, 13447 XResourceInfo *resource_info,XWindows *windows,Image *image, 13448 ExceptionInfo *exception) 13449{ 13450 RectangleInfo 13451 trim_info; 13452 13453 register int 13454 x, 13455 y; 13456 13457 size_t 13458 background, 13459 pixel; 13460 13461 /* 13462 Trim edges from image. 13463 */ 13464 XSetCursorState(display,windows,MagickTrue); 13465 XCheckRefreshWindows(display,windows); 13466 /* 13467 Crop the left edge. 13468 */ 13469 background=XGetPixel(windows->image.ximage,0,0); 13470 trim_info.width=(size_t) windows->image.ximage->width; 13471 for (x=0; x < windows->image.ximage->width; x++) 13472 { 13473 for (y=0; y < windows->image.ximage->height; y++) 13474 { 13475 pixel=XGetPixel(windows->image.ximage,x,y); 13476 if (pixel != background) 13477 break; 13478 } 13479 if (y < windows->image.ximage->height) 13480 break; 13481 } 13482 trim_info.x=(ssize_t) x; 13483 if (trim_info.x == (ssize_t) windows->image.ximage->width) 13484 { 13485 XSetCursorState(display,windows,MagickFalse); 13486 return(MagickFalse); 13487 } 13488 /* 13489 Crop the right edge. 13490 */ 13491 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0); 13492 for (x=windows->image.ximage->width-1; x != 0; x--) 13493 { 13494 for (y=0; y < windows->image.ximage->height; y++) 13495 { 13496 pixel=XGetPixel(windows->image.ximage,x,y); 13497 if (pixel != background) 13498 break; 13499 } 13500 if (y < windows->image.ximage->height) 13501 break; 13502 } 13503 trim_info.width=(size_t) (x-trim_info.x+1); 13504 /* 13505 Crop the top edge. 13506 */ 13507 background=XGetPixel(windows->image.ximage,0,0); 13508 trim_info.height=(size_t) windows->image.ximage->height; 13509 for (y=0; y < windows->image.ximage->height; y++) 13510 { 13511 for (x=0; x < windows->image.ximage->width; x++) 13512 { 13513 pixel=XGetPixel(windows->image.ximage,x,y); 13514 if (pixel != background) 13515 break; 13516 } 13517 if (x < windows->image.ximage->width) 13518 break; 13519 } 13520 trim_info.y=(ssize_t) y; 13521 /* 13522 Crop the bottom edge. 13523 */ 13524 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1); 13525 for (y=windows->image.ximage->height-1; y != 0; y--) 13526 { 13527 for (x=0; x < windows->image.ximage->width; x++) 13528 { 13529 pixel=XGetPixel(windows->image.ximage,x,y); 13530 if (pixel != background) 13531 break; 13532 } 13533 if (x < windows->image.ximage->width) 13534 break; 13535 } 13536 trim_info.height=(size_t) y-trim_info.y+1; 13537 if (((unsigned int) trim_info.width != windows->image.width) || 13538 ((unsigned int) trim_info.height != windows->image.height)) 13539 { 13540 /* 13541 Reconfigure Image window as defined by the trimming rectangle. 13542 */ 13543 XSetCropGeometry(display,windows,&trim_info,image); 13544 windows->image.window_changes.width=(int) trim_info.width; 13545 windows->image.window_changes.height=(int) trim_info.height; 13546 (void) XConfigureImage(display,resource_info,windows,image,exception); 13547 } 13548 XSetCursorState(display,windows,MagickFalse); 13549 return(MagickTrue); 13550} 13551 13552/* 13553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13554% % 13555% % 13556% % 13557+ X V i s u a l D i r e c t o r y I m a g e % 13558% % 13559% % 13560% % 13561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13562% 13563% XVisualDirectoryImage() creates a Visual Image Directory. 13564% 13565% The format of the XVisualDirectoryImage method is: 13566% 13567% Image *XVisualDirectoryImage(Display *display, 13568% XResourceInfo *resource_info,XWindows *windows, 13569% ExceptionInfo *exception) 13570% 13571% A description of each parameter follows: 13572% 13573% o display: Specifies a connection to an X server; returned from 13574% XOpenDisplay. 13575% 13576% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13577% 13578% o windows: Specifies a pointer to a XWindows structure. 13579% 13580% o exception: return any errors or warnings in this structure. 13581% 13582*/ 13583static Image *XVisualDirectoryImage(Display *display, 13584 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception) 13585{ 13586#define TileImageTag "Scale/Image" 13587#define XClientName "montage" 13588 13589 char 13590 **filelist; 13591 13592 Image 13593 *images, 13594 *montage_image, 13595 *next_image, 13596 *thumbnail_image; 13597 13598 ImageInfo 13599 *read_info; 13600 13601 int 13602 number_files; 13603 13604 MagickBooleanType 13605 backdrop; 13606 13607 MagickStatusType 13608 status; 13609 13610 MontageInfo 13611 *montage_info; 13612 13613 RectangleInfo 13614 geometry; 13615 13616 register int 13617 i; 13618 13619 static char 13620 filename[MaxTextExtent] = "\0", 13621 filenames[MaxTextExtent] = "*"; 13622 13623 XResourceInfo 13624 background_resources; 13625 13626 /* 13627 Request file name from user. 13628 */ 13629 XFileBrowserWidget(display,windows,"Directory",filenames); 13630 if (*filenames == '\0') 13631 return((Image *) NULL); 13632 /* 13633 Expand the filenames. 13634 */ 13635 filelist=(char **) AcquireMagickMemory(sizeof(*filelist)); 13636 if (filelist == (char **) NULL) 13637 { 13638 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed", 13639 filenames); 13640 return((Image *) NULL); 13641 } 13642 number_files=1; 13643 filelist[0]=filenames; 13644 status=ExpandFilenames(&number_files,&filelist); 13645 if (IfMagickFalse(status) || (number_files == 0)) 13646 { 13647 if (number_files == 0) 13648 ThrowXWindowException(ImageError,"NoImagesWereFound",filenames) 13649 else 13650 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed", 13651 filenames); 13652 return((Image *) NULL); 13653 } 13654 /* 13655 Set image background resources. 13656 */ 13657 background_resources=(*resource_info); 13658 background_resources.window_id=AcquireString(""); 13659 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent, 13660 "0x%lx",windows->image.id); 13661 background_resources.backdrop=MagickTrue; 13662 /* 13663 Read each image and convert them to a tile. 13664 */ 13665 backdrop=IsMagickTrue( (windows->visual_info->klass == TrueColor) || 13666 (windows->visual_info->klass == DirectColor) ); 13667 read_info=CloneImageInfo(resource_info->image_info); 13668 (void) SetImageOption(read_info,"jpeg:size","120x120"); 13669 (void) CloneString(&read_info->size,DefaultTileGeometry); 13670 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 13671 (void *) NULL); 13672 images=NewImageList(); 13673 XSetCursorState(display,windows,MagickTrue); 13674 XCheckRefreshWindows(display,windows); 13675 for (i=0; i < (int) number_files; i++) 13676 { 13677 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent); 13678 filelist[i]=DestroyString(filelist[i]); 13679 *read_info->magick='\0'; 13680 next_image=ReadImage(read_info,exception); 13681 CatchException(exception); 13682 if (next_image != (Image *) NULL) 13683 { 13684 (void) DeleteImageProperty(next_image,"label"); 13685 (void) SetImageProperty(next_image,"label",InterpretImageProperties( 13686 read_info,next_image,DefaultTileLabel,exception),exception); 13687 (void) ParseRegionGeometry(next_image,read_info->size,&geometry, 13688 exception); 13689 thumbnail_image=ThumbnailImage(next_image,geometry.width, 13690 geometry.height,exception); 13691 if (thumbnail_image != (Image *) NULL) 13692 { 13693 next_image=DestroyImage(next_image); 13694 next_image=thumbnail_image; 13695 } 13696 if (backdrop) 13697 { 13698 (void) XDisplayBackgroundImage(display,&background_resources, 13699 next_image,exception); 13700 XSetCursorState(display,windows,MagickTrue); 13701 } 13702 AppendImageToList(&images,next_image); 13703 if (images->progress_monitor != (MagickProgressMonitor) NULL) 13704 { 13705 MagickBooleanType 13706 proceed; 13707 13708 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i, 13709 (MagickSizeType) number_files); 13710 if (IfMagickFalse(proceed) ) 13711 break; 13712 } 13713 } 13714 } 13715 filelist=(char **) RelinquishMagickMemory(filelist); 13716 if (images == (Image *) NULL) 13717 { 13718 read_info=DestroyImageInfo(read_info); 13719 XSetCursorState(display,windows,MagickFalse); 13720 ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames); 13721 return((Image *) NULL); 13722 } 13723 /* 13724 Create the Visual Image Directory. 13725 */ 13726 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL); 13727 montage_info->pointsize=10; 13728 if (resource_info->font != (char *) NULL) 13729 (void) CloneString(&montage_info->font,resource_info->font); 13730 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent); 13731 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList( 13732 images),exception); 13733 images=DestroyImageList(images); 13734 montage_info=DestroyMontageInfo(montage_info); 13735 read_info=DestroyImageInfo(read_info); 13736 XSetCursorState(display,windows,MagickFalse); 13737 if (montage_image == (Image *) NULL) 13738 return(montage_image); 13739 XClientMessage(display,windows->image.id,windows->im_protocols, 13740 windows->im_next_image,CurrentTime); 13741 return(montage_image); 13742} 13743 13744/* 13745%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13746% % 13747% % 13748% % 13749% X D i s p l a y B a c k g r o u n d I m a g e % 13750% % 13751% % 13752% % 13753%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13754% 13755% XDisplayBackgroundImage() displays an image in the background of a window. 13756% 13757% The format of the XDisplayBackgroundImage method is: 13758% 13759% MagickBooleanType XDisplayBackgroundImage(Display *display, 13760% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13761% 13762% A description of each parameter follows: 13763% 13764% o display: Specifies a connection to an X server; returned from 13765% XOpenDisplay. 13766% 13767% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13768% 13769% o image: the image. 13770% 13771% o exception: return any errors or warnings in this structure. 13772% 13773*/ 13774MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display, 13775 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13776{ 13777 char 13778 geometry[MaxTextExtent], 13779 visual_type[MaxTextExtent]; 13780 13781 int 13782 height, 13783 status, 13784 width; 13785 13786 RectangleInfo 13787 geometry_info; 13788 13789 static XPixelInfo 13790 pixel; 13791 13792 static XStandardColormap 13793 *map_info; 13794 13795 static XVisualInfo 13796 *visual_info = (XVisualInfo *) NULL; 13797 13798 static XWindowInfo 13799 window_info; 13800 13801 size_t 13802 delay; 13803 13804 Window 13805 root_window; 13806 13807 XGCValues 13808 context_values; 13809 13810 XResourceInfo 13811 resources; 13812 13813 XWindowAttributes 13814 window_attributes; 13815 13816 /* 13817 Determine target window. 13818 */ 13819 assert(image != (Image *) NULL); 13820 assert(image->signature == MagickSignature); 13821 if (IfMagickTrue(image->debug) ) 13822 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 13823 resources=(*resource_info); 13824 window_info.id=(Window) NULL; 13825 root_window=XRootWindow(display,XDefaultScreen(display)); 13826 if (LocaleCompare(resources.window_id,"root") == 0) 13827 window_info.id=root_window; 13828 else 13829 { 13830 if (isdigit((int) ((unsigned char) *resources.window_id)) != 0) 13831 window_info.id=XWindowByID(display,root_window, 13832 (Window) strtol((char *) resources.window_id,(char **) NULL,0)); 13833 if (window_info.id == (Window) NULL) 13834 window_info.id=XWindowByName(display,root_window,resources.window_id); 13835 } 13836 if (window_info.id == (Window) NULL) 13837 { 13838 ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists", 13839 resources.window_id); 13840 return(MagickFalse); 13841 } 13842 /* 13843 Determine window visual id. 13844 */ 13845 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); 13846 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); 13847 (void) CopyMagickString(visual_type,"default",MaxTextExtent); 13848 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13849 if (status != 0) 13850 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx", 13851 XVisualIDFromVisual(window_attributes.visual)); 13852 if (visual_info == (XVisualInfo *) NULL) 13853 { 13854 /* 13855 Allocate standard colormap. 13856 */ 13857 map_info=XAllocStandardColormap(); 13858 if (map_info == (XStandardColormap *) NULL) 13859 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", 13860 image->filename); 13861 map_info->colormap=(Colormap) NULL; 13862 pixel.pixels=(unsigned long *) NULL; 13863 /* 13864 Initialize visual info. 13865 */ 13866 resources.map_type=(char *) NULL; 13867 resources.visual_type=visual_type; 13868 visual_info=XBestVisualInfo(display,map_info,&resources); 13869 if (visual_info == (XVisualInfo *) NULL) 13870 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", 13871 resources.visual_type); 13872 /* 13873 Initialize window info. 13874 */ 13875 window_info.ximage=(XImage *) NULL; 13876 window_info.matte_image=(XImage *) NULL; 13877 window_info.pixmap=(Pixmap) NULL; 13878 window_info.matte_pixmap=(Pixmap) NULL; 13879 } 13880 /* 13881 Free previous root colors. 13882 */ 13883 if (window_info.id == root_window) 13884 (void) XDestroyWindowColors(display,root_window); 13885 /* 13886 Initialize Standard Colormap. 13887 */ 13888 resources.colormap=SharedColormap; 13889 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel, 13890 exception); 13891 /* 13892 Graphic context superclass. 13893 */ 13894 context_values.background=pixel.background_color.pixel; 13895 context_values.foreground=pixel.foreground_color.pixel; 13896 pixel.annotate_context=XCreateGC(display,window_info.id, 13897 (size_t) (GCBackground | GCForeground),&context_values); 13898 if (pixel.annotate_context == (GC) NULL) 13899 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 13900 image->filename); 13901 /* 13902 Initialize Image window attributes. 13903 */ 13904 window_info.name=AcquireString("\0"); 13905 window_info.icon_name=AcquireString("\0"); 13906 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, 13907 &resources,&window_info); 13908 /* 13909 Create the X image. 13910 */ 13911 window_info.width=(unsigned int) image->columns; 13912 window_info.height=(unsigned int) image->rows; 13913 if ((image->columns != window_info.width) || 13914 (image->rows != window_info.height)) 13915 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13916 image->filename); 13917 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>", 13918 window_attributes.width,window_attributes.height); 13919 geometry_info.width=window_info.width; 13920 geometry_info.height=window_info.height; 13921 geometry_info.x=(ssize_t) window_info.x; 13922 geometry_info.y=(ssize_t) window_info.y; 13923 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 13924 &geometry_info.width,&geometry_info.height); 13925 window_info.width=(unsigned int) geometry_info.width; 13926 window_info.height=(unsigned int) geometry_info.height; 13927 window_info.x=(int) geometry_info.x; 13928 window_info.y=(int) geometry_info.y; 13929 status=XMakeImage(display,&resources,&window_info,image,window_info.width, 13930 window_info.height,exception); 13931 if (IfMagickFalse(status) ) 13932 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13933 image->filename); 13934 window_info.x=0; 13935 window_info.y=0; 13936 if (IfMagickTrue(image->debug) ) 13937 { 13938 (void) LogMagickEvent(X11Event,GetMagickModule(), 13939 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene, 13940 (double) image->columns,(double) image->rows); 13941 if (image->colors != 0) 13942 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 13943 image->colors); 13944 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick); 13945 } 13946 /* 13947 Adjust image dimensions as specified by backdrop or geometry options. 13948 */ 13949 width=(int) window_info.width; 13950 height=(int) window_info.height; 13951 if (IfMagickTrue(resources.backdrop) ) 13952 { 13953 /* 13954 Center image on window. 13955 */ 13956 window_info.x=(window_attributes.width/2)- 13957 (window_info.ximage->width/2); 13958 window_info.y=(window_attributes.height/2)- 13959 (window_info.ximage->height/2); 13960 width=window_attributes.width; 13961 height=window_attributes.height; 13962 } 13963 if ((resources.image_geometry != (char *) NULL) && 13964 (*resources.image_geometry != '\0')) 13965 { 13966 char 13967 default_geometry[MaxTextExtent]; 13968 13969 int 13970 flags, 13971 gravity; 13972 13973 XSizeHints 13974 *size_hints; 13975 13976 /* 13977 User specified geometry. 13978 */ 13979 size_hints=XAllocSizeHints(); 13980 if (size_hints == (XSizeHints *) NULL) 13981 ThrowXWindowFatalException(ResourceLimitFatalError, 13982 "MemoryAllocationFailed",image->filename); 13983 size_hints->flags=0L; 13984 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d", 13985 width,height); 13986 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, 13987 default_geometry,window_info.border_width,size_hints,&window_info.x, 13988 &window_info.y,&width,&height,&gravity); 13989 if (flags & (XValue | YValue)) 13990 { 13991 width=window_attributes.width; 13992 height=window_attributes.height; 13993 } 13994 (void) XFree((void *) size_hints); 13995 } 13996 /* 13997 Create the X pixmap. 13998 */ 13999 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, 14000 (unsigned int) height,window_info.depth); 14001 if (window_info.pixmap == (Pixmap) NULL) 14002 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", 14003 image->filename); 14004 /* 14005 Display pixmap on the window. 14006 */ 14007 if (((unsigned int) width > window_info.width) || 14008 ((unsigned int) height > window_info.height)) 14009 (void) XFillRectangle(display,window_info.pixmap, 14010 window_info.annotate_context,0,0,(unsigned int) width, 14011 (unsigned int) height); 14012 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, 14013 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int) 14014 window_info.width,(unsigned int) window_info.height); 14015 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); 14016 (void) XClearWindow(display,window_info.id); 14017 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); 14018 XDelay(display,delay == 0UL ? 10UL : delay); 14019 (void) XSync(display,MagickFalse); 14020 return(IsMagickTrue(window_info.id == root_window)); 14021} 14022 14023/* 14024%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14025% % 14026% % 14027% % 14028+ X D i s p l a y I m a g e % 14029% % 14030% % 14031% % 14032%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14033% 14034% XDisplayImage() displays an image via X11. A new image is created and 14035% returned if the user interactively transforms the displayed image. 14036% 14037% The format of the XDisplayImage method is: 14038% 14039% Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14040% char **argv,int argc,Image **image,size_t *state, 14041% ExceptionInfo *exception) 14042% 14043% A description of each parameter follows: 14044% 14045% o nexus: Method XDisplayImage returns an image when the 14046% user chooses 'Open Image' from the command menu or picks a tile 14047% from the image directory. Otherwise a null image is returned. 14048% 14049% o display: Specifies a connection to an X server; returned from 14050% XOpenDisplay. 14051% 14052% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 14053% 14054% o argv: Specifies the application's argument list. 14055% 14056% o argc: Specifies the number of arguments. 14057% 14058% o image: Specifies an address to an address of an Image structure; 14059% 14060% o exception: return any errors or warnings in this structure. 14061% 14062*/ 14063MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14064 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception) 14065{ 14066#define MagnifySize 256 /* must be a power of 2 */ 14067#define MagickMenus 10 14068#define MagickTitle "Commands" 14069 14070 static const char 14071 *CommandMenu[] = 14072 { 14073 "File", 14074 "Edit", 14075 "View", 14076 "Transform", 14077 "Enhance", 14078 "Effects", 14079 "F/X", 14080 "Image Edit", 14081 "Miscellany", 14082 "Help", 14083 (char *) NULL 14084 }, 14085 *FileMenu[] = 14086 { 14087 "Open...", 14088 "Next", 14089 "Former", 14090 "Select...", 14091 "Save...", 14092 "Print...", 14093 "Delete...", 14094 "New...", 14095 "Visual Directory...", 14096 "Quit", 14097 (char *) NULL 14098 }, 14099 *EditMenu[] = 14100 { 14101 "Undo", 14102 "Redo", 14103 "Cut", 14104 "Copy", 14105 "Paste", 14106 (char *) NULL 14107 }, 14108 *ViewMenu[] = 14109 { 14110 "Half Size", 14111 "Original Size", 14112 "Double Size", 14113 "Resize...", 14114 "Apply", 14115 "Refresh", 14116 "Restore", 14117 (char *) NULL 14118 }, 14119 *TransformMenu[] = 14120 { 14121 "Crop", 14122 "Chop", 14123 "Flop", 14124 "Flip", 14125 "Rotate Right", 14126 "Rotate Left", 14127 "Rotate...", 14128 "Shear...", 14129 "Roll...", 14130 "Trim Edges", 14131 (char *) NULL 14132 }, 14133 *EnhanceMenu[] = 14134 { 14135 "Hue...", 14136 "Saturation...", 14137 "Brightness...", 14138 "Gamma...", 14139 "Spiff", 14140 "Dull", 14141 "Contrast Stretch...", 14142 "Sigmoidal Contrast...", 14143 "Normalize", 14144 "Equalize", 14145 "Negate", 14146 "Grayscale", 14147 "Map...", 14148 "Quantize...", 14149 (char *) NULL 14150 }, 14151 *EffectsMenu[] = 14152 { 14153 "Despeckle", 14154 "Emboss", 14155 "Reduce Noise", 14156 "Add Noise...", 14157 "Sharpen...", 14158 "Blur...", 14159 "Threshold...", 14160 "Edge Detect...", 14161 "Spread...", 14162 "Shade...", 14163 "Raise...", 14164 "Segment...", 14165 (char *) NULL 14166 }, 14167 *FXMenu[] = 14168 { 14169 "Solarize...", 14170 "Sepia Tone...", 14171 "Swirl...", 14172 "Implode...", 14173 "Vignette...", 14174 "Wave...", 14175 "Oil Paint...", 14176 "Charcoal Draw...", 14177 (char *) NULL 14178 }, 14179 *ImageEditMenu[] = 14180 { 14181 "Annotate...", 14182 "Draw...", 14183 "Color...", 14184 "Matte...", 14185 "Composite...", 14186 "Add Border...", 14187 "Add Frame...", 14188 "Comment...", 14189 "Launch...", 14190 "Region of Interest...", 14191 (char *) NULL 14192 }, 14193 *MiscellanyMenu[] = 14194 { 14195 "Image Info", 14196 "Zoom Image", 14197 "Show Preview...", 14198 "Show Histogram", 14199 "Show Matte", 14200 "Background...", 14201 "Slide Show...", 14202 "Preferences...", 14203 (char *) NULL 14204 }, 14205 *HelpMenu[] = 14206 { 14207 "Overview", 14208 "Browse Documentation", 14209 "About Display", 14210 (char *) NULL 14211 }, 14212 *ShortCutsMenu[] = 14213 { 14214 "Next", 14215 "Former", 14216 "Open...", 14217 "Save...", 14218 "Print...", 14219 "Undo", 14220 "Restore", 14221 "Image Info", 14222 "Quit", 14223 (char *) NULL 14224 }, 14225 *VirtualMenu[] = 14226 { 14227 "Image Info", 14228 "Print", 14229 "Next", 14230 "Quit", 14231 (char *) NULL 14232 }; 14233 14234 static const char 14235 **Menus[MagickMenus] = 14236 { 14237 FileMenu, 14238 EditMenu, 14239 ViewMenu, 14240 TransformMenu, 14241 EnhanceMenu, 14242 EffectsMenu, 14243 FXMenu, 14244 ImageEditMenu, 14245 MiscellanyMenu, 14246 HelpMenu 14247 }; 14248 14249 static CommandType 14250 CommandMenus[] = 14251 { 14252 NullCommand, 14253 NullCommand, 14254 NullCommand, 14255 NullCommand, 14256 NullCommand, 14257 NullCommand, 14258 NullCommand, 14259 NullCommand, 14260 NullCommand, 14261 NullCommand, 14262 }, 14263 FileCommands[] = 14264 { 14265 OpenCommand, 14266 NextCommand, 14267 FormerCommand, 14268 SelectCommand, 14269 SaveCommand, 14270 PrintCommand, 14271 DeleteCommand, 14272 NewCommand, 14273 VisualDirectoryCommand, 14274 QuitCommand 14275 }, 14276 EditCommands[] = 14277 { 14278 UndoCommand, 14279 RedoCommand, 14280 CutCommand, 14281 CopyCommand, 14282 PasteCommand 14283 }, 14284 ViewCommands[] = 14285 { 14286 HalfSizeCommand, 14287 OriginalSizeCommand, 14288 DoubleSizeCommand, 14289 ResizeCommand, 14290 ApplyCommand, 14291 RefreshCommand, 14292 RestoreCommand 14293 }, 14294 TransformCommands[] = 14295 { 14296 CropCommand, 14297 ChopCommand, 14298 FlopCommand, 14299 FlipCommand, 14300 RotateRightCommand, 14301 RotateLeftCommand, 14302 RotateCommand, 14303 ShearCommand, 14304 RollCommand, 14305 TrimCommand 14306 }, 14307 EnhanceCommands[] = 14308 { 14309 HueCommand, 14310 SaturationCommand, 14311 BrightnessCommand, 14312 GammaCommand, 14313 SpiffCommand, 14314 DullCommand, 14315 ContrastStretchCommand, 14316 SigmoidalContrastCommand, 14317 NormalizeCommand, 14318 EqualizeCommand, 14319 NegateCommand, 14320 GrayscaleCommand, 14321 MapCommand, 14322 QuantizeCommand 14323 }, 14324 EffectsCommands[] = 14325 { 14326 DespeckleCommand, 14327 EmbossCommand, 14328 ReduceNoiseCommand, 14329 AddNoiseCommand, 14330 SharpenCommand, 14331 BlurCommand, 14332 ThresholdCommand, 14333 EdgeDetectCommand, 14334 SpreadCommand, 14335 ShadeCommand, 14336 RaiseCommand, 14337 SegmentCommand 14338 }, 14339 FXCommands[] = 14340 { 14341 SolarizeCommand, 14342 SepiaToneCommand, 14343 SwirlCommand, 14344 ImplodeCommand, 14345 VignetteCommand, 14346 WaveCommand, 14347 OilPaintCommand, 14348 CharcoalDrawCommand 14349 }, 14350 ImageEditCommands[] = 14351 { 14352 AnnotateCommand, 14353 DrawCommand, 14354 ColorCommand, 14355 MatteCommand, 14356 CompositeCommand, 14357 AddBorderCommand, 14358 AddFrameCommand, 14359 CommentCommand, 14360 LaunchCommand, 14361 RegionofInterestCommand 14362 }, 14363 MiscellanyCommands[] = 14364 { 14365 InfoCommand, 14366 ZoomCommand, 14367 ShowPreviewCommand, 14368 ShowHistogramCommand, 14369 ShowMatteCommand, 14370 BackgroundCommand, 14371 SlideShowCommand, 14372 PreferencesCommand 14373 }, 14374 HelpCommands[] = 14375 { 14376 HelpCommand, 14377 BrowseDocumentationCommand, 14378 VersionCommand 14379 }, 14380 ShortCutsCommands[] = 14381 { 14382 NextCommand, 14383 FormerCommand, 14384 OpenCommand, 14385 SaveCommand, 14386 PrintCommand, 14387 UndoCommand, 14388 RestoreCommand, 14389 InfoCommand, 14390 QuitCommand 14391 }, 14392 VirtualCommands[] = 14393 { 14394 InfoCommand, 14395 PrintCommand, 14396 NextCommand, 14397 QuitCommand 14398 }; 14399 14400 static CommandType 14401 *Commands[MagickMenus] = 14402 { 14403 FileCommands, 14404 EditCommands, 14405 ViewCommands, 14406 TransformCommands, 14407 EnhanceCommands, 14408 EffectsCommands, 14409 FXCommands, 14410 ImageEditCommands, 14411 MiscellanyCommands, 14412 HelpCommands 14413 }; 14414 14415 char 14416 command[MaxTextExtent], 14417 *directory, 14418 geometry[MaxTextExtent], 14419 resource_name[MaxTextExtent]; 14420 14421 CommandType 14422 command_type; 14423 14424 Image 14425 *display_image, 14426 *nexus; 14427 14428 int 14429 entry, 14430 id; 14431 14432 KeySym 14433 key_symbol; 14434 14435 MagickStatusType 14436 context_mask, 14437 status; 14438 14439 RectangleInfo 14440 geometry_info; 14441 14442 register int 14443 i; 14444 14445 static char 14446 working_directory[MaxTextExtent]; 14447 14448 static XPoint 14449 vid_info; 14450 14451 static XWindowInfo 14452 *magick_windows[MaxXWindows]; 14453 14454 static unsigned int 14455 number_windows; 14456 14457 struct stat 14458 attributes; 14459 14460 time_t 14461 timer, 14462 timestamp, 14463 update_time; 14464 14465 unsigned int 14466 height, 14467 width; 14468 14469 size_t 14470 delay; 14471 14472 WarningHandler 14473 warning_handler; 14474 14475 Window 14476 root_window; 14477 14478 XClassHint 14479 *class_hints; 14480 14481 XEvent 14482 event; 14483 14484 XFontStruct 14485 *font_info; 14486 14487 XGCValues 14488 context_values; 14489 14490 XPixelInfo 14491 *icon_pixel, 14492 *pixel; 14493 14494 XResourceInfo 14495 *icon_resources; 14496 14497 XStandardColormap 14498 *icon_map, 14499 *map_info; 14500 14501 XVisualInfo 14502 *icon_visual, 14503 *visual_info; 14504 14505 XWindowChanges 14506 window_changes; 14507 14508 XWindows 14509 *windows; 14510 14511 XWMHints 14512 *manager_hints; 14513 14514 assert(image != (Image **) NULL); 14515 assert((*image)->signature == MagickSignature); 14516 if (IfMagickTrue((*image)->debug) ) 14517 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 14518 display_image=(*image); 14519 warning_handler=(WarningHandler) NULL; 14520 windows=XSetWindows((XWindows *) ~0); 14521 if (windows != (XWindows *) NULL) 14522 { 14523 int 14524 status; 14525 14526 if (*working_directory == '\0') 14527 (void) CopyMagickString(working_directory,".",MaxTextExtent); 14528 status=chdir(working_directory); 14529 if (status == -1) 14530 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 14531 "UnableToOpenFile","%s",working_directory); 14532 warning_handler=resource_info->display_warnings ? 14533 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14534 warning_handler=resource_info->display_warnings ? 14535 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14536 } 14537 else 14538 { 14539 /* 14540 Allocate windows structure. 14541 */ 14542 resource_info->colors=display_image->colors; 14543 windows=XSetWindows(XInitializeWindows(display,resource_info)); 14544 if (windows == (XWindows *) NULL) 14545 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow", 14546 (*image)->filename); 14547 /* 14548 Initialize window id's. 14549 */ 14550 number_windows=0; 14551 magick_windows[number_windows++]=(&windows->icon); 14552 magick_windows[number_windows++]=(&windows->backdrop); 14553 magick_windows[number_windows++]=(&windows->image); 14554 magick_windows[number_windows++]=(&windows->info); 14555 magick_windows[number_windows++]=(&windows->command); 14556 magick_windows[number_windows++]=(&windows->widget); 14557 magick_windows[number_windows++]=(&windows->popup); 14558 magick_windows[number_windows++]=(&windows->magnify); 14559 magick_windows[number_windows++]=(&windows->pan); 14560 for (i=0; i < (int) number_windows; i++) 14561 magick_windows[i]->id=(Window) NULL; 14562 vid_info.x=0; 14563 vid_info.y=0; 14564 } 14565 /* 14566 Initialize font info. 14567 */ 14568 if (windows->font_info != (XFontStruct *) NULL) 14569 (void) XFreeFont(display,windows->font_info); 14570 windows->font_info=XBestFont(display,resource_info,MagickFalse); 14571 if (windows->font_info == (XFontStruct *) NULL) 14572 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", 14573 resource_info->font); 14574 /* 14575 Initialize Standard Colormap. 14576 */ 14577 map_info=windows->map_info; 14578 icon_map=windows->icon_map; 14579 visual_info=windows->visual_info; 14580 icon_visual=windows->icon_visual; 14581 pixel=windows->pixel_info; 14582 icon_pixel=windows->icon_pixel; 14583 font_info=windows->font_info; 14584 icon_resources=windows->icon_resources; 14585 class_hints=windows->class_hints; 14586 manager_hints=windows->manager_hints; 14587 root_window=XRootWindow(display,visual_info->screen); 14588 nexus=NewImageList(); 14589 if (IfMagickTrue(display_image->debug) ) 14590 { 14591 (void) LogMagickEvent(X11Event,GetMagickModule(), 14592 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename, 14593 (double) display_image->scene,(double) display_image->columns, 14594 (double) display_image->rows); 14595 if (display_image->colors != 0) 14596 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 14597 display_image->colors); 14598 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", 14599 display_image->magick); 14600 } 14601 XMakeStandardColormap(display,visual_info,resource_info,display_image, 14602 map_info,pixel,exception); 14603 display_image->taint=MagickFalse; 14604 /* 14605 Initialize graphic context. 14606 */ 14607 windows->context.id=(Window) NULL; 14608 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14609 resource_info,&windows->context); 14610 (void) CloneString(&class_hints->res_name,resource_info->client_name); 14611 (void) CloneString(&class_hints->res_class,resource_info->client_name); 14612 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]); 14613 manager_hints->flags=InputHint | StateHint; 14614 manager_hints->input=MagickFalse; 14615 manager_hints->initial_state=WithdrawnState; 14616 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14617 &windows->context); 14618 if (IfMagickTrue(display_image->debug) ) 14619 (void) LogMagickEvent(X11Event,GetMagickModule(), 14620 "Window id: 0x%lx (context)",windows->context.id); 14621 context_values.background=pixel->background_color.pixel; 14622 context_values.font=font_info->fid; 14623 context_values.foreground=pixel->foreground_color.pixel; 14624 context_values.graphics_exposures=MagickFalse; 14625 context_mask=(MagickStatusType) 14626 (GCBackground | GCFont | GCForeground | GCGraphicsExposures); 14627 if (pixel->annotate_context != (GC) NULL) 14628 (void) XFreeGC(display,pixel->annotate_context); 14629 pixel->annotate_context=XCreateGC(display,windows->context.id, 14630 context_mask,&context_values); 14631 if (pixel->annotate_context == (GC) NULL) 14632 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14633 display_image->filename); 14634 context_values.background=pixel->depth_color.pixel; 14635 if (pixel->widget_context != (GC) NULL) 14636 (void) XFreeGC(display,pixel->widget_context); 14637 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask, 14638 &context_values); 14639 if (pixel->widget_context == (GC) NULL) 14640 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14641 display_image->filename); 14642 context_values.background=pixel->foreground_color.pixel; 14643 context_values.foreground=pixel->background_color.pixel; 14644 context_values.plane_mask=context_values.background ^ 14645 context_values.foreground; 14646 if (pixel->highlight_context != (GC) NULL) 14647 (void) XFreeGC(display,pixel->highlight_context); 14648 pixel->highlight_context=XCreateGC(display,windows->context.id, 14649 (size_t) (context_mask | GCPlaneMask),&context_values); 14650 if (pixel->highlight_context == (GC) NULL) 14651 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14652 display_image->filename); 14653 (void) XDestroyWindow(display,windows->context.id); 14654 /* 14655 Initialize icon window. 14656 */ 14657 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, 14658 icon_resources,&windows->icon); 14659 windows->icon.geometry=resource_info->icon_geometry; 14660 XBestIconSize(display,&windows->icon,display_image); 14661 windows->icon.attributes.colormap=XDefaultColormap(display, 14662 icon_visual->screen); 14663 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; 14664 manager_hints->flags=InputHint | StateHint; 14665 manager_hints->input=MagickFalse; 14666 manager_hints->initial_state=IconicState; 14667 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14668 &windows->icon); 14669 if (IfMagickTrue(display_image->debug) ) 14670 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", 14671 windows->icon.id); 14672 /* 14673 Initialize graphic context for icon window. 14674 */ 14675 if (icon_pixel->annotate_context != (GC) NULL) 14676 (void) XFreeGC(display,icon_pixel->annotate_context); 14677 context_values.background=icon_pixel->background_color.pixel; 14678 context_values.foreground=icon_pixel->foreground_color.pixel; 14679 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, 14680 (size_t) (GCBackground | GCForeground),&context_values); 14681 if (icon_pixel->annotate_context == (GC) NULL) 14682 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14683 display_image->filename); 14684 windows->icon.annotate_context=icon_pixel->annotate_context; 14685 /* 14686 Initialize Image window. 14687 */ 14688 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14689 &windows->image); 14690 windows->image.shape=MagickTrue; /* non-rectangular shape hint */ 14691 if (IfMagickFalse(resource_info->use_shared_memory) ) 14692 windows->image.shared_memory=MagickFalse; 14693 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState)) 14694 { 14695 char 14696 *title; 14697 14698 title=InterpretImageProperties(resource_info->image_info,display_image, 14699 resource_info->title,exception); 14700 (void) CopyMagickString(windows->image.name,title,MaxTextExtent); 14701 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent); 14702 title=DestroyString(title); 14703 } 14704 else 14705 { 14706 char 14707 filename[MaxTextExtent]; 14708 14709 /* 14710 Window name is the base of the filename. 14711 */ 14712 GetPathComponent(display_image->magick_filename,TailPath,filename); 14713 if (display_image->scene == 0) 14714 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14715 "%s: %s",MagickPackageName,filename); 14716 else 14717 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14718 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename, 14719 (double) display_image->scene,(double) GetImageListLength( 14720 display_image)); 14721 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent); 14722 } 14723 if (resource_info->immutable) 14724 windows->image.immutable=MagickTrue; 14725 windows->image.use_pixmap=resource_info->use_pixmap; 14726 windows->image.geometry=resource_info->image_geometry; 14727 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 14728 XDisplayWidth(display,visual_info->screen), 14729 XDisplayHeight(display,visual_info->screen)); 14730 geometry_info.width=display_image->columns; 14731 geometry_info.height=display_image->rows; 14732 geometry_info.x=0; 14733 geometry_info.y=0; 14734 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 14735 &geometry_info.width,&geometry_info.height); 14736 windows->image.width=(unsigned int) geometry_info.width; 14737 windows->image.height=(unsigned int) geometry_info.height; 14738 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14739 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14740 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14741 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; 14742 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14743 resource_info,&windows->backdrop); 14744 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) 14745 { 14746 /* 14747 Initialize backdrop window. 14748 */ 14749 windows->backdrop.x=0; 14750 windows->backdrop.y=0; 14751 (void) CloneString(&windows->backdrop.name,"Backdrop"); 14752 windows->backdrop.flags=(size_t) (USSize | USPosition); 14753 windows->backdrop.width=(unsigned int) 14754 XDisplayWidth(display,visual_info->screen); 14755 windows->backdrop.height=(unsigned int) 14756 XDisplayHeight(display,visual_info->screen); 14757 windows->backdrop.border_width=0; 14758 windows->backdrop.immutable=MagickTrue; 14759 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | 14760 ButtonReleaseMask; 14761 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | 14762 StructureNotifyMask; 14763 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14764 manager_hints->icon_window=windows->icon.id; 14765 manager_hints->input=MagickTrue; 14766 manager_hints->initial_state=resource_info->iconic ? IconicState : 14767 NormalState; 14768 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14769 &windows->backdrop); 14770 if (IfMagickTrue(display_image->debug) ) 14771 (void) LogMagickEvent(X11Event,GetMagickModule(), 14772 "Window id: 0x%lx (backdrop)",windows->backdrop.id); 14773 (void) XMapWindow(display,windows->backdrop.id); 14774 (void) XClearWindow(display,windows->backdrop.id); 14775 if (windows->image.id != (Window) NULL) 14776 { 14777 (void) XDestroyWindow(display,windows->image.id); 14778 windows->image.id=(Window) NULL; 14779 } 14780 /* 14781 Position image in the center the backdrop. 14782 */ 14783 windows->image.flags|=USPosition; 14784 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- 14785 (windows->image.width/2); 14786 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- 14787 (windows->image.height/2); 14788 } 14789 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14790 manager_hints->icon_window=windows->icon.id; 14791 manager_hints->input=MagickTrue; 14792 manager_hints->initial_state=resource_info->iconic ? IconicState : 14793 NormalState; 14794 if (windows->group_leader.id != (Window) NULL) 14795 { 14796 /* 14797 Follow the leader. 14798 */ 14799 manager_hints->flags|=WindowGroupHint; 14800 manager_hints->window_group=windows->group_leader.id; 14801 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); 14802 if (IfMagickTrue(display_image->debug) ) 14803 (void) LogMagickEvent(X11Event,GetMagickModule(), 14804 "Window id: 0x%lx (group leader)",windows->group_leader.id); 14805 } 14806 XMakeWindow(display, 14807 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), 14808 argv,argc,class_hints,manager_hints,&windows->image); 14809 (void) XChangeProperty(display,windows->image.id,windows->im_protocols, 14810 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); 14811 if (windows->group_leader.id != (Window) NULL) 14812 (void) XSetTransientForHint(display,windows->image.id, 14813 windows->group_leader.id); 14814 if (IfMagickTrue(display_image->debug) ) 14815 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", 14816 windows->image.id); 14817 /* 14818 Initialize Info widget. 14819 */ 14820 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14821 &windows->info); 14822 (void) CloneString(&windows->info.name,"Info"); 14823 (void) CloneString(&windows->info.icon_name,"Info"); 14824 windows->info.border_width=1; 14825 windows->info.x=2; 14826 windows->info.y=2; 14827 windows->info.flags|=PPosition; 14828 windows->info.attributes.win_gravity=UnmapGravity; 14829 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | 14830 StructureNotifyMask; 14831 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14832 manager_hints->input=MagickFalse; 14833 manager_hints->initial_state=NormalState; 14834 manager_hints->window_group=windows->image.id; 14835 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, 14836 &windows->info); 14837 windows->info.highlight_stipple=XCreateBitmapFromData(display, 14838 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14839 windows->info.shadow_stipple=XCreateBitmapFromData(display, 14840 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14841 (void) XSetTransientForHint(display,windows->info.id,windows->image.id); 14842 if (IfMagickTrue(windows->image.mapped) ) 14843 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14844 if (IfMagickTrue(display_image->debug) ) 14845 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", 14846 windows->info.id); 14847 /* 14848 Initialize Command widget. 14849 */ 14850 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14851 resource_info,&windows->command); 14852 windows->command.data=MagickMenus; 14853 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); 14854 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command", 14855 resource_info->client_name); 14856 windows->command.geometry=XGetResourceClass(resource_info->resource_database, 14857 resource_name,"geometry",(char *) NULL); 14858 (void) CloneString(&windows->command.name,MagickTitle); 14859 windows->command.border_width=0; 14860 windows->command.flags|=PPosition; 14861 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14862 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | 14863 OwnerGrabButtonMask | StructureNotifyMask; 14864 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14865 manager_hints->input=MagickTrue; 14866 manager_hints->initial_state=NormalState; 14867 manager_hints->window_group=windows->image.id; 14868 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14869 &windows->command); 14870 windows->command.highlight_stipple=XCreateBitmapFromData(display, 14871 windows->command.id,(char *) HighlightBitmap,HighlightWidth, 14872 HighlightHeight); 14873 windows->command.shadow_stipple=XCreateBitmapFromData(display, 14874 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14875 (void) XSetTransientForHint(display,windows->command.id,windows->image.id); 14876 if (IfMagickTrue(windows->command.mapped) ) 14877 (void) XMapRaised(display,windows->command.id); 14878 if (IfMagickTrue(display_image->debug) ) 14879 (void) LogMagickEvent(X11Event,GetMagickModule(), 14880 "Window id: 0x%lx (command)",windows->command.id); 14881 /* 14882 Initialize Widget window. 14883 */ 14884 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14885 resource_info,&windows->widget); 14886 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget", 14887 resource_info->client_name); 14888 windows->widget.geometry=XGetResourceClass(resource_info->resource_database, 14889 resource_name,"geometry",(char *) NULL); 14890 windows->widget.border_width=0; 14891 windows->widget.flags|=PPosition; 14892 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14893 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14894 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14895 StructureNotifyMask; 14896 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14897 manager_hints->input=MagickTrue; 14898 manager_hints->initial_state=NormalState; 14899 manager_hints->window_group=windows->image.id; 14900 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14901 &windows->widget); 14902 windows->widget.highlight_stipple=XCreateBitmapFromData(display, 14903 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14904 windows->widget.shadow_stipple=XCreateBitmapFromData(display, 14905 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14906 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); 14907 if (IfMagickTrue(display_image->debug) ) 14908 (void) LogMagickEvent(X11Event,GetMagickModule(), 14909 "Window id: 0x%lx (widget)",windows->widget.id); 14910 /* 14911 Initialize popup window. 14912 */ 14913 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14914 resource_info,&windows->popup); 14915 windows->popup.border_width=0; 14916 windows->popup.flags|=PPosition; 14917 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14918 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14919 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask; 14920 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14921 manager_hints->input=MagickTrue; 14922 manager_hints->initial_state=NormalState; 14923 manager_hints->window_group=windows->image.id; 14924 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14925 &windows->popup); 14926 windows->popup.highlight_stipple=XCreateBitmapFromData(display, 14927 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14928 windows->popup.shadow_stipple=XCreateBitmapFromData(display, 14929 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14930 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); 14931 if (IfMagickTrue(display_image->debug) ) 14932 (void) LogMagickEvent(X11Event,GetMagickModule(), 14933 "Window id: 0x%lx (pop up)",windows->popup.id); 14934 /* 14935 Initialize Magnify window and cursor. 14936 */ 14937 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14938 resource_info,&windows->magnify); 14939 if (IfMagickFalse(resource_info->use_shared_memory) ) 14940 windows->magnify.shared_memory=MagickFalse; 14941 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify", 14942 resource_info->client_name); 14943 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database, 14944 resource_name,"geometry",(char *) NULL); 14945 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX", 14946 resource_info->magnify); 14947 if (windows->magnify.cursor != (Cursor) NULL) 14948 (void) XFreeCursor(display,windows->magnify.cursor); 14949 windows->magnify.cursor=XMakeCursor(display,windows->image.id, 14950 map_info->colormap,resource_info->background_color, 14951 resource_info->foreground_color); 14952 if (windows->magnify.cursor == (Cursor) NULL) 14953 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor", 14954 display_image->filename); 14955 windows->magnify.width=MagnifySize; 14956 windows->magnify.height=MagnifySize; 14957 windows->magnify.flags|=PPosition; 14958 windows->magnify.min_width=MagnifySize; 14959 windows->magnify.min_height=MagnifySize; 14960 windows->magnify.width_inc=MagnifySize; 14961 windows->magnify.height_inc=MagnifySize; 14962 windows->magnify.data=resource_info->magnify; 14963 windows->magnify.attributes.cursor=windows->magnify.cursor; 14964 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask | 14965 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask | 14966 StructureNotifyMask; 14967 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14968 manager_hints->input=MagickTrue; 14969 manager_hints->initial_state=NormalState; 14970 manager_hints->window_group=windows->image.id; 14971 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14972 &windows->magnify); 14973 if (IfMagickTrue(display_image->debug) ) 14974 (void) LogMagickEvent(X11Event,GetMagickModule(), 14975 "Window id: 0x%lx (magnify)",windows->magnify.id); 14976 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id); 14977 /* 14978 Initialize panning window. 14979 */ 14980 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14981 resource_info,&windows->pan); 14982 (void) CloneString(&windows->pan.name,"Pan Icon"); 14983 windows->pan.width=windows->icon.width; 14984 windows->pan.height=windows->icon.height; 14985 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan", 14986 resource_info->client_name); 14987 windows->pan.geometry=XGetResourceClass(resource_info->resource_database, 14988 resource_name,"geometry",(char *) NULL); 14989 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 14990 &windows->pan.width,&windows->pan.height); 14991 windows->pan.flags|=PPosition; 14992 windows->pan.immutable=MagickTrue; 14993 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14994 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask | 14995 StructureNotifyMask; 14996 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14997 manager_hints->input=MagickFalse; 14998 manager_hints->initial_state=NormalState; 14999 manager_hints->window_group=windows->image.id; 15000 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 15001 &windows->pan); 15002 if (IfMagickTrue(display_image->debug) ) 15003 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)", 15004 windows->pan.id); 15005 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id); 15006 if (IfMagickTrue(windows->info.mapped) ) 15007 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15008 if (IfMagickFalse(windows->image.mapped) || 15009 (windows->backdrop.id != (Window) NULL)) 15010 (void) XMapWindow(display,windows->image.id); 15011 /* 15012 Set our progress monitor and warning handlers. 15013 */ 15014 if (warning_handler == (WarningHandler) NULL) 15015 { 15016 warning_handler=resource_info->display_warnings ? 15017 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 15018 warning_handler=resource_info->display_warnings ? 15019 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 15020 } 15021 /* 15022 Initialize Image and Magnify X images. 15023 */ 15024 windows->image.x=0; 15025 windows->image.y=0; 15026 windows->magnify.shape=MagickFalse; 15027 width=(unsigned int) display_image->columns; 15028 height=(unsigned int) display_image->rows; 15029 if ((display_image->columns != width) || (display_image->rows != height)) 15030 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15031 display_image->filename); 15032 status=XMakeImage(display,resource_info,&windows->image,display_image, 15033 width,height,exception); 15034 if (IfMagickFalse(status) ) 15035 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15036 display_image->filename); 15037 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL, 15038 windows->magnify.width,windows->magnify.height,exception); 15039 if (IfMagickFalse(status)) 15040 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15041 display_image->filename); 15042 if (IfMagickTrue(windows->magnify.mapped) ) 15043 (void) XMapRaised(display,windows->magnify.id); 15044 if (IfMagickTrue(windows->pan.mapped) ) 15045 (void) XMapRaised(display,windows->pan.id); 15046 windows->image.window_changes.width=(int) display_image->columns; 15047 windows->image.window_changes.height=(int) display_image->rows; 15048 (void) XConfigureImage(display,resource_info,windows,display_image,exception); 15049 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15050 (void) XSync(display,MagickFalse); 15051 /* 15052 Respond to events. 15053 */ 15054 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L); 15055 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15056 update_time=0; 15057 if (IfMagickTrue(resource_info->update) ) 15058 { 15059 MagickBooleanType 15060 status; 15061 15062 /* 15063 Determine when file data was last modified. 15064 */ 15065 status=GetPathAttributes(display_image->filename,&attributes); 15066 if (IfMagickTrue(status) ) 15067 update_time=attributes.st_mtime; 15068 } 15069 *state&=(~FormerImageState); 15070 *state&=(~MontageImageState); 15071 *state&=(~NextImageState); 15072 do 15073 { 15074 /* 15075 Handle a window event. 15076 */ 15077 if (IfMagickTrue(windows->image.mapped) ) 15078 if ((display_image->delay != 0) || (resource_info->update != 0)) 15079 { 15080 if (timer < time((time_t *) NULL)) 15081 { 15082 if (IfMagickFalse(resource_info->update) ) 15083 *state|=NextImageState | ExitState; 15084 else 15085 { 15086 MagickBooleanType 15087 status; 15088 15089 /* 15090 Determine if image file was modified. 15091 */ 15092 status=GetPathAttributes(display_image->filename,&attributes); 15093 if (IfMagickTrue(status) ) 15094 if (update_time != attributes.st_mtime) 15095 { 15096 /* 15097 Redisplay image. 15098 */ 15099 (void) FormatLocaleString( 15100 resource_info->image_info->filename,MaxTextExtent, 15101 "%s:%s",display_image->magick, 15102 display_image->filename); 15103 nexus=ReadImage(resource_info->image_info,exception); 15104 if (nexus != (Image *) NULL) 15105 { 15106 nexus=DestroyImage(nexus); 15107 *state|=NextImageState | ExitState; 15108 } 15109 } 15110 delay=display_image->delay/MagickMax( 15111 display_image->ticks_per_second,1L); 15112 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15113 } 15114 } 15115 if (XEventsQueued(display,QueuedAfterFlush) == 0) 15116 { 15117 /* 15118 Do not block if delay > 0. 15119 */ 15120 XDelay(display,SuspendTime << 2); 15121 continue; 15122 } 15123 } 15124 timestamp=time((time_t *) NULL); 15125 (void) XNextEvent(display,&event); 15126 if (IfMagickFalse(windows->image.stasis) ) 15127 windows->image.stasis=IsMagickTrue((time((time_t *) NULL)-timestamp) > 0); 15128 if (IfMagickFalse(windows->magnify.stasis) ) 15129 windows->magnify.stasis=IsMagickTrue((time((time_t *) NULL)-timestamp) > 0); 15130 if (event.xany.window == windows->command.id) 15131 { 15132 /* 15133 Select a command from the Command widget. 15134 */ 15135 id=XCommandWidget(display,windows,CommandMenu,&event); 15136 if (id < 0) 15137 continue; 15138 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent); 15139 command_type=CommandMenus[id]; 15140 if (id < MagickMenus) 15141 { 15142 /* 15143 Select a command from a pop-up menu. 15144 */ 15145 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15146 command); 15147 if (entry < 0) 15148 continue; 15149 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent); 15150 command_type=Commands[id][entry]; 15151 } 15152 if (command_type != NullCommand) 15153 nexus=XMagickCommand(display,resource_info,windows,command_type, 15154 &display_image,exception); 15155 continue; 15156 } 15157 switch (event.type) 15158 { 15159 case ButtonPress: 15160 { 15161 if (IfMagickTrue(display_image->debug) ) 15162 (void) LogMagickEvent(X11Event,GetMagickModule(), 15163 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15164 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15165 if ((event.xbutton.button == Button3) && 15166 (event.xbutton.state & Mod1Mask)) 15167 { 15168 /* 15169 Convert Alt-Button3 to Button2. 15170 */ 15171 event.xbutton.button=Button2; 15172 event.xbutton.state&=(~Mod1Mask); 15173 } 15174 if (event.xbutton.window == windows->backdrop.id) 15175 { 15176 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15177 event.xbutton.time); 15178 break; 15179 } 15180 if (event.xbutton.window == windows->image.id) 15181 { 15182 switch (event.xbutton.button) 15183 { 15184 case Button1: 15185 { 15186 if (resource_info->immutable) 15187 { 15188 /* 15189 Select a command from the Virtual menu. 15190 */ 15191 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15192 command); 15193 if (entry >= 0) 15194 nexus=XMagickCommand(display,resource_info,windows, 15195 VirtualCommands[entry],&display_image,exception); 15196 break; 15197 } 15198 /* 15199 Map/unmap Command widget. 15200 */ 15201 if (IfMagickTrue(windows->command.mapped) ) 15202 (void) XWithdrawWindow(display,windows->command.id, 15203 windows->command.screen); 15204 else 15205 { 15206 (void) XCommandWidget(display,windows,CommandMenu, 15207 (XEvent *) NULL); 15208 (void) XMapRaised(display,windows->command.id); 15209 } 15210 break; 15211 } 15212 case Button2: 15213 { 15214 /* 15215 User pressed the image magnify button. 15216 */ 15217 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15218 &display_image,exception); 15219 XMagnifyImage(display,windows,&event,exception); 15220 break; 15221 } 15222 case Button3: 15223 { 15224 if (resource_info->immutable) 15225 { 15226 /* 15227 Select a command from the Virtual menu. 15228 */ 15229 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15230 command); 15231 if (entry >= 0) 15232 nexus=XMagickCommand(display,resource_info,windows, 15233 VirtualCommands[entry],&display_image,exception); 15234 break; 15235 } 15236 if (display_image->montage != (char *) NULL) 15237 { 15238 /* 15239 Open or delete a tile from a visual image directory. 15240 */ 15241 nexus=XTileImage(display,resource_info,windows, 15242 display_image,&event,exception); 15243 if (nexus != (Image *) NULL) 15244 *state|=MontageImageState | NextImageState | ExitState; 15245 vid_info.x=(short int) windows->image.x; 15246 vid_info.y=(short int) windows->image.y; 15247 break; 15248 } 15249 /* 15250 Select a command from the Short Cuts menu. 15251 */ 15252 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15253 command); 15254 if (entry >= 0) 15255 nexus=XMagickCommand(display,resource_info,windows, 15256 ShortCutsCommands[entry],&display_image,exception); 15257 break; 15258 } 15259 case Button4: 15260 { 15261 /* 15262 Wheel up. 15263 */ 15264 XTranslateImage(display,windows,*image,XK_Up); 15265 break; 15266 } 15267 case Button5: 15268 { 15269 /* 15270 Wheel down. 15271 */ 15272 XTranslateImage(display,windows,*image,XK_Down); 15273 break; 15274 } 15275 default: 15276 break; 15277 } 15278 break; 15279 } 15280 if (event.xbutton.window == windows->magnify.id) 15281 { 15282 int 15283 factor; 15284 15285 static const char 15286 *MagnifyMenu[] = 15287 { 15288 "2", 15289 "4", 15290 "5", 15291 "6", 15292 "7", 15293 "8", 15294 "9", 15295 "3", 15296 (char *) NULL, 15297 }; 15298 15299 static KeySym 15300 MagnifyCommands[] = 15301 { 15302 XK_2, 15303 XK_4, 15304 XK_5, 15305 XK_6, 15306 XK_7, 15307 XK_8, 15308 XK_9, 15309 XK_3 15310 }; 15311 15312 /* 15313 Select a magnify factor from the pop-up menu. 15314 */ 15315 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15316 if (factor >= 0) 15317 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor], 15318 exception); 15319 break; 15320 } 15321 if (event.xbutton.window == windows->pan.id) 15322 { 15323 switch (event.xbutton.button) 15324 { 15325 case Button4: 15326 { 15327 /* 15328 Wheel up. 15329 */ 15330 XTranslateImage(display,windows,*image,XK_Up); 15331 break; 15332 } 15333 case Button5: 15334 { 15335 /* 15336 Wheel down. 15337 */ 15338 XTranslateImage(display,windows,*image,XK_Down); 15339 break; 15340 } 15341 default: 15342 { 15343 XPanImage(display,windows,&event,exception); 15344 break; 15345 } 15346 } 15347 break; 15348 } 15349 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15350 1L); 15351 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15352 break; 15353 } 15354 case ButtonRelease: 15355 { 15356 if (IfMagickTrue(display_image->debug) ) 15357 (void) LogMagickEvent(X11Event,GetMagickModule(), 15358 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15359 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15360 break; 15361 } 15362 case ClientMessage: 15363 { 15364 if (IfMagickTrue(display_image->debug) ) 15365 (void) LogMagickEvent(X11Event,GetMagickModule(), 15366 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15367 event.xclient.message_type,event.xclient.format,(unsigned long) 15368 event.xclient.data.l[0]); 15369 if (event.xclient.message_type == windows->im_protocols) 15370 { 15371 if (*event.xclient.data.l == (long) windows->im_update_widget) 15372 { 15373 (void) CloneString(&windows->command.name,MagickTitle); 15374 windows->command.data=MagickMenus; 15375 (void) XCommandWidget(display,windows,CommandMenu, 15376 (XEvent *) NULL); 15377 break; 15378 } 15379 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15380 { 15381 /* 15382 Update graphic context and window colormap. 15383 */ 15384 for (i=0; i < (int) number_windows; i++) 15385 { 15386 if (magick_windows[i]->id == windows->icon.id) 15387 continue; 15388 context_values.background=pixel->background_color.pixel; 15389 context_values.foreground=pixel->foreground_color.pixel; 15390 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15391 context_mask,&context_values); 15392 (void) XChangeGC(display,magick_windows[i]->widget_context, 15393 context_mask,&context_values); 15394 context_values.background=pixel->foreground_color.pixel; 15395 context_values.foreground=pixel->background_color.pixel; 15396 context_values.plane_mask=context_values.background ^ 15397 context_values.foreground; 15398 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15399 (size_t) (context_mask | GCPlaneMask), 15400 &context_values); 15401 magick_windows[i]->attributes.background_pixel= 15402 pixel->background_color.pixel; 15403 magick_windows[i]->attributes.border_pixel= 15404 pixel->border_color.pixel; 15405 magick_windows[i]->attributes.colormap=map_info->colormap; 15406 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15407 (unsigned long) magick_windows[i]->mask, 15408 &magick_windows[i]->attributes); 15409 } 15410 if (IfMagickTrue(windows->pan.mapped) ) 15411 { 15412 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15413 windows->pan.pixmap); 15414 (void) XClearWindow(display,windows->pan.id); 15415 XDrawPanRectangle(display,windows); 15416 } 15417 if (windows->backdrop.id != (Window) NULL) 15418 (void) XInstallColormap(display,map_info->colormap); 15419 break; 15420 } 15421 if (*event.xclient.data.l == (long) windows->im_former_image) 15422 { 15423 *state|=FormerImageState | ExitState; 15424 break; 15425 } 15426 if (*event.xclient.data.l == (long) windows->im_next_image) 15427 { 15428 *state|=NextImageState | ExitState; 15429 break; 15430 } 15431 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15432 { 15433 *state|=RetainColorsState; 15434 break; 15435 } 15436 if (*event.xclient.data.l == (long) windows->im_exit) 15437 { 15438 *state|=ExitState; 15439 break; 15440 } 15441 break; 15442 } 15443 if (event.xclient.message_type == windows->dnd_protocols) 15444 { 15445 Atom 15446 selection, 15447 type; 15448 15449 int 15450 format, 15451 status; 15452 15453 unsigned char 15454 *data; 15455 15456 unsigned long 15457 after, 15458 length; 15459 15460 /* 15461 Display image named by the Drag-and-Drop selection. 15462 */ 15463 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15464 break; 15465 selection=XInternAtom(display,"DndSelection",MagickFalse); 15466 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15467 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15468 &length,&after,&data); 15469 if ((status != Success) || (length == 0)) 15470 break; 15471 if (*event.xclient.data.l == 2) 15472 { 15473 /* 15474 Offix DND. 15475 */ 15476 (void) CopyMagickString(resource_info->image_info->filename, 15477 (char *) data,MaxTextExtent); 15478 } 15479 else 15480 { 15481 /* 15482 XDND. 15483 */ 15484 if (strncmp((char *) data, "file:", 5) != 0) 15485 { 15486 (void) XFree((void *) data); 15487 break; 15488 } 15489 (void) CopyMagickString(resource_info->image_info->filename, 15490 ((char *) data)+5,MaxTextExtent); 15491 } 15492 nexus=ReadImage(resource_info->image_info,exception); 15493 CatchException(exception); 15494 if (nexus != (Image *) NULL) 15495 *state|=NextImageState | ExitState; 15496 (void) XFree((void *) data); 15497 break; 15498 } 15499 /* 15500 If client window delete message, exit. 15501 */ 15502 if (event.xclient.message_type != windows->wm_protocols) 15503 break; 15504 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15505 break; 15506 (void) XWithdrawWindow(display,event.xclient.window, 15507 visual_info->screen); 15508 if (event.xclient.window == windows->image.id) 15509 { 15510 *state|=ExitState; 15511 break; 15512 } 15513 if (event.xclient.window == windows->pan.id) 15514 { 15515 /* 15516 Restore original image size when pan window is deleted. 15517 */ 15518 windows->image.window_changes.width=windows->image.ximage->width; 15519 windows->image.window_changes.height=windows->image.ximage->height; 15520 (void) XConfigureImage(display,resource_info,windows, 15521 display_image,exception); 15522 } 15523 break; 15524 } 15525 case ConfigureNotify: 15526 { 15527 if (IfMagickTrue(display_image->debug) ) 15528 (void) LogMagickEvent(X11Event,GetMagickModule(), 15529 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15530 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15531 event.xconfigure.y,event.xconfigure.send_event); 15532 if (event.xconfigure.window == windows->image.id) 15533 { 15534 /* 15535 Image window has a new configuration. 15536 */ 15537 if (event.xconfigure.send_event != 0) 15538 { 15539 XWindowChanges 15540 window_changes; 15541 15542 /* 15543 Position the transient windows relative of the Image window. 15544 */ 15545 if (windows->command.geometry == (char *) NULL) 15546 if (IfMagickFalse(windows->command.mapped) ) 15547 { 15548 windows->command.x=event.xconfigure.x- 15549 windows->command.width-25; 15550 windows->command.y=event.xconfigure.y; 15551 XConstrainWindowPosition(display,&windows->command); 15552 window_changes.x=windows->command.x; 15553 window_changes.y=windows->command.y; 15554 (void) XReconfigureWMWindow(display,windows->command.id, 15555 windows->command.screen,(unsigned int) (CWX | CWY), 15556 &window_changes); 15557 } 15558 if (windows->widget.geometry == (char *) NULL) 15559 if (IfMagickFalse(windows->widget.mapped) ) 15560 { 15561 windows->widget.x=event.xconfigure.x+ 15562 event.xconfigure.width/10; 15563 windows->widget.y=event.xconfigure.y+ 15564 event.xconfigure.height/10; 15565 XConstrainWindowPosition(display,&windows->widget); 15566 window_changes.x=windows->widget.x; 15567 window_changes.y=windows->widget.y; 15568 (void) XReconfigureWMWindow(display,windows->widget.id, 15569 windows->widget.screen,(unsigned int) (CWX | CWY), 15570 &window_changes); 15571 } 15572 if (windows->magnify.geometry == (char *) NULL) 15573 if (IfMagickFalse(windows->magnify.mapped) ) 15574 { 15575 windows->magnify.x=event.xconfigure.x+ 15576 event.xconfigure.width+25; 15577 windows->magnify.y=event.xconfigure.y; 15578 XConstrainWindowPosition(display,&windows->magnify); 15579 window_changes.x=windows->magnify.x; 15580 window_changes.y=windows->magnify.y; 15581 (void) XReconfigureWMWindow(display,windows->magnify.id, 15582 windows->magnify.screen,(unsigned int) (CWX | CWY), 15583 &window_changes); 15584 } 15585 if (windows->pan.geometry == (char *) NULL) 15586 if (IfMagickFalse(windows->pan.mapped) ) 15587 { 15588 windows->pan.x=event.xconfigure.x+ 15589 event.xconfigure.width+25; 15590 windows->pan.y=event.xconfigure.y+ 15591 windows->magnify.height+50; 15592 XConstrainWindowPosition(display,&windows->pan); 15593 window_changes.x=windows->pan.x; 15594 window_changes.y=windows->pan.y; 15595 (void) XReconfigureWMWindow(display,windows->pan.id, 15596 windows->pan.screen,(unsigned int) (CWX | CWY), 15597 &window_changes); 15598 } 15599 } 15600 if ((event.xconfigure.width == (int) windows->image.width) && 15601 (event.xconfigure.height == (int) windows->image.height)) 15602 break; 15603 windows->image.width=(unsigned int) event.xconfigure.width; 15604 windows->image.height=(unsigned int) event.xconfigure.height; 15605 windows->image.x=0; 15606 windows->image.y=0; 15607 if (display_image->montage != (char *) NULL) 15608 { 15609 windows->image.x=vid_info.x; 15610 windows->image.y=vid_info.y; 15611 } 15612 if (IfMagickTrue(windows->image.mapped) && 15613 IfMagickTrue(windows->image.stasis) ) 15614 { 15615 /* 15616 Update image window configuration. 15617 */ 15618 windows->image.window_changes.width=event.xconfigure.width; 15619 windows->image.window_changes.height=event.xconfigure.height; 15620 (void) XConfigureImage(display,resource_info,windows, 15621 display_image,exception); 15622 } 15623 /* 15624 Update pan window configuration. 15625 */ 15626 if ((event.xconfigure.width < windows->image.ximage->width) || 15627 (event.xconfigure.height < windows->image.ximage->height)) 15628 { 15629 (void) XMapRaised(display,windows->pan.id); 15630 XDrawPanRectangle(display,windows); 15631 } 15632 else 15633 if (IfMagickTrue(windows->pan.mapped) ) 15634 (void) XWithdrawWindow(display,windows->pan.id, 15635 windows->pan.screen); 15636 break; 15637 } 15638 if (event.xconfigure.window == windows->magnify.id) 15639 { 15640 unsigned int 15641 magnify; 15642 15643 /* 15644 Magnify window has a new configuration. 15645 */ 15646 windows->magnify.width=(unsigned int) event.xconfigure.width; 15647 windows->magnify.height=(unsigned int) event.xconfigure.height; 15648 if (IfMagickFalse(windows->magnify.mapped) ) 15649 break; 15650 magnify=1; 15651 while ((int) magnify <= event.xconfigure.width) 15652 magnify<<=1; 15653 while ((int) magnify <= event.xconfigure.height) 15654 magnify<<=1; 15655 magnify>>=1; 15656 if (((int) magnify != event.xconfigure.width) || 15657 ((int) magnify != event.xconfigure.height)) 15658 { 15659 window_changes.width=(int) magnify; 15660 window_changes.height=(int) magnify; 15661 (void) XReconfigureWMWindow(display,windows->magnify.id, 15662 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15663 &window_changes); 15664 break; 15665 } 15666 if (IfMagickTrue(windows->magnify.mapped) && 15667 IfMagickTrue(windows->magnify.stasis) ) 15668 { 15669 status=XMakeImage(display,resource_info,&windows->magnify, 15670 display_image,windows->magnify.width,windows->magnify.height, 15671 exception); 15672 XMakeMagnifyImage(display,windows,exception); 15673 } 15674 break; 15675 } 15676 if (IfMagickTrue(windows->magnify.mapped) && 15677 (event.xconfigure.window == windows->pan.id)) 15678 { 15679 /* 15680 Pan icon window has a new configuration. 15681 */ 15682 if (event.xconfigure.send_event != 0) 15683 { 15684 windows->pan.x=event.xconfigure.x; 15685 windows->pan.y=event.xconfigure.y; 15686 } 15687 windows->pan.width=(unsigned int) event.xconfigure.width; 15688 windows->pan.height=(unsigned int) event.xconfigure.height; 15689 break; 15690 } 15691 if (event.xconfigure.window == windows->icon.id) 15692 { 15693 /* 15694 Icon window has a new configuration. 15695 */ 15696 windows->icon.width=(unsigned int) event.xconfigure.width; 15697 windows->icon.height=(unsigned int) event.xconfigure.height; 15698 break; 15699 } 15700 break; 15701 } 15702 case DestroyNotify: 15703 { 15704 /* 15705 Group leader has exited. 15706 */ 15707 if (IfMagickTrue(display_image->debug) ) 15708 (void) LogMagickEvent(X11Event,GetMagickModule(), 15709 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15710 if (event.xdestroywindow.window == windows->group_leader.id) 15711 { 15712 *state|=ExitState; 15713 break; 15714 } 15715 break; 15716 } 15717 case EnterNotify: 15718 { 15719 /* 15720 Selectively install colormap. 15721 */ 15722 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15723 if (event.xcrossing.mode != NotifyUngrab) 15724 XInstallColormap(display,map_info->colormap); 15725 break; 15726 } 15727 case Expose: 15728 { 15729 if (IfMagickTrue(display_image->debug) ) 15730 (void) LogMagickEvent(X11Event,GetMagickModule(), 15731 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15732 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15733 event.xexpose.y); 15734 /* 15735 Refresh windows that are now exposed. 15736 */ 15737 if ((event.xexpose.window == windows->image.id) && 15738 IfMagickTrue(windows->image.mapped) ) 15739 { 15740 XRefreshWindow(display,&windows->image,&event); 15741 delay=display_image->delay/MagickMax( 15742 display_image->ticks_per_second,1L); 15743 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15744 break; 15745 } 15746 if ((event.xexpose.window == windows->magnify.id) && 15747 IfMagickTrue(windows->magnify.mapped)) 15748 { 15749 XMakeMagnifyImage(display,windows,exception); 15750 break; 15751 } 15752 if (event.xexpose.window == windows->pan.id) 15753 { 15754 XDrawPanRectangle(display,windows); 15755 break; 15756 } 15757 if (event.xexpose.window == windows->icon.id) 15758 { 15759 XRefreshWindow(display,&windows->icon,&event); 15760 break; 15761 } 15762 break; 15763 } 15764 case KeyPress: 15765 { 15766 int 15767 length; 15768 15769 /* 15770 Respond to a user key press. 15771 */ 15772 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15773 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15774 *(command+length)='\0'; 15775 if (IfMagickTrue(display_image->debug) ) 15776 (void) LogMagickEvent(X11Event,GetMagickModule(), 15777 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15778 key_symbol,command); 15779 if (event.xkey.window == windows->image.id) 15780 { 15781 command_type=XImageWindowCommand(display,resource_info,windows, 15782 event.xkey.state,key_symbol,&display_image,exception); 15783 if (command_type != NullCommand) 15784 nexus=XMagickCommand(display,resource_info,windows,command_type, 15785 &display_image,exception); 15786 } 15787 if (event.xkey.window == windows->magnify.id) 15788 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol, 15789 exception); 15790 if (event.xkey.window == windows->pan.id) 15791 { 15792 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15793 (void) XWithdrawWindow(display,windows->pan.id, 15794 windows->pan.screen); 15795 else 15796 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15797 XTextViewWidget(display,resource_info,windows,MagickFalse, 15798 "Help Viewer - Image Pan",ImagePanHelp); 15799 else 15800 XTranslateImage(display,windows,*image,key_symbol); 15801 } 15802 delay=display_image->delay/MagickMax( 15803 display_image->ticks_per_second,1L); 15804 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15805 break; 15806 } 15807 case KeyRelease: 15808 { 15809 /* 15810 Respond to a user key release. 15811 */ 15812 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15813 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15814 if (IfMagickTrue(display_image->debug) ) 15815 (void) LogMagickEvent(X11Event,GetMagickModule(), 15816 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15817 break; 15818 } 15819 case LeaveNotify: 15820 { 15821 /* 15822 Selectively uninstall colormap. 15823 */ 15824 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15825 if (event.xcrossing.mode != NotifyUngrab) 15826 XUninstallColormap(display,map_info->colormap); 15827 break; 15828 } 15829 case MapNotify: 15830 { 15831 if (IfMagickTrue(display_image->debug) ) 15832 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15833 event.xmap.window); 15834 if (event.xmap.window == windows->backdrop.id) 15835 { 15836 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15837 CurrentTime); 15838 windows->backdrop.mapped=MagickTrue; 15839 break; 15840 } 15841 if (event.xmap.window == windows->image.id) 15842 { 15843 if (windows->backdrop.id != (Window) NULL) 15844 (void) XInstallColormap(display,map_info->colormap); 15845 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15846 { 15847 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15848 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15849 } 15850 if (((int) windows->image.width < windows->image.ximage->width) || 15851 ((int) windows->image.height < windows->image.ximage->height)) 15852 (void) XMapRaised(display,windows->pan.id); 15853 windows->image.mapped=MagickTrue; 15854 break; 15855 } 15856 if (event.xmap.window == windows->magnify.id) 15857 { 15858 XMakeMagnifyImage(display,windows,exception); 15859 windows->magnify.mapped=MagickTrue; 15860 (void) XWithdrawWindow(display,windows->info.id, 15861 windows->info.screen); 15862 break; 15863 } 15864 if (event.xmap.window == windows->pan.id) 15865 { 15866 XMakePanImage(display,resource_info,windows,display_image, 15867 exception); 15868 windows->pan.mapped=MagickTrue; 15869 break; 15870 } 15871 if (event.xmap.window == windows->info.id) 15872 { 15873 windows->info.mapped=MagickTrue; 15874 break; 15875 } 15876 if (event.xmap.window == windows->icon.id) 15877 { 15878 MagickBooleanType 15879 taint; 15880 15881 /* 15882 Create an icon image. 15883 */ 15884 taint=display_image->taint; 15885 XMakeStandardColormap(display,icon_visual,icon_resources, 15886 display_image,icon_map,icon_pixel,exception); 15887 (void) XMakeImage(display,icon_resources,&windows->icon, 15888 display_image,windows->icon.width,windows->icon.height, 15889 exception); 15890 display_image->taint=taint; 15891 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15892 windows->icon.pixmap); 15893 (void) XClearWindow(display,windows->icon.id); 15894 (void) XWithdrawWindow(display,windows->info.id, 15895 windows->info.screen); 15896 windows->icon.mapped=MagickTrue; 15897 break; 15898 } 15899 if (event.xmap.window == windows->command.id) 15900 { 15901 windows->command.mapped=MagickTrue; 15902 break; 15903 } 15904 if (event.xmap.window == windows->popup.id) 15905 { 15906 windows->popup.mapped=MagickTrue; 15907 break; 15908 } 15909 if (event.xmap.window == windows->widget.id) 15910 { 15911 windows->widget.mapped=MagickTrue; 15912 break; 15913 } 15914 break; 15915 } 15916 case MappingNotify: 15917 { 15918 (void) XRefreshKeyboardMapping(&event.xmapping); 15919 break; 15920 } 15921 case NoExpose: 15922 break; 15923 case PropertyNotify: 15924 { 15925 Atom 15926 type; 15927 15928 int 15929 format, 15930 status; 15931 15932 unsigned char 15933 *data; 15934 15935 unsigned long 15936 after, 15937 length; 15938 15939 if (IfMagickTrue(display_image->debug) ) 15940 (void) LogMagickEvent(X11Event,GetMagickModule(), 15941 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15942 event.xproperty.atom,event.xproperty.state); 15943 if (event.xproperty.atom != windows->im_remote_command) 15944 break; 15945 /* 15946 Display image named by the remote command protocol. 15947 */ 15948 status=XGetWindowProperty(display,event.xproperty.window, 15949 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom) 15950 AnyPropertyType,&type,&format,&length,&after,&data); 15951 if ((status != Success) || (length == 0)) 15952 break; 15953 if (LocaleCompare((char *) data,"-quit") == 0) 15954 { 15955 XClientMessage(display,windows->image.id,windows->im_protocols, 15956 windows->im_exit,CurrentTime); 15957 (void) XFree((void *) data); 15958 break; 15959 } 15960 (void) CopyMagickString(resource_info->image_info->filename, 15961 (char *) data,MaxTextExtent); 15962 (void) XFree((void *) data); 15963 nexus=ReadImage(resource_info->image_info,exception); 15964 CatchException(exception); 15965 if (nexus != (Image *) NULL) 15966 *state|=NextImageState | ExitState; 15967 break; 15968 } 15969 case ReparentNotify: 15970 { 15971 if (IfMagickTrue(display_image->debug) ) 15972 (void) LogMagickEvent(X11Event,GetMagickModule(), 15973 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 15974 event.xreparent.window); 15975 break; 15976 } 15977 case UnmapNotify: 15978 { 15979 if (IfMagickTrue(display_image->debug) ) 15980 (void) LogMagickEvent(X11Event,GetMagickModule(), 15981 "Unmap Notify: 0x%lx",event.xunmap.window); 15982 if (event.xunmap.window == windows->backdrop.id) 15983 { 15984 windows->backdrop.mapped=MagickFalse; 15985 break; 15986 } 15987 if (event.xunmap.window == windows->image.id) 15988 { 15989 windows->image.mapped=MagickFalse; 15990 break; 15991 } 15992 if (event.xunmap.window == windows->magnify.id) 15993 { 15994 windows->magnify.mapped=MagickFalse; 15995 break; 15996 } 15997 if (event.xunmap.window == windows->pan.id) 15998 { 15999 windows->pan.mapped=MagickFalse; 16000 break; 16001 } 16002 if (event.xunmap.window == windows->info.id) 16003 { 16004 windows->info.mapped=MagickFalse; 16005 break; 16006 } 16007 if (event.xunmap.window == windows->icon.id) 16008 { 16009 if (map_info->colormap == icon_map->colormap) 16010 XConfigureImageColormap(display,resource_info,windows, 16011 display_image,exception); 16012 (void) XFreeStandardColormap(display,icon_visual,icon_map, 16013 icon_pixel); 16014 windows->icon.mapped=MagickFalse; 16015 break; 16016 } 16017 if (event.xunmap.window == windows->command.id) 16018 { 16019 windows->command.mapped=MagickFalse; 16020 break; 16021 } 16022 if (event.xunmap.window == windows->popup.id) 16023 { 16024 if (windows->backdrop.id != (Window) NULL) 16025 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16026 CurrentTime); 16027 windows->popup.mapped=MagickFalse; 16028 break; 16029 } 16030 if (event.xunmap.window == windows->widget.id) 16031 { 16032 if (windows->backdrop.id != (Window) NULL) 16033 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16034 CurrentTime); 16035 windows->widget.mapped=MagickFalse; 16036 break; 16037 } 16038 break; 16039 } 16040 default: 16041 { 16042 if (IfMagickTrue(display_image->debug) ) 16043 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 16044 event.type); 16045 break; 16046 } 16047 } 16048 } while (!(*state & ExitState)); 16049 if ((*state & ExitState) == 0) 16050 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 16051 &display_image,exception); 16052 else 16053 if (IfMagickTrue(resource_info->confirm_edit) ) 16054 { 16055 /* 16056 Query user if image has changed. 16057 */ 16058 if (IfMagickFalse(resource_info->immutable) && 16059 IfMagickTrue(display_image->taint)) 16060 { 16061 int 16062 status; 16063 16064 status=XConfirmWidget(display,windows,"Your image changed.", 16065 "Do you want to save it"); 16066 if (status == 0) 16067 *state&=(~ExitState); 16068 else 16069 if (status > 0) 16070 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 16071 &display_image,exception); 16072 } 16073 } 16074 if ((windows->visual_info->klass == GrayScale) || 16075 (windows->visual_info->klass == PseudoColor) || 16076 (windows->visual_info->klass == DirectColor)) 16077 { 16078 /* 16079 Withdraw pan and Magnify window. 16080 */ 16081 if (IfMagickTrue(windows->info.mapped) ) 16082 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 16083 if (IfMagickTrue(windows->magnify.mapped) ) 16084 (void) XWithdrawWindow(display,windows->magnify.id, 16085 windows->magnify.screen); 16086 if (IfMagickTrue(windows->command.mapped) ) 16087 (void) XWithdrawWindow(display,windows->command.id, 16088 windows->command.screen); 16089 } 16090 if (IfMagickTrue(windows->pan.mapped) ) 16091 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 16092 if (IfMagickFalse(resource_info->backdrop) ) 16093 if (windows->backdrop.mapped) 16094 { 16095 (void) XWithdrawWindow(display,windows->backdrop.id, 16096 windows->backdrop.screen); 16097 (void) XDestroyWindow(display,windows->backdrop.id); 16098 windows->backdrop.id=(Window) NULL; 16099 (void) XWithdrawWindow(display,windows->image.id, 16100 windows->image.screen); 16101 (void) XDestroyWindow(display,windows->image.id); 16102 windows->image.id=(Window) NULL; 16103 } 16104 XSetCursorState(display,windows,MagickTrue); 16105 XCheckRefreshWindows(display,windows); 16106 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 16107 *state&=(~ExitState); 16108 if (*state & ExitState) 16109 { 16110 /* 16111 Free Standard Colormap. 16112 */ 16113 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 16114 if (resource_info->map_type == (char *) NULL) 16115 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 16116 /* 16117 Free X resources. 16118 */ 16119 if (resource_info->copy_image != (Image *) NULL) 16120 { 16121 resource_info->copy_image=DestroyImage(resource_info->copy_image); 16122 resource_info->copy_image=NewImageList(); 16123 } 16124 DestroyXResources(); 16125 } 16126 (void) XSync(display,MagickFalse); 16127 /* 16128 Restore our progress monitor and warning handlers. 16129 */ 16130 (void) SetErrorHandler(warning_handler); 16131 (void) SetWarningHandler(warning_handler); 16132 /* 16133 Change to home directory. 16134 */ 16135 directory=getcwd(working_directory,MaxTextExtent); 16136 (void) directory; 16137 { 16138 int 16139 status; 16140 16141 if (*resource_info->home_directory == '\0') 16142 (void) CopyMagickString(resource_info->home_directory,".",MaxTextExtent); 16143 status=chdir(resource_info->home_directory); 16144 if (status == -1) 16145 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 16146 "UnableToOpenFile","%s",resource_info->home_directory); 16147 } 16148 *image=display_image; 16149 return(nexus); 16150} 16151#else 16152 16153/* 16154%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16155% % 16156% % 16157% % 16158+ D i s p l a y I m a g e s % 16159% % 16160% % 16161% % 16162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16163% 16164% DisplayImages() displays an image sequence to any X window screen. It 16165% returns a value other than 0 if successful. Check the exception member 16166% of image to determine the reason for any failure. 16167% 16168% The format of the DisplayImages method is: 16169% 16170% MagickBooleanType DisplayImages(const ImageInfo *image_info, 16171% Image *images,ExceptionInfo *exception) 16172% 16173% A description of each parameter follows: 16174% 16175% o image_info: the image info. 16176% 16177% o image: the image. 16178% 16179% o exception: return any errors or warnings in this structure. 16180% 16181*/ 16182MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16183 Image *image,ExceptionInfo *exception) 16184{ 16185 assert(image_info != (const ImageInfo *) NULL); 16186 assert(image_info->signature == MagickSignature); 16187 assert(image != (Image *) NULL); 16188 assert(image->signature == MagickSignature); 16189 (void) image_info; 16190 if (IfMagickTrue(image->debug) ) 16191 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16192 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16193 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image->filename); 16194 return(MagickFalse); 16195} 16196 16197/* 16198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16199% % 16200% % 16201% % 16202+ R e m o t e D i s p l a y C o m m a n d % 16203% % 16204% % 16205% % 16206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16207% 16208% RemoteDisplayCommand() encourages a remote display program to display the 16209% specified image filename. 16210% 16211% The format of the RemoteDisplayCommand method is: 16212% 16213% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16214% const char *window,const char *filename,ExceptionInfo *exception) 16215% 16216% A description of each parameter follows: 16217% 16218% o image_info: the image info. 16219% 16220% o window: Specifies the name or id of an X window. 16221% 16222% o filename: the name of the image filename to display. 16223% 16224% o exception: return any errors or warnings in this structure. 16225% 16226*/ 16227MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16228 const char *window,const char *filename,ExceptionInfo *exception) 16229{ 16230 assert(image_info != (const ImageInfo *) NULL); 16231 assert(image_info->signature == MagickSignature); 16232 assert(filename != (char *) NULL); 16233 (void) window; 16234 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16235 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16236 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image_info->filename); 16237 return(MagickFalse); 16238} 16239#endif 16240