display.c revision b83e0e3eef62f085b7b12e2de856fe3315638484
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-2016 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/property.h" 81#include "MagickCore/quantum.h" 82#include "MagickCore/quantum-private.h" 83#include "MagickCore/resize.h" 84#include "MagickCore/resource_.h" 85#include "MagickCore/shear.h" 86#include "MagickCore/segment.h" 87#include "MagickCore/statistic.h" 88#include "MagickCore/string_.h" 89#include "MagickCore/string-private.h" 90#include "MagickCore/transform.h" 91#include "MagickCore/transform-private.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 == MagickCoreSignature); 1678 assert(images != (Image *) NULL); 1679 assert(images->signature == MagickCoreSignature); 1680 if (images->debug != MagickFalse ) 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 == MagickCoreSignature); 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(status != 0 ? MagickTrue : MagickFalse); 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[MagickPathExtent], 1857 text[MagickPathExtent]; 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 (windows->info.mapped != MagickFalse ) 1926 { 1927 /* 1928 Display pointer position. 1929 */ 1930 (void) FormatLocaleString(text,MagickPathExtent," %+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[MagickPathExtent] = "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 (transparent_pen != MagickFalse ) 2019 break; 2020 if (pen_number == (MaxNumberPens-1)) 2021 { 2022 static char 2023 color_name[MagickPathExtent] = "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 (transparent_box != MagickFalse ) 2064 break; 2065 if (pen_number == (MaxNumberPens-1)) 2066 { 2067 static char 2068 color_name[MagickPathExtent] = "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[MagickPathExtent] = "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 (windows->info.mapped != MagickFalse ) 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 ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse)) 2263 annotate_info->stencil=OpaqueStencil; 2264 else 2265 if (transparent_box == MagickFalse) 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) MagickPathExtent,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,MagickPathExtent, 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[MagickPathExtent] = "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=status != 0 ? MagickTrue : MagickFalse; 2815 status=XDisplayBackgroundImage(display,&background_resources,*image, 2816 exception); 2817 if (status != MagickFalse) 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[MagickPathExtent]; 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 (void) ResetMagickMemory(&segment_info,0,sizeof(segment_info)); 2935 do 2936 { 2937 if (windows->info.mapped != MagickFalse ) 2938 { 2939 /* 2940 Display pointer position. 2941 */ 2942 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ", 2943 x+windows->image.x,y+windows->image.y); 2944 XInfoWidget(display,windows,text); 2945 } 2946 /* 2947 Wait for next event. 2948 */ 2949 XScreenEvent(display,windows,&event,exception); 2950 if (event.xany.window == windows->command.id) 2951 { 2952 /* 2953 Select a command from the Command widget. 2954 */ 2955 id=XCommandWidget(display,windows,ChopMenu,&event); 2956 if (id < 0) 2957 continue; 2958 switch (ChopCommands[id]) 2959 { 2960 case ChopDirectionCommand: 2961 { 2962 char 2963 command[MagickPathExtent]; 2964 2965 static const char 2966 *Directions[] = 2967 { 2968 "horizontal", 2969 "vertical", 2970 (char *) NULL, 2971 }; 2972 2973 /* 2974 Select a command from the pop-up menu. 2975 */ 2976 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 2977 if (id >= 0) 2978 direction=DirectionCommands[id]; 2979 break; 2980 } 2981 case ChopHelpCommand: 2982 { 2983 XTextViewWidget(display,resource_info,windows,MagickFalse, 2984 "Help Viewer - Image Chop",ImageChopHelp); 2985 break; 2986 } 2987 case ChopDismissCommand: 2988 { 2989 /* 2990 Prematurely exit. 2991 */ 2992 state|=EscapeState; 2993 state|=ExitState; 2994 break; 2995 } 2996 default: 2997 break; 2998 } 2999 continue; 3000 } 3001 switch (event.type) 3002 { 3003 case ButtonPress: 3004 { 3005 if (event.xbutton.button != Button1) 3006 break; 3007 if (event.xbutton.window != windows->image.id) 3008 break; 3009 /* 3010 User has committed to start point of chopping line. 3011 */ 3012 segment_info.x1=(short int) event.xbutton.x; 3013 segment_info.x2=(short int) event.xbutton.x; 3014 segment_info.y1=(short int) event.xbutton.y; 3015 segment_info.y2=(short int) event.xbutton.y; 3016 state|=ExitState; 3017 break; 3018 } 3019 case ButtonRelease: 3020 break; 3021 case Expose: 3022 break; 3023 case KeyPress: 3024 { 3025 char 3026 command[MagickPathExtent]; 3027 3028 KeySym 3029 key_symbol; 3030 3031 if (event.xkey.window != windows->image.id) 3032 break; 3033 /* 3034 Respond to a user key press. 3035 */ 3036 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3037 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3038 switch ((int) key_symbol) 3039 { 3040 case XK_Escape: 3041 case XK_F20: 3042 { 3043 /* 3044 Prematurely exit. 3045 */ 3046 state|=EscapeState; 3047 state|=ExitState; 3048 break; 3049 } 3050 case XK_F1: 3051 case XK_Help: 3052 { 3053 (void) XSetFunction(display,windows->image.highlight_context, 3054 GXcopy); 3055 XTextViewWidget(display,resource_info,windows,MagickFalse, 3056 "Help Viewer - Image Chop",ImageChopHelp); 3057 (void) XSetFunction(display,windows->image.highlight_context, 3058 GXinvert); 3059 break; 3060 } 3061 default: 3062 { 3063 (void) XBell(display,0); 3064 break; 3065 } 3066 } 3067 break; 3068 } 3069 case MotionNotify: 3070 { 3071 /* 3072 Map and unmap Info widget as text cursor crosses its boundaries. 3073 */ 3074 x=event.xmotion.x; 3075 y=event.xmotion.y; 3076 if (windows->info.mapped != MagickFalse ) 3077 { 3078 if ((x < (int) (windows->info.x+windows->info.width)) && 3079 (y < (int) (windows->info.y+windows->info.height))) 3080 (void) XWithdrawWindow(display,windows->info.id, 3081 windows->info.screen); 3082 } 3083 else 3084 if ((x > (int) (windows->info.x+windows->info.width)) || 3085 (y > (int) (windows->info.y+windows->info.height))) 3086 (void) XMapWindow(display,windows->info.id); 3087 } 3088 } 3089 } while ((state & ExitState) == 0); 3090 (void) XSelectInput(display,windows->image.id, 3091 windows->image.attributes.event_mask); 3092 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3093 if ((state & EscapeState) != 0) 3094 return(MagickTrue); 3095 /* 3096 Draw line as pointer moves until the mouse button is released. 3097 */ 3098 chop_info.width=0; 3099 chop_info.height=0; 3100 chop_info.x=0; 3101 chop_info.y=0; 3102 distance=0; 3103 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3104 state=DefaultState; 3105 do 3106 { 3107 if (distance > 9) 3108 { 3109 /* 3110 Display info and draw chopping line. 3111 */ 3112 if (windows->info.mapped == MagickFalse) 3113 (void) XMapWindow(display,windows->info.id); 3114 (void) FormatLocaleString(text,MagickPathExtent, 3115 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 3116 chop_info.height,(double) chop_info.x,(double) chop_info.y); 3117 XInfoWidget(display,windows,text); 3118 XHighlightLine(display,windows->image.id, 3119 windows->image.highlight_context,&segment_info); 3120 } 3121 else 3122 if (windows->info.mapped != MagickFalse ) 3123 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3124 /* 3125 Wait for next event. 3126 */ 3127 XScreenEvent(display,windows,&event,exception); 3128 if (distance > 9) 3129 XHighlightLine(display,windows->image.id, 3130 windows->image.highlight_context,&segment_info); 3131 switch (event.type) 3132 { 3133 case ButtonPress: 3134 { 3135 segment_info.x2=(short int) event.xmotion.x; 3136 segment_info.y2=(short int) event.xmotion.y; 3137 break; 3138 } 3139 case ButtonRelease: 3140 { 3141 /* 3142 User has committed to chopping line. 3143 */ 3144 segment_info.x2=(short int) event.xbutton.x; 3145 segment_info.y2=(short int) event.xbutton.y; 3146 state|=ExitState; 3147 break; 3148 } 3149 case Expose: 3150 break; 3151 case MotionNotify: 3152 { 3153 segment_info.x2=(short int) event.xmotion.x; 3154 segment_info.y2=(short int) event.xmotion.y; 3155 } 3156 default: 3157 break; 3158 } 3159 /* 3160 Check boundary conditions. 3161 */ 3162 if (segment_info.x2 < 0) 3163 segment_info.x2=0; 3164 else 3165 if (segment_info.x2 > windows->image.ximage->width) 3166 segment_info.x2=windows->image.ximage->width; 3167 if (segment_info.y2 < 0) 3168 segment_info.y2=0; 3169 else 3170 if (segment_info.y2 > windows->image.ximage->height) 3171 segment_info.y2=windows->image.ximage->height; 3172 distance=(unsigned int) 3173 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 3174 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 3175 /* 3176 Compute chopping geometry. 3177 */ 3178 if (direction == HorizontalChopCommand) 3179 { 3180 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 3181 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 3182 chop_info.height=0; 3183 chop_info.y=0; 3184 if (segment_info.x1 > (int) segment_info.x2) 3185 { 3186 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 3187 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 3188 } 3189 } 3190 else 3191 { 3192 chop_info.width=0; 3193 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 3194 chop_info.x=0; 3195 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 3196 if (segment_info.y1 > segment_info.y2) 3197 { 3198 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 3199 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 3200 } 3201 } 3202 } while ((state & ExitState) == 0); 3203 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 3204 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3205 if (distance <= 9) 3206 return(MagickTrue); 3207 /* 3208 Image chopping is relative to image configuration. 3209 */ 3210 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 3211 exception); 3212 XSetCursorState(display,windows,MagickTrue); 3213 XCheckRefreshWindows(display,windows); 3214 windows->image.window_changes.width=windows->image.ximage->width- 3215 (unsigned int) chop_info.width; 3216 windows->image.window_changes.height=windows->image.ximage->height- 3217 (unsigned int) chop_info.height; 3218 width=(unsigned int) (*image)->columns; 3219 height=(unsigned int) (*image)->rows; 3220 x=0; 3221 y=0; 3222 if (windows->image.crop_geometry != (char *) NULL) 3223 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 3224 scale_factor=(double) width/windows->image.ximage->width; 3225 chop_info.x+=x; 3226 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 3227 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 3228 scale_factor=(double) height/windows->image.ximage->height; 3229 chop_info.y+=y; 3230 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 3231 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 3232 /* 3233 Chop image. 3234 */ 3235 chop_image=ChopImage(*image,&chop_info,exception); 3236 XSetCursorState(display,windows,MagickFalse); 3237 if (chop_image == (Image *) NULL) 3238 return(MagickFalse); 3239 *image=DestroyImage(*image); 3240 *image=chop_image; 3241 /* 3242 Update image configuration. 3243 */ 3244 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3245 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3246 return(MagickTrue); 3247} 3248 3249/* 3250%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3251% % 3252% % 3253% % 3254+ X C o l o r E d i t I m a g e % 3255% % 3256% % 3257% % 3258%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3259% 3260% XColorEditImage() allows the user to interactively change the color of one 3261% pixel for a DirectColor image or one colormap entry for a PseudoClass image. 3262% 3263% The format of the XColorEditImage method is: 3264% 3265% MagickBooleanType XColorEditImage(Display *display, 3266% XResourceInfo *resource_info,XWindows *windows,Image **image, 3267% ExceptionInfo *exception) 3268% 3269% A description of each parameter follows: 3270% 3271% o display: Specifies a connection to an X server; returned from 3272% XOpenDisplay. 3273% 3274% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3275% 3276% o windows: Specifies a pointer to a XWindows structure. 3277% 3278% o image: the image; returned from ReadImage. 3279% 3280% o exception: return any errors or warnings in this structure. 3281% 3282*/ 3283static MagickBooleanType XColorEditImage(Display *display, 3284 XResourceInfo *resource_info,XWindows *windows,Image **image, 3285 ExceptionInfo *exception) 3286{ 3287 static const char 3288 *ColorEditMenu[] = 3289 { 3290 "Method", 3291 "Pixel Color", 3292 "Border Color", 3293 "Fuzz", 3294 "Undo", 3295 "Help", 3296 "Dismiss", 3297 (char *) NULL 3298 }; 3299 3300 static const ModeType 3301 ColorEditCommands[] = 3302 { 3303 ColorEditMethodCommand, 3304 ColorEditColorCommand, 3305 ColorEditBorderCommand, 3306 ColorEditFuzzCommand, 3307 ColorEditUndoCommand, 3308 ColorEditHelpCommand, 3309 ColorEditDismissCommand 3310 }; 3311 3312 static PaintMethod 3313 method = PointMethod; 3314 3315 static unsigned int 3316 pen_id = 0; 3317 3318 static XColor 3319 border_color = { 0, 0, 0, 0, 0, 0 }; 3320 3321 char 3322 command[MagickPathExtent], 3323 text[MagickPathExtent]; 3324 3325 Cursor 3326 cursor; 3327 3328 int 3329 entry, 3330 id, 3331 x, 3332 x_offset, 3333 y, 3334 y_offset; 3335 3336 register Quantum 3337 *q; 3338 3339 register ssize_t 3340 i; 3341 3342 unsigned int 3343 height, 3344 width; 3345 3346 size_t 3347 state; 3348 3349 XColor 3350 color; 3351 3352 XEvent 3353 event; 3354 3355 /* 3356 Map Command widget. 3357 */ 3358 (void) CloneString(&windows->command.name,"Color Edit"); 3359 windows->command.data=4; 3360 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 3361 (void) XMapRaised(display,windows->command.id); 3362 XClientMessage(display,windows->image.id,windows->im_protocols, 3363 windows->im_update_widget,CurrentTime); 3364 /* 3365 Make cursor. 3366 */ 3367 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 3368 resource_info->background_color,resource_info->foreground_color); 3369 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3370 /* 3371 Track pointer until button 1 is pressed. 3372 */ 3373 XQueryPosition(display,windows->image.id,&x,&y); 3374 (void) XSelectInput(display,windows->image.id, 3375 windows->image.attributes.event_mask | PointerMotionMask); 3376 state=DefaultState; 3377 do 3378 { 3379 if (windows->info.mapped != MagickFalse ) 3380 { 3381 /* 3382 Display pointer position. 3383 */ 3384 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ", 3385 x+windows->image.x,y+windows->image.y); 3386 XInfoWidget(display,windows,text); 3387 } 3388 /* 3389 Wait for next event. 3390 */ 3391 XScreenEvent(display,windows,&event,exception); 3392 if (event.xany.window == windows->command.id) 3393 { 3394 /* 3395 Select a command from the Command widget. 3396 */ 3397 id=XCommandWidget(display,windows,ColorEditMenu,&event); 3398 if (id < 0) 3399 { 3400 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3401 continue; 3402 } 3403 switch (ColorEditCommands[id]) 3404 { 3405 case ColorEditMethodCommand: 3406 { 3407 char 3408 **methods; 3409 3410 /* 3411 Select a method from the pop-up menu. 3412 */ 3413 methods=(char **) GetCommandOptions(MagickMethodOptions); 3414 if (methods == (char **) NULL) 3415 break; 3416 entry=XMenuWidget(display,windows,ColorEditMenu[id], 3417 (const char **) methods,command); 3418 if (entry >= 0) 3419 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 3420 MagickFalse,methods[entry]); 3421 methods=DestroyStringList(methods); 3422 break; 3423 } 3424 case ColorEditColorCommand: 3425 { 3426 const char 3427 *ColorMenu[MaxNumberPens]; 3428 3429 int 3430 pen_number; 3431 3432 /* 3433 Initialize menu selections. 3434 */ 3435 for (i=0; i < (int) (MaxNumberPens-2); i++) 3436 ColorMenu[i]=resource_info->pen_colors[i]; 3437 ColorMenu[MaxNumberPens-2]="Browser..."; 3438 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3439 /* 3440 Select a pen color from the pop-up menu. 3441 */ 3442 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3443 (const char **) ColorMenu,command); 3444 if (pen_number < 0) 3445 break; 3446 if (pen_number == (MaxNumberPens-2)) 3447 { 3448 static char 3449 color_name[MagickPathExtent] = "gray"; 3450 3451 /* 3452 Select a pen color from a dialog. 3453 */ 3454 resource_info->pen_colors[pen_number]=color_name; 3455 XColorBrowserWidget(display,windows,"Select",color_name); 3456 if (*color_name == '\0') 3457 break; 3458 } 3459 /* 3460 Set pen color. 3461 */ 3462 (void) XParseColor(display,windows->map_info->colormap, 3463 resource_info->pen_colors[pen_number],&color); 3464 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 3465 (unsigned int) MaxColors,&color); 3466 windows->pixel_info->pen_colors[pen_number]=color; 3467 pen_id=(unsigned int) pen_number; 3468 break; 3469 } 3470 case ColorEditBorderCommand: 3471 { 3472 const char 3473 *ColorMenu[MaxNumberPens]; 3474 3475 int 3476 pen_number; 3477 3478 /* 3479 Initialize menu selections. 3480 */ 3481 for (i=0; i < (int) (MaxNumberPens-2); i++) 3482 ColorMenu[i]=resource_info->pen_colors[i]; 3483 ColorMenu[MaxNumberPens-2]="Browser..."; 3484 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3485 /* 3486 Select a pen color from the pop-up menu. 3487 */ 3488 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3489 (const char **) ColorMenu,command); 3490 if (pen_number < 0) 3491 break; 3492 if (pen_number == (MaxNumberPens-2)) 3493 { 3494 static char 3495 color_name[MagickPathExtent] = "gray"; 3496 3497 /* 3498 Select a pen color from a dialog. 3499 */ 3500 resource_info->pen_colors[pen_number]=color_name; 3501 XColorBrowserWidget(display,windows,"Select",color_name); 3502 if (*color_name == '\0') 3503 break; 3504 } 3505 /* 3506 Set border color. 3507 */ 3508 (void) XParseColor(display,windows->map_info->colormap, 3509 resource_info->pen_colors[pen_number],&border_color); 3510 break; 3511 } 3512 case ColorEditFuzzCommand: 3513 { 3514 static char 3515 fuzz[MagickPathExtent]; 3516 3517 static const char 3518 *FuzzMenu[] = 3519 { 3520 "0%", 3521 "2%", 3522 "5%", 3523 "10%", 3524 "15%", 3525 "Dialog...", 3526 (char *) NULL, 3527 }; 3528 3529 /* 3530 Select a command from the pop-up menu. 3531 */ 3532 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 3533 command); 3534 if (entry < 0) 3535 break; 3536 if (entry != 5) 3537 { 3538 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 3539 QuantumRange+1.0); 3540 break; 3541 } 3542 (void) (void) CopyMagickString(fuzz,"20%",MagickPathExtent); 3543 (void) XDialogWidget(display,windows,"Ok", 3544 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 3545 if (*fuzz == '\0') 3546 break; 3547 (void) ConcatenateMagickString(fuzz,"%",MagickPathExtent); 3548 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 3549 1.0); 3550 break; 3551 } 3552 case ColorEditUndoCommand: 3553 { 3554 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 3555 image,exception); 3556 break; 3557 } 3558 case ColorEditHelpCommand: 3559 default: 3560 { 3561 XTextViewWidget(display,resource_info,windows,MagickFalse, 3562 "Help Viewer - Image Annotation",ImageColorEditHelp); 3563 break; 3564 } 3565 case ColorEditDismissCommand: 3566 { 3567 /* 3568 Prematurely exit. 3569 */ 3570 state|=EscapeState; 3571 state|=ExitState; 3572 break; 3573 } 3574 } 3575 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3576 continue; 3577 } 3578 switch (event.type) 3579 { 3580 case ButtonPress: 3581 { 3582 if (event.xbutton.button != Button1) 3583 break; 3584 if ((event.xbutton.window != windows->image.id) && 3585 (event.xbutton.window != windows->magnify.id)) 3586 break; 3587 /* 3588 exit loop. 3589 */ 3590 x=event.xbutton.x; 3591 y=event.xbutton.y; 3592 (void) XMagickCommand(display,resource_info,windows, 3593 SaveToUndoBufferCommand,image,exception); 3594 state|=UpdateConfigurationState; 3595 break; 3596 } 3597 case ButtonRelease: 3598 { 3599 if (event.xbutton.button != Button1) 3600 break; 3601 if ((event.xbutton.window != windows->image.id) && 3602 (event.xbutton.window != windows->magnify.id)) 3603 break; 3604 /* 3605 Update colormap information. 3606 */ 3607 x=event.xbutton.x; 3608 y=event.xbutton.y; 3609 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3610 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3611 XInfoWidget(display,windows,text); 3612 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3613 state&=(~UpdateConfigurationState); 3614 break; 3615 } 3616 case Expose: 3617 break; 3618 case KeyPress: 3619 { 3620 KeySym 3621 key_symbol; 3622 3623 if (event.xkey.window == windows->magnify.id) 3624 { 3625 Window 3626 window; 3627 3628 window=windows->magnify.id; 3629 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 3630 } 3631 if (event.xkey.window != windows->image.id) 3632 break; 3633 /* 3634 Respond to a user key press. 3635 */ 3636 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3637 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3638 switch ((int) key_symbol) 3639 { 3640 case XK_Escape: 3641 case XK_F20: 3642 { 3643 /* 3644 Prematurely exit. 3645 */ 3646 state|=ExitState; 3647 break; 3648 } 3649 case XK_F1: 3650 case XK_Help: 3651 { 3652 XTextViewWidget(display,resource_info,windows,MagickFalse, 3653 "Help Viewer - Image Annotation",ImageColorEditHelp); 3654 break; 3655 } 3656 default: 3657 { 3658 (void) XBell(display,0); 3659 break; 3660 } 3661 } 3662 break; 3663 } 3664 case MotionNotify: 3665 { 3666 /* 3667 Map and unmap Info widget as cursor crosses its boundaries. 3668 */ 3669 x=event.xmotion.x; 3670 y=event.xmotion.y; 3671 if (windows->info.mapped != MagickFalse ) 3672 { 3673 if ((x < (int) (windows->info.x+windows->info.width)) && 3674 (y < (int) (windows->info.y+windows->info.height))) 3675 (void) XWithdrawWindow(display,windows->info.id, 3676 windows->info.screen); 3677 } 3678 else 3679 if ((x > (int) (windows->info.x+windows->info.width)) || 3680 (y > (int) (windows->info.y+windows->info.height))) 3681 (void) XMapWindow(display,windows->info.id); 3682 break; 3683 } 3684 default: 3685 break; 3686 } 3687 if (event.xany.window == windows->magnify.id) 3688 { 3689 x=windows->magnify.x-windows->image.x; 3690 y=windows->magnify.y-windows->image.y; 3691 } 3692 x_offset=x; 3693 y_offset=y; 3694 if ((state & UpdateConfigurationState) != 0) 3695 { 3696 CacheView 3697 *image_view; 3698 3699 int 3700 x, 3701 y; 3702 3703 /* 3704 Pixel edit is relative to image configuration. 3705 */ 3706 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 3707 MagickTrue); 3708 color=windows->pixel_info->pen_colors[pen_id]; 3709 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 3710 width=(unsigned int) (*image)->columns; 3711 height=(unsigned int) (*image)->rows; 3712 x=0; 3713 y=0; 3714 if (windows->image.crop_geometry != (char *) NULL) 3715 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 3716 &width,&height); 3717 x_offset=(int) 3718 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 3719 y_offset=(int) 3720 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 3721 if ((x_offset < 0) || (y_offset < 0)) 3722 continue; 3723 if ((x_offset >= (int) (*image)->columns) || 3724 (y_offset >= (int) (*image)->rows)) 3725 continue; 3726 image_view=AcquireAuthenticCacheView(*image,exception); 3727 switch (method) 3728 { 3729 case PointMethod: 3730 default: 3731 { 3732 /* 3733 Update color information using point algorithm. 3734 */ 3735 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3736 return(MagickFalse); 3737 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 3738 (ssize_t) y_offset,1,1,exception); 3739 if (q == (Quantum *) NULL) 3740 break; 3741 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3742 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3743 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3744 (void) SyncCacheViewAuthenticPixels(image_view,exception); 3745 break; 3746 } 3747 case ReplaceMethod: 3748 { 3749 PixelInfo 3750 pixel, 3751 target; 3752 3753 /* 3754 Update color information using replace algorithm. 3755 */ 3756 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t) 3757 x_offset,(ssize_t) y_offset,&target,exception); 3758 if ((*image)->storage_class == DirectClass) 3759 { 3760 for (y=0; y < (int) (*image)->rows; y++) 3761 { 3762 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3763 (*image)->columns,1,exception); 3764 if (q == (Quantum *) NULL) 3765 break; 3766 for (x=0; x < (int) (*image)->columns; x++) 3767 { 3768 GetPixelInfoPixel(*image,q,&pixel); 3769 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 3770 { 3771 SetPixelRed(*image,ScaleShortToQuantum( 3772 color.red),q); 3773 SetPixelGreen(*image,ScaleShortToQuantum( 3774 color.green),q); 3775 SetPixelBlue(*image,ScaleShortToQuantum( 3776 color.blue),q); 3777 } 3778 q+=GetPixelChannels(*image); 3779 } 3780 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3781 break; 3782 } 3783 } 3784 else 3785 { 3786 for (i=0; i < (ssize_t) (*image)->colors; i++) 3787 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target)) 3788 { 3789 (*image)->colormap[i].red=(double) ScaleShortToQuantum( 3790 color.red); 3791 (*image)->colormap[i].green=(double) ScaleShortToQuantum( 3792 color.green); 3793 (*image)->colormap[i].blue=(double) ScaleShortToQuantum( 3794 color.blue); 3795 } 3796 (void) SyncImage(*image,exception); 3797 } 3798 break; 3799 } 3800 case FloodfillMethod: 3801 case FillToBorderMethod: 3802 { 3803 DrawInfo 3804 *draw_info; 3805 3806 PixelInfo 3807 target; 3808 3809 /* 3810 Update color information using floodfill algorithm. 3811 */ 3812 (void) GetOneVirtualPixelInfo(*image, 3813 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 3814 y_offset,&target,exception); 3815 if (method == FillToBorderMethod) 3816 { 3817 target.red=(double) 3818 ScaleShortToQuantum(border_color.red); 3819 target.green=(double) 3820 ScaleShortToQuantum(border_color.green); 3821 target.blue=(double) 3822 ScaleShortToQuantum(border_color.blue); 3823 } 3824 draw_info=CloneDrawInfo(resource_info->image_info, 3825 (DrawInfo *) NULL); 3826 (void) QueryColorCompliance(resource_info->pen_colors[pen_id], 3827 AllCompliance,&draw_info->fill,exception); 3828 (void) FloodfillPaintImage(*image,draw_info,&target, 3829 (ssize_t)x_offset,(ssize_t)y_offset, 3830 method != FloodfillMethod ? MagickTrue : MagickFalse,exception); 3831 draw_info=DestroyDrawInfo(draw_info); 3832 break; 3833 } 3834 case ResetMethod: 3835 { 3836 /* 3837 Update color information using reset algorithm. 3838 */ 3839 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3840 return(MagickFalse); 3841 for (y=0; y < (int) (*image)->rows; y++) 3842 { 3843 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3844 (*image)->columns,1,exception); 3845 if (q == (Quantum *) NULL) 3846 break; 3847 for (x=0; x < (int) (*image)->columns; x++) 3848 { 3849 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3850 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3851 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3852 q+=GetPixelChannels(*image); 3853 } 3854 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3855 break; 3856 } 3857 break; 3858 } 3859 } 3860 image_view=DestroyCacheView(image_view); 3861 state&=(~UpdateConfigurationState); 3862 } 3863 } while ((state & ExitState) == 0); 3864 (void) XSelectInput(display,windows->image.id, 3865 windows->image.attributes.event_mask); 3866 XSetCursorState(display,windows,MagickFalse); 3867 (void) XFreeCursor(display,cursor); 3868 return(MagickTrue); 3869} 3870 3871/* 3872%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3873% % 3874% % 3875% % 3876+ X C o m p o s i t e I m a g e % 3877% % 3878% % 3879% % 3880%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3881% 3882% XCompositeImage() requests an image name from the user, reads the image and 3883% composites it with the X window image at a location the user chooses with 3884% the pointer. 3885% 3886% The format of the XCompositeImage method is: 3887% 3888% MagickBooleanType XCompositeImage(Display *display, 3889% XResourceInfo *resource_info,XWindows *windows,Image *image, 3890% ExceptionInfo *exception) 3891% 3892% A description of each parameter follows: 3893% 3894% o display: Specifies a connection to an X server; returned from 3895% XOpenDisplay. 3896% 3897% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3898% 3899% o windows: Specifies a pointer to a XWindows structure. 3900% 3901% o image: the image; returned from ReadImage. 3902% 3903% o exception: return any errors or warnings in this structure. 3904% 3905*/ 3906static MagickBooleanType XCompositeImage(Display *display, 3907 XResourceInfo *resource_info,XWindows *windows,Image *image, 3908 ExceptionInfo *exception) 3909{ 3910 static char 3911 displacement_geometry[MagickPathExtent] = "30x30", 3912 filename[MagickPathExtent] = "\0"; 3913 3914 static const char 3915 *CompositeMenu[] = 3916 { 3917 "Operators", 3918 "Dissolve", 3919 "Displace", 3920 "Help", 3921 "Dismiss", 3922 (char *) NULL 3923 }; 3924 3925 static CompositeOperator 3926 compose = CopyCompositeOp; 3927 3928 static const ModeType 3929 CompositeCommands[] = 3930 { 3931 CompositeOperatorsCommand, 3932 CompositeDissolveCommand, 3933 CompositeDisplaceCommand, 3934 CompositeHelpCommand, 3935 CompositeDismissCommand 3936 }; 3937 3938 char 3939 text[MagickPathExtent]; 3940 3941 Cursor 3942 cursor; 3943 3944 Image 3945 *composite_image; 3946 3947 int 3948 entry, 3949 id, 3950 x, 3951 y; 3952 3953 double 3954 blend, 3955 scale_factor; 3956 3957 RectangleInfo 3958 highlight_info, 3959 composite_info; 3960 3961 unsigned int 3962 height, 3963 width; 3964 3965 size_t 3966 state; 3967 3968 XEvent 3969 event; 3970 3971 /* 3972 Request image file name from user. 3973 */ 3974 XFileBrowserWidget(display,windows,"Composite",filename); 3975 if (*filename == '\0') 3976 return(MagickTrue); 3977 /* 3978 Read image. 3979 */ 3980 XSetCursorState(display,windows,MagickTrue); 3981 XCheckRefreshWindows(display,windows); 3982 (void) CopyMagickString(resource_info->image_info->filename,filename, 3983 MagickPathExtent); 3984 composite_image=ReadImage(resource_info->image_info,exception); 3985 CatchException(exception); 3986 XSetCursorState(display,windows,MagickFalse); 3987 if (composite_image == (Image *) NULL) 3988 return(MagickFalse); 3989 /* 3990 Map Command widget. 3991 */ 3992 (void) CloneString(&windows->command.name,"Composite"); 3993 windows->command.data=1; 3994 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 3995 (void) XMapRaised(display,windows->command.id); 3996 XClientMessage(display,windows->image.id,windows->im_protocols, 3997 windows->im_update_widget,CurrentTime); 3998 /* 3999 Track pointer until button 1 is pressed. 4000 */ 4001 XQueryPosition(display,windows->image.id,&x,&y); 4002 (void) XSelectInput(display,windows->image.id, 4003 windows->image.attributes.event_mask | PointerMotionMask); 4004 composite_info.x=(ssize_t) windows->image.x+x; 4005 composite_info.y=(ssize_t) windows->image.y+y; 4006 composite_info.width=0; 4007 composite_info.height=0; 4008 cursor=XCreateFontCursor(display,XC_ul_angle); 4009 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4010 blend=0.0; 4011 state=DefaultState; 4012 do 4013 { 4014 if (windows->info.mapped != MagickFalse ) 4015 { 4016 /* 4017 Display pointer position. 4018 */ 4019 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ", 4020 (long) composite_info.x,(long) composite_info.y); 4021 XInfoWidget(display,windows,text); 4022 } 4023 highlight_info=composite_info; 4024 highlight_info.x=composite_info.x-windows->image.x; 4025 highlight_info.y=composite_info.y-windows->image.y; 4026 XHighlightRectangle(display,windows->image.id, 4027 windows->image.highlight_context,&highlight_info); 4028 /* 4029 Wait for next event. 4030 */ 4031 XScreenEvent(display,windows,&event,exception); 4032 XHighlightRectangle(display,windows->image.id, 4033 windows->image.highlight_context,&highlight_info); 4034 if (event.xany.window == windows->command.id) 4035 { 4036 /* 4037 Select a command from the Command widget. 4038 */ 4039 id=XCommandWidget(display,windows,CompositeMenu,&event); 4040 if (id < 0) 4041 continue; 4042 switch (CompositeCommands[id]) 4043 { 4044 case CompositeOperatorsCommand: 4045 { 4046 char 4047 command[MagickPathExtent], 4048 **operators; 4049 4050 /* 4051 Select a command from the pop-up menu. 4052 */ 4053 operators=GetCommandOptions(MagickComposeOptions); 4054 if (operators == (char **) NULL) 4055 break; 4056 entry=XMenuWidget(display,windows,CompositeMenu[id], 4057 (const char **) operators,command); 4058 if (entry >= 0) 4059 compose=(CompositeOperator) ParseCommandOption( 4060 MagickComposeOptions,MagickFalse,operators[entry]); 4061 operators=DestroyStringList(operators); 4062 break; 4063 } 4064 case CompositeDissolveCommand: 4065 { 4066 static char 4067 factor[MagickPathExtent] = "20.0"; 4068 4069 /* 4070 Dissolve the two images a given percent. 4071 */ 4072 (void) XSetFunction(display,windows->image.highlight_context, 4073 GXcopy); 4074 (void) XDialogWidget(display,windows,"Dissolve", 4075 "Enter the blend factor (0.0 - 99.9%):",factor); 4076 (void) XSetFunction(display,windows->image.highlight_context, 4077 GXinvert); 4078 if (*factor == '\0') 4079 break; 4080 blend=StringToDouble(factor,(char **) NULL); 4081 compose=DissolveCompositeOp; 4082 break; 4083 } 4084 case CompositeDisplaceCommand: 4085 { 4086 /* 4087 Get horizontal and vertical scale displacement geometry. 4088 */ 4089 (void) XSetFunction(display,windows->image.highlight_context, 4090 GXcopy); 4091 (void) XDialogWidget(display,windows,"Displace", 4092 "Enter the horizontal and vertical scale:",displacement_geometry); 4093 (void) XSetFunction(display,windows->image.highlight_context, 4094 GXinvert); 4095 if (*displacement_geometry == '\0') 4096 break; 4097 compose=DisplaceCompositeOp; 4098 break; 4099 } 4100 case CompositeHelpCommand: 4101 { 4102 (void) XSetFunction(display,windows->image.highlight_context, 4103 GXcopy); 4104 XTextViewWidget(display,resource_info,windows,MagickFalse, 4105 "Help Viewer - Image Composite",ImageCompositeHelp); 4106 (void) XSetFunction(display,windows->image.highlight_context, 4107 GXinvert); 4108 break; 4109 } 4110 case CompositeDismissCommand: 4111 { 4112 /* 4113 Prematurely exit. 4114 */ 4115 state|=EscapeState; 4116 state|=ExitState; 4117 break; 4118 } 4119 default: 4120 break; 4121 } 4122 continue; 4123 } 4124 switch (event.type) 4125 { 4126 case ButtonPress: 4127 { 4128 if (image->debug != MagickFalse ) 4129 (void) LogMagickEvent(X11Event,GetMagickModule(), 4130 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 4131 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4132 if (event.xbutton.button != Button1) 4133 break; 4134 if (event.xbutton.window != windows->image.id) 4135 break; 4136 /* 4137 Change cursor. 4138 */ 4139 composite_info.width=composite_image->columns; 4140 composite_info.height=composite_image->rows; 4141 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4142 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4143 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4144 break; 4145 } 4146 case ButtonRelease: 4147 { 4148 if (image->debug != MagickFalse ) 4149 (void) LogMagickEvent(X11Event,GetMagickModule(), 4150 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 4151 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4152 if (event.xbutton.button != Button1) 4153 break; 4154 if (event.xbutton.window != windows->image.id) 4155 break; 4156 if ((composite_info.width != 0) && (composite_info.height != 0)) 4157 { 4158 /* 4159 User has selected the location of the composite image. 4160 */ 4161 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4162 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4163 state|=ExitState; 4164 } 4165 break; 4166 } 4167 case Expose: 4168 break; 4169 case KeyPress: 4170 { 4171 char 4172 command[MagickPathExtent]; 4173 4174 KeySym 4175 key_symbol; 4176 4177 int 4178 length; 4179 4180 if (event.xkey.window != windows->image.id) 4181 break; 4182 /* 4183 Respond to a user key press. 4184 */ 4185 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 4186 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4187 *(command+length)='\0'; 4188 if (image->debug != MagickFalse ) 4189 (void) LogMagickEvent(X11Event,GetMagickModule(), 4190 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 4191 switch ((int) key_symbol) 4192 { 4193 case XK_Escape: 4194 case XK_F20: 4195 { 4196 /* 4197 Prematurely exit. 4198 */ 4199 composite_image=DestroyImage(composite_image); 4200 state|=EscapeState; 4201 state|=ExitState; 4202 break; 4203 } 4204 case XK_F1: 4205 case XK_Help: 4206 { 4207 (void) XSetFunction(display,windows->image.highlight_context, 4208 GXcopy); 4209 XTextViewWidget(display,resource_info,windows,MagickFalse, 4210 "Help Viewer - Image Composite",ImageCompositeHelp); 4211 (void) XSetFunction(display,windows->image.highlight_context, 4212 GXinvert); 4213 break; 4214 } 4215 default: 4216 { 4217 (void) XBell(display,0); 4218 break; 4219 } 4220 } 4221 break; 4222 } 4223 case MotionNotify: 4224 { 4225 /* 4226 Map and unmap Info widget as text cursor crosses its boundaries. 4227 */ 4228 x=event.xmotion.x; 4229 y=event.xmotion.y; 4230 if (windows->info.mapped != MagickFalse ) 4231 { 4232 if ((x < (int) (windows->info.x+windows->info.width)) && 4233 (y < (int) (windows->info.y+windows->info.height))) 4234 (void) XWithdrawWindow(display,windows->info.id, 4235 windows->info.screen); 4236 } 4237 else 4238 if ((x > (int) (windows->info.x+windows->info.width)) || 4239 (y > (int) (windows->info.y+windows->info.height))) 4240 (void) XMapWindow(display,windows->info.id); 4241 composite_info.x=(ssize_t) windows->image.x+x; 4242 composite_info.y=(ssize_t) windows->image.y+y; 4243 break; 4244 } 4245 default: 4246 { 4247 if (image->debug != MagickFalse ) 4248 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 4249 event.type); 4250 break; 4251 } 4252 } 4253 } while ((state & ExitState) == 0); 4254 (void) XSelectInput(display,windows->image.id, 4255 windows->image.attributes.event_mask); 4256 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4257 XSetCursorState(display,windows,MagickFalse); 4258 (void) XFreeCursor(display,cursor); 4259 if ((state & EscapeState) != 0) 4260 return(MagickTrue); 4261 /* 4262 Image compositing is relative to image configuration. 4263 */ 4264 XSetCursorState(display,windows,MagickTrue); 4265 XCheckRefreshWindows(display,windows); 4266 width=(unsigned int) image->columns; 4267 height=(unsigned int) image->rows; 4268 x=0; 4269 y=0; 4270 if (windows->image.crop_geometry != (char *) NULL) 4271 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 4272 scale_factor=(double) width/windows->image.ximage->width; 4273 composite_info.x+=x; 4274 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 4275 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 4276 scale_factor=(double) height/windows->image.ximage->height; 4277 composite_info.y+=y; 4278 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 4279 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 4280 if ((composite_info.width != composite_image->columns) || 4281 (composite_info.height != composite_image->rows)) 4282 { 4283 Image 4284 *resize_image; 4285 4286 /* 4287 Scale composite image. 4288 */ 4289 resize_image=ResizeImage(composite_image,composite_info.width, 4290 composite_info.height,composite_image->filter,exception); 4291 composite_image=DestroyImage(composite_image); 4292 if (resize_image == (Image *) NULL) 4293 { 4294 XSetCursorState(display,windows,MagickFalse); 4295 return(MagickFalse); 4296 } 4297 composite_image=resize_image; 4298 } 4299 if (compose == DisplaceCompositeOp) 4300 (void) SetImageArtifact(composite_image,"compose:args", 4301 displacement_geometry); 4302 if (blend != 0.0) 4303 { 4304 CacheView 4305 *image_view; 4306 4307 int 4308 y; 4309 4310 Quantum 4311 opacity; 4312 4313 register int 4314 x; 4315 4316 register Quantum 4317 *q; 4318 4319 /* 4320 Create mattes for blending. 4321 */ 4322 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception); 4323 opacity=(Quantum) (ScaleQuantumToChar(QuantumRange)- 4324 ((ssize_t) ScaleQuantumToChar(QuantumRange)*blend)/100); 4325 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 4326 return(MagickFalse); 4327 image->alpha_trait=BlendPixelTrait; 4328 image_view=AcquireAuthenticCacheView(image,exception); 4329 for (y=0; y < (int) image->rows; y++) 4330 { 4331 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 4332 exception); 4333 if (q == (Quantum *) NULL) 4334 break; 4335 for (x=0; x < (int) image->columns; x++) 4336 { 4337 SetPixelAlpha(image,opacity,q); 4338 q+=GetPixelChannels(image); 4339 } 4340 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 4341 break; 4342 } 4343 image_view=DestroyCacheView(image_view); 4344 } 4345 /* 4346 Composite image with X Image window. 4347 */ 4348 (void) CompositeImage(image,composite_image,compose,MagickTrue, 4349 composite_info.x,composite_info.y,exception); 4350 composite_image=DestroyImage(composite_image); 4351 XSetCursorState(display,windows,MagickFalse); 4352 /* 4353 Update image configuration. 4354 */ 4355 XConfigureImageColormap(display,resource_info,windows,image,exception); 4356 (void) XConfigureImage(display,resource_info,windows,image,exception); 4357 return(MagickTrue); 4358} 4359 4360/* 4361%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4362% % 4363% % 4364% % 4365+ X C o n f i g u r e I m a g e % 4366% % 4367% % 4368% % 4369%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4370% 4371% XConfigureImage() creates a new X image. It also notifies the window 4372% manager of the new image size and configures the transient widows. 4373% 4374% The format of the XConfigureImage method is: 4375% 4376% MagickBooleanType XConfigureImage(Display *display, 4377% XResourceInfo *resource_info,XWindows *windows,Image *image, 4378% ExceptionInfo *exception) 4379% 4380% A description of each parameter follows: 4381% 4382% o display: Specifies a connection to an X server; returned from 4383% XOpenDisplay. 4384% 4385% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4386% 4387% o windows: Specifies a pointer to a XWindows structure. 4388% 4389% o image: the image. 4390% 4391% o exception: return any errors or warnings in this structure. 4392% 4393% o exception: return any errors or warnings in this structure. 4394% 4395*/ 4396static MagickBooleanType XConfigureImage(Display *display, 4397 XResourceInfo *resource_info,XWindows *windows,Image *image, 4398 ExceptionInfo *exception) 4399{ 4400 char 4401 geometry[MagickPathExtent]; 4402 4403 MagickStatusType 4404 status; 4405 4406 size_t 4407 mask, 4408 height, 4409 width; 4410 4411 ssize_t 4412 x, 4413 y; 4414 4415 XSizeHints 4416 *size_hints; 4417 4418 XWindowChanges 4419 window_changes; 4420 4421 /* 4422 Dismiss if window dimensions are zero. 4423 */ 4424 width=(unsigned int) windows->image.window_changes.width; 4425 height=(unsigned int) windows->image.window_changes.height; 4426 if (image->debug != MagickFalse ) 4427 (void) LogMagickEvent(X11Event,GetMagickModule(), 4428 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 4429 windows->image.ximage->height,(double) width,(double) height); 4430 if ((width*height) == 0) 4431 return(MagickTrue); 4432 x=0; 4433 y=0; 4434 /* 4435 Resize image to fit Image window dimensions. 4436 */ 4437 XSetCursorState(display,windows,MagickTrue); 4438 (void) XFlush(display); 4439 if (((int) width != windows->image.ximage->width) || 4440 ((int) height != windows->image.ximage->height)) 4441 image->taint=MagickTrue; 4442 windows->magnify.x=(int) 4443 width*windows->magnify.x/windows->image.ximage->width; 4444 windows->magnify.y=(int) 4445 height*windows->magnify.y/windows->image.ximage->height; 4446 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 4447 windows->image.y=(int) 4448 (height*windows->image.y/windows->image.ximage->height); 4449 status=XMakeImage(display,resource_info,&windows->image,image, 4450 (unsigned int) width,(unsigned int) height,exception); 4451 if (status == MagickFalse) 4452 XNoticeWidget(display,windows,"Unable to configure X image:", 4453 windows->image.name); 4454 /* 4455 Notify window manager of the new configuration. 4456 */ 4457 if (resource_info->image_geometry != (char *) NULL) 4458 (void) FormatLocaleString(geometry,MagickPathExtent,"%s>!", 4459 resource_info->image_geometry); 4460 else 4461 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>!", 4462 XDisplayWidth(display,windows->image.screen), 4463 XDisplayHeight(display,windows->image.screen)); 4464 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 4465 window_changes.width=(int) width; 4466 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 4467 window_changes.width=XDisplayWidth(display,windows->image.screen); 4468 window_changes.height=(int) height; 4469 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 4470 window_changes.height=XDisplayHeight(display,windows->image.screen); 4471 mask=(size_t) (CWWidth | CWHeight); 4472 if (resource_info->backdrop) 4473 { 4474 mask|=CWX | CWY; 4475 window_changes.x=(int) 4476 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 4477 window_changes.y=(int) 4478 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 4479 } 4480 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 4481 (unsigned int) mask,&window_changes); 4482 (void) XClearWindow(display,windows->image.id); 4483 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 4484 /* 4485 Update Magnify window configuration. 4486 */ 4487 if (windows->magnify.mapped != MagickFalse ) 4488 XMakeMagnifyImage(display,windows,exception); 4489 windows->pan.crop_geometry=windows->image.crop_geometry; 4490 XBestIconSize(display,&windows->pan,image); 4491 while (((windows->pan.width << 1) < MaxIconSize) && 4492 ((windows->pan.height << 1) < MaxIconSize)) 4493 { 4494 windows->pan.width<<=1; 4495 windows->pan.height<<=1; 4496 } 4497 if (windows->pan.geometry != (char *) NULL) 4498 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 4499 &windows->pan.width,&windows->pan.height); 4500 window_changes.width=(int) windows->pan.width; 4501 window_changes.height=(int) windows->pan.height; 4502 size_hints=XAllocSizeHints(); 4503 if (size_hints != (XSizeHints *) NULL) 4504 { 4505 /* 4506 Set new size hints. 4507 */ 4508 size_hints->flags=PSize | PMinSize | PMaxSize; 4509 size_hints->width=window_changes.width; 4510 size_hints->height=window_changes.height; 4511 size_hints->min_width=size_hints->width; 4512 size_hints->min_height=size_hints->height; 4513 size_hints->max_width=size_hints->width; 4514 size_hints->max_height=size_hints->height; 4515 (void) XSetNormalHints(display,windows->pan.id,size_hints); 4516 (void) XFree((void *) size_hints); 4517 } 4518 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 4519 (unsigned int) (CWWidth | CWHeight),&window_changes); 4520 /* 4521 Update icon window configuration. 4522 */ 4523 windows->icon.crop_geometry=windows->image.crop_geometry; 4524 XBestIconSize(display,&windows->icon,image); 4525 window_changes.width=(int) windows->icon.width; 4526 window_changes.height=(int) windows->icon.height; 4527 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 4528 (unsigned int) (CWWidth | CWHeight),&window_changes); 4529 XSetCursorState(display,windows,MagickFalse); 4530 return(status != 0 ? MagickTrue : MagickFalse); 4531} 4532 4533/* 4534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4535% % 4536% % 4537% % 4538+ X C r o p I m a g e % 4539% % 4540% % 4541% % 4542%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4543% 4544% XCropImage() allows the user to select a region of the image and crop, copy, 4545% or cut it. For copy or cut, the image can subsequently be composited onto 4546% the image with XPasteImage. 4547% 4548% The format of the XCropImage method is: 4549% 4550% MagickBooleanType XCropImage(Display *display, 4551% XResourceInfo *resource_info,XWindows *windows,Image *image, 4552% const ClipboardMode mode,ExceptionInfo *exception) 4553% 4554% A description of each parameter follows: 4555% 4556% o display: Specifies a connection to an X server; returned from 4557% XOpenDisplay. 4558% 4559% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4560% 4561% o windows: Specifies a pointer to a XWindows structure. 4562% 4563% o image: the image; returned from ReadImage. 4564% 4565% o mode: This unsigned value specified whether the image should be 4566% cropped, copied, or cut. 4567% 4568% o exception: return any errors or warnings in this structure. 4569% 4570*/ 4571static MagickBooleanType XCropImage(Display *display, 4572 XResourceInfo *resource_info,XWindows *windows,Image *image, 4573 const ClipboardMode mode,ExceptionInfo *exception) 4574{ 4575 static const char 4576 *CropModeMenu[] = 4577 { 4578 "Help", 4579 "Dismiss", 4580 (char *) NULL 4581 }, 4582 *RectifyModeMenu[] = 4583 { 4584 "Crop", 4585 "Help", 4586 "Dismiss", 4587 (char *) NULL 4588 }; 4589 4590 static const ModeType 4591 CropCommands[] = 4592 { 4593 CropHelpCommand, 4594 CropDismissCommand 4595 }, 4596 RectifyCommands[] = 4597 { 4598 RectifyCopyCommand, 4599 RectifyHelpCommand, 4600 RectifyDismissCommand 4601 }; 4602 4603 CacheView 4604 *image_view; 4605 4606 char 4607 command[MagickPathExtent], 4608 text[MagickPathExtent]; 4609 4610 Cursor 4611 cursor; 4612 4613 int 4614 id, 4615 x, 4616 y; 4617 4618 KeySym 4619 key_symbol; 4620 4621 Image 4622 *crop_image; 4623 4624 double 4625 scale_factor; 4626 4627 RectangleInfo 4628 crop_info, 4629 highlight_info; 4630 4631 register Quantum 4632 *q; 4633 4634 unsigned int 4635 height, 4636 width; 4637 4638 size_t 4639 state; 4640 4641 XEvent 4642 event; 4643 4644 /* 4645 Map Command widget. 4646 */ 4647 switch (mode) 4648 { 4649 case CopyMode: 4650 { 4651 (void) CloneString(&windows->command.name,"Copy"); 4652 break; 4653 } 4654 case CropMode: 4655 { 4656 (void) CloneString(&windows->command.name,"Crop"); 4657 break; 4658 } 4659 case CutMode: 4660 { 4661 (void) CloneString(&windows->command.name,"Cut"); 4662 break; 4663 } 4664 } 4665 RectifyModeMenu[0]=windows->command.name; 4666 windows->command.data=0; 4667 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 4668 (void) XMapRaised(display,windows->command.id); 4669 XClientMessage(display,windows->image.id,windows->im_protocols, 4670 windows->im_update_widget,CurrentTime); 4671 /* 4672 Track pointer until button 1 is pressed. 4673 */ 4674 XQueryPosition(display,windows->image.id,&x,&y); 4675 (void) XSelectInput(display,windows->image.id, 4676 windows->image.attributes.event_mask | PointerMotionMask); 4677 crop_info.x=(ssize_t) windows->image.x+x; 4678 crop_info.y=(ssize_t) windows->image.y+y; 4679 crop_info.width=0; 4680 crop_info.height=0; 4681 cursor=XCreateFontCursor(display,XC_fleur); 4682 state=DefaultState; 4683 do 4684 { 4685 if (windows->info.mapped != MagickFalse ) 4686 { 4687 /* 4688 Display pointer position. 4689 */ 4690 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ", 4691 (long) crop_info.x,(long) crop_info.y); 4692 XInfoWidget(display,windows,text); 4693 } 4694 /* 4695 Wait for next event. 4696 */ 4697 XScreenEvent(display,windows,&event,exception); 4698 if (event.xany.window == windows->command.id) 4699 { 4700 /* 4701 Select a command from the Command widget. 4702 */ 4703 id=XCommandWidget(display,windows,CropModeMenu,&event); 4704 if (id < 0) 4705 continue; 4706 switch (CropCommands[id]) 4707 { 4708 case CropHelpCommand: 4709 { 4710 switch (mode) 4711 { 4712 case CopyMode: 4713 { 4714 XTextViewWidget(display,resource_info,windows,MagickFalse, 4715 "Help Viewer - Image Copy",ImageCopyHelp); 4716 break; 4717 } 4718 case CropMode: 4719 { 4720 XTextViewWidget(display,resource_info,windows,MagickFalse, 4721 "Help Viewer - Image Crop",ImageCropHelp); 4722 break; 4723 } 4724 case CutMode: 4725 { 4726 XTextViewWidget(display,resource_info,windows,MagickFalse, 4727 "Help Viewer - Image Cut",ImageCutHelp); 4728 break; 4729 } 4730 } 4731 break; 4732 } 4733 case CropDismissCommand: 4734 { 4735 /* 4736 Prematurely exit. 4737 */ 4738 state|=EscapeState; 4739 state|=ExitState; 4740 break; 4741 } 4742 default: 4743 break; 4744 } 4745 continue; 4746 } 4747 switch (event.type) 4748 { 4749 case ButtonPress: 4750 { 4751 if (event.xbutton.button != Button1) 4752 break; 4753 if (event.xbutton.window != windows->image.id) 4754 break; 4755 /* 4756 Note first corner of cropping rectangle-- exit loop. 4757 */ 4758 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4759 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4760 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4761 state|=ExitState; 4762 break; 4763 } 4764 case ButtonRelease: 4765 break; 4766 case Expose: 4767 break; 4768 case KeyPress: 4769 { 4770 if (event.xkey.window != windows->image.id) 4771 break; 4772 /* 4773 Respond to a user key press. 4774 */ 4775 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 4776 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4777 switch ((int) key_symbol) 4778 { 4779 case XK_Escape: 4780 case XK_F20: 4781 { 4782 /* 4783 Prematurely exit. 4784 */ 4785 state|=EscapeState; 4786 state|=ExitState; 4787 break; 4788 } 4789 case XK_F1: 4790 case XK_Help: 4791 { 4792 switch (mode) 4793 { 4794 case CopyMode: 4795 { 4796 XTextViewWidget(display,resource_info,windows,MagickFalse, 4797 "Help Viewer - Image Copy",ImageCopyHelp); 4798 break; 4799 } 4800 case CropMode: 4801 { 4802 XTextViewWidget(display,resource_info,windows,MagickFalse, 4803 "Help Viewer - Image Crop",ImageCropHelp); 4804 break; 4805 } 4806 case CutMode: 4807 { 4808 XTextViewWidget(display,resource_info,windows,MagickFalse, 4809 "Help Viewer - Image Cut",ImageCutHelp); 4810 break; 4811 } 4812 } 4813 break; 4814 } 4815 default: 4816 { 4817 (void) XBell(display,0); 4818 break; 4819 } 4820 } 4821 break; 4822 } 4823 case MotionNotify: 4824 { 4825 if (event.xmotion.window != windows->image.id) 4826 break; 4827 /* 4828 Map and unmap Info widget as text cursor crosses its boundaries. 4829 */ 4830 x=event.xmotion.x; 4831 y=event.xmotion.y; 4832 if (windows->info.mapped != MagickFalse ) 4833 { 4834 if ((x < (int) (windows->info.x+windows->info.width)) && 4835 (y < (int) (windows->info.y+windows->info.height))) 4836 (void) XWithdrawWindow(display,windows->info.id, 4837 windows->info.screen); 4838 } 4839 else 4840 if ((x > (int) (windows->info.x+windows->info.width)) || 4841 (y > (int) (windows->info.y+windows->info.height))) 4842 (void) XMapWindow(display,windows->info.id); 4843 crop_info.x=(ssize_t) windows->image.x+x; 4844 crop_info.y=(ssize_t) windows->image.y+y; 4845 break; 4846 } 4847 default: 4848 break; 4849 } 4850 } while ((state & ExitState) == 0); 4851 (void) XSelectInput(display,windows->image.id, 4852 windows->image.attributes.event_mask); 4853 if ((state & EscapeState) != 0) 4854 { 4855 /* 4856 User want to exit without cropping. 4857 */ 4858 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4859 (void) XFreeCursor(display,cursor); 4860 return(MagickTrue); 4861 } 4862 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4863 do 4864 { 4865 /* 4866 Size rectangle as pointer moves until the mouse button is released. 4867 */ 4868 x=(int) crop_info.x; 4869 y=(int) crop_info.y; 4870 crop_info.width=0; 4871 crop_info.height=0; 4872 state=DefaultState; 4873 do 4874 { 4875 highlight_info=crop_info; 4876 highlight_info.x=crop_info.x-windows->image.x; 4877 highlight_info.y=crop_info.y-windows->image.y; 4878 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4879 { 4880 /* 4881 Display info and draw cropping rectangle. 4882 */ 4883 if (windows->info.mapped == MagickFalse) 4884 (void) XMapWindow(display,windows->info.id); 4885 (void) FormatLocaleString(text,MagickPathExtent, 4886 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4887 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4888 XInfoWidget(display,windows,text); 4889 XHighlightRectangle(display,windows->image.id, 4890 windows->image.highlight_context,&highlight_info); 4891 } 4892 else 4893 if (windows->info.mapped != MagickFalse ) 4894 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4895 /* 4896 Wait for next event. 4897 */ 4898 XScreenEvent(display,windows,&event,exception); 4899 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4900 XHighlightRectangle(display,windows->image.id, 4901 windows->image.highlight_context,&highlight_info); 4902 switch (event.type) 4903 { 4904 case ButtonPress: 4905 { 4906 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4907 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4908 break; 4909 } 4910 case ButtonRelease: 4911 { 4912 /* 4913 User has committed to cropping rectangle. 4914 */ 4915 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4916 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4917 XSetCursorState(display,windows,MagickFalse); 4918 state|=ExitState; 4919 windows->command.data=0; 4920 (void) XCommandWidget(display,windows,RectifyModeMenu, 4921 (XEvent *) NULL); 4922 break; 4923 } 4924 case Expose: 4925 break; 4926 case MotionNotify: 4927 { 4928 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 4929 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 4930 } 4931 default: 4932 break; 4933 } 4934 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 4935 ((state & ExitState) != 0)) 4936 { 4937 /* 4938 Check boundary conditions. 4939 */ 4940 if (crop_info.x < 0) 4941 crop_info.x=0; 4942 else 4943 if (crop_info.x > (ssize_t) windows->image.ximage->width) 4944 crop_info.x=(ssize_t) windows->image.ximage->width; 4945 if ((int) crop_info.x < x) 4946 crop_info.width=(unsigned int) (x-crop_info.x); 4947 else 4948 { 4949 crop_info.width=(unsigned int) (crop_info.x-x); 4950 crop_info.x=(ssize_t) x; 4951 } 4952 if (crop_info.y < 0) 4953 crop_info.y=0; 4954 else 4955 if (crop_info.y > (ssize_t) windows->image.ximage->height) 4956 crop_info.y=(ssize_t) windows->image.ximage->height; 4957 if ((int) crop_info.y < y) 4958 crop_info.height=(unsigned int) (y-crop_info.y); 4959 else 4960 { 4961 crop_info.height=(unsigned int) (crop_info.y-y); 4962 crop_info.y=(ssize_t) y; 4963 } 4964 } 4965 } while ((state & ExitState) == 0); 4966 /* 4967 Wait for user to grab a corner of the rectangle or press return. 4968 */ 4969 state=DefaultState; 4970 (void) XMapWindow(display,windows->info.id); 4971 do 4972 { 4973 if (windows->info.mapped != MagickFalse ) 4974 { 4975 /* 4976 Display pointer position. 4977 */ 4978 (void) FormatLocaleString(text,MagickPathExtent, 4979 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4980 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4981 XInfoWidget(display,windows,text); 4982 } 4983 highlight_info=crop_info; 4984 highlight_info.x=crop_info.x-windows->image.x; 4985 highlight_info.y=crop_info.y-windows->image.y; 4986 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 4987 { 4988 state|=EscapeState; 4989 state|=ExitState; 4990 break; 4991 } 4992 XHighlightRectangle(display,windows->image.id, 4993 windows->image.highlight_context,&highlight_info); 4994 XScreenEvent(display,windows,&event,exception); 4995 if (event.xany.window == windows->command.id) 4996 { 4997 /* 4998 Select a command from the Command widget. 4999 */ 5000 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5001 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 5002 (void) XSetFunction(display,windows->image.highlight_context, 5003 GXinvert); 5004 XHighlightRectangle(display,windows->image.id, 5005 windows->image.highlight_context,&highlight_info); 5006 if (id >= 0) 5007 switch (RectifyCommands[id]) 5008 { 5009 case RectifyCopyCommand: 5010 { 5011 state|=ExitState; 5012 break; 5013 } 5014 case RectifyHelpCommand: 5015 { 5016 (void) XSetFunction(display,windows->image.highlight_context, 5017 GXcopy); 5018 switch (mode) 5019 { 5020 case CopyMode: 5021 { 5022 XTextViewWidget(display,resource_info,windows,MagickFalse, 5023 "Help Viewer - Image Copy",ImageCopyHelp); 5024 break; 5025 } 5026 case CropMode: 5027 { 5028 XTextViewWidget(display,resource_info,windows,MagickFalse, 5029 "Help Viewer - Image Crop",ImageCropHelp); 5030 break; 5031 } 5032 case CutMode: 5033 { 5034 XTextViewWidget(display,resource_info,windows,MagickFalse, 5035 "Help Viewer - Image Cut",ImageCutHelp); 5036 break; 5037 } 5038 } 5039 (void) XSetFunction(display,windows->image.highlight_context, 5040 GXinvert); 5041 break; 5042 } 5043 case RectifyDismissCommand: 5044 { 5045 /* 5046 Prematurely exit. 5047 */ 5048 state|=EscapeState; 5049 state|=ExitState; 5050 break; 5051 } 5052 default: 5053 break; 5054 } 5055 continue; 5056 } 5057 XHighlightRectangle(display,windows->image.id, 5058 windows->image.highlight_context,&highlight_info); 5059 switch (event.type) 5060 { 5061 case ButtonPress: 5062 { 5063 if (event.xbutton.button != Button1) 5064 break; 5065 if (event.xbutton.window != windows->image.id) 5066 break; 5067 x=windows->image.x+event.xbutton.x; 5068 y=windows->image.y+event.xbutton.y; 5069 if ((x < (int) (crop_info.x+RoiDelta)) && 5070 (x > (int) (crop_info.x-RoiDelta)) && 5071 (y < (int) (crop_info.y+RoiDelta)) && 5072 (y > (int) (crop_info.y-RoiDelta))) 5073 { 5074 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5075 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5076 state|=UpdateConfigurationState; 5077 break; 5078 } 5079 if ((x < (int) (crop_info.x+RoiDelta)) && 5080 (x > (int) (crop_info.x-RoiDelta)) && 5081 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5082 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5083 { 5084 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5085 state|=UpdateConfigurationState; 5086 break; 5087 } 5088 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5089 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5090 (y < (int) (crop_info.y+RoiDelta)) && 5091 (y > (int) (crop_info.y-RoiDelta))) 5092 { 5093 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5094 state|=UpdateConfigurationState; 5095 break; 5096 } 5097 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5098 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5099 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5100 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5101 { 5102 state|=UpdateConfigurationState; 5103 break; 5104 } 5105 } 5106 case ButtonRelease: 5107 { 5108 if (event.xbutton.window == windows->pan.id) 5109 if ((highlight_info.x != crop_info.x-windows->image.x) || 5110 (highlight_info.y != crop_info.y-windows->image.y)) 5111 XHighlightRectangle(display,windows->image.id, 5112 windows->image.highlight_context,&highlight_info); 5113 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5114 event.xbutton.time); 5115 break; 5116 } 5117 case Expose: 5118 { 5119 if (event.xexpose.window == windows->image.id) 5120 if (event.xexpose.count == 0) 5121 { 5122 event.xexpose.x=(int) highlight_info.x; 5123 event.xexpose.y=(int) highlight_info.y; 5124 event.xexpose.width=(int) highlight_info.width; 5125 event.xexpose.height=(int) highlight_info.height; 5126 XRefreshWindow(display,&windows->image,&event); 5127 } 5128 if (event.xexpose.window == windows->info.id) 5129 if (event.xexpose.count == 0) 5130 XInfoWidget(display,windows,text); 5131 break; 5132 } 5133 case KeyPress: 5134 { 5135 if (event.xkey.window != windows->image.id) 5136 break; 5137 /* 5138 Respond to a user key press. 5139 */ 5140 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5141 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5142 switch ((int) key_symbol) 5143 { 5144 case XK_Escape: 5145 case XK_F20: 5146 state|=EscapeState; 5147 case XK_Return: 5148 { 5149 state|=ExitState; 5150 break; 5151 } 5152 case XK_Home: 5153 case XK_KP_Home: 5154 { 5155 crop_info.x=(ssize_t) (windows->image.width/2L-crop_info.width/ 5156 2L); 5157 crop_info.y=(ssize_t) (windows->image.height/2L-crop_info.height/ 5158 2L); 5159 break; 5160 } 5161 case XK_Left: 5162 case XK_KP_Left: 5163 { 5164 crop_info.x--; 5165 break; 5166 } 5167 case XK_Up: 5168 case XK_KP_Up: 5169 case XK_Next: 5170 { 5171 crop_info.y--; 5172 break; 5173 } 5174 case XK_Right: 5175 case XK_KP_Right: 5176 { 5177 crop_info.x++; 5178 break; 5179 } 5180 case XK_Prior: 5181 case XK_Down: 5182 case XK_KP_Down: 5183 { 5184 crop_info.y++; 5185 break; 5186 } 5187 case XK_F1: 5188 case XK_Help: 5189 { 5190 (void) XSetFunction(display,windows->image.highlight_context, 5191 GXcopy); 5192 switch (mode) 5193 { 5194 case CopyMode: 5195 { 5196 XTextViewWidget(display,resource_info,windows,MagickFalse, 5197 "Help Viewer - Image Copy",ImageCopyHelp); 5198 break; 5199 } 5200 case CropMode: 5201 { 5202 XTextViewWidget(display,resource_info,windows,MagickFalse, 5203 "Help Viewer - Image Cropg",ImageCropHelp); 5204 break; 5205 } 5206 case CutMode: 5207 { 5208 XTextViewWidget(display,resource_info,windows,MagickFalse, 5209 "Help Viewer - Image Cutg",ImageCutHelp); 5210 break; 5211 } 5212 } 5213 (void) XSetFunction(display,windows->image.highlight_context, 5214 GXinvert); 5215 break; 5216 } 5217 default: 5218 { 5219 (void) XBell(display,0); 5220 break; 5221 } 5222 } 5223 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5224 event.xkey.time); 5225 break; 5226 } 5227 case KeyRelease: 5228 break; 5229 case MotionNotify: 5230 { 5231 if (event.xmotion.window != windows->image.id) 5232 break; 5233 /* 5234 Map and unmap Info widget as text cursor crosses its boundaries. 5235 */ 5236 x=event.xmotion.x; 5237 y=event.xmotion.y; 5238 if (windows->info.mapped != MagickFalse ) 5239 { 5240 if ((x < (int) (windows->info.x+windows->info.width)) && 5241 (y < (int) (windows->info.y+windows->info.height))) 5242 (void) XWithdrawWindow(display,windows->info.id, 5243 windows->info.screen); 5244 } 5245 else 5246 if ((x > (int) (windows->info.x+windows->info.width)) || 5247 (y > (int) (windows->info.y+windows->info.height))) 5248 (void) XMapWindow(display,windows->info.id); 5249 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 5250 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 5251 break; 5252 } 5253 case SelectionRequest: 5254 { 5255 XSelectionEvent 5256 notify; 5257 5258 XSelectionRequestEvent 5259 *request; 5260 5261 /* 5262 Set primary selection. 5263 */ 5264 (void) FormatLocaleString(text,MagickPathExtent, 5265 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 5266 crop_info.height,(double) crop_info.x,(double) crop_info.y); 5267 request=(&(event.xselectionrequest)); 5268 (void) XChangeProperty(request->display,request->requestor, 5269 request->property,request->target,8,PropModeReplace, 5270 (unsigned char *) text,(int) strlen(text)); 5271 notify.type=SelectionNotify; 5272 notify.display=request->display; 5273 notify.requestor=request->requestor; 5274 notify.selection=request->selection; 5275 notify.target=request->target; 5276 notify.time=request->time; 5277 if (request->property == None) 5278 notify.property=request->target; 5279 else 5280 notify.property=request->property; 5281 (void) XSendEvent(request->display,request->requestor,False,0, 5282 (XEvent *) ¬ify); 5283 } 5284 default: 5285 break; 5286 } 5287 if ((state & UpdateConfigurationState) != 0) 5288 { 5289 (void) XPutBackEvent(display,&event); 5290 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5291 break; 5292 } 5293 } while ((state & ExitState) == 0); 5294 } while ((state & ExitState) == 0); 5295 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5296 XSetCursorState(display,windows,MagickFalse); 5297 if ((state & EscapeState) != 0) 5298 return(MagickTrue); 5299 if (mode == CropMode) 5300 if (((int) crop_info.width != windows->image.ximage->width) || 5301 ((int) crop_info.height != windows->image.ximage->height)) 5302 { 5303 /* 5304 Reconfigure Image window as defined by cropping rectangle. 5305 */ 5306 XSetCropGeometry(display,windows,&crop_info,image); 5307 windows->image.window_changes.width=(int) crop_info.width; 5308 windows->image.window_changes.height=(int) crop_info.height; 5309 (void) XConfigureImage(display,resource_info,windows,image,exception); 5310 return(MagickTrue); 5311 } 5312 /* 5313 Copy image before applying image transforms. 5314 */ 5315 XSetCursorState(display,windows,MagickTrue); 5316 XCheckRefreshWindows(display,windows); 5317 width=(unsigned int) image->columns; 5318 height=(unsigned int) image->rows; 5319 x=0; 5320 y=0; 5321 if (windows->image.crop_geometry != (char *) NULL) 5322 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 5323 scale_factor=(double) width/windows->image.ximage->width; 5324 crop_info.x+=x; 5325 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 5326 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 5327 scale_factor=(double) height/windows->image.ximage->height; 5328 crop_info.y+=y; 5329 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 5330 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5); 5331 crop_image=CropImage(image,&crop_info,exception); 5332 XSetCursorState(display,windows,MagickFalse); 5333 if (crop_image == (Image *) NULL) 5334 return(MagickFalse); 5335 if (resource_info->copy_image != (Image *) NULL) 5336 resource_info->copy_image=DestroyImage(resource_info->copy_image); 5337 resource_info->copy_image=crop_image; 5338 if (mode == CopyMode) 5339 { 5340 (void) XConfigureImage(display,resource_info,windows,image,exception); 5341 return(MagickTrue); 5342 } 5343 /* 5344 Cut image. 5345 */ 5346 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 5347 return(MagickFalse); 5348 image->alpha_trait=BlendPixelTrait; 5349 image_view=AcquireAuthenticCacheView(image,exception); 5350 for (y=0; y < (int) crop_info.height; y++) 5351 { 5352 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y, 5353 crop_info.width,1,exception); 5354 if (q == (Quantum *) NULL) 5355 break; 5356 for (x=0; x < (int) crop_info.width; x++) 5357 { 5358 SetPixelAlpha(image,TransparentAlpha,q); 5359 q+=GetPixelChannels(image); 5360 } 5361 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 5362 break; 5363 } 5364 image_view=DestroyCacheView(image_view); 5365 /* 5366 Update image configuration. 5367 */ 5368 XConfigureImageColormap(display,resource_info,windows,image,exception); 5369 (void) XConfigureImage(display,resource_info,windows,image,exception); 5370 return(MagickTrue); 5371} 5372 5373/* 5374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5375% % 5376% % 5377% % 5378+ X D r a w I m a g e % 5379% % 5380% % 5381% % 5382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5383% 5384% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on 5385% the image. 5386% 5387% The format of the XDrawEditImage method is: 5388% 5389% MagickBooleanType XDrawEditImage(Display *display, 5390% XResourceInfo *resource_info,XWindows *windows,Image **image, 5391% ExceptionInfo *exception) 5392% 5393% A description of each parameter follows: 5394% 5395% o display: Specifies a connection to an X server; returned from 5396% XOpenDisplay. 5397% 5398% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 5399% 5400% o windows: Specifies a pointer to a XWindows structure. 5401% 5402% o image: the image. 5403% 5404% o exception: return any errors or warnings in this structure. 5405% 5406*/ 5407static MagickBooleanType XDrawEditImage(Display *display, 5408 XResourceInfo *resource_info,XWindows *windows,Image **image, 5409 ExceptionInfo *exception) 5410{ 5411 static const char 5412 *DrawMenu[] = 5413 { 5414 "Element", 5415 "Color", 5416 "Stipple", 5417 "Width", 5418 "Undo", 5419 "Help", 5420 "Dismiss", 5421 (char *) NULL 5422 }; 5423 5424 static ElementType 5425 element = PointElement; 5426 5427 static const ModeType 5428 DrawCommands[] = 5429 { 5430 DrawElementCommand, 5431 DrawColorCommand, 5432 DrawStippleCommand, 5433 DrawWidthCommand, 5434 DrawUndoCommand, 5435 DrawHelpCommand, 5436 DrawDismissCommand 5437 }; 5438 5439 static Pixmap 5440 stipple = (Pixmap) NULL; 5441 5442 static unsigned int 5443 pen_id = 0, 5444 line_width = 1; 5445 5446 char 5447 command[MagickPathExtent], 5448 text[MagickPathExtent]; 5449 5450 Cursor 5451 cursor; 5452 5453 int 5454 entry, 5455 id, 5456 number_coordinates, 5457 x, 5458 y; 5459 5460 double 5461 degrees; 5462 5463 MagickStatusType 5464 status; 5465 5466 RectangleInfo 5467 rectangle_info; 5468 5469 register int 5470 i; 5471 5472 unsigned int 5473 distance, 5474 height, 5475 max_coordinates, 5476 width; 5477 5478 size_t 5479 state; 5480 5481 Window 5482 root_window; 5483 5484 XDrawInfo 5485 draw_info; 5486 5487 XEvent 5488 event; 5489 5490 XPoint 5491 *coordinate_info; 5492 5493 XSegment 5494 line_info; 5495 5496 /* 5497 Allocate polygon info. 5498 */ 5499 max_coordinates=2048; 5500 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates, 5501 sizeof(*coordinate_info)); 5502 if (coordinate_info == (XPoint *) NULL) 5503 { 5504 (void) ThrowMagickException(exception,GetMagickModule(), 5505 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 5506 return(MagickFalse); 5507 } 5508 /* 5509 Map Command widget. 5510 */ 5511 (void) CloneString(&windows->command.name,"Draw"); 5512 windows->command.data=4; 5513 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL); 5514 (void) XMapRaised(display,windows->command.id); 5515 XClientMessage(display,windows->image.id,windows->im_protocols, 5516 windows->im_update_widget,CurrentTime); 5517 /* 5518 Wait for first button press. 5519 */ 5520 root_window=XRootWindow(display,XDefaultScreen(display)); 5521 draw_info.stencil=OpaqueStencil; 5522 status=MagickTrue; 5523 cursor=XCreateFontCursor(display,XC_tcross); 5524 for ( ; ; ) 5525 { 5526 XQueryPosition(display,windows->image.id,&x,&y); 5527 (void) XSelectInput(display,windows->image.id, 5528 windows->image.attributes.event_mask | PointerMotionMask); 5529 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5530 state=DefaultState; 5531 do 5532 { 5533 if (windows->info.mapped != MagickFalse ) 5534 { 5535 /* 5536 Display pointer position. 5537 */ 5538 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ", 5539 x+windows->image.x,y+windows->image.y); 5540 XInfoWidget(display,windows,text); 5541 } 5542 /* 5543 Wait for next event. 5544 */ 5545 XScreenEvent(display,windows,&event,exception); 5546 if (event.xany.window == windows->command.id) 5547 { 5548 /* 5549 Select a command from the Command widget. 5550 */ 5551 id=XCommandWidget(display,windows,DrawMenu,&event); 5552 if (id < 0) 5553 continue; 5554 switch (DrawCommands[id]) 5555 { 5556 case DrawElementCommand: 5557 { 5558 static const char 5559 *Elements[] = 5560 { 5561 "point", 5562 "line", 5563 "rectangle", 5564 "fill rectangle", 5565 "circle", 5566 "fill circle", 5567 "ellipse", 5568 "fill ellipse", 5569 "polygon", 5570 "fill polygon", 5571 (char *) NULL, 5572 }; 5573 5574 /* 5575 Select a command from the pop-up menu. 5576 */ 5577 element=(ElementType) (XMenuWidget(display,windows, 5578 DrawMenu[id],Elements,command)+1); 5579 break; 5580 } 5581 case DrawColorCommand: 5582 { 5583 const char 5584 *ColorMenu[MaxNumberPens+1]; 5585 5586 int 5587 pen_number; 5588 5589 MagickBooleanType 5590 transparent; 5591 5592 XColor 5593 color; 5594 5595 /* 5596 Initialize menu selections. 5597 */ 5598 for (i=0; i < (int) (MaxNumberPens-2); i++) 5599 ColorMenu[i]=resource_info->pen_colors[i]; 5600 ColorMenu[MaxNumberPens-2]="transparent"; 5601 ColorMenu[MaxNumberPens-1]="Browser..."; 5602 ColorMenu[MaxNumberPens]=(char *) NULL; 5603 /* 5604 Select a pen color from the pop-up menu. 5605 */ 5606 pen_number=XMenuWidget(display,windows,DrawMenu[id], 5607 (const char **) ColorMenu,command); 5608 if (pen_number < 0) 5609 break; 5610 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue : 5611 MagickFalse; 5612 if (transparent != MagickFalse ) 5613 { 5614 draw_info.stencil=TransparentStencil; 5615 break; 5616 } 5617 if (pen_number == (MaxNumberPens-1)) 5618 { 5619 static char 5620 color_name[MagickPathExtent] = "gray"; 5621 5622 /* 5623 Select a pen color from a dialog. 5624 */ 5625 resource_info->pen_colors[pen_number]=color_name; 5626 XColorBrowserWidget(display,windows,"Select",color_name); 5627 if (*color_name == '\0') 5628 break; 5629 } 5630 /* 5631 Set pen color. 5632 */ 5633 (void) XParseColor(display,windows->map_info->colormap, 5634 resource_info->pen_colors[pen_number],&color); 5635 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 5636 (unsigned int) MaxColors,&color); 5637 windows->pixel_info->pen_colors[pen_number]=color; 5638 pen_id=(unsigned int) pen_number; 5639 draw_info.stencil=OpaqueStencil; 5640 break; 5641 } 5642 case DrawStippleCommand: 5643 { 5644 Image 5645 *stipple_image; 5646 5647 ImageInfo 5648 *image_info; 5649 5650 int 5651 status; 5652 5653 static char 5654 filename[MagickPathExtent] = "\0"; 5655 5656 static const char 5657 *StipplesMenu[] = 5658 { 5659 "Brick", 5660 "Diagonal", 5661 "Scales", 5662 "Vertical", 5663 "Wavy", 5664 "Translucent", 5665 "Opaque", 5666 (char *) NULL, 5667 (char *) NULL, 5668 }; 5669 5670 /* 5671 Select a command from the pop-up menu. 5672 */ 5673 StipplesMenu[7]="Open..."; 5674 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu, 5675 command); 5676 if (entry < 0) 5677 break; 5678 if (stipple != (Pixmap) NULL) 5679 (void) XFreePixmap(display,stipple); 5680 stipple=(Pixmap) NULL; 5681 if (entry != 7) 5682 { 5683 switch (entry) 5684 { 5685 case 0: 5686 { 5687 stipple=XCreateBitmapFromData(display,root_window, 5688 (char *) BricksBitmap,BricksWidth,BricksHeight); 5689 break; 5690 } 5691 case 1: 5692 { 5693 stipple=XCreateBitmapFromData(display,root_window, 5694 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight); 5695 break; 5696 } 5697 case 2: 5698 { 5699 stipple=XCreateBitmapFromData(display,root_window, 5700 (char *) ScalesBitmap,ScalesWidth,ScalesHeight); 5701 break; 5702 } 5703 case 3: 5704 { 5705 stipple=XCreateBitmapFromData(display,root_window, 5706 (char *) VerticalBitmap,VerticalWidth,VerticalHeight); 5707 break; 5708 } 5709 case 4: 5710 { 5711 stipple=XCreateBitmapFromData(display,root_window, 5712 (char *) WavyBitmap,WavyWidth,WavyHeight); 5713 break; 5714 } 5715 case 5: 5716 { 5717 stipple=XCreateBitmapFromData(display,root_window, 5718 (char *) HighlightBitmap,HighlightWidth, 5719 HighlightHeight); 5720 break; 5721 } 5722 case 6: 5723 default: 5724 { 5725 stipple=XCreateBitmapFromData(display,root_window, 5726 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight); 5727 break; 5728 } 5729 } 5730 break; 5731 } 5732 XFileBrowserWidget(display,windows,"Stipple",filename); 5733 if (*filename == '\0') 5734 break; 5735 /* 5736 Read image. 5737 */ 5738 XSetCursorState(display,windows,MagickTrue); 5739 XCheckRefreshWindows(display,windows); 5740 image_info=AcquireImageInfo(); 5741 (void) CopyMagickString(image_info->filename,filename, 5742 MagickPathExtent); 5743 stipple_image=ReadImage(image_info,exception); 5744 CatchException(exception); 5745 XSetCursorState(display,windows,MagickFalse); 5746 if (stipple_image == (Image *) NULL) 5747 break; 5748 (void) AcquireUniqueFileResource(filename); 5749 (void) FormatLocaleString(stipple_image->filename,MagickPathExtent, 5750 "xbm:%s",filename); 5751 (void) WriteImage(image_info,stipple_image,exception); 5752 stipple_image=DestroyImage(stipple_image); 5753 image_info=DestroyImageInfo(image_info); 5754 status=XReadBitmapFile(display,root_window,filename,&width, 5755 &height,&stipple,&x,&y); 5756 (void) RelinquishUniqueFileResource(filename); 5757 if ((status != BitmapSuccess) != 0) 5758 XNoticeWidget(display,windows,"Unable to read X bitmap image:", 5759 filename); 5760 break; 5761 } 5762 case DrawWidthCommand: 5763 { 5764 static char 5765 width[MagickPathExtent] = "0"; 5766 5767 static const char 5768 *WidthsMenu[] = 5769 { 5770 "1", 5771 "2", 5772 "4", 5773 "8", 5774 "16", 5775 "Dialog...", 5776 (char *) NULL, 5777 }; 5778 5779 /* 5780 Select a command from the pop-up menu. 5781 */ 5782 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu, 5783 command); 5784 if (entry < 0) 5785 break; 5786 if (entry != 5) 5787 { 5788 line_width=(unsigned int) StringToUnsignedLong( 5789 WidthsMenu[entry]); 5790 break; 5791 } 5792 (void) XDialogWidget(display,windows,"Ok","Enter line width:", 5793 width); 5794 if (*width == '\0') 5795 break; 5796 line_width=(unsigned int) StringToUnsignedLong(width); 5797 break; 5798 } 5799 case DrawUndoCommand: 5800 { 5801 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 5802 image,exception); 5803 break; 5804 } 5805 case DrawHelpCommand: 5806 { 5807 XTextViewWidget(display,resource_info,windows,MagickFalse, 5808 "Help Viewer - Image Rotation",ImageDrawHelp); 5809 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5810 break; 5811 } 5812 case DrawDismissCommand: 5813 { 5814 /* 5815 Prematurely exit. 5816 */ 5817 state|=EscapeState; 5818 state|=ExitState; 5819 break; 5820 } 5821 default: 5822 break; 5823 } 5824 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5825 continue; 5826 } 5827 switch (event.type) 5828 { 5829 case ButtonPress: 5830 { 5831 if (event.xbutton.button != Button1) 5832 break; 5833 if (event.xbutton.window != windows->image.id) 5834 break; 5835 /* 5836 exit loop. 5837 */ 5838 x=event.xbutton.x; 5839 y=event.xbutton.y; 5840 state|=ExitState; 5841 break; 5842 } 5843 case ButtonRelease: 5844 break; 5845 case Expose: 5846 break; 5847 case KeyPress: 5848 { 5849 KeySym 5850 key_symbol; 5851 5852 if (event.xkey.window != windows->image.id) 5853 break; 5854 /* 5855 Respond to a user key press. 5856 */ 5857 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5858 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5859 switch ((int) key_symbol) 5860 { 5861 case XK_Escape: 5862 case XK_F20: 5863 { 5864 /* 5865 Prematurely exit. 5866 */ 5867 state|=EscapeState; 5868 state|=ExitState; 5869 break; 5870 } 5871 case XK_F1: 5872 case XK_Help: 5873 { 5874 XTextViewWidget(display,resource_info,windows,MagickFalse, 5875 "Help Viewer - Image Rotation",ImageDrawHelp); 5876 break; 5877 } 5878 default: 5879 { 5880 (void) XBell(display,0); 5881 break; 5882 } 5883 } 5884 break; 5885 } 5886 case MotionNotify: 5887 { 5888 /* 5889 Map and unmap Info widget as text cursor crosses its boundaries. 5890 */ 5891 x=event.xmotion.x; 5892 y=event.xmotion.y; 5893 if (windows->info.mapped != MagickFalse ) 5894 { 5895 if ((x < (int) (windows->info.x+windows->info.width)) && 5896 (y < (int) (windows->info.y+windows->info.height))) 5897 (void) XWithdrawWindow(display,windows->info.id, 5898 windows->info.screen); 5899 } 5900 else 5901 if ((x > (int) (windows->info.x+windows->info.width)) || 5902 (y > (int) (windows->info.y+windows->info.height))) 5903 (void) XMapWindow(display,windows->info.id); 5904 break; 5905 } 5906 } 5907 } while ((state & ExitState) == 0); 5908 (void) XSelectInput(display,windows->image.id, 5909 windows->image.attributes.event_mask); 5910 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 5911 if ((state & EscapeState) != 0) 5912 break; 5913 /* 5914 Draw element as pointer moves until the button is released. 5915 */ 5916 distance=0; 5917 degrees=0.0; 5918 line_info.x1=x; 5919 line_info.y1=y; 5920 line_info.x2=x; 5921 line_info.y2=y; 5922 rectangle_info.x=(ssize_t) x; 5923 rectangle_info.y=(ssize_t) y; 5924 rectangle_info.width=0; 5925 rectangle_info.height=0; 5926 number_coordinates=1; 5927 coordinate_info->x=x; 5928 coordinate_info->y=y; 5929 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 5930 state=DefaultState; 5931 do 5932 { 5933 switch (element) 5934 { 5935 case PointElement: 5936 default: 5937 { 5938 if (number_coordinates > 1) 5939 { 5940 (void) XDrawLines(display,windows->image.id, 5941 windows->image.highlight_context,coordinate_info, 5942 number_coordinates,CoordModeOrigin); 5943 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d", 5944 coordinate_info[number_coordinates-1].x, 5945 coordinate_info[number_coordinates-1].y); 5946 XInfoWidget(display,windows,text); 5947 } 5948 break; 5949 } 5950 case LineElement: 5951 { 5952 if (distance > 9) 5953 { 5954 /* 5955 Display angle of the line. 5956 */ 5957 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 5958 line_info.y1),(double) (line_info.x2-line_info.x1))); 5959 (void) FormatLocaleString(text,MagickPathExtent," %g", 5960 (double) degrees); 5961 XInfoWidget(display,windows,text); 5962 XHighlightLine(display,windows->image.id, 5963 windows->image.highlight_context,&line_info); 5964 } 5965 else 5966 if (windows->info.mapped != MagickFalse ) 5967 (void) XWithdrawWindow(display,windows->info.id, 5968 windows->info.screen); 5969 break; 5970 } 5971 case RectangleElement: 5972 case FillRectangleElement: 5973 { 5974 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5975 { 5976 /* 5977 Display info and draw drawing rectangle. 5978 */ 5979 (void) FormatLocaleString(text,MagickPathExtent, 5980 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5981 (double) rectangle_info.height,(double) rectangle_info.x, 5982 (double) rectangle_info.y); 5983 XInfoWidget(display,windows,text); 5984 XHighlightRectangle(display,windows->image.id, 5985 windows->image.highlight_context,&rectangle_info); 5986 } 5987 else 5988 if (windows->info.mapped != MagickFalse ) 5989 (void) XWithdrawWindow(display,windows->info.id, 5990 windows->info.screen); 5991 break; 5992 } 5993 case CircleElement: 5994 case FillCircleElement: 5995 case EllipseElement: 5996 case FillEllipseElement: 5997 { 5998 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5999 { 6000 /* 6001 Display info and draw drawing rectangle. 6002 */ 6003 (void) FormatLocaleString(text,MagickPathExtent, 6004 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 6005 (double) rectangle_info.height,(double) rectangle_info.x, 6006 (double) rectangle_info.y); 6007 XInfoWidget(display,windows,text); 6008 XHighlightEllipse(display,windows->image.id, 6009 windows->image.highlight_context,&rectangle_info); 6010 } 6011 else 6012 if (windows->info.mapped != MagickFalse ) 6013 (void) XWithdrawWindow(display,windows->info.id, 6014 windows->info.screen); 6015 break; 6016 } 6017 case PolygonElement: 6018 case FillPolygonElement: 6019 { 6020 if (number_coordinates > 1) 6021 (void) XDrawLines(display,windows->image.id, 6022 windows->image.highlight_context,coordinate_info, 6023 number_coordinates,CoordModeOrigin); 6024 if (distance > 9) 6025 { 6026 /* 6027 Display angle of the line. 6028 */ 6029 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 6030 line_info.y1),(double) (line_info.x2-line_info.x1))); 6031 (void) FormatLocaleString(text,MagickPathExtent," %g", 6032 (double) degrees); 6033 XInfoWidget(display,windows,text); 6034 XHighlightLine(display,windows->image.id, 6035 windows->image.highlight_context,&line_info); 6036 } 6037 else 6038 if (windows->info.mapped != MagickFalse ) 6039 (void) XWithdrawWindow(display,windows->info.id, 6040 windows->info.screen); 6041 break; 6042 } 6043 } 6044 /* 6045 Wait for next event. 6046 */ 6047 XScreenEvent(display,windows,&event,exception); 6048 switch (element) 6049 { 6050 case PointElement: 6051 default: 6052 { 6053 if (number_coordinates > 1) 6054 (void) XDrawLines(display,windows->image.id, 6055 windows->image.highlight_context,coordinate_info, 6056 number_coordinates,CoordModeOrigin); 6057 break; 6058 } 6059 case LineElement: 6060 { 6061 if (distance > 9) 6062 XHighlightLine(display,windows->image.id, 6063 windows->image.highlight_context,&line_info); 6064 break; 6065 } 6066 case RectangleElement: 6067 case FillRectangleElement: 6068 { 6069 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6070 XHighlightRectangle(display,windows->image.id, 6071 windows->image.highlight_context,&rectangle_info); 6072 break; 6073 } 6074 case CircleElement: 6075 case FillCircleElement: 6076 case EllipseElement: 6077 case FillEllipseElement: 6078 { 6079 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6080 XHighlightEllipse(display,windows->image.id, 6081 windows->image.highlight_context,&rectangle_info); 6082 break; 6083 } 6084 case PolygonElement: 6085 case FillPolygonElement: 6086 { 6087 if (number_coordinates > 1) 6088 (void) XDrawLines(display,windows->image.id, 6089 windows->image.highlight_context,coordinate_info, 6090 number_coordinates,CoordModeOrigin); 6091 if (distance > 9) 6092 XHighlightLine(display,windows->image.id, 6093 windows->image.highlight_context,&line_info); 6094 break; 6095 } 6096 } 6097 switch (event.type) 6098 { 6099 case ButtonPress: 6100 break; 6101 case ButtonRelease: 6102 { 6103 /* 6104 User has committed to element. 6105 */ 6106 line_info.x2=event.xbutton.x; 6107 line_info.y2=event.xbutton.y; 6108 rectangle_info.x=(ssize_t) event.xbutton.x; 6109 rectangle_info.y=(ssize_t) event.xbutton.y; 6110 coordinate_info[number_coordinates].x=event.xbutton.x; 6111 coordinate_info[number_coordinates].y=event.xbutton.y; 6112 if (((element != PolygonElement) && 6113 (element != FillPolygonElement)) || (distance <= 9)) 6114 { 6115 state|=ExitState; 6116 break; 6117 } 6118 number_coordinates++; 6119 if (number_coordinates < (int) max_coordinates) 6120 { 6121 line_info.x1=event.xbutton.x; 6122 line_info.y1=event.xbutton.y; 6123 break; 6124 } 6125 max_coordinates<<=1; 6126 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6127 max_coordinates,sizeof(*coordinate_info)); 6128 if (coordinate_info == (XPoint *) NULL) 6129 (void) ThrowMagickException(exception,GetMagickModule(), 6130 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6131 break; 6132 } 6133 case Expose: 6134 break; 6135 case MotionNotify: 6136 { 6137 if (event.xmotion.window != windows->image.id) 6138 break; 6139 if (element != PointElement) 6140 { 6141 line_info.x2=event.xmotion.x; 6142 line_info.y2=event.xmotion.y; 6143 rectangle_info.x=(ssize_t) event.xmotion.x; 6144 rectangle_info.y=(ssize_t) event.xmotion.y; 6145 break; 6146 } 6147 coordinate_info[number_coordinates].x=event.xbutton.x; 6148 coordinate_info[number_coordinates].y=event.xbutton.y; 6149 number_coordinates++; 6150 if (number_coordinates < (int) max_coordinates) 6151 break; 6152 max_coordinates<<=1; 6153 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6154 max_coordinates,sizeof(*coordinate_info)); 6155 if (coordinate_info == (XPoint *) NULL) 6156 (void) ThrowMagickException(exception,GetMagickModule(), 6157 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6158 break; 6159 } 6160 default: 6161 break; 6162 } 6163 /* 6164 Check boundary conditions. 6165 */ 6166 if (line_info.x2 < 0) 6167 line_info.x2=0; 6168 else 6169 if (line_info.x2 > (int) windows->image.width) 6170 line_info.x2=(short) windows->image.width; 6171 if (line_info.y2 < 0) 6172 line_info.y2=0; 6173 else 6174 if (line_info.y2 > (int) windows->image.height) 6175 line_info.y2=(short) windows->image.height; 6176 distance=(unsigned int) 6177 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+ 6178 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1))); 6179 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) || 6180 ((state & ExitState) != 0)) 6181 { 6182 if (rectangle_info.x < 0) 6183 rectangle_info.x=0; 6184 else 6185 if (rectangle_info.x > (ssize_t) windows->image.width) 6186 rectangle_info.x=(ssize_t) windows->image.width; 6187 if ((int) rectangle_info.x < x) 6188 rectangle_info.width=(unsigned int) (x-rectangle_info.x); 6189 else 6190 { 6191 rectangle_info.width=(unsigned int) (rectangle_info.x-x); 6192 rectangle_info.x=(ssize_t) x; 6193 } 6194 if (rectangle_info.y < 0) 6195 rectangle_info.y=0; 6196 else 6197 if (rectangle_info.y > (ssize_t) windows->image.height) 6198 rectangle_info.y=(ssize_t) windows->image.height; 6199 if ((int) rectangle_info.y < y) 6200 rectangle_info.height=(unsigned int) (y-rectangle_info.y); 6201 else 6202 { 6203 rectangle_info.height=(unsigned int) (rectangle_info.y-y); 6204 rectangle_info.y=(ssize_t) y; 6205 } 6206 } 6207 } while ((state & ExitState) == 0); 6208 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 6209 if ((element == PointElement) || (element == PolygonElement) || 6210 (element == FillPolygonElement)) 6211 { 6212 /* 6213 Determine polygon bounding box. 6214 */ 6215 rectangle_info.x=(ssize_t) coordinate_info->x; 6216 rectangle_info.y=(ssize_t) coordinate_info->y; 6217 x=coordinate_info->x; 6218 y=coordinate_info->y; 6219 for (i=1; i < number_coordinates; i++) 6220 { 6221 if (coordinate_info[i].x > x) 6222 x=coordinate_info[i].x; 6223 if (coordinate_info[i].y > y) 6224 y=coordinate_info[i].y; 6225 if ((ssize_t) coordinate_info[i].x < rectangle_info.x) 6226 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0); 6227 if ((ssize_t) coordinate_info[i].y < rectangle_info.y) 6228 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0); 6229 } 6230 rectangle_info.width=(size_t) (x-rectangle_info.x); 6231 rectangle_info.height=(size_t) (y-rectangle_info.y); 6232 for (i=0; i < number_coordinates; i++) 6233 { 6234 coordinate_info[i].x-=rectangle_info.x; 6235 coordinate_info[i].y-=rectangle_info.y; 6236 } 6237 } 6238 else 6239 if (distance <= 9) 6240 continue; 6241 else 6242 if ((element == RectangleElement) || 6243 (element == CircleElement) || (element == EllipseElement)) 6244 { 6245 rectangle_info.width--; 6246 rectangle_info.height--; 6247 } 6248 /* 6249 Drawing is relative to image configuration. 6250 */ 6251 draw_info.x=(int) rectangle_info.x; 6252 draw_info.y=(int) rectangle_info.y; 6253 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand, 6254 image,exception); 6255 width=(unsigned int) (*image)->columns; 6256 height=(unsigned int) (*image)->rows; 6257 x=0; 6258 y=0; 6259 if (windows->image.crop_geometry != (char *) NULL) 6260 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 6261 draw_info.x+=windows->image.x-(line_width/2); 6262 if (draw_info.x < 0) 6263 draw_info.x=0; 6264 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width); 6265 draw_info.y+=windows->image.y-(line_width/2); 6266 if (draw_info.y < 0) 6267 draw_info.y=0; 6268 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height; 6269 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1); 6270 if (draw_info.width > (unsigned int) (*image)->columns) 6271 draw_info.width=(unsigned int) (*image)->columns; 6272 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1); 6273 if (draw_info.height > (unsigned int) (*image)->rows) 6274 draw_info.height=(unsigned int) (*image)->rows; 6275 (void) FormatLocaleString(draw_info.geometry,MagickPathExtent,"%ux%u%+d%+d", 6276 width*draw_info.width/windows->image.ximage->width, 6277 height*draw_info.height/windows->image.ximage->height, 6278 draw_info.x+x,draw_info.y+y); 6279 /* 6280 Initialize drawing attributes. 6281 */ 6282 draw_info.degrees=0.0; 6283 draw_info.element=element; 6284 draw_info.stipple=stipple; 6285 draw_info.line_width=line_width; 6286 draw_info.line_info=line_info; 6287 if (line_info.x1 > (int) (line_width/2)) 6288 draw_info.line_info.x1=(short) line_width/2; 6289 if (line_info.y1 > (int) (line_width/2)) 6290 draw_info.line_info.y1=(short) line_width/2; 6291 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2)); 6292 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2)); 6293 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0)) 6294 { 6295 draw_info.line_info.x2=(-draw_info.line_info.x2); 6296 draw_info.line_info.y2=(-draw_info.line_info.y2); 6297 } 6298 if (draw_info.line_info.x2 < 0) 6299 { 6300 draw_info.line_info.x2=(-draw_info.line_info.x2); 6301 Swap(draw_info.line_info.x1,draw_info.line_info.x2); 6302 } 6303 if (draw_info.line_info.y2 < 0) 6304 { 6305 draw_info.line_info.y2=(-draw_info.line_info.y2); 6306 Swap(draw_info.line_info.y1,draw_info.line_info.y2); 6307 } 6308 draw_info.rectangle_info=rectangle_info; 6309 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2)) 6310 draw_info.rectangle_info.x=(ssize_t) line_width/2; 6311 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2)) 6312 draw_info.rectangle_info.y=(ssize_t) line_width/2; 6313 draw_info.number_coordinates=(unsigned int) number_coordinates; 6314 draw_info.coordinate_info=coordinate_info; 6315 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 6316 /* 6317 Draw element on image. 6318 */ 6319 XSetCursorState(display,windows,MagickTrue); 6320 XCheckRefreshWindows(display,windows); 6321 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception); 6322 XSetCursorState(display,windows,MagickFalse); 6323 /* 6324 Update image colormap and return to image drawing. 6325 */ 6326 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6327 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6328 } 6329 XSetCursorState(display,windows,MagickFalse); 6330 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info); 6331 return(status != 0 ? MagickTrue : MagickFalse); 6332} 6333 6334/* 6335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6336% % 6337% % 6338% % 6339+ X D r a w P a n R e c t a n g l e % 6340% % 6341% % 6342% % 6343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6344% 6345% XDrawPanRectangle() draws a rectangle in the pan window. The pan window 6346% displays a zoom image and the rectangle shows which portion of the image is 6347% displayed in the Image window. 6348% 6349% The format of the XDrawPanRectangle method is: 6350% 6351% XDrawPanRectangle(Display *display,XWindows *windows) 6352% 6353% A description of each parameter follows: 6354% 6355% o display: Specifies a connection to an X server; returned from 6356% XOpenDisplay. 6357% 6358% o windows: Specifies a pointer to a XWindows structure. 6359% 6360*/ 6361static void XDrawPanRectangle(Display *display,XWindows *windows) 6362{ 6363 double 6364 scale_factor; 6365 6366 RectangleInfo 6367 highlight_info; 6368 6369 /* 6370 Determine dimensions of the panning rectangle. 6371 */ 6372 scale_factor=(double) windows->pan.width/windows->image.ximage->width; 6373 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5); 6374 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5); 6375 scale_factor=(double) 6376 windows->pan.height/windows->image.ximage->height; 6377 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5); 6378 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5); 6379 /* 6380 Display the panning rectangle. 6381 */ 6382 (void) XClearWindow(display,windows->pan.id); 6383 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context, 6384 &highlight_info); 6385} 6386 6387/* 6388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6389% % 6390% % 6391% % 6392+ X I m a g e C a c h e % 6393% % 6394% % 6395% % 6396%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6397% 6398% XImageCache() handles the creation, manipulation, and destruction of the 6399% image cache (undo and redo buffers). 6400% 6401% The format of the XImageCache method is: 6402% 6403% void XImageCache(Display *display,XResourceInfo *resource_info, 6404% XWindows *windows,const CommandType command,Image **image, 6405% ExceptionInfo *exception) 6406% 6407% A description of each parameter follows: 6408% 6409% o display: Specifies a connection to an X server; returned from 6410% XOpenDisplay. 6411% 6412% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6413% 6414% o windows: Specifies a pointer to a XWindows structure. 6415% 6416% o command: Specifies a command to perform. 6417% 6418% o image: the image; XImageCache may transform the image and return a new 6419% image pointer. 6420% 6421% o exception: return any errors or warnings in this structure. 6422% 6423*/ 6424static void XImageCache(Display *display,XResourceInfo *resource_info, 6425 XWindows *windows,const CommandType command,Image **image, 6426 ExceptionInfo *exception) 6427{ 6428 Image 6429 *cache_image; 6430 6431 static Image 6432 *redo_image = (Image *) NULL, 6433 *undo_image = (Image *) NULL; 6434 6435 switch (command) 6436 { 6437 case FreeBuffersCommand: 6438 { 6439 /* 6440 Free memory from the undo and redo cache. 6441 */ 6442 while (undo_image != (Image *) NULL) 6443 { 6444 cache_image=undo_image; 6445 undo_image=GetPreviousImageInList(undo_image); 6446 cache_image->list=DestroyImage(cache_image->list); 6447 cache_image=DestroyImage(cache_image); 6448 } 6449 undo_image=NewImageList(); 6450 if (redo_image != (Image *) NULL) 6451 redo_image=DestroyImage(redo_image); 6452 redo_image=NewImageList(); 6453 return; 6454 } 6455 case UndoCommand: 6456 { 6457 char 6458 image_geometry[MagickPathExtent]; 6459 6460 /* 6461 Undo the last image transformation. 6462 */ 6463 if (undo_image == (Image *) NULL) 6464 { 6465 (void) XBell(display,0); 6466 return; 6467 } 6468 cache_image=undo_image; 6469 undo_image=GetPreviousImageInList(undo_image); 6470 windows->image.window_changes.width=(int) cache_image->columns; 6471 windows->image.window_changes.height=(int) cache_image->rows; 6472 (void) FormatLocaleString(image_geometry,MagickPathExtent,"%dx%d!", 6473 windows->image.ximage->width,windows->image.ximage->height); 6474 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 6475 exception); 6476 if (windows->image.crop_geometry != (char *) NULL) 6477 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 6478 windows->image.crop_geometry); 6479 windows->image.crop_geometry=cache_image->geometry; 6480 if (redo_image != (Image *) NULL) 6481 redo_image=DestroyImage(redo_image); 6482 redo_image=(*image); 6483 *image=cache_image->list; 6484 cache_image=DestroyImage(cache_image); 6485 if (windows->image.orphan != MagickFalse ) 6486 return; 6487 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6488 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6489 return; 6490 } 6491 case CutCommand: 6492 case PasteCommand: 6493 case ApplyCommand: 6494 case HalfSizeCommand: 6495 case OriginalSizeCommand: 6496 case DoubleSizeCommand: 6497 case ResizeCommand: 6498 case TrimCommand: 6499 case CropCommand: 6500 case ChopCommand: 6501 case FlipCommand: 6502 case FlopCommand: 6503 case RotateRightCommand: 6504 case RotateLeftCommand: 6505 case RotateCommand: 6506 case ShearCommand: 6507 case RollCommand: 6508 case NegateCommand: 6509 case ContrastStretchCommand: 6510 case SigmoidalContrastCommand: 6511 case NormalizeCommand: 6512 case EqualizeCommand: 6513 case HueCommand: 6514 case SaturationCommand: 6515 case BrightnessCommand: 6516 case GammaCommand: 6517 case SpiffCommand: 6518 case DullCommand: 6519 case GrayscaleCommand: 6520 case MapCommand: 6521 case QuantizeCommand: 6522 case DespeckleCommand: 6523 case EmbossCommand: 6524 case ReduceNoiseCommand: 6525 case AddNoiseCommand: 6526 case SharpenCommand: 6527 case BlurCommand: 6528 case ThresholdCommand: 6529 case EdgeDetectCommand: 6530 case SpreadCommand: 6531 case ShadeCommand: 6532 case RaiseCommand: 6533 case SegmentCommand: 6534 case SolarizeCommand: 6535 case SepiaToneCommand: 6536 case SwirlCommand: 6537 case ImplodeCommand: 6538 case VignetteCommand: 6539 case WaveCommand: 6540 case OilPaintCommand: 6541 case CharcoalDrawCommand: 6542 case AnnotateCommand: 6543 case AddBorderCommand: 6544 case AddFrameCommand: 6545 case CompositeCommand: 6546 case CommentCommand: 6547 case LaunchCommand: 6548 case RegionofInterestCommand: 6549 case SaveToUndoBufferCommand: 6550 case RedoCommand: 6551 { 6552 Image 6553 *previous_image; 6554 6555 ssize_t 6556 bytes; 6557 6558 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo)); 6559 if (undo_image != (Image *) NULL) 6560 { 6561 /* 6562 Ensure the undo cache has enough memory available. 6563 */ 6564 previous_image=undo_image; 6565 while (previous_image != (Image *) NULL) 6566 { 6567 bytes+=previous_image->list->columns*previous_image->list->rows* 6568 sizeof(PixelInfo); 6569 if (bytes <= (ssize_t) (resource_info->undo_cache << 20)) 6570 { 6571 previous_image=GetPreviousImageInList(previous_image); 6572 continue; 6573 } 6574 bytes-=previous_image->list->columns*previous_image->list->rows* 6575 sizeof(PixelInfo); 6576 if (previous_image == undo_image) 6577 undo_image=NewImageList(); 6578 else 6579 previous_image->next->previous=NewImageList(); 6580 break; 6581 } 6582 while (previous_image != (Image *) NULL) 6583 { 6584 /* 6585 Delete any excess memory from undo cache. 6586 */ 6587 cache_image=previous_image; 6588 previous_image=GetPreviousImageInList(previous_image); 6589 cache_image->list=DestroyImage(cache_image->list); 6590 cache_image=DestroyImage(cache_image); 6591 } 6592 } 6593 if (bytes > (ssize_t) (resource_info->undo_cache << 20)) 6594 break; 6595 /* 6596 Save image before transformations are applied. 6597 */ 6598 cache_image=AcquireImage((ImageInfo *) NULL,exception); 6599 if (cache_image == (Image *) NULL) 6600 break; 6601 XSetCursorState(display,windows,MagickTrue); 6602 XCheckRefreshWindows(display,windows); 6603 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception); 6604 XSetCursorState(display,windows,MagickFalse); 6605 if (cache_image->list == (Image *) NULL) 6606 { 6607 cache_image=DestroyImage(cache_image); 6608 break; 6609 } 6610 cache_image->columns=(size_t) windows->image.ximage->width; 6611 cache_image->rows=(size_t) windows->image.ximage->height; 6612 cache_image->geometry=windows->image.crop_geometry; 6613 if (windows->image.crop_geometry != (char *) NULL) 6614 { 6615 cache_image->geometry=AcquireString((char *) NULL); 6616 (void) CopyMagickString(cache_image->geometry, 6617 windows->image.crop_geometry,MagickPathExtent); 6618 } 6619 if (undo_image == (Image *) NULL) 6620 { 6621 undo_image=cache_image; 6622 break; 6623 } 6624 undo_image->next=cache_image; 6625 undo_image->next->previous=undo_image; 6626 undo_image=undo_image->next; 6627 break; 6628 } 6629 default: 6630 break; 6631 } 6632 if (command == RedoCommand) 6633 { 6634 /* 6635 Redo the last image transformation. 6636 */ 6637 if (redo_image == (Image *) NULL) 6638 { 6639 (void) XBell(display,0); 6640 return; 6641 } 6642 windows->image.window_changes.width=(int) redo_image->columns; 6643 windows->image.window_changes.height=(int) redo_image->rows; 6644 if (windows->image.crop_geometry != (char *) NULL) 6645 windows->image.crop_geometry=(char *) 6646 RelinquishMagickMemory(windows->image.crop_geometry); 6647 windows->image.crop_geometry=redo_image->geometry; 6648 *image=DestroyImage(*image); 6649 *image=redo_image; 6650 redo_image=NewImageList(); 6651 if (windows->image.orphan != MagickFalse ) 6652 return; 6653 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6654 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6655 return; 6656 } 6657 if (command != InfoCommand) 6658 return; 6659 /* 6660 Display image info. 6661 */ 6662 XSetCursorState(display,windows,MagickTrue); 6663 XCheckRefreshWindows(display,windows); 6664 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception); 6665 XSetCursorState(display,windows,MagickFalse); 6666} 6667 6668/* 6669%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6670% % 6671% % 6672% % 6673+ X I m a g e W i n d o w C o m m a n d % 6674% % 6675% % 6676% % 6677%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6678% 6679% XImageWindowCommand() makes a transform to the image or Image window as 6680% specified by a user menu button or keyboard command. 6681% 6682% The format of the XImageWindowCommand method is: 6683% 6684% CommandType XImageWindowCommand(Display *display, 6685% XResourceInfo *resource_info,XWindows *windows, 6686% const MagickStatusType state,KeySym key_symbol,Image **image, 6687% ExceptionInfo *exception) 6688% 6689% A description of each parameter follows: 6690% 6691% o nexus: Method XImageWindowCommand returns an image when the 6692% user chooses 'Open Image' from the command menu. Otherwise a null 6693% image is returned. 6694% 6695% o display: Specifies a connection to an X server; returned from 6696% XOpenDisplay. 6697% 6698% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6699% 6700% o windows: Specifies a pointer to a XWindows structure. 6701% 6702% o state: key mask. 6703% 6704% o key_symbol: Specifies a command to perform. 6705% 6706% o image: the image; XImageWIndowCommand may transform the image and 6707% return a new image pointer. 6708% 6709% o exception: return any errors or warnings in this structure. 6710% 6711*/ 6712static CommandType XImageWindowCommand(Display *display, 6713 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state, 6714 KeySym key_symbol,Image **image,ExceptionInfo *exception) 6715{ 6716 static char 6717 delta[MagickPathExtent] = ""; 6718 6719 static const char 6720 Digits[] = "01234567890"; 6721 6722 static KeySym 6723 last_symbol = XK_0; 6724 6725 if ((key_symbol >= XK_0) && (key_symbol <= XK_9)) 6726 { 6727 if (((last_symbol < XK_0) || (last_symbol > XK_9))) 6728 { 6729 *delta='\0'; 6730 resource_info->quantum=1; 6731 } 6732 last_symbol=key_symbol; 6733 delta[strlen(delta)+1]='\0'; 6734 delta[strlen(delta)]=Digits[key_symbol-XK_0]; 6735 resource_info->quantum=StringToLong(delta); 6736 return(NullCommand); 6737 } 6738 last_symbol=key_symbol; 6739 if (resource_info->immutable) 6740 { 6741 /* 6742 Virtual image window has a restricted command set. 6743 */ 6744 switch (key_symbol) 6745 { 6746 case XK_question: 6747 return(InfoCommand); 6748 case XK_p: 6749 case XK_Print: 6750 return(PrintCommand); 6751 case XK_space: 6752 return(NextCommand); 6753 case XK_q: 6754 case XK_Escape: 6755 return(QuitCommand); 6756 default: 6757 break; 6758 } 6759 return(NullCommand); 6760 } 6761 switch ((int) key_symbol) 6762 { 6763 case XK_o: 6764 { 6765 if ((state & ControlMask) == 0) 6766 break; 6767 return(OpenCommand); 6768 } 6769 case XK_space: 6770 return(NextCommand); 6771 case XK_BackSpace: 6772 return(FormerCommand); 6773 case XK_s: 6774 { 6775 if ((state & Mod1Mask) != 0) 6776 return(SwirlCommand); 6777 if ((state & ControlMask) == 0) 6778 return(ShearCommand); 6779 return(SaveCommand); 6780 } 6781 case XK_p: 6782 case XK_Print: 6783 { 6784 if ((state & Mod1Mask) != 0) 6785 return(OilPaintCommand); 6786 if ((state & Mod4Mask) != 0) 6787 return(ColorCommand); 6788 if ((state & ControlMask) == 0) 6789 return(NullCommand); 6790 return(PrintCommand); 6791 } 6792 case XK_d: 6793 { 6794 if ((state & Mod4Mask) != 0) 6795 return(DrawCommand); 6796 if ((state & ControlMask) == 0) 6797 return(NullCommand); 6798 return(DeleteCommand); 6799 } 6800 case XK_Select: 6801 { 6802 if ((state & ControlMask) == 0) 6803 return(NullCommand); 6804 return(SelectCommand); 6805 } 6806 case XK_n: 6807 { 6808 if ((state & ControlMask) == 0) 6809 return(NullCommand); 6810 return(NewCommand); 6811 } 6812 case XK_q: 6813 case XK_Escape: 6814 return(QuitCommand); 6815 case XK_z: 6816 case XK_Undo: 6817 { 6818 if ((state & ControlMask) == 0) 6819 return(NullCommand); 6820 return(UndoCommand); 6821 } 6822 case XK_r: 6823 case XK_Redo: 6824 { 6825 if ((state & ControlMask) == 0) 6826 return(RollCommand); 6827 return(RedoCommand); 6828 } 6829 case XK_x: 6830 { 6831 if ((state & ControlMask) == 0) 6832 return(NullCommand); 6833 return(CutCommand); 6834 } 6835 case XK_c: 6836 { 6837 if ((state & Mod1Mask) != 0) 6838 return(CharcoalDrawCommand); 6839 if ((state & ControlMask) == 0) 6840 return(CropCommand); 6841 return(CopyCommand); 6842 } 6843 case XK_v: 6844 case XK_Insert: 6845 { 6846 if ((state & Mod4Mask) != 0) 6847 return(CompositeCommand); 6848 if ((state & ControlMask) == 0) 6849 return(FlipCommand); 6850 return(PasteCommand); 6851 } 6852 case XK_less: 6853 return(HalfSizeCommand); 6854 case XK_minus: 6855 return(OriginalSizeCommand); 6856 case XK_greater: 6857 return(DoubleSizeCommand); 6858 case XK_percent: 6859 return(ResizeCommand); 6860 case XK_at: 6861 return(RefreshCommand); 6862 case XK_bracketleft: 6863 return(ChopCommand); 6864 case XK_h: 6865 return(FlopCommand); 6866 case XK_slash: 6867 return(RotateRightCommand); 6868 case XK_backslash: 6869 return(RotateLeftCommand); 6870 case XK_asterisk: 6871 return(RotateCommand); 6872 case XK_t: 6873 return(TrimCommand); 6874 case XK_H: 6875 return(HueCommand); 6876 case XK_S: 6877 return(SaturationCommand); 6878 case XK_L: 6879 return(BrightnessCommand); 6880 case XK_G: 6881 return(GammaCommand); 6882 case XK_C: 6883 return(SpiffCommand); 6884 case XK_Z: 6885 return(DullCommand); 6886 case XK_N: 6887 return(NormalizeCommand); 6888 case XK_equal: 6889 return(EqualizeCommand); 6890 case XK_asciitilde: 6891 return(NegateCommand); 6892 case XK_period: 6893 return(GrayscaleCommand); 6894 case XK_numbersign: 6895 return(QuantizeCommand); 6896 case XK_F2: 6897 return(DespeckleCommand); 6898 case XK_F3: 6899 return(EmbossCommand); 6900 case XK_F4: 6901 return(ReduceNoiseCommand); 6902 case XK_F5: 6903 return(AddNoiseCommand); 6904 case XK_F6: 6905 return(SharpenCommand); 6906 case XK_F7: 6907 return(BlurCommand); 6908 case XK_F8: 6909 return(ThresholdCommand); 6910 case XK_F9: 6911 return(EdgeDetectCommand); 6912 case XK_F10: 6913 return(SpreadCommand); 6914 case XK_F11: 6915 return(ShadeCommand); 6916 case XK_F12: 6917 return(RaiseCommand); 6918 case XK_F13: 6919 return(SegmentCommand); 6920 case XK_i: 6921 { 6922 if ((state & Mod1Mask) == 0) 6923 return(NullCommand); 6924 return(ImplodeCommand); 6925 } 6926 case XK_w: 6927 { 6928 if ((state & Mod1Mask) == 0) 6929 return(NullCommand); 6930 return(WaveCommand); 6931 } 6932 case XK_m: 6933 { 6934 if ((state & Mod4Mask) == 0) 6935 return(NullCommand); 6936 return(MatteCommand); 6937 } 6938 case XK_b: 6939 { 6940 if ((state & Mod4Mask) == 0) 6941 return(NullCommand); 6942 return(AddBorderCommand); 6943 } 6944 case XK_f: 6945 { 6946 if ((state & Mod4Mask) == 0) 6947 return(NullCommand); 6948 return(AddFrameCommand); 6949 } 6950 case XK_exclam: 6951 { 6952 if ((state & Mod4Mask) == 0) 6953 return(NullCommand); 6954 return(CommentCommand); 6955 } 6956 case XK_a: 6957 { 6958 if ((state & Mod1Mask) != 0) 6959 return(ApplyCommand); 6960 if ((state & Mod4Mask) != 0) 6961 return(AnnotateCommand); 6962 if ((state & ControlMask) == 0) 6963 return(NullCommand); 6964 return(RegionofInterestCommand); 6965 } 6966 case XK_question: 6967 return(InfoCommand); 6968 case XK_plus: 6969 return(ZoomCommand); 6970 case XK_P: 6971 { 6972 if ((state & ShiftMask) == 0) 6973 return(NullCommand); 6974 return(ShowPreviewCommand); 6975 } 6976 case XK_Execute: 6977 return(LaunchCommand); 6978 case XK_F1: 6979 return(HelpCommand); 6980 case XK_Find: 6981 return(BrowseDocumentationCommand); 6982 case XK_Menu: 6983 { 6984 (void) XMapRaised(display,windows->command.id); 6985 return(NullCommand); 6986 } 6987 case XK_Next: 6988 case XK_Prior: 6989 case XK_Home: 6990 case XK_KP_Home: 6991 { 6992 XTranslateImage(display,windows,*image,key_symbol); 6993 return(NullCommand); 6994 } 6995 case XK_Up: 6996 case XK_KP_Up: 6997 case XK_Down: 6998 case XK_KP_Down: 6999 case XK_Left: 7000 case XK_KP_Left: 7001 case XK_Right: 7002 case XK_KP_Right: 7003 { 7004 if ((state & Mod1Mask) != 0) 7005 { 7006 RectangleInfo 7007 crop_info; 7008 7009 /* 7010 Trim one pixel from edge of image. 7011 */ 7012 crop_info.x=0; 7013 crop_info.y=0; 7014 crop_info.width=(size_t) windows->image.ximage->width; 7015 crop_info.height=(size_t) windows->image.ximage->height; 7016 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up)) 7017 { 7018 if (resource_info->quantum >= (int) crop_info.height) 7019 resource_info->quantum=(int) crop_info.height-1; 7020 crop_info.height-=resource_info->quantum; 7021 } 7022 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down)) 7023 { 7024 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y)) 7025 resource_info->quantum=(int) (crop_info.height-crop_info.y-1); 7026 crop_info.y+=resource_info->quantum; 7027 crop_info.height-=resource_info->quantum; 7028 } 7029 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left)) 7030 { 7031 if (resource_info->quantum >= (int) crop_info.width) 7032 resource_info->quantum=(int) crop_info.width-1; 7033 crop_info.width-=resource_info->quantum; 7034 } 7035 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right)) 7036 { 7037 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x)) 7038 resource_info->quantum=(int) (crop_info.width-crop_info.x-1); 7039 crop_info.x+=resource_info->quantum; 7040 crop_info.width-=resource_info->quantum; 7041 } 7042 if ((int) (windows->image.x+windows->image.width) > 7043 (int) crop_info.width) 7044 windows->image.x=(int) (crop_info.width-windows->image.width); 7045 if ((int) (windows->image.y+windows->image.height) > 7046 (int) crop_info.height) 7047 windows->image.y=(int) (crop_info.height-windows->image.height); 7048 XSetCropGeometry(display,windows,&crop_info,*image); 7049 windows->image.window_changes.width=(int) crop_info.width; 7050 windows->image.window_changes.height=(int) crop_info.height; 7051 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None); 7052 (void) XConfigureImage(display,resource_info,windows,*image, 7053 exception); 7054 return(NullCommand); 7055 } 7056 XTranslateImage(display,windows,*image,key_symbol); 7057 return(NullCommand); 7058 } 7059 default: 7060 return(NullCommand); 7061 } 7062 return(NullCommand); 7063} 7064 7065/* 7066%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7067% % 7068% % 7069% % 7070+ X M a g i c k C o m m a n d % 7071% % 7072% % 7073% % 7074%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7075% 7076% XMagickCommand() makes a transform to the image or Image window as 7077% specified by a user menu button or keyboard command. 7078% 7079% The format of the XMagickCommand method is: 7080% 7081% Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7082% XWindows *windows,const CommandType command,Image **image, 7083% ExceptionInfo *exception) 7084% 7085% A description of each parameter follows: 7086% 7087% o display: Specifies a connection to an X server; returned from 7088% XOpenDisplay. 7089% 7090% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 7091% 7092% o windows: Specifies a pointer to a XWindows structure. 7093% 7094% o command: Specifies a command to perform. 7095% 7096% o image: the image; XMagickCommand may transform the image and return a 7097% new image pointer. 7098% 7099% o exception: return any errors or warnings in this structure. 7100% 7101*/ 7102static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7103 XWindows *windows,const CommandType command,Image **image, 7104 ExceptionInfo *exception) 7105{ 7106 char 7107 filename[MagickPathExtent], 7108 geometry[MagickPathExtent], 7109 modulate_factors[MagickPathExtent]; 7110 7111 GeometryInfo 7112 geometry_info; 7113 7114 Image 7115 *nexus; 7116 7117 ImageInfo 7118 *image_info; 7119 7120 int 7121 x, 7122 y; 7123 7124 MagickStatusType 7125 flags, 7126 status; 7127 7128 QuantizeInfo 7129 quantize_info; 7130 7131 RectangleInfo 7132 page_geometry; 7133 7134 register int 7135 i; 7136 7137 static char 7138 color[MagickPathExtent] = "gray"; 7139 7140 unsigned int 7141 height, 7142 width; 7143 7144 /* 7145 Process user command. 7146 */ 7147 XCheckRefreshWindows(display,windows); 7148 XImageCache(display,resource_info,windows,command,image,exception); 7149 nexus=NewImageList(); 7150 windows->image.window_changes.width=windows->image.ximage->width; 7151 windows->image.window_changes.height=windows->image.ximage->height; 7152 image_info=CloneImageInfo(resource_info->image_info); 7153 SetGeometryInfo(&geometry_info); 7154 GetQuantizeInfo(&quantize_info); 7155 switch (command) 7156 { 7157 case OpenCommand: 7158 { 7159 /* 7160 Load image. 7161 */ 7162 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 7163 break; 7164 } 7165 case NextCommand: 7166 { 7167 /* 7168 Display next image. 7169 */ 7170 for (i=0; i < resource_info->quantum; i++) 7171 XClientMessage(display,windows->image.id,windows->im_protocols, 7172 windows->im_next_image,CurrentTime); 7173 break; 7174 } 7175 case FormerCommand: 7176 { 7177 /* 7178 Display former image. 7179 */ 7180 for (i=0; i < resource_info->quantum; i++) 7181 XClientMessage(display,windows->image.id,windows->im_protocols, 7182 windows->im_former_image,CurrentTime); 7183 break; 7184 } 7185 case SelectCommand: 7186 { 7187 int 7188 status; 7189 7190 /* 7191 Select image. 7192 */ 7193 if (*resource_info->home_directory == '\0') 7194 (void) CopyMagickString(resource_info->home_directory,".", 7195 MagickPathExtent); 7196 status=chdir(resource_info->home_directory); 7197 if (status == -1) 7198 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 7199 "UnableToOpenFile","%s",resource_info->home_directory); 7200 nexus=XOpenImage(display,resource_info,windows,MagickTrue); 7201 break; 7202 } 7203 case SaveCommand: 7204 { 7205 /* 7206 Save image. 7207 */ 7208 status=XSaveImage(display,resource_info,windows,*image,exception); 7209 if (status == MagickFalse) 7210 { 7211 char 7212 message[MagickPathExtent]; 7213 7214 (void) FormatLocaleString(message,MagickPathExtent,"%s:%s", 7215 exception->reason != (char *) NULL ? exception->reason : "", 7216 exception->description != (char *) NULL ? exception->description : 7217 ""); 7218 XNoticeWidget(display,windows,"Unable to save file:",message); 7219 break; 7220 } 7221 break; 7222 } 7223 case PrintCommand: 7224 { 7225 /* 7226 Print image. 7227 */ 7228 status=XPrintImage(display,resource_info,windows,*image,exception); 7229 if (status == MagickFalse) 7230 { 7231 char 7232 message[MagickPathExtent]; 7233 7234 (void) FormatLocaleString(message,MagickPathExtent,"%s:%s", 7235 exception->reason != (char *) NULL ? exception->reason : "", 7236 exception->description != (char *) NULL ? exception->description : 7237 ""); 7238 XNoticeWidget(display,windows,"Unable to print file:",message); 7239 break; 7240 } 7241 break; 7242 } 7243 case DeleteCommand: 7244 { 7245 static char 7246 filename[MagickPathExtent] = "\0"; 7247 7248 /* 7249 Delete image file. 7250 */ 7251 XFileBrowserWidget(display,windows,"Delete",filename); 7252 if (*filename == '\0') 7253 break; 7254 status=ShredFile(filename); 7255 if (status != MagickFalse ) 7256 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7257 break; 7258 } 7259 case NewCommand: 7260 { 7261 int 7262 status; 7263 7264 static char 7265 color[MagickPathExtent] = "gray", 7266 geometry[MagickPathExtent] = "640x480"; 7267 7268 static const char 7269 *format = "gradient"; 7270 7271 /* 7272 Query user for canvas geometry. 7273 */ 7274 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7275 geometry); 7276 if (*geometry == '\0') 7277 break; 7278 if (status == 0) 7279 format="xc"; 7280 XColorBrowserWidget(display,windows,"Select",color); 7281 if (*color == '\0') 7282 break; 7283 /* 7284 Create canvas. 7285 */ 7286 (void) FormatLocaleString(image_info->filename,MagickPathExtent, 7287 "%s:%s",format,color); 7288 (void) CloneString(&image_info->size,geometry); 7289 nexus=ReadImage(image_info,exception); 7290 CatchException(exception); 7291 XClientMessage(display,windows->image.id,windows->im_protocols, 7292 windows->im_next_image,CurrentTime); 7293 break; 7294 } 7295 case VisualDirectoryCommand: 7296 { 7297 /* 7298 Visual Image directory. 7299 */ 7300 nexus=XVisualDirectoryImage(display,resource_info,windows,exception); 7301 break; 7302 } 7303 case QuitCommand: 7304 { 7305 /* 7306 exit program. 7307 */ 7308 if (resource_info->confirm_exit == MagickFalse) 7309 XClientMessage(display,windows->image.id,windows->im_protocols, 7310 windows->im_exit,CurrentTime); 7311 else 7312 { 7313 int 7314 status; 7315 7316 /* 7317 Confirm program exit. 7318 */ 7319 status=XConfirmWidget(display,windows,"Do you really want to exit", 7320 resource_info->client_name); 7321 if (status > 0) 7322 XClientMessage(display,windows->image.id,windows->im_protocols, 7323 windows->im_exit,CurrentTime); 7324 } 7325 break; 7326 } 7327 case CutCommand: 7328 { 7329 /* 7330 Cut image. 7331 */ 7332 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception); 7333 break; 7334 } 7335 case CopyCommand: 7336 { 7337 /* 7338 Copy image. 7339 */ 7340 (void) XCropImage(display,resource_info,windows,*image,CopyMode, 7341 exception); 7342 break; 7343 } 7344 case PasteCommand: 7345 { 7346 /* 7347 Paste image. 7348 */ 7349 status=XPasteImage(display,resource_info,windows,*image,exception); 7350 if (status == MagickFalse) 7351 { 7352 XNoticeWidget(display,windows,"Unable to paste X image", 7353 (*image)->filename); 7354 break; 7355 } 7356 break; 7357 } 7358 case HalfSizeCommand: 7359 { 7360 /* 7361 Half image size. 7362 */ 7363 windows->image.window_changes.width=windows->image.ximage->width/2; 7364 windows->image.window_changes.height=windows->image.ximage->height/2; 7365 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7366 break; 7367 } 7368 case OriginalSizeCommand: 7369 { 7370 /* 7371 Original image size. 7372 */ 7373 windows->image.window_changes.width=(int) (*image)->columns; 7374 windows->image.window_changes.height=(int) (*image)->rows; 7375 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7376 break; 7377 } 7378 case DoubleSizeCommand: 7379 { 7380 /* 7381 Double the image size. 7382 */ 7383 windows->image.window_changes.width=windows->image.ximage->width << 1; 7384 windows->image.window_changes.height=windows->image.ximage->height << 1; 7385 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7386 break; 7387 } 7388 case ResizeCommand: 7389 { 7390 int 7391 status; 7392 7393 size_t 7394 height, 7395 width; 7396 7397 ssize_t 7398 x, 7399 y; 7400 7401 /* 7402 Resize image. 7403 */ 7404 width=(size_t) windows->image.ximage->width; 7405 height=(size_t) windows->image.ximage->height; 7406 x=0; 7407 y=0; 7408 (void) FormatLocaleString(geometry,MagickPathExtent,"%.20gx%.20g+0+0", 7409 (double) width,(double) height); 7410 status=XDialogWidget(display,windows,"Resize", 7411 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7412 if (*geometry == '\0') 7413 break; 7414 if (status == 0) 7415 (void) ConcatenateMagickString(geometry,"!",MagickPathExtent); 7416 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7417 windows->image.window_changes.width=(int) width; 7418 windows->image.window_changes.height=(int) height; 7419 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7420 break; 7421 } 7422 case ApplyCommand: 7423 { 7424 char 7425 image_geometry[MagickPathExtent]; 7426 7427 if ((windows->image.crop_geometry == (char *) NULL) && 7428 ((int) (*image)->columns == windows->image.ximage->width) && 7429 ((int) (*image)->rows == windows->image.ximage->height)) 7430 break; 7431 /* 7432 Apply size transforms to image. 7433 */ 7434 XSetCursorState(display,windows,MagickTrue); 7435 XCheckRefreshWindows(display,windows); 7436 /* 7437 Crop and/or scale displayed image. 7438 */ 7439 (void) FormatLocaleString(image_geometry,MagickPathExtent,"%dx%d!", 7440 windows->image.ximage->width,windows->image.ximage->height); 7441 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 7442 exception); 7443 if (windows->image.crop_geometry != (char *) NULL) 7444 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 7445 windows->image.crop_geometry); 7446 windows->image.x=0; 7447 windows->image.y=0; 7448 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7449 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7450 break; 7451 } 7452 case RefreshCommand: 7453 { 7454 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7455 break; 7456 } 7457 case RestoreCommand: 7458 { 7459 /* 7460 Restore Image window to its original size. 7461 */ 7462 if ((windows->image.width == (unsigned int) (*image)->columns) && 7463 (windows->image.height == (unsigned int) (*image)->rows) && 7464 (windows->image.crop_geometry == (char *) NULL)) 7465 { 7466 (void) XBell(display,0); 7467 break; 7468 } 7469 windows->image.window_changes.width=(int) (*image)->columns; 7470 windows->image.window_changes.height=(int) (*image)->rows; 7471 if (windows->image.crop_geometry != (char *) NULL) 7472 { 7473 windows->image.crop_geometry=(char *) 7474 RelinquishMagickMemory(windows->image.crop_geometry); 7475 windows->image.crop_geometry=(char *) NULL; 7476 windows->image.x=0; 7477 windows->image.y=0; 7478 } 7479 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7480 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7481 break; 7482 } 7483 case CropCommand: 7484 { 7485 /* 7486 Crop image. 7487 */ 7488 (void) XCropImage(display,resource_info,windows,*image,CropMode, 7489 exception); 7490 break; 7491 } 7492 case ChopCommand: 7493 { 7494 /* 7495 Chop image. 7496 */ 7497 status=XChopImage(display,resource_info,windows,image,exception); 7498 if (status == MagickFalse) 7499 { 7500 XNoticeWidget(display,windows,"Unable to cut X image", 7501 (*image)->filename); 7502 break; 7503 } 7504 break; 7505 } 7506 case FlopCommand: 7507 { 7508 Image 7509 *flop_image; 7510 7511 /* 7512 Flop image scanlines. 7513 */ 7514 XSetCursorState(display,windows,MagickTrue); 7515 XCheckRefreshWindows(display,windows); 7516 flop_image=FlopImage(*image,exception); 7517 if (flop_image != (Image *) NULL) 7518 { 7519 *image=DestroyImage(*image); 7520 *image=flop_image; 7521 } 7522 CatchException(exception); 7523 XSetCursorState(display,windows,MagickFalse); 7524 if (windows->image.crop_geometry != (char *) NULL) 7525 { 7526 /* 7527 Flop crop geometry. 7528 */ 7529 width=(unsigned int) (*image)->columns; 7530 height=(unsigned int) (*image)->rows; 7531 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7532 &width,&height); 7533 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent, 7534 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7535 } 7536 if (windows->image.orphan != MagickFalse ) 7537 break; 7538 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7539 break; 7540 } 7541 case FlipCommand: 7542 { 7543 Image 7544 *flip_image; 7545 7546 /* 7547 Flip image scanlines. 7548 */ 7549 XSetCursorState(display,windows,MagickTrue); 7550 XCheckRefreshWindows(display,windows); 7551 flip_image=FlipImage(*image,exception); 7552 if (flip_image != (Image *) NULL) 7553 { 7554 *image=DestroyImage(*image); 7555 *image=flip_image; 7556 } 7557 CatchException(exception); 7558 XSetCursorState(display,windows,MagickFalse); 7559 if (windows->image.crop_geometry != (char *) NULL) 7560 { 7561 /* 7562 Flip crop geometry. 7563 */ 7564 width=(unsigned int) (*image)->columns; 7565 height=(unsigned int) (*image)->rows; 7566 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7567 &width,&height); 7568 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent, 7569 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7570 } 7571 if (windows->image.orphan != MagickFalse ) 7572 break; 7573 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7574 break; 7575 } 7576 case RotateRightCommand: 7577 { 7578 /* 7579 Rotate image 90 degrees clockwise. 7580 */ 7581 status=XRotateImage(display,resource_info,windows,90.0,image,exception); 7582 if (status == MagickFalse) 7583 { 7584 XNoticeWidget(display,windows,"Unable to rotate X image", 7585 (*image)->filename); 7586 break; 7587 } 7588 break; 7589 } 7590 case RotateLeftCommand: 7591 { 7592 /* 7593 Rotate image 90 degrees counter-clockwise. 7594 */ 7595 status=XRotateImage(display,resource_info,windows,-90.0,image,exception); 7596 if (status == MagickFalse) 7597 { 7598 XNoticeWidget(display,windows,"Unable to rotate X image", 7599 (*image)->filename); 7600 break; 7601 } 7602 break; 7603 } 7604 case RotateCommand: 7605 { 7606 /* 7607 Rotate image. 7608 */ 7609 status=XRotateImage(display,resource_info,windows,0.0,image,exception); 7610 if (status == MagickFalse) 7611 { 7612 XNoticeWidget(display,windows,"Unable to rotate X image", 7613 (*image)->filename); 7614 break; 7615 } 7616 break; 7617 } 7618 case ShearCommand: 7619 { 7620 Image 7621 *shear_image; 7622 7623 static char 7624 geometry[MagickPathExtent] = "45.0x45.0"; 7625 7626 /* 7627 Query user for shear color and geometry. 7628 */ 7629 XColorBrowserWidget(display,windows,"Select",color); 7630 if (*color == '\0') 7631 break; 7632 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7633 geometry); 7634 if (*geometry == '\0') 7635 break; 7636 /* 7637 Shear image. 7638 */ 7639 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7640 exception); 7641 XSetCursorState(display,windows,MagickTrue); 7642 XCheckRefreshWindows(display,windows); 7643 (void) QueryColorCompliance(color,AllCompliance, 7644 &(*image)->background_color,exception); 7645 flags=ParseGeometry(geometry,&geometry_info); 7646 if ((flags & SigmaValue) == 0) 7647 geometry_info.sigma=geometry_info.rho; 7648 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7649 exception); 7650 if (shear_image != (Image *) NULL) 7651 { 7652 *image=DestroyImage(*image); 7653 *image=shear_image; 7654 } 7655 CatchException(exception); 7656 XSetCursorState(display,windows,MagickFalse); 7657 if (windows->image.orphan != MagickFalse ) 7658 break; 7659 windows->image.window_changes.width=(int) (*image)->columns; 7660 windows->image.window_changes.height=(int) (*image)->rows; 7661 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7662 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7663 break; 7664 } 7665 case RollCommand: 7666 { 7667 Image 7668 *roll_image; 7669 7670 static char 7671 geometry[MagickPathExtent] = "+2+2"; 7672 7673 /* 7674 Query user for the roll geometry. 7675 */ 7676 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7677 geometry); 7678 if (*geometry == '\0') 7679 break; 7680 /* 7681 Roll image. 7682 */ 7683 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7684 exception); 7685 XSetCursorState(display,windows,MagickTrue); 7686 XCheckRefreshWindows(display,windows); 7687 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7688 exception); 7689 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7690 exception); 7691 if (roll_image != (Image *) NULL) 7692 { 7693 *image=DestroyImage(*image); 7694 *image=roll_image; 7695 } 7696 CatchException(exception); 7697 XSetCursorState(display,windows,MagickFalse); 7698 if (windows->image.orphan != MagickFalse ) 7699 break; 7700 windows->image.window_changes.width=(int) (*image)->columns; 7701 windows->image.window_changes.height=(int) (*image)->rows; 7702 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7703 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7704 break; 7705 } 7706 case TrimCommand: 7707 { 7708 static char 7709 fuzz[MagickPathExtent]; 7710 7711 /* 7712 Query user for the fuzz factor. 7713 */ 7714 (void) FormatLocaleString(fuzz,MagickPathExtent,"%g%%",100.0* 7715 (*image)->fuzz/(QuantumRange+1.0)); 7716 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7717 if (*fuzz == '\0') 7718 break; 7719 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0); 7720 /* 7721 Trim image. 7722 */ 7723 status=XTrimImage(display,resource_info,windows,*image,exception); 7724 if (status == MagickFalse) 7725 { 7726 XNoticeWidget(display,windows,"Unable to trim X image", 7727 (*image)->filename); 7728 break; 7729 } 7730 break; 7731 } 7732 case HueCommand: 7733 { 7734 static char 7735 hue_percent[MagickPathExtent] = "110"; 7736 7737 /* 7738 Query user for percent hue change. 7739 */ 7740 (void) XDialogWidget(display,windows,"Apply", 7741 "Enter percent change in image hue (0-200):",hue_percent); 7742 if (*hue_percent == '\0') 7743 break; 7744 /* 7745 Vary the image hue. 7746 */ 7747 XSetCursorState(display,windows,MagickTrue); 7748 XCheckRefreshWindows(display,windows); 7749 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MagickPathExtent); 7750 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7751 MagickPathExtent); 7752 (void) ModulateImage(*image,modulate_factors,exception); 7753 XSetCursorState(display,windows,MagickFalse); 7754 if (windows->image.orphan != MagickFalse ) 7755 break; 7756 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7757 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7758 break; 7759 } 7760 case SaturationCommand: 7761 { 7762 static char 7763 saturation_percent[MagickPathExtent] = "110"; 7764 7765 /* 7766 Query user for percent saturation change. 7767 */ 7768 (void) XDialogWidget(display,windows,"Apply", 7769 "Enter percent change in color saturation (0-200):",saturation_percent); 7770 if (*saturation_percent == '\0') 7771 break; 7772 /* 7773 Vary color saturation. 7774 */ 7775 XSetCursorState(display,windows,MagickTrue); 7776 XCheckRefreshWindows(display,windows); 7777 (void) CopyMagickString(modulate_factors,"100.0/",MagickPathExtent); 7778 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7779 MagickPathExtent); 7780 (void) ModulateImage(*image,modulate_factors,exception); 7781 XSetCursorState(display,windows,MagickFalse); 7782 if (windows->image.orphan != MagickFalse ) 7783 break; 7784 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7785 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7786 break; 7787 } 7788 case BrightnessCommand: 7789 { 7790 static char 7791 brightness_percent[MagickPathExtent] = "110"; 7792 7793 /* 7794 Query user for percent brightness change. 7795 */ 7796 (void) XDialogWidget(display,windows,"Apply", 7797 "Enter percent change in color brightness (0-200):",brightness_percent); 7798 if (*brightness_percent == '\0') 7799 break; 7800 /* 7801 Vary the color brightness. 7802 */ 7803 XSetCursorState(display,windows,MagickTrue); 7804 XCheckRefreshWindows(display,windows); 7805 (void) CopyMagickString(modulate_factors,brightness_percent, 7806 MagickPathExtent); 7807 (void) ModulateImage(*image,modulate_factors,exception); 7808 XSetCursorState(display,windows,MagickFalse); 7809 if (windows->image.orphan != MagickFalse ) 7810 break; 7811 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7812 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7813 break; 7814 } 7815 case GammaCommand: 7816 { 7817 static char 7818 factor[MagickPathExtent] = "1.6"; 7819 7820 /* 7821 Query user for gamma value. 7822 */ 7823 (void) XDialogWidget(display,windows,"Gamma", 7824 "Enter gamma value (e.g. 1.2):",factor); 7825 if (*factor == '\0') 7826 break; 7827 /* 7828 Gamma correct image. 7829 */ 7830 XSetCursorState(display,windows,MagickTrue); 7831 XCheckRefreshWindows(display,windows); 7832 (void) GammaImage(*image,strtod(factor,(char **) NULL),exception); 7833 XSetCursorState(display,windows,MagickFalse); 7834 if (windows->image.orphan != MagickFalse ) 7835 break; 7836 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7837 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7838 break; 7839 } 7840 case SpiffCommand: 7841 { 7842 /* 7843 Sharpen the image contrast. 7844 */ 7845 XSetCursorState(display,windows,MagickTrue); 7846 XCheckRefreshWindows(display,windows); 7847 (void) ContrastImage(*image,MagickTrue,exception); 7848 XSetCursorState(display,windows,MagickFalse); 7849 if (windows->image.orphan != MagickFalse ) 7850 break; 7851 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7852 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7853 break; 7854 } 7855 case DullCommand: 7856 { 7857 /* 7858 Dull the image contrast. 7859 */ 7860 XSetCursorState(display,windows,MagickTrue); 7861 XCheckRefreshWindows(display,windows); 7862 (void) ContrastImage(*image,MagickFalse,exception); 7863 XSetCursorState(display,windows,MagickFalse); 7864 if (windows->image.orphan != MagickFalse ) 7865 break; 7866 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7867 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7868 break; 7869 } 7870 case ContrastStretchCommand: 7871 { 7872 double 7873 black_point, 7874 white_point; 7875 7876 static char 7877 levels[MagickPathExtent] = "1%"; 7878 7879 /* 7880 Query user for gamma value. 7881 */ 7882 (void) XDialogWidget(display,windows,"Contrast Stretch", 7883 "Enter black and white points:",levels); 7884 if (*levels == '\0') 7885 break; 7886 /* 7887 Contrast stretch image. 7888 */ 7889 XSetCursorState(display,windows,MagickTrue); 7890 XCheckRefreshWindows(display,windows); 7891 flags=ParseGeometry(levels,&geometry_info); 7892 black_point=geometry_info.rho; 7893 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7894 if ((flags & PercentValue) != 0) 7895 { 7896 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7897 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7898 } 7899 white_point=(double) (*image)->columns*(*image)->rows-white_point; 7900 (void) ContrastStretchImage(*image,black_point,white_point, 7901 exception); 7902 XSetCursorState(display,windows,MagickFalse); 7903 if (windows->image.orphan != MagickFalse ) 7904 break; 7905 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7906 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7907 break; 7908 } 7909 case SigmoidalContrastCommand: 7910 { 7911 GeometryInfo 7912 geometry_info; 7913 7914 MagickStatusType 7915 flags; 7916 7917 static char 7918 levels[MagickPathExtent] = "3x50%"; 7919 7920 /* 7921 Query user for gamma value. 7922 */ 7923 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7924 "Enter contrast and midpoint:",levels); 7925 if (*levels == '\0') 7926 break; 7927 /* 7928 Contrast stretch image. 7929 */ 7930 XSetCursorState(display,windows,MagickTrue); 7931 XCheckRefreshWindows(display,windows); 7932 flags=ParseGeometry(levels,&geometry_info); 7933 if ((flags & SigmaValue) == 0) 7934 geometry_info.sigma=1.0*QuantumRange/2.0; 7935 if ((flags & PercentValue) != 0) 7936 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0; 7937 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho, 7938 geometry_info.sigma,exception); 7939 XSetCursorState(display,windows,MagickFalse); 7940 if (windows->image.orphan != MagickFalse ) 7941 break; 7942 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7943 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7944 break; 7945 } 7946 case NormalizeCommand: 7947 { 7948 /* 7949 Perform histogram normalization on the image. 7950 */ 7951 XSetCursorState(display,windows,MagickTrue); 7952 XCheckRefreshWindows(display,windows); 7953 (void) NormalizeImage(*image,exception); 7954 XSetCursorState(display,windows,MagickFalse); 7955 if (windows->image.orphan != MagickFalse ) 7956 break; 7957 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7958 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7959 break; 7960 } 7961 case EqualizeCommand: 7962 { 7963 /* 7964 Perform histogram equalization on the image. 7965 */ 7966 XSetCursorState(display,windows,MagickTrue); 7967 XCheckRefreshWindows(display,windows); 7968 (void) EqualizeImage(*image,exception); 7969 XSetCursorState(display,windows,MagickFalse); 7970 if (windows->image.orphan != MagickFalse ) 7971 break; 7972 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7973 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7974 break; 7975 } 7976 case NegateCommand: 7977 { 7978 /* 7979 Negate colors in image. 7980 */ 7981 XSetCursorState(display,windows,MagickTrue); 7982 XCheckRefreshWindows(display,windows); 7983 (void) NegateImage(*image,MagickFalse,exception); 7984 XSetCursorState(display,windows,MagickFalse); 7985 if (windows->image.orphan != MagickFalse ) 7986 break; 7987 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7988 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7989 break; 7990 } 7991 case GrayscaleCommand: 7992 { 7993 /* 7994 Convert image to grayscale. 7995 */ 7996 XSetCursorState(display,windows,MagickTrue); 7997 XCheckRefreshWindows(display,windows); 7998 (void) SetImageType(*image,(*image)->alpha_trait == UndefinedPixelTrait ? 7999 GrayscaleType : GrayscaleAlphaType,exception); 8000 XSetCursorState(display,windows,MagickFalse); 8001 if (windows->image.orphan != MagickFalse ) 8002 break; 8003 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8004 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8005 break; 8006 } 8007 case MapCommand: 8008 { 8009 Image 8010 *affinity_image; 8011 8012 static char 8013 filename[MagickPathExtent] = "\0"; 8014 8015 /* 8016 Request image file name from user. 8017 */ 8018 XFileBrowserWidget(display,windows,"Map",filename); 8019 if (*filename == '\0') 8020 break; 8021 /* 8022 Map image. 8023 */ 8024 XSetCursorState(display,windows,MagickTrue); 8025 XCheckRefreshWindows(display,windows); 8026 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent); 8027 affinity_image=ReadImage(image_info,exception); 8028 if (affinity_image != (Image *) NULL) 8029 { 8030 (void) RemapImage(&quantize_info,*image,affinity_image,exception); 8031 affinity_image=DestroyImage(affinity_image); 8032 } 8033 CatchException(exception); 8034 XSetCursorState(display,windows,MagickFalse); 8035 if (windows->image.orphan != MagickFalse ) 8036 break; 8037 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8038 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8039 break; 8040 } 8041 case QuantizeCommand: 8042 { 8043 int 8044 status; 8045 8046 static char 8047 colors[MagickPathExtent] = "256"; 8048 8049 /* 8050 Query user for maximum number of colors. 8051 */ 8052 status=XDialogWidget(display,windows,"Quantize", 8053 "Maximum number of colors:",colors); 8054 if (*colors == '\0') 8055 break; 8056 /* 8057 Color reduce the image. 8058 */ 8059 XSetCursorState(display,windows,MagickTrue); 8060 XCheckRefreshWindows(display,windows); 8061 quantize_info.number_colors=StringToUnsignedLong(colors); 8062 quantize_info.dither_method=status != 0 ? RiemersmaDitherMethod : 8063 NoDitherMethod; 8064 (void) QuantizeImage(&quantize_info,*image,exception); 8065 XSetCursorState(display,windows,MagickFalse); 8066 if (windows->image.orphan != MagickFalse ) 8067 break; 8068 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8069 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8070 break; 8071 } 8072 case DespeckleCommand: 8073 { 8074 Image 8075 *despeckle_image; 8076 8077 /* 8078 Despeckle image. 8079 */ 8080 XSetCursorState(display,windows,MagickTrue); 8081 XCheckRefreshWindows(display,windows); 8082 despeckle_image=DespeckleImage(*image,exception); 8083 if (despeckle_image != (Image *) NULL) 8084 { 8085 *image=DestroyImage(*image); 8086 *image=despeckle_image; 8087 } 8088 CatchException(exception); 8089 XSetCursorState(display,windows,MagickFalse); 8090 if (windows->image.orphan != MagickFalse ) 8091 break; 8092 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8093 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8094 break; 8095 } 8096 case EmbossCommand: 8097 { 8098 Image 8099 *emboss_image; 8100 8101 static char 8102 radius[MagickPathExtent] = "0.0x1.0"; 8103 8104 /* 8105 Query user for emboss radius. 8106 */ 8107 (void) XDialogWidget(display,windows,"Emboss", 8108 "Enter the emboss radius and standard deviation:",radius); 8109 if (*radius == '\0') 8110 break; 8111 /* 8112 Reduce noise in the image. 8113 */ 8114 XSetCursorState(display,windows,MagickTrue); 8115 XCheckRefreshWindows(display,windows); 8116 flags=ParseGeometry(radius,&geometry_info); 8117 if ((flags & SigmaValue) == 0) 8118 geometry_info.sigma=1.0; 8119 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma, 8120 exception); 8121 if (emboss_image != (Image *) NULL) 8122 { 8123 *image=DestroyImage(*image); 8124 *image=emboss_image; 8125 } 8126 CatchException(exception); 8127 XSetCursorState(display,windows,MagickFalse); 8128 if (windows->image.orphan != MagickFalse ) 8129 break; 8130 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8131 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8132 break; 8133 } 8134 case ReduceNoiseCommand: 8135 { 8136 Image 8137 *noise_image; 8138 8139 static char 8140 radius[MagickPathExtent] = "0"; 8141 8142 /* 8143 Query user for noise radius. 8144 */ 8145 (void) XDialogWidget(display,windows,"Reduce Noise", 8146 "Enter the noise radius:",radius); 8147 if (*radius == '\0') 8148 break; 8149 /* 8150 Reduce noise in the image. 8151 */ 8152 XSetCursorState(display,windows,MagickTrue); 8153 XCheckRefreshWindows(display,windows); 8154 flags=ParseGeometry(radius,&geometry_info); 8155 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t) 8156 geometry_info.rho,(size_t) geometry_info.rho,exception); 8157 if (noise_image != (Image *) NULL) 8158 { 8159 *image=DestroyImage(*image); 8160 *image=noise_image; 8161 } 8162 CatchException(exception); 8163 XSetCursorState(display,windows,MagickFalse); 8164 if (windows->image.orphan != MagickFalse ) 8165 break; 8166 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8167 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8168 break; 8169 } 8170 case AddNoiseCommand: 8171 { 8172 char 8173 **noises; 8174 8175 Image 8176 *noise_image; 8177 8178 static char 8179 noise_type[MagickPathExtent] = "Gaussian"; 8180 8181 /* 8182 Add noise to the image. 8183 */ 8184 noises=GetCommandOptions(MagickNoiseOptions); 8185 if (noises == (char **) NULL) 8186 break; 8187 XListBrowserWidget(display,windows,&windows->widget, 8188 (const char **) noises,"Add Noise", 8189 "Select a type of noise to add to your image:",noise_type); 8190 noises=DestroyStringList(noises); 8191 if (*noise_type == '\0') 8192 break; 8193 XSetCursorState(display,windows,MagickTrue); 8194 XCheckRefreshWindows(display,windows); 8195 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption( 8196 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception); 8197 if (noise_image != (Image *) NULL) 8198 { 8199 *image=DestroyImage(*image); 8200 *image=noise_image; 8201 } 8202 CatchException(exception); 8203 XSetCursorState(display,windows,MagickFalse); 8204 if (windows->image.orphan != MagickFalse ) 8205 break; 8206 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8207 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8208 break; 8209 } 8210 case SharpenCommand: 8211 { 8212 Image 8213 *sharp_image; 8214 8215 static char 8216 radius[MagickPathExtent] = "0.0x1.0"; 8217 8218 /* 8219 Query user for sharpen radius. 8220 */ 8221 (void) XDialogWidget(display,windows,"Sharpen", 8222 "Enter the sharpen radius and standard deviation:",radius); 8223 if (*radius == '\0') 8224 break; 8225 /* 8226 Sharpen image scanlines. 8227 */ 8228 XSetCursorState(display,windows,MagickTrue); 8229 XCheckRefreshWindows(display,windows); 8230 flags=ParseGeometry(radius,&geometry_info); 8231 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma, 8232 exception); 8233 if (sharp_image != (Image *) NULL) 8234 { 8235 *image=DestroyImage(*image); 8236 *image=sharp_image; 8237 } 8238 CatchException(exception); 8239 XSetCursorState(display,windows,MagickFalse); 8240 if (windows->image.orphan != MagickFalse ) 8241 break; 8242 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8243 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8244 break; 8245 } 8246 case BlurCommand: 8247 { 8248 Image 8249 *blur_image; 8250 8251 static char 8252 radius[MagickPathExtent] = "0.0x1.0"; 8253 8254 /* 8255 Query user for blur radius. 8256 */ 8257 (void) XDialogWidget(display,windows,"Blur", 8258 "Enter the blur radius and standard deviation:",radius); 8259 if (*radius == '\0') 8260 break; 8261 /* 8262 Blur an image. 8263 */ 8264 XSetCursorState(display,windows,MagickTrue); 8265 XCheckRefreshWindows(display,windows); 8266 flags=ParseGeometry(radius,&geometry_info); 8267 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma, 8268 exception); 8269 if (blur_image != (Image *) NULL) 8270 { 8271 *image=DestroyImage(*image); 8272 *image=blur_image; 8273 } 8274 CatchException(exception); 8275 XSetCursorState(display,windows,MagickFalse); 8276 if (windows->image.orphan != MagickFalse ) 8277 break; 8278 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8279 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8280 break; 8281 } 8282 case ThresholdCommand: 8283 { 8284 double 8285 threshold; 8286 8287 static char 8288 factor[MagickPathExtent] = "128"; 8289 8290 /* 8291 Query user for threshold value. 8292 */ 8293 (void) XDialogWidget(display,windows,"Threshold", 8294 "Enter threshold value:",factor); 8295 if (*factor == '\0') 8296 break; 8297 /* 8298 Gamma correct image. 8299 */ 8300 XSetCursorState(display,windows,MagickTrue); 8301 XCheckRefreshWindows(display,windows); 8302 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8303 (void) BilevelImage(*image,threshold,exception); 8304 XSetCursorState(display,windows,MagickFalse); 8305 if (windows->image.orphan != MagickFalse ) 8306 break; 8307 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8308 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8309 break; 8310 } 8311 case EdgeDetectCommand: 8312 { 8313 Image 8314 *edge_image; 8315 8316 static char 8317 radius[MagickPathExtent] = "0"; 8318 8319 /* 8320 Query user for edge factor. 8321 */ 8322 (void) XDialogWidget(display,windows,"Detect Edges", 8323 "Enter the edge detect radius:",radius); 8324 if (*radius == '\0') 8325 break; 8326 /* 8327 Detect edge in image. 8328 */ 8329 XSetCursorState(display,windows,MagickTrue); 8330 XCheckRefreshWindows(display,windows); 8331 flags=ParseGeometry(radius,&geometry_info); 8332 edge_image=EdgeImage(*image,geometry_info.rho,exception); 8333 if (edge_image != (Image *) NULL) 8334 { 8335 *image=DestroyImage(*image); 8336 *image=edge_image; 8337 } 8338 CatchException(exception); 8339 XSetCursorState(display,windows,MagickFalse); 8340 if (windows->image.orphan != MagickFalse ) 8341 break; 8342 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8343 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8344 break; 8345 } 8346 case SpreadCommand: 8347 { 8348 Image 8349 *spread_image; 8350 8351 static char 8352 amount[MagickPathExtent] = "2"; 8353 8354 /* 8355 Query user for spread amount. 8356 */ 8357 (void) XDialogWidget(display,windows,"Spread", 8358 "Enter the displacement amount:",amount); 8359 if (*amount == '\0') 8360 break; 8361 /* 8362 Displace image pixels by a random amount. 8363 */ 8364 XSetCursorState(display,windows,MagickTrue); 8365 XCheckRefreshWindows(display,windows); 8366 flags=ParseGeometry(amount,&geometry_info); 8367 spread_image=EdgeImage(*image,geometry_info.rho,exception); 8368 if (spread_image != (Image *) NULL) 8369 { 8370 *image=DestroyImage(*image); 8371 *image=spread_image; 8372 } 8373 CatchException(exception); 8374 XSetCursorState(display,windows,MagickFalse); 8375 if (windows->image.orphan != MagickFalse ) 8376 break; 8377 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8378 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8379 break; 8380 } 8381 case ShadeCommand: 8382 { 8383 Image 8384 *shade_image; 8385 8386 int 8387 status; 8388 8389 static char 8390 geometry[MagickPathExtent] = "30x30"; 8391 8392 /* 8393 Query user for the shade geometry. 8394 */ 8395 status=XDialogWidget(display,windows,"Shade", 8396 "Enter the azimuth and elevation of the light source:",geometry); 8397 if (*geometry == '\0') 8398 break; 8399 /* 8400 Shade image pixels. 8401 */ 8402 XSetCursorState(display,windows,MagickTrue); 8403 XCheckRefreshWindows(display,windows); 8404 flags=ParseGeometry(geometry,&geometry_info); 8405 if ((flags & SigmaValue) == 0) 8406 geometry_info.sigma=1.0; 8407 shade_image=ShadeImage(*image,status != 0 ? MagickTrue : MagickFalse, 8408 geometry_info.rho,geometry_info.sigma,exception); 8409 if (shade_image != (Image *) NULL) 8410 { 8411 *image=DestroyImage(*image); 8412 *image=shade_image; 8413 } 8414 CatchException(exception); 8415 XSetCursorState(display,windows,MagickFalse); 8416 if (windows->image.orphan != MagickFalse ) 8417 break; 8418 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8419 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8420 break; 8421 } 8422 case RaiseCommand: 8423 { 8424 static char 8425 bevel_width[MagickPathExtent] = "10"; 8426 8427 /* 8428 Query user for bevel width. 8429 */ 8430 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8431 if (*bevel_width == '\0') 8432 break; 8433 /* 8434 Raise an image. 8435 */ 8436 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8437 exception); 8438 XSetCursorState(display,windows,MagickTrue); 8439 XCheckRefreshWindows(display,windows); 8440 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8441 exception); 8442 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception); 8443 XSetCursorState(display,windows,MagickFalse); 8444 if (windows->image.orphan != MagickFalse ) 8445 break; 8446 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8447 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8448 break; 8449 } 8450 case SegmentCommand: 8451 { 8452 static char 8453 threshold[MagickPathExtent] = "1.0x1.5"; 8454 8455 /* 8456 Query user for smoothing threshold. 8457 */ 8458 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8459 threshold); 8460 if (*threshold == '\0') 8461 break; 8462 /* 8463 Segment an image. 8464 */ 8465 XSetCursorState(display,windows,MagickTrue); 8466 XCheckRefreshWindows(display,windows); 8467 flags=ParseGeometry(threshold,&geometry_info); 8468 if ((flags & SigmaValue) == 0) 8469 geometry_info.sigma=1.0; 8470 (void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho, 8471 geometry_info.sigma,exception); 8472 XSetCursorState(display,windows,MagickFalse); 8473 if (windows->image.orphan != MagickFalse ) 8474 break; 8475 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8476 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8477 break; 8478 } 8479 case SepiaToneCommand: 8480 { 8481 double 8482 threshold; 8483 8484 Image 8485 *sepia_image; 8486 8487 static char 8488 factor[MagickPathExtent] = "80%"; 8489 8490 /* 8491 Query user for sepia-tone factor. 8492 */ 8493 (void) XDialogWidget(display,windows,"Sepia Tone", 8494 "Enter the sepia tone factor (0 - 99.9%):",factor); 8495 if (*factor == '\0') 8496 break; 8497 /* 8498 Sepia tone image pixels. 8499 */ 8500 XSetCursorState(display,windows,MagickTrue); 8501 XCheckRefreshWindows(display,windows); 8502 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8503 sepia_image=SepiaToneImage(*image,threshold,exception); 8504 if (sepia_image != (Image *) NULL) 8505 { 8506 *image=DestroyImage(*image); 8507 *image=sepia_image; 8508 } 8509 CatchException(exception); 8510 XSetCursorState(display,windows,MagickFalse); 8511 if (windows->image.orphan != MagickFalse ) 8512 break; 8513 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8514 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8515 break; 8516 } 8517 case SolarizeCommand: 8518 { 8519 double 8520 threshold; 8521 8522 static char 8523 factor[MagickPathExtent] = "60%"; 8524 8525 /* 8526 Query user for solarize factor. 8527 */ 8528 (void) XDialogWidget(display,windows,"Solarize", 8529 "Enter the solarize factor (0 - 99.9%):",factor); 8530 if (*factor == '\0') 8531 break; 8532 /* 8533 Solarize image pixels. 8534 */ 8535 XSetCursorState(display,windows,MagickTrue); 8536 XCheckRefreshWindows(display,windows); 8537 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8538 (void) SolarizeImage(*image,threshold,exception); 8539 XSetCursorState(display,windows,MagickFalse); 8540 if (windows->image.orphan != MagickFalse ) 8541 break; 8542 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8543 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8544 break; 8545 } 8546 case SwirlCommand: 8547 { 8548 Image 8549 *swirl_image; 8550 8551 static char 8552 degrees[MagickPathExtent] = "60"; 8553 8554 /* 8555 Query user for swirl angle. 8556 */ 8557 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8558 degrees); 8559 if (*degrees == '\0') 8560 break; 8561 /* 8562 Swirl image pixels about the center. 8563 */ 8564 XSetCursorState(display,windows,MagickTrue); 8565 XCheckRefreshWindows(display,windows); 8566 flags=ParseGeometry(degrees,&geometry_info); 8567 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate, 8568 exception); 8569 if (swirl_image != (Image *) NULL) 8570 { 8571 *image=DestroyImage(*image); 8572 *image=swirl_image; 8573 } 8574 CatchException(exception); 8575 XSetCursorState(display,windows,MagickFalse); 8576 if (windows->image.orphan != MagickFalse ) 8577 break; 8578 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8579 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8580 break; 8581 } 8582 case ImplodeCommand: 8583 { 8584 Image 8585 *implode_image; 8586 8587 static char 8588 factor[MagickPathExtent] = "0.3"; 8589 8590 /* 8591 Query user for implode factor. 8592 */ 8593 (void) XDialogWidget(display,windows,"Implode", 8594 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8595 if (*factor == '\0') 8596 break; 8597 /* 8598 Implode image pixels about the center. 8599 */ 8600 XSetCursorState(display,windows,MagickTrue); 8601 XCheckRefreshWindows(display,windows); 8602 flags=ParseGeometry(factor,&geometry_info); 8603 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate, 8604 exception); 8605 if (implode_image != (Image *) NULL) 8606 { 8607 *image=DestroyImage(*image); 8608 *image=implode_image; 8609 } 8610 CatchException(exception); 8611 XSetCursorState(display,windows,MagickFalse); 8612 if (windows->image.orphan != MagickFalse ) 8613 break; 8614 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8615 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8616 break; 8617 } 8618 case VignetteCommand: 8619 { 8620 Image 8621 *vignette_image; 8622 8623 static char 8624 geometry[MagickPathExtent] = "0x20"; 8625 8626 /* 8627 Query user for the vignette geometry. 8628 */ 8629 (void) XDialogWidget(display,windows,"Vignette", 8630 "Enter the radius, sigma, and x and y offsets:",geometry); 8631 if (*geometry == '\0') 8632 break; 8633 /* 8634 Soften the edges of the image in vignette style 8635 */ 8636 XSetCursorState(display,windows,MagickTrue); 8637 XCheckRefreshWindows(display,windows); 8638 flags=ParseGeometry(geometry,&geometry_info); 8639 if ((flags & SigmaValue) == 0) 8640 geometry_info.sigma=1.0; 8641 if ((flags & XiValue) == 0) 8642 geometry_info.xi=0.1*(*image)->columns; 8643 if ((flags & PsiValue) == 0) 8644 geometry_info.psi=0.1*(*image)->rows; 8645 vignette_image=VignetteImage(*image,geometry_info.rho,0.0,(ssize_t) 8646 ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5), 8647 exception); 8648 if (vignette_image != (Image *) NULL) 8649 { 8650 *image=DestroyImage(*image); 8651 *image=vignette_image; 8652 } 8653 CatchException(exception); 8654 XSetCursorState(display,windows,MagickFalse); 8655 if (windows->image.orphan != MagickFalse ) 8656 break; 8657 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8658 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8659 break; 8660 } 8661 case WaveCommand: 8662 { 8663 Image 8664 *wave_image; 8665 8666 static char 8667 geometry[MagickPathExtent] = "25x150"; 8668 8669 /* 8670 Query user for the wave geometry. 8671 */ 8672 (void) XDialogWidget(display,windows,"Wave", 8673 "Enter the amplitude and length of the wave:",geometry); 8674 if (*geometry == '\0') 8675 break; 8676 /* 8677 Alter an image along a sine wave. 8678 */ 8679 XSetCursorState(display,windows,MagickTrue); 8680 XCheckRefreshWindows(display,windows); 8681 flags=ParseGeometry(geometry,&geometry_info); 8682 if ((flags & SigmaValue) == 0) 8683 geometry_info.sigma=1.0; 8684 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8685 (*image)->interpolate,exception); 8686 if (wave_image != (Image *) NULL) 8687 { 8688 *image=DestroyImage(*image); 8689 *image=wave_image; 8690 } 8691 CatchException(exception); 8692 XSetCursorState(display,windows,MagickFalse); 8693 if (windows->image.orphan != MagickFalse ) 8694 break; 8695 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8696 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8697 break; 8698 } 8699 case OilPaintCommand: 8700 { 8701 Image 8702 *paint_image; 8703 8704 static char 8705 radius[MagickPathExtent] = "0"; 8706 8707 /* 8708 Query user for circular neighborhood radius. 8709 */ 8710 (void) XDialogWidget(display,windows,"Oil Paint", 8711 "Enter the mask radius:",radius); 8712 if (*radius == '\0') 8713 break; 8714 /* 8715 OilPaint image scanlines. 8716 */ 8717 XSetCursorState(display,windows,MagickTrue); 8718 XCheckRefreshWindows(display,windows); 8719 flags=ParseGeometry(radius,&geometry_info); 8720 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma, 8721 exception); 8722 if (paint_image != (Image *) NULL) 8723 { 8724 *image=DestroyImage(*image); 8725 *image=paint_image; 8726 } 8727 CatchException(exception); 8728 XSetCursorState(display,windows,MagickFalse); 8729 if (windows->image.orphan != MagickFalse ) 8730 break; 8731 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8732 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8733 break; 8734 } 8735 case CharcoalDrawCommand: 8736 { 8737 Image 8738 *charcoal_image; 8739 8740 static char 8741 radius[MagickPathExtent] = "0x1"; 8742 8743 /* 8744 Query user for charcoal radius. 8745 */ 8746 (void) XDialogWidget(display,windows,"Charcoal Draw", 8747 "Enter the charcoal radius and sigma:",radius); 8748 if (*radius == '\0') 8749 break; 8750 /* 8751 Charcoal the image. 8752 */ 8753 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8754 exception); 8755 XSetCursorState(display,windows,MagickTrue); 8756 XCheckRefreshWindows(display,windows); 8757 flags=ParseGeometry(radius,&geometry_info); 8758 if ((flags & SigmaValue) == 0) 8759 geometry_info.sigma=geometry_info.rho; 8760 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8761 exception); 8762 if (charcoal_image != (Image *) NULL) 8763 { 8764 *image=DestroyImage(*image); 8765 *image=charcoal_image; 8766 } 8767 CatchException(exception); 8768 XSetCursorState(display,windows,MagickFalse); 8769 if (windows->image.orphan != MagickFalse ) 8770 break; 8771 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8772 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8773 break; 8774 } 8775 case AnnotateCommand: 8776 { 8777 /* 8778 Annotate the image with text. 8779 */ 8780 status=XAnnotateEditImage(display,resource_info,windows,*image,exception); 8781 if (status == MagickFalse) 8782 { 8783 XNoticeWidget(display,windows,"Unable to annotate X image", 8784 (*image)->filename); 8785 break; 8786 } 8787 break; 8788 } 8789 case DrawCommand: 8790 { 8791 /* 8792 Draw image. 8793 */ 8794 status=XDrawEditImage(display,resource_info,windows,image,exception); 8795 if (status == MagickFalse) 8796 { 8797 XNoticeWidget(display,windows,"Unable to draw on the X image", 8798 (*image)->filename); 8799 break; 8800 } 8801 break; 8802 } 8803 case ColorCommand: 8804 { 8805 /* 8806 Color edit. 8807 */ 8808 status=XColorEditImage(display,resource_info,windows,image,exception); 8809 if (status == MagickFalse) 8810 { 8811 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8812 (*image)->filename); 8813 break; 8814 } 8815 break; 8816 } 8817 case MatteCommand: 8818 { 8819 /* 8820 Matte edit. 8821 */ 8822 status=XMatteEditImage(display,resource_info,windows,image,exception); 8823 if (status == MagickFalse) 8824 { 8825 XNoticeWidget(display,windows,"Unable to matte edit X image", 8826 (*image)->filename); 8827 break; 8828 } 8829 break; 8830 } 8831 case CompositeCommand: 8832 { 8833 /* 8834 Composite image. 8835 */ 8836 status=XCompositeImage(display,resource_info,windows,*image, 8837 exception); 8838 if (status == MagickFalse) 8839 { 8840 XNoticeWidget(display,windows,"Unable to composite X image", 8841 (*image)->filename); 8842 break; 8843 } 8844 break; 8845 } 8846 case AddBorderCommand: 8847 { 8848 Image 8849 *border_image; 8850 8851 static char 8852 geometry[MagickPathExtent] = "6x6"; 8853 8854 /* 8855 Query user for border color and geometry. 8856 */ 8857 XColorBrowserWidget(display,windows,"Select",color); 8858 if (*color == '\0') 8859 break; 8860 (void) XDialogWidget(display,windows,"Add Border", 8861 "Enter border geometry:",geometry); 8862 if (*geometry == '\0') 8863 break; 8864 /* 8865 Add a border to the image. 8866 */ 8867 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8868 exception); 8869 XSetCursorState(display,windows,MagickTrue); 8870 XCheckRefreshWindows(display,windows); 8871 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color, 8872 exception); 8873 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8874 exception); 8875 border_image=BorderImage(*image,&page_geometry,(*image)->compose, 8876 exception); 8877 if (border_image != (Image *) NULL) 8878 { 8879 *image=DestroyImage(*image); 8880 *image=border_image; 8881 } 8882 CatchException(exception); 8883 XSetCursorState(display,windows,MagickFalse); 8884 if (windows->image.orphan != MagickFalse ) 8885 break; 8886 windows->image.window_changes.width=(int) (*image)->columns; 8887 windows->image.window_changes.height=(int) (*image)->rows; 8888 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8889 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8890 break; 8891 } 8892 case AddFrameCommand: 8893 { 8894 FrameInfo 8895 frame_info; 8896 8897 Image 8898 *frame_image; 8899 8900 static char 8901 geometry[MagickPathExtent] = "6x6"; 8902 8903 /* 8904 Query user for frame color and geometry. 8905 */ 8906 XColorBrowserWidget(display,windows,"Select",color); 8907 if (*color == '\0') 8908 break; 8909 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8910 geometry); 8911 if (*geometry == '\0') 8912 break; 8913 /* 8914 Surround image with an ornamental border. 8915 */ 8916 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8917 exception); 8918 XSetCursorState(display,windows,MagickTrue); 8919 XCheckRefreshWindows(display,windows); 8920 (void) QueryColorCompliance(color,AllCompliance,&(*image)->alpha_color, 8921 exception); 8922 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8923 exception); 8924 frame_info.width=page_geometry.width; 8925 frame_info.height=page_geometry.height; 8926 frame_info.outer_bevel=page_geometry.x; 8927 frame_info.inner_bevel=page_geometry.y; 8928 frame_info.x=(ssize_t) frame_info.width; 8929 frame_info.y=(ssize_t) frame_info.height; 8930 frame_info.width=(*image)->columns+2*frame_info.width; 8931 frame_info.height=(*image)->rows+2*frame_info.height; 8932 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception); 8933 if (frame_image != (Image *) NULL) 8934 { 8935 *image=DestroyImage(*image); 8936 *image=frame_image; 8937 } 8938 CatchException(exception); 8939 XSetCursorState(display,windows,MagickFalse); 8940 if (windows->image.orphan != MagickFalse ) 8941 break; 8942 windows->image.window_changes.width=(int) (*image)->columns; 8943 windows->image.window_changes.height=(int) (*image)->rows; 8944 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8945 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8946 break; 8947 } 8948 case CommentCommand: 8949 { 8950 const char 8951 *value; 8952 8953 FILE 8954 *file; 8955 8956 int 8957 unique_file; 8958 8959 /* 8960 Edit image comment. 8961 */ 8962 unique_file=AcquireUniqueFileResource(image_info->filename); 8963 if (unique_file == -1) 8964 XNoticeWidget(display,windows,"Unable to edit image comment", 8965 image_info->filename); 8966 value=GetImageProperty(*image,"comment",exception); 8967 if (value == (char *) NULL) 8968 unique_file=close(unique_file)-1; 8969 else 8970 { 8971 register const char 8972 *p; 8973 8974 file=fdopen(unique_file,"w"); 8975 if (file == (FILE *) NULL) 8976 { 8977 XNoticeWidget(display,windows,"Unable to edit image comment", 8978 image_info->filename); 8979 break; 8980 } 8981 for (p=value; *p != '\0'; p++) 8982 (void) fputc((int) *p,file); 8983 (void) fputc('\n',file); 8984 (void) fclose(file); 8985 } 8986 XSetCursorState(display,windows,MagickTrue); 8987 XCheckRefreshWindows(display,windows); 8988 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 8989 exception); 8990 if (status == MagickFalse) 8991 XNoticeWidget(display,windows,"Unable to edit image comment", 8992 (char *) NULL); 8993 else 8994 { 8995 char 8996 *comment; 8997 8998 comment=FileToString(image_info->filename,~0UL,exception); 8999 if (comment != (char *) NULL) 9000 { 9001 (void) SetImageProperty(*image,"comment",comment,exception); 9002 (*image)->taint=MagickTrue; 9003 } 9004 } 9005 (void) RelinquishUniqueFileResource(image_info->filename); 9006 XSetCursorState(display,windows,MagickFalse); 9007 break; 9008 } 9009 case LaunchCommand: 9010 { 9011 /* 9012 Launch program. 9013 */ 9014 XSetCursorState(display,windows,MagickTrue); 9015 XCheckRefreshWindows(display,windows); 9016 (void) AcquireUniqueFilename(filename); 9017 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"launch:%s", 9018 filename); 9019 status=WriteImage(image_info,*image,exception); 9020 if (status == MagickFalse) 9021 XNoticeWidget(display,windows,"Unable to launch image editor", 9022 (char *) NULL); 9023 else 9024 { 9025 nexus=ReadImage(resource_info->image_info,exception); 9026 CatchException(exception); 9027 XClientMessage(display,windows->image.id,windows->im_protocols, 9028 windows->im_next_image,CurrentTime); 9029 } 9030 (void) RelinquishUniqueFileResource(filename); 9031 XSetCursorState(display,windows,MagickFalse); 9032 break; 9033 } 9034 case RegionofInterestCommand: 9035 { 9036 /* 9037 Apply an image processing technique to a region of interest. 9038 */ 9039 (void) XROIImage(display,resource_info,windows,image,exception); 9040 break; 9041 } 9042 case InfoCommand: 9043 break; 9044 case ZoomCommand: 9045 { 9046 /* 9047 Zoom image. 9048 */ 9049 if (windows->magnify.mapped != MagickFalse ) 9050 (void) XRaiseWindow(display,windows->magnify.id); 9051 else 9052 { 9053 /* 9054 Make magnify image. 9055 */ 9056 XSetCursorState(display,windows,MagickTrue); 9057 (void) XMapRaised(display,windows->magnify.id); 9058 XSetCursorState(display,windows,MagickFalse); 9059 } 9060 break; 9061 } 9062 case ShowPreviewCommand: 9063 { 9064 char 9065 **previews, 9066 value[MagickPathExtent]; 9067 9068 Image 9069 *preview_image; 9070 9071 static char 9072 preview_type[MagickPathExtent] = "Gamma"; 9073 9074 /* 9075 Select preview type from menu. 9076 */ 9077 previews=GetCommandOptions(MagickPreviewOptions); 9078 if (previews == (char **) NULL) 9079 break; 9080 XListBrowserWidget(display,windows,&windows->widget, 9081 (const char **) previews,"Preview", 9082 "Select an enhancement, effect, or F/X:",preview_type); 9083 previews=DestroyStringList(previews); 9084 if (*preview_type == '\0') 9085 break; 9086 /* 9087 Show image preview. 9088 */ 9089 XSetCursorState(display,windows,MagickTrue); 9090 XCheckRefreshWindows(display,windows); 9091 image_info->preview_type=(PreviewType) 9092 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type); 9093 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double) 9094 windows->image.id); 9095 (void) SetImageProperty(*image,"group",value,exception); 9096 (void) DeleteImageProperty(*image,"label"); 9097 (void) SetImageProperty(*image,"label","Preview",exception); 9098 (void) AcquireUniqueFilename(filename); 9099 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"preview:%s", 9100 filename); 9101 status=WriteImage(image_info,*image,exception); 9102 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent); 9103 preview_image=ReadImage(image_info,exception); 9104 (void) RelinquishUniqueFileResource(filename); 9105 if (preview_image == (Image *) NULL) 9106 break; 9107 (void) FormatLocaleString(preview_image->filename,MagickPathExtent,"show:%s", 9108 filename); 9109 status=WriteImage(image_info,preview_image,exception); 9110 preview_image=DestroyImage(preview_image); 9111 if (status == MagickFalse) 9112 XNoticeWidget(display,windows,"Unable to show image preview", 9113 (*image)->filename); 9114 XDelay(display,1500); 9115 XSetCursorState(display,windows,MagickFalse); 9116 break; 9117 } 9118 case ShowHistogramCommand: 9119 { 9120 char 9121 value[MagickPathExtent]; 9122 9123 Image 9124 *histogram_image; 9125 9126 /* 9127 Show image histogram. 9128 */ 9129 XSetCursorState(display,windows,MagickTrue); 9130 XCheckRefreshWindows(display,windows); 9131 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double) 9132 windows->image.id); 9133 (void) SetImageProperty(*image,"group",value,exception); 9134 (void) DeleteImageProperty(*image,"label"); 9135 (void) SetImageProperty(*image,"label","Histogram",exception); 9136 (void) AcquireUniqueFilename(filename); 9137 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"histogram:%s", 9138 filename); 9139 status=WriteImage(image_info,*image,exception); 9140 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent); 9141 histogram_image=ReadImage(image_info,exception); 9142 (void) RelinquishUniqueFileResource(filename); 9143 if (histogram_image == (Image *) NULL) 9144 break; 9145 (void) FormatLocaleString(histogram_image->filename,MagickPathExtent, 9146 "show:%s",filename); 9147 status=WriteImage(image_info,histogram_image,exception); 9148 histogram_image=DestroyImage(histogram_image); 9149 if (status == MagickFalse) 9150 XNoticeWidget(display,windows,"Unable to show histogram", 9151 (*image)->filename); 9152 XDelay(display,1500); 9153 XSetCursorState(display,windows,MagickFalse); 9154 break; 9155 } 9156 case ShowMatteCommand: 9157 { 9158 char 9159 value[MagickPathExtent]; 9160 9161 Image 9162 *matte_image; 9163 9164 if ((*image)->alpha_trait == UndefinedPixelTrait) 9165 { 9166 XNoticeWidget(display,windows, 9167 "Image does not have any matte information",(*image)->filename); 9168 break; 9169 } 9170 /* 9171 Show image matte. 9172 */ 9173 XSetCursorState(display,windows,MagickTrue); 9174 XCheckRefreshWindows(display,windows); 9175 (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double) 9176 windows->image.id); 9177 (void) SetImageProperty(*image,"group",value,exception); 9178 (void) DeleteImageProperty(*image,"label"); 9179 (void) SetImageProperty(*image,"label","Matte",exception); 9180 (void) AcquireUniqueFilename(filename); 9181 (void) FormatLocaleString((*image)->filename,MagickPathExtent,"matte:%s", 9182 filename); 9183 status=WriteImage(image_info,*image,exception); 9184 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent); 9185 matte_image=ReadImage(image_info,exception); 9186 (void) RelinquishUniqueFileResource(filename); 9187 if (matte_image == (Image *) NULL) 9188 break; 9189 (void) FormatLocaleString(matte_image->filename,MagickPathExtent,"show:%s", 9190 filename); 9191 status=WriteImage(image_info,matte_image,exception); 9192 matte_image=DestroyImage(matte_image); 9193 if (status == MagickFalse) 9194 XNoticeWidget(display,windows,"Unable to show matte", 9195 (*image)->filename); 9196 XDelay(display,1500); 9197 XSetCursorState(display,windows,MagickFalse); 9198 break; 9199 } 9200 case BackgroundCommand: 9201 { 9202 /* 9203 Background image. 9204 */ 9205 status=XBackgroundImage(display,resource_info,windows,image,exception); 9206 if (status == MagickFalse) 9207 break; 9208 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9209 if (nexus != (Image *) NULL) 9210 XClientMessage(display,windows->image.id,windows->im_protocols, 9211 windows->im_next_image,CurrentTime); 9212 break; 9213 } 9214 case SlideShowCommand: 9215 { 9216 static char 9217 delay[MagickPathExtent] = "5"; 9218 9219 /* 9220 Display next image after pausing. 9221 */ 9222 (void) XDialogWidget(display,windows,"Slide Show", 9223 "Pause how many 1/100ths of a second between images:",delay); 9224 if (*delay == '\0') 9225 break; 9226 resource_info->delay=StringToUnsignedLong(delay); 9227 XClientMessage(display,windows->image.id,windows->im_protocols, 9228 windows->im_next_image,CurrentTime); 9229 break; 9230 } 9231 case PreferencesCommand: 9232 { 9233 /* 9234 Set user preferences. 9235 */ 9236 status=XPreferencesWidget(display,resource_info,windows); 9237 if (status == MagickFalse) 9238 break; 9239 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9240 if (nexus != (Image *) NULL) 9241 XClientMessage(display,windows->image.id,windows->im_protocols, 9242 windows->im_next_image,CurrentTime); 9243 break; 9244 } 9245 case HelpCommand: 9246 { 9247 /* 9248 User requested help. 9249 */ 9250 XTextViewWidget(display,resource_info,windows,MagickFalse, 9251 "Help Viewer - Display",DisplayHelp); 9252 break; 9253 } 9254 case BrowseDocumentationCommand: 9255 { 9256 Atom 9257 mozilla_atom; 9258 9259 Window 9260 mozilla_window, 9261 root_window; 9262 9263 /* 9264 Browse the ImageMagick documentation. 9265 */ 9266 root_window=XRootWindow(display,XDefaultScreen(display)); 9267 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); 9268 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); 9269 if (mozilla_window != (Window) NULL) 9270 { 9271 char 9272 command[MagickPathExtent], 9273 *url; 9274 9275 /* 9276 Display documentation using Netscape remote control. 9277 */ 9278 url=GetMagickHomeURL(); 9279 (void) FormatLocaleString(command,MagickPathExtent, 9280 "openurl(%s,new-tab)",url); 9281 url=DestroyString(url); 9282 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); 9283 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING, 9284 8,PropModeReplace,(unsigned char *) command,(int) strlen(command)); 9285 XSetCursorState(display,windows,MagickFalse); 9286 break; 9287 } 9288 XSetCursorState(display,windows,MagickTrue); 9289 XCheckRefreshWindows(display,windows); 9290 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL, 9291 exception); 9292 if (status == MagickFalse) 9293 XNoticeWidget(display,windows,"Unable to browse documentation", 9294 (char *) NULL); 9295 XDelay(display,1500); 9296 XSetCursorState(display,windows,MagickFalse); 9297 break; 9298 } 9299 case VersionCommand: 9300 { 9301 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), 9302 GetMagickCopyright()); 9303 break; 9304 } 9305 case SaveToUndoBufferCommand: 9306 break; 9307 default: 9308 { 9309 (void) XBell(display,0); 9310 break; 9311 } 9312 } 9313 image_info=DestroyImageInfo(image_info); 9314 return(nexus); 9315} 9316 9317/* 9318%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9319% % 9320% % 9321% % 9322+ X M a g n i f y I m a g e % 9323% % 9324% % 9325% % 9326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9327% 9328% XMagnifyImage() magnifies portions of the image as indicated by the pointer. 9329% The magnified portion is displayed in a separate window. 9330% 9331% The format of the XMagnifyImage method is: 9332% 9333% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9334% ExceptionInfo *exception) 9335% 9336% A description of each parameter follows: 9337% 9338% o display: Specifies a connection to an X server; returned from 9339% XOpenDisplay. 9340% 9341% o windows: Specifies a pointer to a XWindows structure. 9342% 9343% o event: Specifies a pointer to a XEvent structure. If it is NULL, 9344% the entire image is refreshed. 9345% 9346% o exception: return any errors or warnings in this structure. 9347% 9348*/ 9349static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9350 ExceptionInfo *exception) 9351{ 9352 char 9353 text[MagickPathExtent]; 9354 9355 register int 9356 x, 9357 y; 9358 9359 size_t 9360 state; 9361 9362 /* 9363 Update magnified image until the mouse button is released. 9364 */ 9365 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor); 9366 state=DefaultState; 9367 x=event->xbutton.x; 9368 y=event->xbutton.y; 9369 windows->magnify.x=(int) windows->image.x+x; 9370 windows->magnify.y=(int) windows->image.y+y; 9371 do 9372 { 9373 /* 9374 Map and unmap Info widget as text cursor crosses its boundaries. 9375 */ 9376 if (windows->info.mapped != MagickFalse ) 9377 { 9378 if ((x < (int) (windows->info.x+windows->info.width)) && 9379 (y < (int) (windows->info.y+windows->info.height))) 9380 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 9381 } 9382 else 9383 if ((x > (int) (windows->info.x+windows->info.width)) || 9384 (y > (int) (windows->info.y+windows->info.height))) 9385 (void) XMapWindow(display,windows->info.id); 9386 if (windows->info.mapped != MagickFalse ) 9387 { 9388 /* 9389 Display pointer position. 9390 */ 9391 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ", 9392 windows->magnify.x,windows->magnify.y); 9393 XInfoWidget(display,windows,text); 9394 } 9395 /* 9396 Wait for next event. 9397 */ 9398 XScreenEvent(display,windows,event,exception); 9399 switch (event->type) 9400 { 9401 case ButtonPress: 9402 break; 9403 case ButtonRelease: 9404 { 9405 /* 9406 User has finished magnifying image. 9407 */ 9408 x=event->xbutton.x; 9409 y=event->xbutton.y; 9410 state|=ExitState; 9411 break; 9412 } 9413 case Expose: 9414 break; 9415 case MotionNotify: 9416 { 9417 x=event->xmotion.x; 9418 y=event->xmotion.y; 9419 break; 9420 } 9421 default: 9422 break; 9423 } 9424 /* 9425 Check boundary conditions. 9426 */ 9427 if (x < 0) 9428 x=0; 9429 else 9430 if (x >= (int) windows->image.width) 9431 x=(int) windows->image.width-1; 9432 if (y < 0) 9433 y=0; 9434 else 9435 if (y >= (int) windows->image.height) 9436 y=(int) windows->image.height-1; 9437 } while ((state & ExitState) == 0); 9438 /* 9439 Display magnified image. 9440 */ 9441 XSetCursorState(display,windows,MagickFalse); 9442} 9443 9444/* 9445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9446% % 9447% % 9448% % 9449+ X M a g n i f y W i n d o w C o m m a n d % 9450% % 9451% % 9452% % 9453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9454% 9455% XMagnifyWindowCommand() moves the image within an Magnify window by one 9456% pixel as specified by the key symbol. 9457% 9458% The format of the XMagnifyWindowCommand method is: 9459% 9460% void XMagnifyWindowCommand(Display *display,XWindows *windows, 9461% const MagickStatusType state,const KeySym key_symbol, 9462% ExceptionInfo *exception) 9463% 9464% A description of each parameter follows: 9465% 9466% o display: Specifies a connection to an X server; returned from 9467% XOpenDisplay. 9468% 9469% o windows: Specifies a pointer to a XWindows structure. 9470% 9471% o state: key mask. 9472% 9473% o key_symbol: Specifies a KeySym which indicates which side of the image 9474% to trim. 9475% 9476% o exception: return any errors or warnings in this structure. 9477% 9478*/ 9479static void XMagnifyWindowCommand(Display *display,XWindows *windows, 9480 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception) 9481{ 9482 unsigned int 9483 quantum; 9484 9485 /* 9486 User specified a magnify factor or position. 9487 */ 9488 quantum=1; 9489 if ((state & Mod1Mask) != 0) 9490 quantum=10; 9491 switch ((int) key_symbol) 9492 { 9493 case QuitCommand: 9494 { 9495 (void) XWithdrawWindow(display,windows->magnify.id, 9496 windows->magnify.screen); 9497 break; 9498 } 9499 case XK_Home: 9500 case XK_KP_Home: 9501 { 9502 windows->magnify.x=(int) windows->image.width/2; 9503 windows->magnify.y=(int) windows->image.height/2; 9504 break; 9505 } 9506 case XK_Left: 9507 case XK_KP_Left: 9508 { 9509 if (windows->magnify.x > 0) 9510 windows->magnify.x-=quantum; 9511 break; 9512 } 9513 case XK_Up: 9514 case XK_KP_Up: 9515 { 9516 if (windows->magnify.y > 0) 9517 windows->magnify.y-=quantum; 9518 break; 9519 } 9520 case XK_Right: 9521 case XK_KP_Right: 9522 { 9523 if (windows->magnify.x < (int) (windows->image.ximage->width-1)) 9524 windows->magnify.x+=quantum; 9525 break; 9526 } 9527 case XK_Down: 9528 case XK_KP_Down: 9529 { 9530 if (windows->magnify.y < (int) (windows->image.ximage->height-1)) 9531 windows->magnify.y+=quantum; 9532 break; 9533 } 9534 case XK_0: 9535 case XK_1: 9536 case XK_2: 9537 case XK_3: 9538 case XK_4: 9539 case XK_5: 9540 case XK_6: 9541 case XK_7: 9542 case XK_8: 9543 case XK_9: 9544 { 9545 windows->magnify.data=(key_symbol-XK_0); 9546 break; 9547 } 9548 case XK_KP_0: 9549 case XK_KP_1: 9550 case XK_KP_2: 9551 case XK_KP_3: 9552 case XK_KP_4: 9553 case XK_KP_5: 9554 case XK_KP_6: 9555 case XK_KP_7: 9556 case XK_KP_8: 9557 case XK_KP_9: 9558 { 9559 windows->magnify.data=(key_symbol-XK_KP_0); 9560 break; 9561 } 9562 default: 9563 break; 9564 } 9565 XMakeMagnifyImage(display,windows,exception); 9566} 9567 9568/* 9569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9570% % 9571% % 9572% % 9573+ X M a k e P a n I m a g e % 9574% % 9575% % 9576% % 9577%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9578% 9579% XMakePanImage() creates a thumbnail of the image and displays it in the Pan 9580% icon window. 9581% 9582% The format of the XMakePanImage method is: 9583% 9584% void XMakePanImage(Display *display,XResourceInfo *resource_info, 9585% XWindows *windows,Image *image,ExceptionInfo *exception) 9586% 9587% A description of each parameter follows: 9588% 9589% o display: Specifies a connection to an X server; returned from 9590% XOpenDisplay. 9591% 9592% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9593% 9594% o windows: Specifies a pointer to a XWindows structure. 9595% 9596% o image: the image. 9597% 9598% o exception: return any errors or warnings in this structure. 9599% 9600*/ 9601static void XMakePanImage(Display *display,XResourceInfo *resource_info, 9602 XWindows *windows,Image *image,ExceptionInfo *exception) 9603{ 9604 MagickStatusType 9605 status; 9606 9607 /* 9608 Create and display image for panning icon. 9609 */ 9610 XSetCursorState(display,windows,MagickTrue); 9611 XCheckRefreshWindows(display,windows); 9612 windows->pan.x=(int) windows->image.x; 9613 windows->pan.y=(int) windows->image.y; 9614 status=XMakeImage(display,resource_info,&windows->pan,image, 9615 windows->pan.width,windows->pan.height,exception); 9616 if (status == MagickFalse) 9617 ThrowXWindowException(ResourceLimitError, 9618 "MemoryAllocationFailed",image->filename); 9619 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 9620 windows->pan.pixmap); 9621 (void) XClearWindow(display,windows->pan.id); 9622 XDrawPanRectangle(display,windows); 9623 XSetCursorState(display,windows,MagickFalse); 9624} 9625 9626/* 9627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9628% % 9629% % 9630% % 9631+ X M a t t a E d i t I m a g e % 9632% % 9633% % 9634% % 9635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9636% 9637% XMatteEditImage() allows the user to interactively change the Matte channel 9638% of an image. If the image is PseudoClass it is promoted to DirectClass 9639% before the matte information is stored. 9640% 9641% The format of the XMatteEditImage method is: 9642% 9643% MagickBooleanType XMatteEditImage(Display *display, 9644% XResourceInfo *resource_info,XWindows *windows,Image **image, 9645% ExceptionInfo *exception) 9646% 9647% A description of each parameter follows: 9648% 9649% o display: Specifies a connection to an X server; returned from 9650% XOpenDisplay. 9651% 9652% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9653% 9654% o windows: Specifies a pointer to a XWindows structure. 9655% 9656% o image: the image; returned from ReadImage. 9657% 9658% o exception: return any errors or warnings in this structure. 9659% 9660*/ 9661static MagickBooleanType XMatteEditImage(Display *display, 9662 XResourceInfo *resource_info,XWindows *windows,Image **image, 9663 ExceptionInfo *exception) 9664{ 9665 static char 9666 matte[MagickPathExtent] = "0"; 9667 9668 static const char 9669 *MatteEditMenu[] = 9670 { 9671 "Method", 9672 "Border Color", 9673 "Fuzz", 9674 "Matte Value", 9675 "Undo", 9676 "Help", 9677 "Dismiss", 9678 (char *) NULL 9679 }; 9680 9681 static const ModeType 9682 MatteEditCommands[] = 9683 { 9684 MatteEditMethod, 9685 MatteEditBorderCommand, 9686 MatteEditFuzzCommand, 9687 MatteEditValueCommand, 9688 MatteEditUndoCommand, 9689 MatteEditHelpCommand, 9690 MatteEditDismissCommand 9691 }; 9692 9693 static PaintMethod 9694 method = PointMethod; 9695 9696 static XColor 9697 border_color = { 0, 0, 0, 0, 0, 0 }; 9698 9699 char 9700 command[MagickPathExtent], 9701 text[MagickPathExtent]; 9702 9703 Cursor 9704 cursor; 9705 9706 int 9707 entry, 9708 id, 9709 x, 9710 x_offset, 9711 y, 9712 y_offset; 9713 9714 register int 9715 i; 9716 9717 register Quantum 9718 *q; 9719 9720 unsigned int 9721 height, 9722 width; 9723 9724 size_t 9725 state; 9726 9727 XEvent 9728 event; 9729 9730 /* 9731 Map Command widget. 9732 */ 9733 (void) CloneString(&windows->command.name,"Matte Edit"); 9734 windows->command.data=4; 9735 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL); 9736 (void) XMapRaised(display,windows->command.id); 9737 XClientMessage(display,windows->image.id,windows->im_protocols, 9738 windows->im_update_widget,CurrentTime); 9739 /* 9740 Make cursor. 9741 */ 9742 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 9743 resource_info->background_color,resource_info->foreground_color); 9744 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9745 /* 9746 Track pointer until button 1 is pressed. 9747 */ 9748 XQueryPosition(display,windows->image.id,&x,&y); 9749 (void) XSelectInput(display,windows->image.id, 9750 windows->image.attributes.event_mask | PointerMotionMask); 9751 state=DefaultState; 9752 do 9753 { 9754 if (windows->info.mapped != MagickFalse ) 9755 { 9756 /* 9757 Display pointer position. 9758 */ 9759 (void) FormatLocaleString(text,MagickPathExtent," %+d%+d ", 9760 x+windows->image.x,y+windows->image.y); 9761 XInfoWidget(display,windows,text); 9762 } 9763 /* 9764 Wait for next event. 9765 */ 9766 XScreenEvent(display,windows,&event,exception); 9767 if (event.xany.window == windows->command.id) 9768 { 9769 /* 9770 Select a command from the Command widget. 9771 */ 9772 id=XCommandWidget(display,windows,MatteEditMenu,&event); 9773 if (id < 0) 9774 { 9775 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9776 continue; 9777 } 9778 switch (MatteEditCommands[id]) 9779 { 9780 case MatteEditMethod: 9781 { 9782 char 9783 **methods; 9784 9785 /* 9786 Select a method from the pop-up menu. 9787 */ 9788 methods=GetCommandOptions(MagickMethodOptions); 9789 if (methods == (char **) NULL) 9790 break; 9791 entry=XMenuWidget(display,windows,MatteEditMenu[id], 9792 (const char **) methods,command); 9793 if (entry >= 0) 9794 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 9795 MagickFalse,methods[entry]); 9796 methods=DestroyStringList(methods); 9797 break; 9798 } 9799 case MatteEditBorderCommand: 9800 { 9801 const char 9802 *ColorMenu[MaxNumberPens]; 9803 9804 int 9805 pen_number; 9806 9807 /* 9808 Initialize menu selections. 9809 */ 9810 for (i=0; i < (int) (MaxNumberPens-2); i++) 9811 ColorMenu[i]=resource_info->pen_colors[i]; 9812 ColorMenu[MaxNumberPens-2]="Browser..."; 9813 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 9814 /* 9815 Select a pen color from the pop-up menu. 9816 */ 9817 pen_number=XMenuWidget(display,windows,MatteEditMenu[id], 9818 (const char **) ColorMenu,command); 9819 if (pen_number < 0) 9820 break; 9821 if (pen_number == (MaxNumberPens-2)) 9822 { 9823 static char 9824 color_name[MagickPathExtent] = "gray"; 9825 9826 /* 9827 Select a pen color from a dialog. 9828 */ 9829 resource_info->pen_colors[pen_number]=color_name; 9830 XColorBrowserWidget(display,windows,"Select",color_name); 9831 if (*color_name == '\0') 9832 break; 9833 } 9834 /* 9835 Set border color. 9836 */ 9837 (void) XParseColor(display,windows->map_info->colormap, 9838 resource_info->pen_colors[pen_number],&border_color); 9839 break; 9840 } 9841 case MatteEditFuzzCommand: 9842 { 9843 static char 9844 fuzz[MagickPathExtent]; 9845 9846 static const char 9847 *FuzzMenu[] = 9848 { 9849 "0%", 9850 "2%", 9851 "5%", 9852 "10%", 9853 "15%", 9854 "Dialog...", 9855 (char *) NULL, 9856 }; 9857 9858 /* 9859 Select a command from the pop-up menu. 9860 */ 9861 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu, 9862 command); 9863 if (entry < 0) 9864 break; 9865 if (entry != 5) 9866 { 9867 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 9868 QuantumRange+1.0); 9869 break; 9870 } 9871 (void) CopyMagickString(fuzz,"20%",MagickPathExtent); 9872 (void) XDialogWidget(display,windows,"Ok", 9873 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 9874 if (*fuzz == '\0') 9875 break; 9876 (void) ConcatenateMagickString(fuzz,"%",MagickPathExtent); 9877 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 9878 1.0); 9879 break; 9880 } 9881 case MatteEditValueCommand: 9882 { 9883 static char 9884 message[MagickPathExtent]; 9885 9886 static const char 9887 *MatteMenu[] = 9888 { 9889 "Opaque", 9890 "Transparent", 9891 "Dialog...", 9892 (char *) NULL, 9893 }; 9894 9895 /* 9896 Select a command from the pop-up menu. 9897 */ 9898 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu, 9899 command); 9900 if (entry < 0) 9901 break; 9902 if (entry != 2) 9903 { 9904 (void) FormatLocaleString(matte,MagickPathExtent,QuantumFormat, 9905 OpaqueAlpha); 9906 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9907 (void) FormatLocaleString(matte,MagickPathExtent,QuantumFormat, 9908 (Quantum) TransparentAlpha); 9909 break; 9910 } 9911 (void) FormatLocaleString(message,MagickPathExtent, 9912 "Enter matte value (0 - " QuantumFormat "):",(Quantum) 9913 QuantumRange); 9914 (void) XDialogWidget(display,windows,"Matte",message,matte); 9915 if (*matte == '\0') 9916 break; 9917 break; 9918 } 9919 case MatteEditUndoCommand: 9920 { 9921 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 9922 image,exception); 9923 break; 9924 } 9925 case MatteEditHelpCommand: 9926 { 9927 XTextViewWidget(display,resource_info,windows,MagickFalse, 9928 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9929 break; 9930 } 9931 case MatteEditDismissCommand: 9932 { 9933 /* 9934 Prematurely exit. 9935 */ 9936 state|=EscapeState; 9937 state|=ExitState; 9938 break; 9939 } 9940 default: 9941 break; 9942 } 9943 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9944 continue; 9945 } 9946 switch (event.type) 9947 { 9948 case ButtonPress: 9949 { 9950 if (event.xbutton.button != Button1) 9951 break; 9952 if ((event.xbutton.window != windows->image.id) && 9953 (event.xbutton.window != windows->magnify.id)) 9954 break; 9955 /* 9956 Update matte data. 9957 */ 9958 x=event.xbutton.x; 9959 y=event.xbutton.y; 9960 (void) XMagickCommand(display,resource_info,windows, 9961 SaveToUndoBufferCommand,image,exception); 9962 state|=UpdateConfigurationState; 9963 break; 9964 } 9965 case ButtonRelease: 9966 { 9967 if (event.xbutton.button != Button1) 9968 break; 9969 if ((event.xbutton.window != windows->image.id) && 9970 (event.xbutton.window != windows->magnify.id)) 9971 break; 9972 /* 9973 Update colormap information. 9974 */ 9975 x=event.xbutton.x; 9976 y=event.xbutton.y; 9977 XConfigureImageColormap(display,resource_info,windows,*image,exception); 9978 (void) XConfigureImage(display,resource_info,windows,*image,exception); 9979 XInfoWidget(display,windows,text); 9980 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9981 state&=(~UpdateConfigurationState); 9982 break; 9983 } 9984 case Expose: 9985 break; 9986 case KeyPress: 9987 { 9988 char 9989 command[MagickPathExtent]; 9990 9991 KeySym 9992 key_symbol; 9993 9994 if (event.xkey.window == windows->magnify.id) 9995 { 9996 Window 9997 window; 9998 9999 window=windows->magnify.id; 10000 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 10001 } 10002 if (event.xkey.window != windows->image.id) 10003 break; 10004 /* 10005 Respond to a user key press. 10006 */ 10007 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 10008 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10009 switch ((int) key_symbol) 10010 { 10011 case XK_Escape: 10012 case XK_F20: 10013 { 10014 /* 10015 Prematurely exit. 10016 */ 10017 state|=ExitState; 10018 break; 10019 } 10020 case XK_F1: 10021 case XK_Help: 10022 { 10023 XTextViewWidget(display,resource_info,windows,MagickFalse, 10024 "Help Viewer - Matte Edit",ImageMatteEditHelp); 10025 break; 10026 } 10027 default: 10028 { 10029 (void) XBell(display,0); 10030 break; 10031 } 10032 } 10033 break; 10034 } 10035 case MotionNotify: 10036 { 10037 /* 10038 Map and unmap Info widget as cursor crosses its boundaries. 10039 */ 10040 x=event.xmotion.x; 10041 y=event.xmotion.y; 10042 if (windows->info.mapped != MagickFalse ) 10043 { 10044 if ((x < (int) (windows->info.x+windows->info.width)) && 10045 (y < (int) (windows->info.y+windows->info.height))) 10046 (void) XWithdrawWindow(display,windows->info.id, 10047 windows->info.screen); 10048 } 10049 else 10050 if ((x > (int) (windows->info.x+windows->info.width)) || 10051 (y > (int) (windows->info.y+windows->info.height))) 10052 (void) XMapWindow(display,windows->info.id); 10053 break; 10054 } 10055 default: 10056 break; 10057 } 10058 if (event.xany.window == windows->magnify.id) 10059 { 10060 x=windows->magnify.x-windows->image.x; 10061 y=windows->magnify.y-windows->image.y; 10062 } 10063 x_offset=x; 10064 y_offset=y; 10065 if ((state & UpdateConfigurationState) != 0) 10066 { 10067 CacheView 10068 *image_view; 10069 10070 int 10071 x, 10072 y; 10073 10074 /* 10075 Matte edit is relative to image configuration. 10076 */ 10077 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 10078 MagickTrue); 10079 XPutPixel(windows->image.ximage,x_offset,y_offset, 10080 windows->pixel_info->background_color.pixel); 10081 width=(unsigned int) (*image)->columns; 10082 height=(unsigned int) (*image)->rows; 10083 x=0; 10084 y=0; 10085 if (windows->image.crop_geometry != (char *) NULL) 10086 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width, 10087 &height); 10088 x_offset=(int) (width*(windows->image.x+x_offset)/ 10089 windows->image.ximage->width+x); 10090 y_offset=(int) (height*(windows->image.y+y_offset)/ 10091 windows->image.ximage->height+y); 10092 if ((x_offset < 0) || (y_offset < 0)) 10093 continue; 10094 if ((x_offset >= (int) (*image)->columns) || 10095 (y_offset >= (int) (*image)->rows)) 10096 continue; 10097 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10098 return(MagickFalse); 10099 if ((*image)->alpha_trait == UndefinedPixelTrait) 10100 (void) SetImageAlphaChannel(*image,OpaqueAlphaChannel,exception); 10101 image_view=AcquireAuthenticCacheView(*image,exception); 10102 switch (method) 10103 { 10104 case PointMethod: 10105 default: 10106 { 10107 /* 10108 Update matte information using point algorithm. 10109 */ 10110 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset, 10111 (ssize_t) y_offset,1,1,exception); 10112 if (q == (Quantum *) NULL) 10113 break; 10114 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10115 (void) SyncCacheViewAuthenticPixels(image_view,exception); 10116 break; 10117 } 10118 case ReplaceMethod: 10119 { 10120 PixelInfo 10121 pixel, 10122 target; 10123 10124 /* 10125 Update matte information using replace algorithm. 10126 */ 10127 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t) 10128 x_offset,(ssize_t) y_offset,&target,exception); 10129 for (y=0; y < (int) (*image)->rows; y++) 10130 { 10131 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10132 (*image)->columns,1,exception); 10133 if (q == (Quantum *) NULL) 10134 break; 10135 for (x=0; x < (int) (*image)->columns; x++) 10136 { 10137 GetPixelInfoPixel(*image,q,&pixel); 10138 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 10139 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10140 q+=GetPixelChannels(*image); 10141 } 10142 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10143 break; 10144 } 10145 break; 10146 } 10147 case FloodfillMethod: 10148 case FillToBorderMethod: 10149 { 10150 ChannelType 10151 channel_mask; 10152 10153 DrawInfo 10154 *draw_info; 10155 10156 PixelInfo 10157 target; 10158 10159 /* 10160 Update matte information using floodfill algorithm. 10161 */ 10162 (void) GetOneVirtualPixelInfo(*image, 10163 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 10164 y_offset,&target,exception); 10165 if (method == FillToBorderMethod) 10166 { 10167 target.red=(double) ScaleShortToQuantum( 10168 border_color.red); 10169 target.green=(double) ScaleShortToQuantum( 10170 border_color.green); 10171 target.blue=(double) ScaleShortToQuantum( 10172 border_color.blue); 10173 } 10174 draw_info=CloneDrawInfo(resource_info->image_info, 10175 (DrawInfo *) NULL); 10176 draw_info->fill.alpha=(double) ClampToQuantum( 10177 StringToDouble(matte,(char **) NULL)); 10178 channel_mask=SetImageChannelMask(*image,AlphaChannel); 10179 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 10180 x_offset,(ssize_t) y_offset, 10181 method != FloodfillMethod ? MagickTrue : MagickFalse,exception); 10182 (void) SetPixelChannelMask(*image,channel_mask); 10183 draw_info=DestroyDrawInfo(draw_info); 10184 break; 10185 } 10186 case ResetMethod: 10187 { 10188 /* 10189 Update matte information using reset algorithm. 10190 */ 10191 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10192 return(MagickFalse); 10193 for (y=0; y < (int) (*image)->rows; y++) 10194 { 10195 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10196 (*image)->columns,1,exception); 10197 if (q == (Quantum *) NULL) 10198 break; 10199 for (x=0; x < (int) (*image)->columns; x++) 10200 { 10201 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10202 q+=GetPixelChannels(*image); 10203 } 10204 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10205 break; 10206 } 10207 if (StringToLong(matte) == (long) OpaqueAlpha) 10208 (*image)->alpha_trait=UndefinedPixelTrait; 10209 break; 10210 } 10211 } 10212 image_view=DestroyCacheView(image_view); 10213 state&=(~UpdateConfigurationState); 10214 } 10215 } while ((state & ExitState) == 0); 10216 (void) XSelectInput(display,windows->image.id, 10217 windows->image.attributes.event_mask); 10218 XSetCursorState(display,windows,MagickFalse); 10219 (void) XFreeCursor(display,cursor); 10220 return(MagickTrue); 10221} 10222 10223/* 10224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10225% % 10226% % 10227% % 10228+ X O p e n I m a g e % 10229% % 10230% % 10231% % 10232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10233% 10234% XOpenImage() loads an image from a file. 10235% 10236% The format of the XOpenImage method is: 10237% 10238% Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10239% XWindows *windows,const unsigned int command) 10240% 10241% A description of each parameter follows: 10242% 10243% o display: Specifies a connection to an X server; returned from 10244% XOpenDisplay. 10245% 10246% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10247% 10248% o windows: Specifies a pointer to a XWindows structure. 10249% 10250% o command: A value other than zero indicates that the file is selected 10251% from the command line argument list. 10252% 10253*/ 10254static Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10255 XWindows *windows,const MagickBooleanType command) 10256{ 10257 const MagickInfo 10258 *magick_info; 10259 10260 ExceptionInfo 10261 *exception; 10262 10263 Image 10264 *nexus; 10265 10266 ImageInfo 10267 *image_info; 10268 10269 static char 10270 filename[MagickPathExtent] = "\0"; 10271 10272 /* 10273 Request file name from user. 10274 */ 10275 if (command == MagickFalse) 10276 XFileBrowserWidget(display,windows,"Open",filename); 10277 else 10278 { 10279 char 10280 **filelist, 10281 **files; 10282 10283 int 10284 count, 10285 status; 10286 10287 register int 10288 i, 10289 j; 10290 10291 /* 10292 Select next image from the command line. 10293 */ 10294 status=XGetCommand(display,windows->image.id,&files,&count); 10295 if (status == 0) 10296 { 10297 ThrowXWindowException(XServerError,"UnableToGetProperty","..."); 10298 return((Image *) NULL); 10299 } 10300 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10301 if (filelist == (char **) NULL) 10302 { 10303 ThrowXWindowException(ResourceLimitError, 10304 "MemoryAllocationFailed","..."); 10305 (void) XFreeStringList(files); 10306 return((Image *) NULL); 10307 } 10308 j=0; 10309 for (i=1; i < count; i++) 10310 if (*files[i] != '-') 10311 filelist[j++]=files[i]; 10312 filelist[j]=(char *) NULL; 10313 XListBrowserWidget(display,windows,&windows->widget, 10314 (const char **) filelist,"Load","Select Image to Load:",filename); 10315 filelist=(char **) RelinquishMagickMemory(filelist); 10316 (void) XFreeStringList(files); 10317 } 10318 if (*filename == '\0') 10319 return((Image *) NULL); 10320 image_info=CloneImageInfo(resource_info->image_info); 10321 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL, 10322 (void *) NULL); 10323 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent); 10324 exception=AcquireExceptionInfo(); 10325 (void) SetImageInfo(image_info,0,exception); 10326 if (LocaleCompare(image_info->magick,"X") == 0) 10327 { 10328 char 10329 seconds[MagickPathExtent]; 10330 10331 /* 10332 User may want to delay the X server screen grab. 10333 */ 10334 (void) CopyMagickString(seconds,"0",MagickPathExtent); 10335 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:", 10336 seconds); 10337 if (*seconds == '\0') 10338 return((Image *) NULL); 10339 XDelay(display,(size_t) (1000*StringToLong(seconds))); 10340 } 10341 magick_info=GetMagickInfo(image_info->magick,exception); 10342 if ((magick_info != (const MagickInfo *) NULL) && 10343 GetMagickRawSupport(magick_info) == MagickTrue) 10344 { 10345 char 10346 geometry[MagickPathExtent]; 10347 10348 /* 10349 Request image size from the user. 10350 */ 10351 (void) CopyMagickString(geometry,"512x512",MagickPathExtent); 10352 if (image_info->size != (char *) NULL) 10353 (void) CopyMagickString(geometry,image_info->size,MagickPathExtent); 10354 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:", 10355 geometry); 10356 (void) CloneString(&image_info->size,geometry); 10357 } 10358 /* 10359 Load the image. 10360 */ 10361 XSetCursorState(display,windows,MagickTrue); 10362 XCheckRefreshWindows(display,windows); 10363 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent); 10364 nexus=ReadImage(image_info,exception); 10365 CatchException(exception); 10366 XSetCursorState(display,windows,MagickFalse); 10367 if (nexus != (Image *) NULL) 10368 XClientMessage(display,windows->image.id,windows->im_protocols, 10369 windows->im_next_image,CurrentTime); 10370 else 10371 { 10372 char 10373 *text, 10374 **textlist; 10375 10376 /* 10377 Unknown image format. 10378 */ 10379 text=FileToString(filename,~0UL,exception); 10380 if (text == (char *) NULL) 10381 return((Image *) NULL); 10382 textlist=StringToList(text); 10383 if (textlist != (char **) NULL) 10384 { 10385 char 10386 title[MagickPathExtent]; 10387 10388 register int 10389 i; 10390 10391 (void) FormatLocaleString(title,MagickPathExtent, 10392 "Unknown format: %s",filename); 10393 XTextViewWidget(display,resource_info,windows,MagickTrue,title, 10394 (const char **) textlist); 10395 for (i=0; textlist[i] != (char *) NULL; i++) 10396 textlist[i]=DestroyString(textlist[i]); 10397 textlist=(char **) RelinquishMagickMemory(textlist); 10398 } 10399 text=DestroyString(text); 10400 } 10401 exception=DestroyExceptionInfo(exception); 10402 image_info=DestroyImageInfo(image_info); 10403 return(nexus); 10404} 10405 10406/* 10407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10408% % 10409% % 10410% % 10411+ X P a n I m a g e % 10412% % 10413% % 10414% % 10415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10416% 10417% XPanImage() pans the image until the mouse button is released. 10418% 10419% The format of the XPanImage method is: 10420% 10421% void XPanImage(Display *display,XWindows *windows,XEvent *event, 10422% ExceptionInfo *exception) 10423% 10424% A description of each parameter follows: 10425% 10426% o display: Specifies a connection to an X server; returned from 10427% XOpenDisplay. 10428% 10429% o windows: Specifies a pointer to a XWindows structure. 10430% 10431% o event: Specifies a pointer to a XEvent structure. If it is NULL, 10432% the entire image is refreshed. 10433% 10434% o exception: return any errors or warnings in this structure. 10435% 10436*/ 10437static void XPanImage(Display *display,XWindows *windows,XEvent *event, 10438 ExceptionInfo *exception) 10439{ 10440 char 10441 text[MagickPathExtent]; 10442 10443 Cursor 10444 cursor; 10445 10446 double 10447 x_factor, 10448 y_factor; 10449 10450 RectangleInfo 10451 pan_info; 10452 10453 size_t 10454 state; 10455 10456 /* 10457 Define cursor. 10458 */ 10459 if ((windows->image.ximage->width > (int) windows->image.width) && 10460 (windows->image.ximage->height > (int) windows->image.height)) 10461 cursor=XCreateFontCursor(display,XC_fleur); 10462 else 10463 if (windows->image.ximage->width > (int) windows->image.width) 10464 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow); 10465 else 10466 if (windows->image.ximage->height > (int) windows->image.height) 10467 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow); 10468 else 10469 cursor=XCreateFontCursor(display,XC_arrow); 10470 (void) XCheckDefineCursor(display,windows->pan.id,cursor); 10471 /* 10472 Pan image as pointer moves until the mouse button is released. 10473 */ 10474 x_factor=(double) windows->image.ximage->width/windows->pan.width; 10475 y_factor=(double) windows->image.ximage->height/windows->pan.height; 10476 pan_info.width=windows->pan.width*windows->image.width/ 10477 windows->image.ximage->width; 10478 pan_info.height=windows->pan.height*windows->image.height/ 10479 windows->image.ximage->height; 10480 pan_info.x=0; 10481 pan_info.y=0; 10482 state=UpdateConfigurationState; 10483 do 10484 { 10485 switch (event->type) 10486 { 10487 case ButtonPress: 10488 { 10489 /* 10490 User choose an initial pan location. 10491 */ 10492 pan_info.x=(ssize_t) event->xbutton.x; 10493 pan_info.y=(ssize_t) event->xbutton.y; 10494 state|=UpdateConfigurationState; 10495 break; 10496 } 10497 case ButtonRelease: 10498 { 10499 /* 10500 User has finished panning the image. 10501 */ 10502 pan_info.x=(ssize_t) event->xbutton.x; 10503 pan_info.y=(ssize_t) event->xbutton.y; 10504 state|=UpdateConfigurationState | ExitState; 10505 break; 10506 } 10507 case MotionNotify: 10508 { 10509 pan_info.x=(ssize_t) event->xmotion.x; 10510 pan_info.y=(ssize_t) event->xmotion.y; 10511 state|=UpdateConfigurationState; 10512 } 10513 default: 10514 break; 10515 } 10516 if ((state & UpdateConfigurationState) != 0) 10517 { 10518 /* 10519 Check boundary conditions. 10520 */ 10521 if (pan_info.x < (ssize_t) (pan_info.width/2)) 10522 pan_info.x=0; 10523 else 10524 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2))); 10525 if (pan_info.x < 0) 10526 pan_info.x=0; 10527 else 10528 if ((int) (pan_info.x+windows->image.width) > 10529 windows->image.ximage->width) 10530 pan_info.x=(ssize_t) 10531 (windows->image.ximage->width-windows->image.width); 10532 if (pan_info.y < (ssize_t) (pan_info.height/2)) 10533 pan_info.y=0; 10534 else 10535 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2))); 10536 if (pan_info.y < 0) 10537 pan_info.y=0; 10538 else 10539 if ((int) (pan_info.y+windows->image.height) > 10540 windows->image.ximage->height) 10541 pan_info.y=(ssize_t) 10542 (windows->image.ximage->height-windows->image.height); 10543 if ((windows->image.x != (int) pan_info.x) || 10544 (windows->image.y != (int) pan_info.y)) 10545 { 10546 /* 10547 Display image pan offset. 10548 */ 10549 windows->image.x=(int) pan_info.x; 10550 windows->image.y=(int) pan_info.y; 10551 (void) FormatLocaleString(text,MagickPathExtent," %ux%u%+d%+d ", 10552 windows->image.width,windows->image.height,windows->image.x, 10553 windows->image.y); 10554 XInfoWidget(display,windows,text); 10555 /* 10556 Refresh Image window. 10557 */ 10558 XDrawPanRectangle(display,windows); 10559 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 10560 } 10561 state&=(~UpdateConfigurationState); 10562 } 10563 /* 10564 Wait for next event. 10565 */ 10566 if ((state & ExitState) == 0) 10567 XScreenEvent(display,windows,event,exception); 10568 } while ((state & ExitState) == 0); 10569 /* 10570 Restore cursor. 10571 */ 10572 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor); 10573 (void) XFreeCursor(display,cursor); 10574 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 10575} 10576 10577/* 10578%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10579% % 10580% % 10581% % 10582+ X P a s t e I m a g e % 10583% % 10584% % 10585% % 10586%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10587% 10588% XPasteImage() pastes an image previously saved with XCropImage in the X 10589% window image at a location the user chooses with the pointer. 10590% 10591% The format of the XPasteImage method is: 10592% 10593% MagickBooleanType XPasteImage(Display *display, 10594% XResourceInfo *resource_info,XWindows *windows,Image *image, 10595% ExceptionInfo *exception) 10596% 10597% A description of each parameter follows: 10598% 10599% o display: Specifies a connection to an X server; returned from 10600% XOpenDisplay. 10601% 10602% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10603% 10604% o windows: Specifies a pointer to a XWindows structure. 10605% 10606% o image: the image; returned from ReadImage. 10607% 10608% o exception: return any errors or warnings in this structure. 10609% 10610*/ 10611static MagickBooleanType XPasteImage(Display *display, 10612 XResourceInfo *resource_info,XWindows *windows,Image *image, 10613 ExceptionInfo *exception) 10614{ 10615 static const char 10616 *PasteMenu[] = 10617 { 10618 "Operator", 10619 "Help", 10620 "Dismiss", 10621 (char *) NULL 10622 }; 10623 10624 static const ModeType 10625 PasteCommands[] = 10626 { 10627 PasteOperatorsCommand, 10628 PasteHelpCommand, 10629 PasteDismissCommand 10630 }; 10631 10632 static CompositeOperator 10633 compose = CopyCompositeOp; 10634 10635 char 10636 text[MagickPathExtent]; 10637 10638 Cursor 10639 cursor; 10640 10641 Image 10642 *paste_image; 10643 10644 int 10645 entry, 10646 id, 10647 x, 10648 y; 10649 10650 double 10651 scale_factor; 10652 10653 RectangleInfo 10654 highlight_info, 10655 paste_info; 10656 10657 unsigned int 10658 height, 10659 width; 10660 10661 size_t 10662 state; 10663 10664 XEvent 10665 event; 10666 10667 /* 10668 Copy image. 10669 */ 10670 if (resource_info->copy_image == (Image *) NULL) 10671 return(MagickFalse); 10672 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception); 10673 /* 10674 Map Command widget. 10675 */ 10676 (void) CloneString(&windows->command.name,"Paste"); 10677 windows->command.data=1; 10678 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL); 10679 (void) XMapRaised(display,windows->command.id); 10680 XClientMessage(display,windows->image.id,windows->im_protocols, 10681 windows->im_update_widget,CurrentTime); 10682 /* 10683 Track pointer until button 1 is pressed. 10684 */ 10685 XSetCursorState(display,windows,MagickFalse); 10686 XQueryPosition(display,windows->image.id,&x,&y); 10687 (void) XSelectInput(display,windows->image.id, 10688 windows->image.attributes.event_mask | PointerMotionMask); 10689 paste_info.x=(ssize_t) windows->image.x+x; 10690 paste_info.y=(ssize_t) windows->image.y+y; 10691 paste_info.width=0; 10692 paste_info.height=0; 10693 cursor=XCreateFontCursor(display,XC_ul_angle); 10694 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 10695 state=DefaultState; 10696 do 10697 { 10698 if (windows->info.mapped != MagickFalse ) 10699 { 10700 /* 10701 Display pointer position. 10702 */ 10703 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ", 10704 (long) paste_info.x,(long) paste_info.y); 10705 XInfoWidget(display,windows,text); 10706 } 10707 highlight_info=paste_info; 10708 highlight_info.x=paste_info.x-windows->image.x; 10709 highlight_info.y=paste_info.y-windows->image.y; 10710 XHighlightRectangle(display,windows->image.id, 10711 windows->image.highlight_context,&highlight_info); 10712 /* 10713 Wait for next event. 10714 */ 10715 XScreenEvent(display,windows,&event,exception); 10716 XHighlightRectangle(display,windows->image.id, 10717 windows->image.highlight_context,&highlight_info); 10718 if (event.xany.window == windows->command.id) 10719 { 10720 /* 10721 Select a command from the Command widget. 10722 */ 10723 id=XCommandWidget(display,windows,PasteMenu,&event); 10724 if (id < 0) 10725 continue; 10726 switch (PasteCommands[id]) 10727 { 10728 case PasteOperatorsCommand: 10729 { 10730 char 10731 command[MagickPathExtent], 10732 **operators; 10733 10734 /* 10735 Select a command from the pop-up menu. 10736 */ 10737 operators=GetCommandOptions(MagickComposeOptions); 10738 if (operators == (char **) NULL) 10739 break; 10740 entry=XMenuWidget(display,windows,PasteMenu[id], 10741 (const char **) operators,command); 10742 if (entry >= 0) 10743 compose=(CompositeOperator) ParseCommandOption( 10744 MagickComposeOptions,MagickFalse,operators[entry]); 10745 operators=DestroyStringList(operators); 10746 break; 10747 } 10748 case PasteHelpCommand: 10749 { 10750 XTextViewWidget(display,resource_info,windows,MagickFalse, 10751 "Help Viewer - Image Composite",ImagePasteHelp); 10752 break; 10753 } 10754 case PasteDismissCommand: 10755 { 10756 /* 10757 Prematurely exit. 10758 */ 10759 state|=EscapeState; 10760 state|=ExitState; 10761 break; 10762 } 10763 default: 10764 break; 10765 } 10766 continue; 10767 } 10768 switch (event.type) 10769 { 10770 case ButtonPress: 10771 { 10772 if (image->debug != MagickFalse ) 10773 (void) LogMagickEvent(X11Event,GetMagickModule(), 10774 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 10775 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10776 if (event.xbutton.button != Button1) 10777 break; 10778 if (event.xbutton.window != windows->image.id) 10779 break; 10780 /* 10781 Paste rectangle is relative to image configuration. 10782 */ 10783 width=(unsigned int) image->columns; 10784 height=(unsigned int) image->rows; 10785 x=0; 10786 y=0; 10787 if (windows->image.crop_geometry != (char *) NULL) 10788 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 10789 &width,&height); 10790 scale_factor=(double) windows->image.ximage->width/width; 10791 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5); 10792 scale_factor=(double) windows->image.ximage->height/height; 10793 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5); 10794 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10795 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10796 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10797 break; 10798 } 10799 case ButtonRelease: 10800 { 10801 if (image->debug != MagickFalse ) 10802 (void) LogMagickEvent(X11Event,GetMagickModule(), 10803 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 10804 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10805 if (event.xbutton.button != Button1) 10806 break; 10807 if (event.xbutton.window != windows->image.id) 10808 break; 10809 if ((paste_info.width != 0) && (paste_info.height != 0)) 10810 { 10811 /* 10812 User has selected the location of the paste image. 10813 */ 10814 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10815 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10816 state|=ExitState; 10817 } 10818 break; 10819 } 10820 case Expose: 10821 break; 10822 case KeyPress: 10823 { 10824 char 10825 command[MagickPathExtent]; 10826 10827 KeySym 10828 key_symbol; 10829 10830 int 10831 length; 10832 10833 if (event.xkey.window != windows->image.id) 10834 break; 10835 /* 10836 Respond to a user key press. 10837 */ 10838 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 10839 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10840 *(command+length)='\0'; 10841 if (image->debug != MagickFalse ) 10842 (void) LogMagickEvent(X11Event,GetMagickModule(), 10843 "Key press: 0x%lx (%s)",(long) key_symbol,command); 10844 switch ((int) key_symbol) 10845 { 10846 case XK_Escape: 10847 case XK_F20: 10848 { 10849 /* 10850 Prematurely exit. 10851 */ 10852 paste_image=DestroyImage(paste_image); 10853 state|=EscapeState; 10854 state|=ExitState; 10855 break; 10856 } 10857 case XK_F1: 10858 case XK_Help: 10859 { 10860 (void) XSetFunction(display,windows->image.highlight_context, 10861 GXcopy); 10862 XTextViewWidget(display,resource_info,windows,MagickFalse, 10863 "Help Viewer - Image Composite",ImagePasteHelp); 10864 (void) XSetFunction(display,windows->image.highlight_context, 10865 GXinvert); 10866 break; 10867 } 10868 default: 10869 { 10870 (void) XBell(display,0); 10871 break; 10872 } 10873 } 10874 break; 10875 } 10876 case MotionNotify: 10877 { 10878 /* 10879 Map and unmap Info widget as text cursor crosses its boundaries. 10880 */ 10881 x=event.xmotion.x; 10882 y=event.xmotion.y; 10883 if (windows->info.mapped != MagickFalse ) 10884 { 10885 if ((x < (int) (windows->info.x+windows->info.width)) && 10886 (y < (int) (windows->info.y+windows->info.height))) 10887 (void) XWithdrawWindow(display,windows->info.id, 10888 windows->info.screen); 10889 } 10890 else 10891 if ((x > (int) (windows->info.x+windows->info.width)) || 10892 (y > (int) (windows->info.y+windows->info.height))) 10893 (void) XMapWindow(display,windows->info.id); 10894 paste_info.x=(ssize_t) windows->image.x+x; 10895 paste_info.y=(ssize_t) windows->image.y+y; 10896 break; 10897 } 10898 default: 10899 { 10900 if (image->debug != MagickFalse ) 10901 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 10902 event.type); 10903 break; 10904 } 10905 } 10906 } while ((state & ExitState) == 0); 10907 (void) XSelectInput(display,windows->image.id, 10908 windows->image.attributes.event_mask); 10909 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 10910 XSetCursorState(display,windows,MagickFalse); 10911 (void) XFreeCursor(display,cursor); 10912 if ((state & EscapeState) != 0) 10913 return(MagickTrue); 10914 /* 10915 Image pasting is relative to image configuration. 10916 */ 10917 XSetCursorState(display,windows,MagickTrue); 10918 XCheckRefreshWindows(display,windows); 10919 width=(unsigned int) image->columns; 10920 height=(unsigned int) image->rows; 10921 x=0; 10922 y=0; 10923 if (windows->image.crop_geometry != (char *) NULL) 10924 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 10925 scale_factor=(double) width/windows->image.ximage->width; 10926 paste_info.x+=x; 10927 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5); 10928 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5); 10929 scale_factor=(double) height/windows->image.ximage->height; 10930 paste_info.y+=y; 10931 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5); 10932 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5); 10933 /* 10934 Paste image with X Image window. 10935 */ 10936 (void) CompositeImage(image,paste_image,compose,MagickTrue,paste_info.x, 10937 paste_info.y,exception); 10938 paste_image=DestroyImage(paste_image); 10939 XSetCursorState(display,windows,MagickFalse); 10940 /* 10941 Update image colormap. 10942 */ 10943 XConfigureImageColormap(display,resource_info,windows,image,exception); 10944 (void) XConfigureImage(display,resource_info,windows,image,exception); 10945 return(MagickTrue); 10946} 10947 10948/* 10949%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10950% % 10951% % 10952% % 10953+ X P r i n t I m a g e % 10954% % 10955% % 10956% % 10957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10958% 10959% XPrintImage() prints an image to a Postscript printer. 10960% 10961% The format of the XPrintImage method is: 10962% 10963% MagickBooleanType XPrintImage(Display *display, 10964% XResourceInfo *resource_info,XWindows *windows,Image *image, 10965% ExceptionInfo *exception) 10966% 10967% A description of each parameter follows: 10968% 10969% o display: Specifies a connection to an X server; returned from 10970% XOpenDisplay. 10971% 10972% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10973% 10974% o windows: Specifies a pointer to a XWindows structure. 10975% 10976% o image: the image. 10977% 10978% o exception: return any errors or warnings in this structure. 10979% 10980*/ 10981static MagickBooleanType XPrintImage(Display *display, 10982 XResourceInfo *resource_info,XWindows *windows,Image *image, 10983 ExceptionInfo *exception) 10984{ 10985 char 10986 filename[MagickPathExtent], 10987 geometry[MagickPathExtent]; 10988 10989 Image 10990 *print_image; 10991 10992 ImageInfo 10993 *image_info; 10994 10995 MagickStatusType 10996 status; 10997 10998 /* 10999 Request Postscript page geometry from user. 11000 */ 11001 image_info=CloneImageInfo(resource_info->image_info); 11002 (void) FormatLocaleString(geometry,MagickPathExtent,"Letter"); 11003 if (image_info->page != (char *) NULL) 11004 (void) CopyMagickString(geometry,image_info->page,MagickPathExtent); 11005 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 11006 "Select Postscript Page Geometry:",geometry); 11007 if (*geometry == '\0') 11008 return(MagickTrue); 11009 image_info->page=GetPageGeometry(geometry); 11010 /* 11011 Apply image transforms. 11012 */ 11013 XSetCursorState(display,windows,MagickTrue); 11014 XCheckRefreshWindows(display,windows); 11015 print_image=CloneImage(image,0,0,MagickTrue,exception); 11016 if (print_image == (Image *) NULL) 11017 return(MagickFalse); 11018 (void) FormatLocaleString(geometry,MagickPathExtent,"%dx%d!", 11019 windows->image.ximage->width,windows->image.ximage->height); 11020 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry, 11021 exception); 11022 /* 11023 Print image. 11024 */ 11025 (void) AcquireUniqueFilename(filename); 11026 (void) FormatLocaleString(print_image->filename,MagickPathExtent,"print:%s", 11027 filename); 11028 status=WriteImage(image_info,print_image,exception); 11029 (void) RelinquishUniqueFileResource(filename); 11030 print_image=DestroyImage(print_image); 11031 image_info=DestroyImageInfo(image_info); 11032 XSetCursorState(display,windows,MagickFalse); 11033 return(status != 0 ? MagickTrue : MagickFalse); 11034} 11035 11036/* 11037%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11038% % 11039% % 11040% % 11041+ X R O I I m a g e % 11042% % 11043% % 11044% % 11045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11046% 11047% XROIImage() applies an image processing technique to a region of interest. 11048% 11049% The format of the XROIImage method is: 11050% 11051% MagickBooleanType XROIImage(Display *display, 11052% XResourceInfo *resource_info,XWindows *windows,Image **image, 11053% ExceptionInfo *exception) 11054% 11055% A description of each parameter follows: 11056% 11057% o display: Specifies a connection to an X server; returned from 11058% XOpenDisplay. 11059% 11060% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11061% 11062% o windows: Specifies a pointer to a XWindows structure. 11063% 11064% o image: the image; returned from ReadImage. 11065% 11066% o exception: return any errors or warnings in this structure. 11067% 11068*/ 11069static MagickBooleanType XROIImage(Display *display, 11070 XResourceInfo *resource_info,XWindows *windows,Image **image, 11071 ExceptionInfo *exception) 11072{ 11073#define ApplyMenus 7 11074 11075 static const char 11076 *ROIMenu[] = 11077 { 11078 "Help", 11079 "Dismiss", 11080 (char *) NULL 11081 }, 11082 *ApplyMenu[] = 11083 { 11084 "File", 11085 "Edit", 11086 "Transform", 11087 "Enhance", 11088 "Effects", 11089 "F/X", 11090 "Miscellany", 11091 "Help", 11092 "Dismiss", 11093 (char *) NULL 11094 }, 11095 *FileMenu[] = 11096 { 11097 "Save...", 11098 "Print...", 11099 (char *) NULL 11100 }, 11101 *EditMenu[] = 11102 { 11103 "Undo", 11104 "Redo", 11105 (char *) NULL 11106 }, 11107 *TransformMenu[] = 11108 { 11109 "Flop", 11110 "Flip", 11111 "Rotate Right", 11112 "Rotate Left", 11113 (char *) NULL 11114 }, 11115 *EnhanceMenu[] = 11116 { 11117 "Hue...", 11118 "Saturation...", 11119 "Brightness...", 11120 "Gamma...", 11121 "Spiff", 11122 "Dull", 11123 "Contrast Stretch...", 11124 "Sigmoidal Contrast...", 11125 "Normalize", 11126 "Equalize", 11127 "Negate", 11128 "Grayscale", 11129 "Map...", 11130 "Quantize...", 11131 (char *) NULL 11132 }, 11133 *EffectsMenu[] = 11134 { 11135 "Despeckle", 11136 "Emboss", 11137 "Reduce Noise", 11138 "Add Noise", 11139 "Sharpen...", 11140 "Blur...", 11141 "Threshold...", 11142 "Edge Detect...", 11143 "Spread...", 11144 "Shade...", 11145 "Raise...", 11146 "Segment...", 11147 (char *) NULL 11148 }, 11149 *FXMenu[] = 11150 { 11151 "Solarize...", 11152 "Sepia Tone...", 11153 "Swirl...", 11154 "Implode...", 11155 "Vignette...", 11156 "Wave...", 11157 "Oil Paint...", 11158 "Charcoal Draw...", 11159 (char *) NULL 11160 }, 11161 *MiscellanyMenu[] = 11162 { 11163 "Image Info", 11164 "Zoom Image", 11165 "Show Preview...", 11166 "Show Histogram", 11167 "Show Matte", 11168 (char *) NULL 11169 }; 11170 11171 static const char 11172 **Menus[ApplyMenus] = 11173 { 11174 FileMenu, 11175 EditMenu, 11176 TransformMenu, 11177 EnhanceMenu, 11178 EffectsMenu, 11179 FXMenu, 11180 MiscellanyMenu 11181 }; 11182 11183 static const CommandType 11184 ApplyCommands[] = 11185 { 11186 NullCommand, 11187 NullCommand, 11188 NullCommand, 11189 NullCommand, 11190 NullCommand, 11191 NullCommand, 11192 NullCommand, 11193 HelpCommand, 11194 QuitCommand 11195 }, 11196 FileCommands[] = 11197 { 11198 SaveCommand, 11199 PrintCommand 11200 }, 11201 EditCommands[] = 11202 { 11203 UndoCommand, 11204 RedoCommand 11205 }, 11206 TransformCommands[] = 11207 { 11208 FlopCommand, 11209 FlipCommand, 11210 RotateRightCommand, 11211 RotateLeftCommand 11212 }, 11213 EnhanceCommands[] = 11214 { 11215 HueCommand, 11216 SaturationCommand, 11217 BrightnessCommand, 11218 GammaCommand, 11219 SpiffCommand, 11220 DullCommand, 11221 ContrastStretchCommand, 11222 SigmoidalContrastCommand, 11223 NormalizeCommand, 11224 EqualizeCommand, 11225 NegateCommand, 11226 GrayscaleCommand, 11227 MapCommand, 11228 QuantizeCommand 11229 }, 11230 EffectsCommands[] = 11231 { 11232 DespeckleCommand, 11233 EmbossCommand, 11234 ReduceNoiseCommand, 11235 AddNoiseCommand, 11236 SharpenCommand, 11237 BlurCommand, 11238 EdgeDetectCommand, 11239 SpreadCommand, 11240 ShadeCommand, 11241 RaiseCommand, 11242 SegmentCommand 11243 }, 11244 FXCommands[] = 11245 { 11246 SolarizeCommand, 11247 SepiaToneCommand, 11248 SwirlCommand, 11249 ImplodeCommand, 11250 VignetteCommand, 11251 WaveCommand, 11252 OilPaintCommand, 11253 CharcoalDrawCommand 11254 }, 11255 MiscellanyCommands[] = 11256 { 11257 InfoCommand, 11258 ZoomCommand, 11259 ShowPreviewCommand, 11260 ShowHistogramCommand, 11261 ShowMatteCommand 11262 }, 11263 ROICommands[] = 11264 { 11265 ROIHelpCommand, 11266 ROIDismissCommand 11267 }; 11268 11269 static const CommandType 11270 *Commands[ApplyMenus] = 11271 { 11272 FileCommands, 11273 EditCommands, 11274 TransformCommands, 11275 EnhanceCommands, 11276 EffectsCommands, 11277 FXCommands, 11278 MiscellanyCommands 11279 }; 11280 11281 char 11282 command[MagickPathExtent], 11283 text[MagickPathExtent]; 11284 11285 CommandType 11286 command_type; 11287 11288 Cursor 11289 cursor; 11290 11291 Image 11292 *roi_image; 11293 11294 int 11295 entry, 11296 id, 11297 x, 11298 y; 11299 11300 double 11301 scale_factor; 11302 11303 MagickProgressMonitor 11304 progress_monitor; 11305 11306 RectangleInfo 11307 crop_info, 11308 highlight_info, 11309 roi_info; 11310 11311 unsigned int 11312 height, 11313 width; 11314 11315 size_t 11316 state; 11317 11318 XEvent 11319 event; 11320 11321 /* 11322 Map Command widget. 11323 */ 11324 (void) CloneString(&windows->command.name,"ROI"); 11325 windows->command.data=0; 11326 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL); 11327 (void) XMapRaised(display,windows->command.id); 11328 XClientMessage(display,windows->image.id,windows->im_protocols, 11329 windows->im_update_widget,CurrentTime); 11330 /* 11331 Track pointer until button 1 is pressed. 11332 */ 11333 XQueryPosition(display,windows->image.id,&x,&y); 11334 (void) XSelectInput(display,windows->image.id, 11335 windows->image.attributes.event_mask | PointerMotionMask); 11336 roi_info.x=(ssize_t) windows->image.x+x; 11337 roi_info.y=(ssize_t) windows->image.y+y; 11338 roi_info.width=0; 11339 roi_info.height=0; 11340 cursor=XCreateFontCursor(display,XC_fleur); 11341 state=DefaultState; 11342 do 11343 { 11344 if (windows->info.mapped != MagickFalse ) 11345 { 11346 /* 11347 Display pointer position. 11348 */ 11349 (void) FormatLocaleString(text,MagickPathExtent," %+ld%+ld ", 11350 (long) roi_info.x,(long) roi_info.y); 11351 XInfoWidget(display,windows,text); 11352 } 11353 /* 11354 Wait for next event. 11355 */ 11356 XScreenEvent(display,windows,&event,exception); 11357 if (event.xany.window == windows->command.id) 11358 { 11359 /* 11360 Select a command from the Command widget. 11361 */ 11362 id=XCommandWidget(display,windows,ROIMenu,&event); 11363 if (id < 0) 11364 continue; 11365 switch (ROICommands[id]) 11366 { 11367 case ROIHelpCommand: 11368 { 11369 XTextViewWidget(display,resource_info,windows,MagickFalse, 11370 "Help Viewer - Region of Interest",ImageROIHelp); 11371 break; 11372 } 11373 case ROIDismissCommand: 11374 { 11375 /* 11376 Prematurely exit. 11377 */ 11378 state|=EscapeState; 11379 state|=ExitState; 11380 break; 11381 } 11382 default: 11383 break; 11384 } 11385 continue; 11386 } 11387 switch (event.type) 11388 { 11389 case ButtonPress: 11390 { 11391 if (event.xbutton.button != Button1) 11392 break; 11393 if (event.xbutton.window != windows->image.id) 11394 break; 11395 /* 11396 Note first corner of region of interest rectangle-- exit loop. 11397 */ 11398 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11399 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11400 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11401 state|=ExitState; 11402 break; 11403 } 11404 case ButtonRelease: 11405 break; 11406 case Expose: 11407 break; 11408 case KeyPress: 11409 { 11410 KeySym 11411 key_symbol; 11412 11413 if (event.xkey.window != windows->image.id) 11414 break; 11415 /* 11416 Respond to a user key press. 11417 */ 11418 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11419 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11420 switch ((int) key_symbol) 11421 { 11422 case XK_Escape: 11423 case XK_F20: 11424 { 11425 /* 11426 Prematurely exit. 11427 */ 11428 state|=EscapeState; 11429 state|=ExitState; 11430 break; 11431 } 11432 case XK_F1: 11433 case XK_Help: 11434 { 11435 XTextViewWidget(display,resource_info,windows,MagickFalse, 11436 "Help Viewer - Region of Interest",ImageROIHelp); 11437 break; 11438 } 11439 default: 11440 { 11441 (void) XBell(display,0); 11442 break; 11443 } 11444 } 11445 break; 11446 } 11447 case MotionNotify: 11448 { 11449 /* 11450 Map and unmap Info widget as text cursor crosses its boundaries. 11451 */ 11452 x=event.xmotion.x; 11453 y=event.xmotion.y; 11454 if (windows->info.mapped != MagickFalse ) 11455 { 11456 if ((x < (int) (windows->info.x+windows->info.width)) && 11457 (y < (int) (windows->info.y+windows->info.height))) 11458 (void) XWithdrawWindow(display,windows->info.id, 11459 windows->info.screen); 11460 } 11461 else 11462 if ((x > (int) (windows->info.x+windows->info.width)) || 11463 (y > (int) (windows->info.y+windows->info.height))) 11464 (void) XMapWindow(display,windows->info.id); 11465 roi_info.x=(ssize_t) windows->image.x+x; 11466 roi_info.y=(ssize_t) windows->image.y+y; 11467 break; 11468 } 11469 default: 11470 break; 11471 } 11472 } while ((state & ExitState) == 0); 11473 (void) XSelectInput(display,windows->image.id, 11474 windows->image.attributes.event_mask); 11475 if ((state & EscapeState) != 0) 11476 { 11477 /* 11478 User want to exit without region of interest. 11479 */ 11480 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11481 (void) XFreeCursor(display,cursor); 11482 return(MagickTrue); 11483 } 11484 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11485 do 11486 { 11487 /* 11488 Size rectangle as pointer moves until the mouse button is released. 11489 */ 11490 x=(int) roi_info.x; 11491 y=(int) roi_info.y; 11492 roi_info.width=0; 11493 roi_info.height=0; 11494 state=DefaultState; 11495 do 11496 { 11497 highlight_info=roi_info; 11498 highlight_info.x=roi_info.x-windows->image.x; 11499 highlight_info.y=roi_info.y-windows->image.y; 11500 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11501 { 11502 /* 11503 Display info and draw region of interest rectangle. 11504 */ 11505 if (windows->info.mapped == MagickFalse) 11506 (void) XMapWindow(display,windows->info.id); 11507 (void) FormatLocaleString(text,MagickPathExtent, 11508 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11509 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11510 XInfoWidget(display,windows,text); 11511 XHighlightRectangle(display,windows->image.id, 11512 windows->image.highlight_context,&highlight_info); 11513 } 11514 else 11515 if (windows->info.mapped != MagickFalse ) 11516 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11517 /* 11518 Wait for next event. 11519 */ 11520 XScreenEvent(display,windows,&event,exception); 11521 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11522 XHighlightRectangle(display,windows->image.id, 11523 windows->image.highlight_context,&highlight_info); 11524 switch (event.type) 11525 { 11526 case ButtonPress: 11527 { 11528 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11529 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11530 break; 11531 } 11532 case ButtonRelease: 11533 { 11534 /* 11535 User has committed to region of interest rectangle. 11536 */ 11537 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11538 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11539 XSetCursorState(display,windows,MagickFalse); 11540 state|=ExitState; 11541 if (LocaleCompare(windows->command.name,"Apply") == 0) 11542 break; 11543 (void) CloneString(&windows->command.name,"Apply"); 11544 windows->command.data=ApplyMenus; 11545 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL); 11546 break; 11547 } 11548 case Expose: 11549 break; 11550 case MotionNotify: 11551 { 11552 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11553 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11554 } 11555 default: 11556 break; 11557 } 11558 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) || 11559 ((state & ExitState) != 0)) 11560 { 11561 /* 11562 Check boundary conditions. 11563 */ 11564 if (roi_info.x < 0) 11565 roi_info.x=0; 11566 else 11567 if (roi_info.x > (ssize_t) windows->image.ximage->width) 11568 roi_info.x=(ssize_t) windows->image.ximage->width; 11569 if ((int) roi_info.x < x) 11570 roi_info.width=(unsigned int) (x-roi_info.x); 11571 else 11572 { 11573 roi_info.width=(unsigned int) (roi_info.x-x); 11574 roi_info.x=(ssize_t) x; 11575 } 11576 if (roi_info.y < 0) 11577 roi_info.y=0; 11578 else 11579 if (roi_info.y > (ssize_t) windows->image.ximage->height) 11580 roi_info.y=(ssize_t) windows->image.ximage->height; 11581 if ((int) roi_info.y < y) 11582 roi_info.height=(unsigned int) (y-roi_info.y); 11583 else 11584 { 11585 roi_info.height=(unsigned int) (roi_info.y-y); 11586 roi_info.y=(ssize_t) y; 11587 } 11588 } 11589 } while ((state & ExitState) == 0); 11590 /* 11591 Wait for user to grab a corner of the rectangle or press return. 11592 */ 11593 state=DefaultState; 11594 command_type=NullCommand; 11595 crop_info.x=0; 11596 crop_info.y=0; 11597 (void) XMapWindow(display,windows->info.id); 11598 do 11599 { 11600 if (windows->info.mapped != MagickFalse ) 11601 { 11602 /* 11603 Display pointer position. 11604 */ 11605 (void) FormatLocaleString(text,MagickPathExtent, 11606 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11607 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11608 XInfoWidget(display,windows,text); 11609 } 11610 highlight_info=roi_info; 11611 highlight_info.x=roi_info.x-windows->image.x; 11612 highlight_info.y=roi_info.y-windows->image.y; 11613 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11614 { 11615 state|=EscapeState; 11616 state|=ExitState; 11617 break; 11618 } 11619 if ((state & UpdateRegionState) != 0) 11620 { 11621 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11622 switch (command_type) 11623 { 11624 case UndoCommand: 11625 case RedoCommand: 11626 { 11627 (void) XMagickCommand(display,resource_info,windows,command_type, 11628 image,exception); 11629 break; 11630 } 11631 default: 11632 { 11633 /* 11634 Region of interest is relative to image configuration. 11635 */ 11636 progress_monitor=SetImageProgressMonitor(*image, 11637 (MagickProgressMonitor) NULL,(*image)->client_data); 11638 crop_info=roi_info; 11639 width=(unsigned int) (*image)->columns; 11640 height=(unsigned int) (*image)->rows; 11641 x=0; 11642 y=0; 11643 if (windows->image.crop_geometry != (char *) NULL) 11644 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11645 &width,&height); 11646 scale_factor=(double) width/windows->image.ximage->width; 11647 crop_info.x+=x; 11648 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11649 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11650 scale_factor=(double) 11651 height/windows->image.ximage->height; 11652 crop_info.y+=y; 11653 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11654 crop_info.height=(unsigned int) 11655 (scale_factor*crop_info.height+0.5); 11656 roi_image=CropImage(*image,&crop_info,exception); 11657 (void) SetImageProgressMonitor(*image,progress_monitor, 11658 (*image)->client_data); 11659 if (roi_image == (Image *) NULL) 11660 continue; 11661 /* 11662 Apply image processing technique to the region of interest. 11663 */ 11664 windows->image.orphan=MagickTrue; 11665 (void) XMagickCommand(display,resource_info,windows,command_type, 11666 &roi_image,exception); 11667 progress_monitor=SetImageProgressMonitor(*image, 11668 (MagickProgressMonitor) NULL,(*image)->client_data); 11669 (void) XMagickCommand(display,resource_info,windows, 11670 SaveToUndoBufferCommand,image,exception); 11671 windows->image.orphan=MagickFalse; 11672 (void) CompositeImage(*image,roi_image,CopyCompositeOp, 11673 MagickTrue,crop_info.x,crop_info.y,exception); 11674 roi_image=DestroyImage(roi_image); 11675 (void) SetImageProgressMonitor(*image,progress_monitor, 11676 (*image)->client_data); 11677 break; 11678 } 11679 } 11680 if (command_type != InfoCommand) 11681 { 11682 XConfigureImageColormap(display,resource_info,windows,*image, 11683 exception); 11684 (void) XConfigureImage(display,resource_info,windows,*image, 11685 exception); 11686 } 11687 XCheckRefreshWindows(display,windows); 11688 XInfoWidget(display,windows,text); 11689 (void) XSetFunction(display,windows->image.highlight_context, 11690 GXinvert); 11691 state&=(~UpdateRegionState); 11692 } 11693 XHighlightRectangle(display,windows->image.id, 11694 windows->image.highlight_context,&highlight_info); 11695 XScreenEvent(display,windows,&event,exception); 11696 if (event.xany.window == windows->command.id) 11697 { 11698 /* 11699 Select a command from the Command widget. 11700 */ 11701 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11702 command_type=NullCommand; 11703 id=XCommandWidget(display,windows,ApplyMenu,&event); 11704 if (id >= 0) 11705 { 11706 (void) CopyMagickString(command,ApplyMenu[id],MagickPathExtent); 11707 command_type=ApplyCommands[id]; 11708 if (id < ApplyMenus) 11709 { 11710 /* 11711 Select a command from a pop-up menu. 11712 */ 11713 entry=XMenuWidget(display,windows,ApplyMenu[id], 11714 (const char **) Menus[id],command); 11715 if (entry >= 0) 11716 { 11717 (void) CopyMagickString(command,Menus[id][entry], 11718 MagickPathExtent); 11719 command_type=Commands[id][entry]; 11720 } 11721 } 11722 } 11723 (void) XSetFunction(display,windows->image.highlight_context, 11724 GXinvert); 11725 XHighlightRectangle(display,windows->image.id, 11726 windows->image.highlight_context,&highlight_info); 11727 if (command_type == HelpCommand) 11728 { 11729 (void) XSetFunction(display,windows->image.highlight_context, 11730 GXcopy); 11731 XTextViewWidget(display,resource_info,windows,MagickFalse, 11732 "Help Viewer - Region of Interest",ImageROIHelp); 11733 (void) XSetFunction(display,windows->image.highlight_context, 11734 GXinvert); 11735 continue; 11736 } 11737 if (command_type == QuitCommand) 11738 { 11739 /* 11740 exit. 11741 */ 11742 state|=EscapeState; 11743 state|=ExitState; 11744 continue; 11745 } 11746 if (command_type != NullCommand) 11747 state|=UpdateRegionState; 11748 continue; 11749 } 11750 XHighlightRectangle(display,windows->image.id, 11751 windows->image.highlight_context,&highlight_info); 11752 switch (event.type) 11753 { 11754 case ButtonPress: 11755 { 11756 x=windows->image.x; 11757 y=windows->image.y; 11758 if (event.xbutton.button != Button1) 11759 break; 11760 if (event.xbutton.window != windows->image.id) 11761 break; 11762 x=windows->image.x+event.xbutton.x; 11763 y=windows->image.y+event.xbutton.y; 11764 if ((x < (int) (roi_info.x+RoiDelta)) && 11765 (x > (int) (roi_info.x-RoiDelta)) && 11766 (y < (int) (roi_info.y+RoiDelta)) && 11767 (y > (int) (roi_info.y-RoiDelta))) 11768 { 11769 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11770 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11771 state|=UpdateConfigurationState; 11772 break; 11773 } 11774 if ((x < (int) (roi_info.x+RoiDelta)) && 11775 (x > (int) (roi_info.x-RoiDelta)) && 11776 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11777 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11778 { 11779 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11780 state|=UpdateConfigurationState; 11781 break; 11782 } 11783 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11784 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11785 (y < (int) (roi_info.y+RoiDelta)) && 11786 (y > (int) (roi_info.y-RoiDelta))) 11787 { 11788 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11789 state|=UpdateConfigurationState; 11790 break; 11791 } 11792 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11793 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11794 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11795 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11796 { 11797 state|=UpdateConfigurationState; 11798 break; 11799 } 11800 } 11801 case ButtonRelease: 11802 { 11803 if (event.xbutton.window == windows->pan.id) 11804 if ((highlight_info.x != crop_info.x-windows->image.x) || 11805 (highlight_info.y != crop_info.y-windows->image.y)) 11806 XHighlightRectangle(display,windows->image.id, 11807 windows->image.highlight_context,&highlight_info); 11808 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11809 event.xbutton.time); 11810 break; 11811 } 11812 case Expose: 11813 { 11814 if (event.xexpose.window == windows->image.id) 11815 if (event.xexpose.count == 0) 11816 { 11817 event.xexpose.x=(int) highlight_info.x; 11818 event.xexpose.y=(int) highlight_info.y; 11819 event.xexpose.width=(int) highlight_info.width; 11820 event.xexpose.height=(int) highlight_info.height; 11821 XRefreshWindow(display,&windows->image,&event); 11822 } 11823 if (event.xexpose.window == windows->info.id) 11824 if (event.xexpose.count == 0) 11825 XInfoWidget(display,windows,text); 11826 break; 11827 } 11828 case KeyPress: 11829 { 11830 KeySym 11831 key_symbol; 11832 11833 if (event.xkey.window != windows->image.id) 11834 break; 11835 /* 11836 Respond to a user key press. 11837 */ 11838 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11839 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11840 switch ((int) key_symbol) 11841 { 11842 case XK_Shift_L: 11843 case XK_Shift_R: 11844 break; 11845 case XK_Escape: 11846 case XK_F20: 11847 state|=EscapeState; 11848 case XK_Return: 11849 { 11850 state|=ExitState; 11851 break; 11852 } 11853 case XK_Home: 11854 case XK_KP_Home: 11855 { 11856 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11857 roi_info.y=(ssize_t) (windows->image.height/2L- 11858 roi_info.height/2L); 11859 break; 11860 } 11861 case XK_Left: 11862 case XK_KP_Left: 11863 { 11864 roi_info.x--; 11865 break; 11866 } 11867 case XK_Up: 11868 case XK_KP_Up: 11869 case XK_Next: 11870 { 11871 roi_info.y--; 11872 break; 11873 } 11874 case XK_Right: 11875 case XK_KP_Right: 11876 { 11877 roi_info.x++; 11878 break; 11879 } 11880 case XK_Prior: 11881 case XK_Down: 11882 case XK_KP_Down: 11883 { 11884 roi_info.y++; 11885 break; 11886 } 11887 case XK_F1: 11888 case XK_Help: 11889 { 11890 (void) XSetFunction(display,windows->image.highlight_context, 11891 GXcopy); 11892 XTextViewWidget(display,resource_info,windows,MagickFalse, 11893 "Help Viewer - Region of Interest",ImageROIHelp); 11894 (void) XSetFunction(display,windows->image.highlight_context, 11895 GXinvert); 11896 break; 11897 } 11898 default: 11899 { 11900 command_type=XImageWindowCommand(display,resource_info,windows, 11901 event.xkey.state,key_symbol,image,exception); 11902 if (command_type != NullCommand) 11903 state|=UpdateRegionState; 11904 break; 11905 } 11906 } 11907 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11908 event.xkey.time); 11909 break; 11910 } 11911 case KeyRelease: 11912 break; 11913 case MotionNotify: 11914 { 11915 if (event.xbutton.window != windows->image.id) 11916 break; 11917 /* 11918 Map and unmap Info widget as text cursor crosses its boundaries. 11919 */ 11920 x=event.xmotion.x; 11921 y=event.xmotion.y; 11922 if (windows->info.mapped != MagickFalse ) 11923 { 11924 if ((x < (int) (windows->info.x+windows->info.width)) && 11925 (y < (int) (windows->info.y+windows->info.height))) 11926 (void) XWithdrawWindow(display,windows->info.id, 11927 windows->info.screen); 11928 } 11929 else 11930 if ((x > (int) (windows->info.x+windows->info.width)) || 11931 (y > (int) (windows->info.y+windows->info.height))) 11932 (void) XMapWindow(display,windows->info.id); 11933 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11934 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11935 break; 11936 } 11937 case SelectionRequest: 11938 { 11939 XSelectionEvent 11940 notify; 11941 11942 XSelectionRequestEvent 11943 *request; 11944 11945 /* 11946 Set primary selection. 11947 */ 11948 (void) FormatLocaleString(text,MagickPathExtent, 11949 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11950 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11951 request=(&(event.xselectionrequest)); 11952 (void) XChangeProperty(request->display,request->requestor, 11953 request->property,request->target,8,PropModeReplace, 11954 (unsigned char *) text,(int) strlen(text)); 11955 notify.type=SelectionNotify; 11956 notify.display=request->display; 11957 notify.requestor=request->requestor; 11958 notify.selection=request->selection; 11959 notify.target=request->target; 11960 notify.time=request->time; 11961 if (request->property == None) 11962 notify.property=request->target; 11963 else 11964 notify.property=request->property; 11965 (void) XSendEvent(request->display,request->requestor,False,0, 11966 (XEvent *) ¬ify); 11967 } 11968 default: 11969 break; 11970 } 11971 if ((state & UpdateConfigurationState) != 0) 11972 { 11973 (void) XPutBackEvent(display,&event); 11974 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11975 break; 11976 } 11977 } while ((state & ExitState) == 0); 11978 } while ((state & ExitState) == 0); 11979 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11980 XSetCursorState(display,windows,MagickFalse); 11981 if ((state & EscapeState) != 0) 11982 return(MagickTrue); 11983 return(MagickTrue); 11984} 11985 11986/* 11987%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11988% % 11989% % 11990% % 11991+ X R o t a t e I m a g e % 11992% % 11993% % 11994% % 11995%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11996% 11997% XRotateImage() rotates the X image. If the degrees parameter if zero, the 11998% rotation angle is computed from the slope of a line drawn by the user. 11999% 12000% The format of the XRotateImage method is: 12001% 12002% MagickBooleanType XRotateImage(Display *display, 12003% XResourceInfo *resource_info,XWindows *windows,double degrees, 12004% Image **image,ExceptionInfo *exception) 12005% 12006% A description of each parameter follows: 12007% 12008% o display: Specifies a connection to an X server; returned from 12009% XOpenDisplay. 12010% 12011% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12012% 12013% o windows: Specifies a pointer to a XWindows structure. 12014% 12015% o degrees: Specifies the number of degrees to rotate the image. 12016% 12017% o image: the image. 12018% 12019% o exception: return any errors or warnings in this structure. 12020% 12021*/ 12022static MagickBooleanType XRotateImage(Display *display, 12023 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image, 12024 ExceptionInfo *exception) 12025{ 12026 static const char 12027 *RotateMenu[] = 12028 { 12029 "Pixel Color", 12030 "Direction", 12031 "Help", 12032 "Dismiss", 12033 (char *) NULL 12034 }; 12035 12036 static ModeType 12037 direction = HorizontalRotateCommand; 12038 12039 static const ModeType 12040 DirectionCommands[] = 12041 { 12042 HorizontalRotateCommand, 12043 VerticalRotateCommand 12044 }, 12045 RotateCommands[] = 12046 { 12047 RotateColorCommand, 12048 RotateDirectionCommand, 12049 RotateHelpCommand, 12050 RotateDismissCommand 12051 }; 12052 12053 static unsigned int 12054 pen_id = 0; 12055 12056 char 12057 command[MagickPathExtent], 12058 text[MagickPathExtent]; 12059 12060 Image 12061 *rotate_image; 12062 12063 int 12064 id, 12065 x, 12066 y; 12067 12068 double 12069 normalized_degrees; 12070 12071 register int 12072 i; 12073 12074 unsigned int 12075 height, 12076 rotations, 12077 width; 12078 12079 if (degrees == 0.0) 12080 { 12081 unsigned int 12082 distance; 12083 12084 size_t 12085 state; 12086 12087 XEvent 12088 event; 12089 12090 XSegment 12091 rotate_info; 12092 12093 /* 12094 Map Command widget. 12095 */ 12096 (void) CloneString(&windows->command.name,"Rotate"); 12097 windows->command.data=2; 12098 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 12099 (void) XMapRaised(display,windows->command.id); 12100 XClientMessage(display,windows->image.id,windows->im_protocols, 12101 windows->im_update_widget,CurrentTime); 12102 /* 12103 Wait for first button press. 12104 */ 12105 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12106 XQueryPosition(display,windows->image.id,&x,&y); 12107 rotate_info.x1=x; 12108 rotate_info.y1=y; 12109 rotate_info.x2=x; 12110 rotate_info.y2=y; 12111 state=DefaultState; 12112 do 12113 { 12114 XHighlightLine(display,windows->image.id, 12115 windows->image.highlight_context,&rotate_info); 12116 /* 12117 Wait for next event. 12118 */ 12119 XScreenEvent(display,windows,&event,exception); 12120 XHighlightLine(display,windows->image.id, 12121 windows->image.highlight_context,&rotate_info); 12122 if (event.xany.window == windows->command.id) 12123 { 12124 /* 12125 Select a command from the Command widget. 12126 */ 12127 id=XCommandWidget(display,windows,RotateMenu,&event); 12128 if (id < 0) 12129 continue; 12130 (void) XSetFunction(display,windows->image.highlight_context, 12131 GXcopy); 12132 switch (RotateCommands[id]) 12133 { 12134 case RotateColorCommand: 12135 { 12136 const char 12137 *ColorMenu[MaxNumberPens]; 12138 12139 int 12140 pen_number; 12141 12142 XColor 12143 color; 12144 12145 /* 12146 Initialize menu selections. 12147 */ 12148 for (i=0; i < (int) (MaxNumberPens-2); i++) 12149 ColorMenu[i]=resource_info->pen_colors[i]; 12150 ColorMenu[MaxNumberPens-2]="Browser..."; 12151 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12152 /* 12153 Select a pen color from the pop-up menu. 12154 */ 12155 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12156 (const char **) ColorMenu,command); 12157 if (pen_number < 0) 12158 break; 12159 if (pen_number == (MaxNumberPens-2)) 12160 { 12161 static char 12162 color_name[MagickPathExtent] = "gray"; 12163 12164 /* 12165 Select a pen color from a dialog. 12166 */ 12167 resource_info->pen_colors[pen_number]=color_name; 12168 XColorBrowserWidget(display,windows,"Select",color_name); 12169 if (*color_name == '\0') 12170 break; 12171 } 12172 /* 12173 Set pen color. 12174 */ 12175 (void) XParseColor(display,windows->map_info->colormap, 12176 resource_info->pen_colors[pen_number],&color); 12177 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12178 (unsigned int) MaxColors,&color); 12179 windows->pixel_info->pen_colors[pen_number]=color; 12180 pen_id=(unsigned int) pen_number; 12181 break; 12182 } 12183 case RotateDirectionCommand: 12184 { 12185 static const char 12186 *Directions[] = 12187 { 12188 "horizontal", 12189 "vertical", 12190 (char *) NULL, 12191 }; 12192 12193 /* 12194 Select a command from the pop-up menu. 12195 */ 12196 id=XMenuWidget(display,windows,RotateMenu[id], 12197 Directions,command); 12198 if (id >= 0) 12199 direction=DirectionCommands[id]; 12200 break; 12201 } 12202 case RotateHelpCommand: 12203 { 12204 XTextViewWidget(display,resource_info,windows,MagickFalse, 12205 "Help Viewer - Image Rotation",ImageRotateHelp); 12206 break; 12207 } 12208 case RotateDismissCommand: 12209 { 12210 /* 12211 Prematurely exit. 12212 */ 12213 state|=EscapeState; 12214 state|=ExitState; 12215 break; 12216 } 12217 default: 12218 break; 12219 } 12220 (void) XSetFunction(display,windows->image.highlight_context, 12221 GXinvert); 12222 continue; 12223 } 12224 switch (event.type) 12225 { 12226 case ButtonPress: 12227 { 12228 if (event.xbutton.button != Button1) 12229 break; 12230 if (event.xbutton.window != windows->image.id) 12231 break; 12232 /* 12233 exit loop. 12234 */ 12235 (void) XSetFunction(display,windows->image.highlight_context, 12236 GXcopy); 12237 rotate_info.x1=event.xbutton.x; 12238 rotate_info.y1=event.xbutton.y; 12239 state|=ExitState; 12240 break; 12241 } 12242 case ButtonRelease: 12243 break; 12244 case Expose: 12245 break; 12246 case KeyPress: 12247 { 12248 char 12249 command[MagickPathExtent]; 12250 12251 KeySym 12252 key_symbol; 12253 12254 if (event.xkey.window != windows->image.id) 12255 break; 12256 /* 12257 Respond to a user key press. 12258 */ 12259 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12260 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12261 switch ((int) key_symbol) 12262 { 12263 case XK_Escape: 12264 case XK_F20: 12265 { 12266 /* 12267 Prematurely exit. 12268 */ 12269 state|=EscapeState; 12270 state|=ExitState; 12271 break; 12272 } 12273 case XK_F1: 12274 case XK_Help: 12275 { 12276 (void) XSetFunction(display,windows->image.highlight_context, 12277 GXcopy); 12278 XTextViewWidget(display,resource_info,windows,MagickFalse, 12279 "Help Viewer - Image Rotation",ImageRotateHelp); 12280 (void) XSetFunction(display,windows->image.highlight_context, 12281 GXinvert); 12282 break; 12283 } 12284 default: 12285 { 12286 (void) XBell(display,0); 12287 break; 12288 } 12289 } 12290 break; 12291 } 12292 case MotionNotify: 12293 { 12294 rotate_info.x1=event.xmotion.x; 12295 rotate_info.y1=event.xmotion.y; 12296 } 12297 } 12298 rotate_info.x2=rotate_info.x1; 12299 rotate_info.y2=rotate_info.y1; 12300 if (direction == HorizontalRotateCommand) 12301 rotate_info.x2+=32; 12302 else 12303 rotate_info.y2-=32; 12304 } while ((state & ExitState) == 0); 12305 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12306 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12307 if ((state & EscapeState) != 0) 12308 return(MagickTrue); 12309 /* 12310 Draw line as pointer moves until the mouse button is released. 12311 */ 12312 distance=0; 12313 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12314 state=DefaultState; 12315 do 12316 { 12317 if (distance > 9) 12318 { 12319 /* 12320 Display info and draw rotation line. 12321 */ 12322 if (windows->info.mapped == MagickFalse) 12323 (void) XMapWindow(display,windows->info.id); 12324 (void) FormatLocaleString(text,MagickPathExtent," %g", 12325 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12326 XInfoWidget(display,windows,text); 12327 XHighlightLine(display,windows->image.id, 12328 windows->image.highlight_context,&rotate_info); 12329 } 12330 else 12331 if (windows->info.mapped != MagickFalse ) 12332 (void) XWithdrawWindow(display,windows->info.id, 12333 windows->info.screen); 12334 /* 12335 Wait for next event. 12336 */ 12337 XScreenEvent(display,windows,&event,exception); 12338 if (distance > 9) 12339 XHighlightLine(display,windows->image.id, 12340 windows->image.highlight_context,&rotate_info); 12341 switch (event.type) 12342 { 12343 case ButtonPress: 12344 break; 12345 case ButtonRelease: 12346 { 12347 /* 12348 User has committed to rotation line. 12349 */ 12350 rotate_info.x2=event.xbutton.x; 12351 rotate_info.y2=event.xbutton.y; 12352 state|=ExitState; 12353 break; 12354 } 12355 case Expose: 12356 break; 12357 case MotionNotify: 12358 { 12359 rotate_info.x2=event.xmotion.x; 12360 rotate_info.y2=event.xmotion.y; 12361 } 12362 default: 12363 break; 12364 } 12365 /* 12366 Check boundary conditions. 12367 */ 12368 if (rotate_info.x2 < 0) 12369 rotate_info.x2=0; 12370 else 12371 if (rotate_info.x2 > (int) windows->image.width) 12372 rotate_info.x2=(short) windows->image.width; 12373 if (rotate_info.y2 < 0) 12374 rotate_info.y2=0; 12375 else 12376 if (rotate_info.y2 > (int) windows->image.height) 12377 rotate_info.y2=(short) windows->image.height; 12378 /* 12379 Compute rotation angle from the slope of the line. 12380 */ 12381 degrees=0.0; 12382 distance=(unsigned int) 12383 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12384 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12385 if (distance > 9) 12386 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12387 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12388 } while ((state & ExitState) == 0); 12389 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12390 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12391 if (distance <= 9) 12392 return(MagickTrue); 12393 } 12394 if (direction == VerticalRotateCommand) 12395 degrees-=90.0; 12396 if (degrees == 0.0) 12397 return(MagickTrue); 12398 /* 12399 Rotate image. 12400 */ 12401 normalized_degrees=degrees; 12402 while (normalized_degrees < -45.0) 12403 normalized_degrees+=360.0; 12404 for (rotations=0; normalized_degrees > 45.0; rotations++) 12405 normalized_degrees-=90.0; 12406 if (normalized_degrees != 0.0) 12407 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 12408 exception); 12409 XSetCursorState(display,windows,MagickTrue); 12410 XCheckRefreshWindows(display,windows); 12411 (*image)->background_color.red=(double) ScaleShortToQuantum( 12412 windows->pixel_info->pen_colors[pen_id].red); 12413 (*image)->background_color.green=(double) ScaleShortToQuantum( 12414 windows->pixel_info->pen_colors[pen_id].green); 12415 (*image)->background_color.blue=(double) ScaleShortToQuantum( 12416 windows->pixel_info->pen_colors[pen_id].blue); 12417 rotate_image=RotateImage(*image,degrees,exception); 12418 XSetCursorState(display,windows,MagickFalse); 12419 if (rotate_image == (Image *) NULL) 12420 return(MagickFalse); 12421 *image=DestroyImage(*image); 12422 *image=rotate_image; 12423 if (windows->image.crop_geometry != (char *) NULL) 12424 { 12425 /* 12426 Rotate crop geometry. 12427 */ 12428 width=(unsigned int) (*image)->columns; 12429 height=(unsigned int) (*image)->rows; 12430 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12431 switch (rotations % 4) 12432 { 12433 default: 12434 case 0: 12435 break; 12436 case 1: 12437 { 12438 /* 12439 Rotate 90 degrees. 12440 */ 12441 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent, 12442 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12443 (int) height-y,x); 12444 break; 12445 } 12446 case 2: 12447 { 12448 /* 12449 Rotate 180 degrees. 12450 */ 12451 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent, 12452 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12453 break; 12454 } 12455 case 3: 12456 { 12457 /* 12458 Rotate 270 degrees. 12459 */ 12460 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent, 12461 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12462 break; 12463 } 12464 } 12465 } 12466 if (windows->image.orphan != MagickFalse ) 12467 return(MagickTrue); 12468 if (normalized_degrees != 0.0) 12469 { 12470 /* 12471 Update image colormap. 12472 */ 12473 windows->image.window_changes.width=(int) (*image)->columns; 12474 windows->image.window_changes.height=(int) (*image)->rows; 12475 if (windows->image.crop_geometry != (char *) NULL) 12476 { 12477 /* 12478 Obtain dimensions of image from crop geometry. 12479 */ 12480 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12481 &width,&height); 12482 windows->image.window_changes.width=(int) width; 12483 windows->image.window_changes.height=(int) height; 12484 } 12485 XConfigureImageColormap(display,resource_info,windows,*image,exception); 12486 } 12487 else 12488 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12489 { 12490 windows->image.window_changes.width=windows->image.ximage->height; 12491 windows->image.window_changes.height=windows->image.ximage->width; 12492 } 12493 /* 12494 Update image configuration. 12495 */ 12496 (void) XConfigureImage(display,resource_info,windows,*image,exception); 12497 return(MagickTrue); 12498} 12499 12500/* 12501%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12502% % 12503% % 12504% % 12505+ X S a v e I m a g e % 12506% % 12507% % 12508% % 12509%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12510% 12511% XSaveImage() saves an image to a file. 12512% 12513% The format of the XSaveImage method is: 12514% 12515% MagickBooleanType XSaveImage(Display *display, 12516% XResourceInfo *resource_info,XWindows *windows,Image *image, 12517% ExceptionInfo *exception) 12518% 12519% A description of each parameter follows: 12520% 12521% o display: Specifies a connection to an X server; returned from 12522% XOpenDisplay. 12523% 12524% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12525% 12526% o windows: Specifies a pointer to a XWindows structure. 12527% 12528% o image: the image. 12529% 12530% o exception: return any errors or warnings in this structure. 12531% 12532*/ 12533static MagickBooleanType XSaveImage(Display *display, 12534 XResourceInfo *resource_info,XWindows *windows,Image *image, 12535 ExceptionInfo *exception) 12536{ 12537 char 12538 filename[MagickPathExtent], 12539 geometry[MagickPathExtent]; 12540 12541 Image 12542 *save_image; 12543 12544 ImageInfo 12545 *image_info; 12546 12547 MagickStatusType 12548 status; 12549 12550 /* 12551 Request file name from user. 12552 */ 12553 if (resource_info->write_filename != (char *) NULL) 12554 (void) CopyMagickString(filename,resource_info->write_filename, 12555 MagickPathExtent); 12556 else 12557 { 12558 char 12559 path[MagickPathExtent]; 12560 12561 int 12562 status; 12563 12564 GetPathComponent(image->filename,HeadPath,path); 12565 GetPathComponent(image->filename,TailPath,filename); 12566 if (*path != '\0') 12567 { 12568 status=chdir(path); 12569 if (status == -1) 12570 (void) ThrowMagickException(exception,GetMagickModule(), 12571 FileOpenError,"UnableToOpenFile","%s",path); 12572 } 12573 } 12574 XFileBrowserWidget(display,windows,"Save",filename); 12575 if (*filename == '\0') 12576 return(MagickTrue); 12577 if (IsPathAccessible(filename) != MagickFalse ) 12578 { 12579 int 12580 status; 12581 12582 /* 12583 File exists-- seek user's permission before overwriting. 12584 */ 12585 status=XConfirmWidget(display,windows,"Overwrite",filename); 12586 if (status <= 0) 12587 return(MagickTrue); 12588 } 12589 image_info=CloneImageInfo(resource_info->image_info); 12590 (void) CopyMagickString(image_info->filename,filename,MagickPathExtent); 12591 (void) SetImageInfo(image_info,1,exception); 12592 if ((LocaleCompare(image_info->magick,"JPEG") == 0) || 12593 (LocaleCompare(image_info->magick,"JPG") == 0)) 12594 { 12595 char 12596 quality[MagickPathExtent]; 12597 12598 int 12599 status; 12600 12601 /* 12602 Request JPEG quality from user. 12603 */ 12604 (void) FormatLocaleString(quality,MagickPathExtent,"%.20g",(double) 12605 image->quality); 12606 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", 12607 quality); 12608 if (*quality == '\0') 12609 return(MagickTrue); 12610 image->quality=StringToUnsignedLong(quality); 12611 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace; 12612 } 12613 if ((LocaleCompare(image_info->magick,"EPS") == 0) || 12614 (LocaleCompare(image_info->magick,"PDF") == 0) || 12615 (LocaleCompare(image_info->magick,"PS") == 0) || 12616 (LocaleCompare(image_info->magick,"PS2") == 0)) 12617 { 12618 char 12619 geometry[MagickPathExtent]; 12620 12621 /* 12622 Request page geometry from user. 12623 */ 12624 (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent); 12625 if (LocaleCompare(image_info->magick,"PDF") == 0) 12626 (void) CopyMagickString(geometry,PSPageGeometry,MagickPathExtent); 12627 if (image_info->page != (char *) NULL) 12628 (void) CopyMagickString(geometry,image_info->page,MagickPathExtent); 12629 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 12630 "Select page geometry:",geometry); 12631 if (*geometry != '\0') 12632 image_info->page=GetPageGeometry(geometry); 12633 } 12634 /* 12635 Apply image transforms. 12636 */ 12637 XSetCursorState(display,windows,MagickTrue); 12638 XCheckRefreshWindows(display,windows); 12639 save_image=CloneImage(image,0,0,MagickTrue,exception); 12640 if (save_image == (Image *) NULL) 12641 return(MagickFalse); 12642 (void) FormatLocaleString(geometry,MagickPathExtent,"%dx%d!", 12643 windows->image.ximage->width,windows->image.ximage->height); 12644 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry, 12645 exception); 12646 /* 12647 Write image. 12648 */ 12649 (void) CopyMagickString(save_image->filename,filename,MagickPathExtent); 12650 status=WriteImage(image_info,save_image,exception); 12651 if (status != MagickFalse ) 12652 image->taint=MagickFalse; 12653 save_image=DestroyImage(save_image); 12654 image_info=DestroyImageInfo(image_info); 12655 XSetCursorState(display,windows,MagickFalse); 12656 return(status != 0 ? MagickTrue : MagickFalse); 12657} 12658 12659/* 12660%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12661% % 12662% % 12663% % 12664+ X S c r e e n E v e n t % 12665% % 12666% % 12667% % 12668%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12669% 12670% XScreenEvent() handles global events associated with the Pan and Magnify 12671% windows. 12672% 12673% The format of the XScreenEvent function is: 12674% 12675% void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12676% ExceptionInfo *exception) 12677% 12678% A description of each parameter follows: 12679% 12680% o display: Specifies a pointer to the Display structure; returned from 12681% XOpenDisplay. 12682% 12683% o windows: Specifies a pointer to a XWindows structure. 12684% 12685% o event: Specifies a pointer to a X11 XEvent structure. 12686% 12687% o exception: return any errors or warnings in this structure. 12688% 12689*/ 12690 12691#if defined(__cplusplus) || defined(c_plusplus) 12692extern "C" { 12693#endif 12694 12695static int XPredicate(Display *magick_unused(display),XEvent *event,char *data) 12696{ 12697 register XWindows 12698 *windows; 12699 12700 windows=(XWindows *) data; 12701 if ((event->type == ClientMessage) && 12702 (event->xclient.window == windows->image.id)) 12703 return(MagickFalse); 12704 return(MagickTrue); 12705} 12706 12707#if defined(__cplusplus) || defined(c_plusplus) 12708} 12709#endif 12710 12711static void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12712 ExceptionInfo *exception) 12713{ 12714 register int 12715 x, 12716 y; 12717 12718 (void) XIfEvent(display,event,XPredicate,(char *) windows); 12719 if (event->xany.window == windows->command.id) 12720 return; 12721 switch (event->type) 12722 { 12723 case ButtonPress: 12724 case ButtonRelease: 12725 { 12726 if ((event->xbutton.button == Button3) && 12727 (event->xbutton.state & Mod1Mask)) 12728 { 12729 /* 12730 Convert Alt-Button3 to Button2. 12731 */ 12732 event->xbutton.button=Button2; 12733 event->xbutton.state&=(~Mod1Mask); 12734 } 12735 if (event->xbutton.window == windows->backdrop.id) 12736 { 12737 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent, 12738 event->xbutton.time); 12739 break; 12740 } 12741 if (event->xbutton.window == windows->pan.id) 12742 { 12743 XPanImage(display,windows,event,exception); 12744 break; 12745 } 12746 if (event->xbutton.window == windows->image.id) 12747 if (event->xbutton.button == Button2) 12748 { 12749 /* 12750 Update magnified image. 12751 */ 12752 x=event->xbutton.x; 12753 y=event->xbutton.y; 12754 if (x < 0) 12755 x=0; 12756 else 12757 if (x >= (int) windows->image.width) 12758 x=(int) (windows->image.width-1); 12759 windows->magnify.x=(int) windows->image.x+x; 12760 if (y < 0) 12761 y=0; 12762 else 12763 if (y >= (int) windows->image.height) 12764 y=(int) (windows->image.height-1); 12765 windows->magnify.y=windows->image.y+y; 12766 if (windows->magnify.mapped == MagickFalse) 12767 (void) XMapRaised(display,windows->magnify.id); 12768 XMakeMagnifyImage(display,windows,exception); 12769 if (event->type == ButtonRelease) 12770 (void) XWithdrawWindow(display,windows->info.id, 12771 windows->info.screen); 12772 break; 12773 } 12774 break; 12775 } 12776 case ClientMessage: 12777 { 12778 /* 12779 If client window delete message, exit. 12780 */ 12781 if (event->xclient.message_type != windows->wm_protocols) 12782 break; 12783 if (*event->xclient.data.l != (long) windows->wm_delete_window) 12784 break; 12785 if (event->xclient.window == windows->magnify.id) 12786 { 12787 (void) XWithdrawWindow(display,windows->magnify.id, 12788 windows->magnify.screen); 12789 break; 12790 } 12791 break; 12792 } 12793 case ConfigureNotify: 12794 { 12795 if (event->xconfigure.window == windows->magnify.id) 12796 { 12797 unsigned int 12798 magnify; 12799 12800 /* 12801 Magnify window has a new configuration. 12802 */ 12803 windows->magnify.width=(unsigned int) event->xconfigure.width; 12804 windows->magnify.height=(unsigned int) event->xconfigure.height; 12805 if (windows->magnify.mapped == MagickFalse) 12806 break; 12807 magnify=1; 12808 while ((int) magnify <= event->xconfigure.width) 12809 magnify<<=1; 12810 while ((int) magnify <= event->xconfigure.height) 12811 magnify<<=1; 12812 magnify>>=1; 12813 if (((int) magnify != event->xconfigure.width) || 12814 ((int) magnify != event->xconfigure.height)) 12815 { 12816 XWindowChanges 12817 window_changes; 12818 12819 window_changes.width=(int) magnify; 12820 window_changes.height=(int) magnify; 12821 (void) XReconfigureWMWindow(display,windows->magnify.id, 12822 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 12823 &window_changes); 12824 break; 12825 } 12826 XMakeMagnifyImage(display,windows,exception); 12827 break; 12828 } 12829 break; 12830 } 12831 case Expose: 12832 { 12833 if (event->xexpose.window == windows->image.id) 12834 { 12835 XRefreshWindow(display,&windows->image,event); 12836 break; 12837 } 12838 if (event->xexpose.window == windows->pan.id) 12839 if (event->xexpose.count == 0) 12840 { 12841 XDrawPanRectangle(display,windows); 12842 break; 12843 } 12844 if (event->xexpose.window == windows->magnify.id) 12845 if (event->xexpose.count == 0) 12846 { 12847 XMakeMagnifyImage(display,windows,exception); 12848 break; 12849 } 12850 break; 12851 } 12852 case KeyPress: 12853 { 12854 char 12855 command[MagickPathExtent]; 12856 12857 KeySym 12858 key_symbol; 12859 12860 if (event->xkey.window != windows->magnify.id) 12861 break; 12862 /* 12863 Respond to a user key press. 12864 */ 12865 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int) 12866 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12867 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol, 12868 exception); 12869 break; 12870 } 12871 case MapNotify: 12872 { 12873 if (event->xmap.window == windows->magnify.id) 12874 { 12875 windows->magnify.mapped=MagickTrue; 12876 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12877 break; 12878 } 12879 if (event->xmap.window == windows->info.id) 12880 { 12881 windows->info.mapped=MagickTrue; 12882 break; 12883 } 12884 break; 12885 } 12886 case MotionNotify: 12887 { 12888 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; 12889 if (event->xmotion.window == windows->image.id) 12890 if (windows->magnify.mapped != MagickFalse ) 12891 { 12892 /* 12893 Update magnified image. 12894 */ 12895 x=event->xmotion.x; 12896 y=event->xmotion.y; 12897 if (x < 0) 12898 x=0; 12899 else 12900 if (x >= (int) windows->image.width) 12901 x=(int) (windows->image.width-1); 12902 windows->magnify.x=(int) windows->image.x+x; 12903 if (y < 0) 12904 y=0; 12905 else 12906 if (y >= (int) windows->image.height) 12907 y=(int) (windows->image.height-1); 12908 windows->magnify.y=windows->image.y+y; 12909 XMakeMagnifyImage(display,windows,exception); 12910 } 12911 break; 12912 } 12913 case UnmapNotify: 12914 { 12915 if (event->xunmap.window == windows->magnify.id) 12916 { 12917 windows->magnify.mapped=MagickFalse; 12918 break; 12919 } 12920 if (event->xunmap.window == windows->info.id) 12921 { 12922 windows->info.mapped=MagickFalse; 12923 break; 12924 } 12925 break; 12926 } 12927 default: 12928 break; 12929 } 12930} 12931 12932/* 12933%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12934% % 12935% % 12936% % 12937+ X S e t C r o p G e o m e t r y % 12938% % 12939% % 12940% % 12941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12942% 12943% XSetCropGeometry() accepts a cropping geometry relative to the Image window 12944% and translates it to a cropping geometry relative to the image. 12945% 12946% The format of the XSetCropGeometry method is: 12947% 12948% void XSetCropGeometry(Display *display,XWindows *windows, 12949% RectangleInfo *crop_info,Image *image) 12950% 12951% A description of each parameter follows: 12952% 12953% o display: Specifies a connection to an X server; returned from 12954% XOpenDisplay. 12955% 12956% o windows: Specifies a pointer to a XWindows structure. 12957% 12958% o crop_info: A pointer to a RectangleInfo that defines a region of the 12959% Image window to crop. 12960% 12961% o image: the image. 12962% 12963*/ 12964static void XSetCropGeometry(Display *display,XWindows *windows, 12965 RectangleInfo *crop_info,Image *image) 12966{ 12967 char 12968 text[MagickPathExtent]; 12969 12970 int 12971 x, 12972 y; 12973 12974 double 12975 scale_factor; 12976 12977 unsigned int 12978 height, 12979 width; 12980 12981 if (windows->info.mapped != MagickFalse ) 12982 { 12983 /* 12984 Display info on cropping rectangle. 12985 */ 12986 (void) FormatLocaleString(text,MagickPathExtent," %.20gx%.20g%+.20g%+.20g", 12987 (double) crop_info->width,(double) crop_info->height,(double) 12988 crop_info->x,(double) crop_info->y); 12989 XInfoWidget(display,windows,text); 12990 } 12991 /* 12992 Cropping geometry is relative to any previous crop geometry. 12993 */ 12994 x=0; 12995 y=0; 12996 width=(unsigned int) image->columns; 12997 height=(unsigned int) image->rows; 12998 if (windows->image.crop_geometry != (char *) NULL) 12999 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13000 else 13001 windows->image.crop_geometry=AcquireString((char *) NULL); 13002 /* 13003 Define the crop geometry string from the cropping rectangle. 13004 */ 13005 scale_factor=(double) width/windows->image.ximage->width; 13006 if (crop_info->x > 0) 13007 x+=(int) (scale_factor*crop_info->x+0.5); 13008 width=(unsigned int) (scale_factor*crop_info->width+0.5); 13009 if (width == 0) 13010 width=1; 13011 scale_factor=(double) height/windows->image.ximage->height; 13012 if (crop_info->y > 0) 13013 y+=(int) (scale_factor*crop_info->y+0.5); 13014 height=(unsigned int) (scale_factor*crop_info->height+0.5); 13015 if (height == 0) 13016 height=1; 13017 (void) FormatLocaleString(windows->image.crop_geometry,MagickPathExtent, 13018 "%ux%u%+d%+d",width,height,x,y); 13019} 13020 13021/* 13022%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13023% % 13024% % 13025% % 13026+ X T i l e I m a g e % 13027% % 13028% % 13029% % 13030%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13031% 13032% XTileImage() loads or deletes a selected tile from a visual image directory. 13033% The load or delete command is chosen from a menu. 13034% 13035% The format of the XTileImage method is: 13036% 13037% Image *XTileImage(Display *display,XResourceInfo *resource_info, 13038% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13039% 13040% A description of each parameter follows: 13041% 13042% o tile_image: XTileImage reads or deletes the tile image 13043% and returns it. A null image is returned if an error occurs. 13044% 13045% o display: Specifies a connection to an X server; returned from 13046% XOpenDisplay. 13047% 13048% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13049% 13050% o windows: Specifies a pointer to a XWindows structure. 13051% 13052% o image: the image; returned from ReadImage. 13053% 13054% o event: Specifies a pointer to a XEvent structure. If it is NULL, 13055% the entire image is refreshed. 13056% 13057% o exception: return any errors or warnings in this structure. 13058% 13059*/ 13060static Image *XTileImage(Display *display,XResourceInfo *resource_info, 13061 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13062{ 13063 static const char 13064 *VerbMenu[] = 13065 { 13066 "Load", 13067 "Next", 13068 "Former", 13069 "Delete", 13070 "Update", 13071 (char *) NULL, 13072 }; 13073 13074 static const ModeType 13075 TileCommands[] = 13076 { 13077 TileLoadCommand, 13078 TileNextCommand, 13079 TileFormerCommand, 13080 TileDeleteCommand, 13081 TileUpdateCommand 13082 }; 13083 13084 char 13085 command[MagickPathExtent], 13086 filename[MagickPathExtent]; 13087 13088 Image 13089 *tile_image; 13090 13091 int 13092 id, 13093 status, 13094 tile, 13095 x, 13096 y; 13097 13098 double 13099 scale_factor; 13100 13101 register char 13102 *p, 13103 *q; 13104 13105 register int 13106 i; 13107 13108 unsigned int 13109 height, 13110 width; 13111 13112 /* 13113 Tile image is relative to montage image configuration. 13114 */ 13115 x=0; 13116 y=0; 13117 width=(unsigned int) image->columns; 13118 height=(unsigned int) image->rows; 13119 if (windows->image.crop_geometry != (char *) NULL) 13120 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13121 scale_factor=(double) width/windows->image.ximage->width; 13122 event->xbutton.x+=windows->image.x; 13123 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5); 13124 scale_factor=(double) height/windows->image.ximage->height; 13125 event->xbutton.y+=windows->image.y; 13126 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5); 13127 /* 13128 Determine size and location of each tile in the visual image directory. 13129 */ 13130 width=(unsigned int) image->columns; 13131 height=(unsigned int) image->rows; 13132 x=0; 13133 y=0; 13134 (void) XParseGeometry(image->montage,&x,&y,&width,&height); 13135 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+ 13136 (event->xbutton.x-x)/width; 13137 if (tile < 0) 13138 { 13139 /* 13140 Button press is outside any tile. 13141 */ 13142 (void) XBell(display,0); 13143 return((Image *) NULL); 13144 } 13145 /* 13146 Determine file name from the tile directory. 13147 */ 13148 p=image->directory; 13149 for (i=tile; (i != 0) && (*p != '\0'); ) 13150 { 13151 if (*p == '\n') 13152 i--; 13153 p++; 13154 } 13155 if (*p == '\0') 13156 { 13157 /* 13158 Button press is outside any tile. 13159 */ 13160 (void) XBell(display,0); 13161 return((Image *) NULL); 13162 } 13163 /* 13164 Select a command from the pop-up menu. 13165 */ 13166 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command); 13167 if (id < 0) 13168 return((Image *) NULL); 13169 q=p; 13170 while ((*q != '\n') && (*q != '\0')) 13171 q++; 13172 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13173 /* 13174 Perform command for the selected tile. 13175 */ 13176 XSetCursorState(display,windows,MagickTrue); 13177 XCheckRefreshWindows(display,windows); 13178 tile_image=NewImageList(); 13179 switch (TileCommands[id]) 13180 { 13181 case TileLoadCommand: 13182 { 13183 /* 13184 Load tile image. 13185 */ 13186 XCheckRefreshWindows(display,windows); 13187 (void) CopyMagickString(resource_info->image_info->magick,"MIFF", 13188 MagickPathExtent); 13189 (void) CopyMagickString(resource_info->image_info->filename,filename, 13190 MagickPathExtent); 13191 tile_image=ReadImage(resource_info->image_info,exception); 13192 CatchException(exception); 13193 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13194 break; 13195 } 13196 case TileNextCommand: 13197 { 13198 /* 13199 Display next image. 13200 */ 13201 XClientMessage(display,windows->image.id,windows->im_protocols, 13202 windows->im_next_image,CurrentTime); 13203 break; 13204 } 13205 case TileFormerCommand: 13206 { 13207 /* 13208 Display former image. 13209 */ 13210 XClientMessage(display,windows->image.id,windows->im_protocols, 13211 windows->im_former_image,CurrentTime); 13212 break; 13213 } 13214 case TileDeleteCommand: 13215 { 13216 /* 13217 Delete tile image. 13218 */ 13219 if (IsPathAccessible(filename) == MagickFalse) 13220 { 13221 XNoticeWidget(display,windows,"Image file does not exist:",filename); 13222 break; 13223 } 13224 status=XConfirmWidget(display,windows,"Really delete tile",filename); 13225 if (status <= 0) 13226 break; 13227 status=ShredFile(filename); 13228 if (status != MagickFalse ) 13229 { 13230 XNoticeWidget(display,windows,"Unable to delete image file:", 13231 filename); 13232 break; 13233 } 13234 } 13235 case TileUpdateCommand: 13236 { 13237 int 13238 x_offset, 13239 y_offset; 13240 13241 PixelInfo 13242 pixel; 13243 13244 register int 13245 j; 13246 13247 register Quantum 13248 *s; 13249 13250 /* 13251 Ensure all the images exist. 13252 */ 13253 tile=0; 13254 GetPixelInfo(image,&pixel); 13255 for (p=image->directory; *p != '\0'; p++) 13256 { 13257 CacheView 13258 *image_view; 13259 13260 q=p; 13261 while ((*q != '\n') && (*q != '\0')) 13262 q++; 13263 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13264 p=q; 13265 if (IsPathAccessible(filename) != MagickFalse ) 13266 { 13267 tile++; 13268 continue; 13269 } 13270 /* 13271 Overwrite tile with background color. 13272 */ 13273 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x); 13274 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y); 13275 image_view=AcquireAuthenticCacheView(image,exception); 13276 (void) GetOneCacheViewVirtualPixelInfo(image_view,0,0,&pixel,exception); 13277 for (i=0; i < (int) height; i++) 13278 { 13279 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t) 13280 y_offset+i,width,1,exception); 13281 if (s == (Quantum *) NULL) 13282 break; 13283 for (j=0; j < (int) width; j++) 13284 { 13285 SetPixelViaPixelInfo(image,&pixel,s); 13286 s+=GetPixelChannels(image); 13287 } 13288 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 13289 break; 13290 } 13291 image_view=DestroyCacheView(image_view); 13292 tile++; 13293 } 13294 windows->image.window_changes.width=(int) image->columns; 13295 windows->image.window_changes.height=(int) image->rows; 13296 XConfigureImageColormap(display,resource_info,windows,image,exception); 13297 (void) XConfigureImage(display,resource_info,windows,image,exception); 13298 break; 13299 } 13300 default: 13301 break; 13302 } 13303 XSetCursorState(display,windows,MagickFalse); 13304 return(tile_image); 13305} 13306 13307/* 13308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13309% % 13310% % 13311% % 13312+ X T r a n s l a t e I m a g e % 13313% % 13314% % 13315% % 13316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13317% 13318% XTranslateImage() translates the image within an Image window by one pixel 13319% as specified by the key symbol. If the image has a montage string the 13320% translation is respect to the width and height contained within the string. 13321% 13322% The format of the XTranslateImage method is: 13323% 13324% void XTranslateImage(Display *display,XWindows *windows, 13325% Image *image,const KeySym key_symbol) 13326% 13327% A description of each parameter follows: 13328% 13329% o display: Specifies a connection to an X server; returned from 13330% XOpenDisplay. 13331% 13332% o windows: Specifies a pointer to a XWindows structure. 13333% 13334% o image: the image. 13335% 13336% o key_symbol: Specifies a KeySym which indicates which side of the image 13337% to trim. 13338% 13339*/ 13340static void XTranslateImage(Display *display,XWindows *windows, 13341 Image *image,const KeySym key_symbol) 13342{ 13343 char 13344 text[MagickPathExtent]; 13345 13346 int 13347 x, 13348 y; 13349 13350 unsigned int 13351 x_offset, 13352 y_offset; 13353 13354 /* 13355 User specified a pan position offset. 13356 */ 13357 x_offset=windows->image.width; 13358 y_offset=windows->image.height; 13359 if (image->montage != (char *) NULL) 13360 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset); 13361 switch ((int) key_symbol) 13362 { 13363 case XK_Home: 13364 case XK_KP_Home: 13365 { 13366 windows->image.x=(int) windows->image.width/2; 13367 windows->image.y=(int) windows->image.height/2; 13368 break; 13369 } 13370 case XK_Left: 13371 case XK_KP_Left: 13372 { 13373 windows->image.x-=x_offset; 13374 break; 13375 } 13376 case XK_Next: 13377 case XK_Up: 13378 case XK_KP_Up: 13379 { 13380 windows->image.y-=y_offset; 13381 break; 13382 } 13383 case XK_Right: 13384 case XK_KP_Right: 13385 { 13386 windows->image.x+=x_offset; 13387 break; 13388 } 13389 case XK_Prior: 13390 case XK_Down: 13391 case XK_KP_Down: 13392 { 13393 windows->image.y+=y_offset; 13394 break; 13395 } 13396 default: 13397 return; 13398 } 13399 /* 13400 Check boundary conditions. 13401 */ 13402 if (windows->image.x < 0) 13403 windows->image.x=0; 13404 else 13405 if ((int) (windows->image.x+windows->image.width) > 13406 windows->image.ximage->width) 13407 windows->image.x=(int) windows->image.ximage->width-windows->image.width; 13408 if (windows->image.y < 0) 13409 windows->image.y=0; 13410 else 13411 if ((int) (windows->image.y+windows->image.height) > 13412 windows->image.ximage->height) 13413 windows->image.y=(int) windows->image.ximage->height-windows->image.height; 13414 /* 13415 Refresh Image window. 13416 */ 13417 (void) FormatLocaleString(text,MagickPathExtent," %ux%u%+d%+d ", 13418 windows->image.width,windows->image.height,windows->image.x, 13419 windows->image.y); 13420 XInfoWidget(display,windows,text); 13421 XCheckRefreshWindows(display,windows); 13422 XDrawPanRectangle(display,windows); 13423 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 13424 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13425} 13426 13427/* 13428%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13429% % 13430% % 13431% % 13432+ X T r i m I m a g e % 13433% % 13434% % 13435% % 13436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13437% 13438% XTrimImage() trims the edges from the Image window. 13439% 13440% The format of the XTrimImage method is: 13441% 13442% MagickBooleanType XTrimImage(Display *display, 13443% XResourceInfo *resource_info,XWindows *windows,Image *image, 13444% ExceptionInfo *exception) 13445% 13446% A description of each parameter follows: 13447% 13448% o display: Specifies a connection to an X server; returned from 13449% XOpenDisplay. 13450% 13451% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13452% 13453% o windows: Specifies a pointer to a XWindows structure. 13454% 13455% o image: the image. 13456% 13457% o exception: return any errors or warnings in this structure. 13458% 13459*/ 13460static MagickBooleanType XTrimImage(Display *display, 13461 XResourceInfo *resource_info,XWindows *windows,Image *image, 13462 ExceptionInfo *exception) 13463{ 13464 RectangleInfo 13465 trim_info; 13466 13467 register int 13468 x, 13469 y; 13470 13471 size_t 13472 background, 13473 pixel; 13474 13475 /* 13476 Trim edges from image. 13477 */ 13478 XSetCursorState(display,windows,MagickTrue); 13479 XCheckRefreshWindows(display,windows); 13480 /* 13481 Crop the left edge. 13482 */ 13483 background=XGetPixel(windows->image.ximage,0,0); 13484 trim_info.width=(size_t) windows->image.ximage->width; 13485 for (x=0; x < windows->image.ximage->width; x++) 13486 { 13487 for (y=0; y < windows->image.ximage->height; y++) 13488 { 13489 pixel=XGetPixel(windows->image.ximage,x,y); 13490 if (pixel != background) 13491 break; 13492 } 13493 if (y < windows->image.ximage->height) 13494 break; 13495 } 13496 trim_info.x=(ssize_t) x; 13497 if (trim_info.x == (ssize_t) windows->image.ximage->width) 13498 { 13499 XSetCursorState(display,windows,MagickFalse); 13500 return(MagickFalse); 13501 } 13502 /* 13503 Crop the right edge. 13504 */ 13505 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0); 13506 for (x=windows->image.ximage->width-1; x != 0; x--) 13507 { 13508 for (y=0; y < windows->image.ximage->height; y++) 13509 { 13510 pixel=XGetPixel(windows->image.ximage,x,y); 13511 if (pixel != background) 13512 break; 13513 } 13514 if (y < windows->image.ximage->height) 13515 break; 13516 } 13517 trim_info.width=(size_t) (x-trim_info.x+1); 13518 /* 13519 Crop the top edge. 13520 */ 13521 background=XGetPixel(windows->image.ximage,0,0); 13522 trim_info.height=(size_t) windows->image.ximage->height; 13523 for (y=0; y < windows->image.ximage->height; y++) 13524 { 13525 for (x=0; x < windows->image.ximage->width; x++) 13526 { 13527 pixel=XGetPixel(windows->image.ximage,x,y); 13528 if (pixel != background) 13529 break; 13530 } 13531 if (x < windows->image.ximage->width) 13532 break; 13533 } 13534 trim_info.y=(ssize_t) y; 13535 /* 13536 Crop the bottom edge. 13537 */ 13538 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1); 13539 for (y=windows->image.ximage->height-1; y != 0; y--) 13540 { 13541 for (x=0; x < windows->image.ximage->width; x++) 13542 { 13543 pixel=XGetPixel(windows->image.ximage,x,y); 13544 if (pixel != background) 13545 break; 13546 } 13547 if (x < windows->image.ximage->width) 13548 break; 13549 } 13550 trim_info.height=(size_t) y-trim_info.y+1; 13551 if (((unsigned int) trim_info.width != windows->image.width) || 13552 ((unsigned int) trim_info.height != windows->image.height)) 13553 { 13554 /* 13555 Reconfigure Image window as defined by the trimming rectangle. 13556 */ 13557 XSetCropGeometry(display,windows,&trim_info,image); 13558 windows->image.window_changes.width=(int) trim_info.width; 13559 windows->image.window_changes.height=(int) trim_info.height; 13560 (void) XConfigureImage(display,resource_info,windows,image,exception); 13561 } 13562 XSetCursorState(display,windows,MagickFalse); 13563 return(MagickTrue); 13564} 13565 13566/* 13567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13568% % 13569% % 13570% % 13571+ X V i s u a l D i r e c t o r y I m a g e % 13572% % 13573% % 13574% % 13575%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13576% 13577% XVisualDirectoryImage() creates a Visual Image Directory. 13578% 13579% The format of the XVisualDirectoryImage method is: 13580% 13581% Image *XVisualDirectoryImage(Display *display, 13582% XResourceInfo *resource_info,XWindows *windows, 13583% ExceptionInfo *exception) 13584% 13585% A description of each parameter follows: 13586% 13587% o display: Specifies a connection to an X server; returned from 13588% XOpenDisplay. 13589% 13590% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13591% 13592% o windows: Specifies a pointer to a XWindows structure. 13593% 13594% o exception: return any errors or warnings in this structure. 13595% 13596*/ 13597static Image *XVisualDirectoryImage(Display *display, 13598 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception) 13599{ 13600#define TileImageTag "Scale/Image" 13601#define XClientName "montage" 13602 13603 char 13604 **filelist; 13605 13606 Image 13607 *images, 13608 *montage_image, 13609 *next_image, 13610 *thumbnail_image; 13611 13612 ImageInfo 13613 *read_info; 13614 13615 int 13616 number_files; 13617 13618 MagickBooleanType 13619 backdrop; 13620 13621 MagickStatusType 13622 status; 13623 13624 MontageInfo 13625 *montage_info; 13626 13627 RectangleInfo 13628 geometry; 13629 13630 register int 13631 i; 13632 13633 static char 13634 filename[MagickPathExtent] = "\0", 13635 filenames[MagickPathExtent] = "*"; 13636 13637 XResourceInfo 13638 background_resources; 13639 13640 /* 13641 Request file name from user. 13642 */ 13643 XFileBrowserWidget(display,windows,"Directory",filenames); 13644 if (*filenames == '\0') 13645 return((Image *) NULL); 13646 /* 13647 Expand the filenames. 13648 */ 13649 filelist=(char **) AcquireMagickMemory(sizeof(*filelist)); 13650 if (filelist == (char **) NULL) 13651 { 13652 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed", 13653 filenames); 13654 return((Image *) NULL); 13655 } 13656 number_files=1; 13657 filelist[0]=filenames; 13658 status=ExpandFilenames(&number_files,&filelist); 13659 if ((status == MagickFalse) || (number_files == 0)) 13660 { 13661 if (number_files == 0) 13662 ThrowXWindowException(ImageError,"NoImagesWereFound",filenames) 13663 else 13664 ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed", 13665 filenames); 13666 return((Image *) NULL); 13667 } 13668 /* 13669 Set image background resources. 13670 */ 13671 background_resources=(*resource_info); 13672 background_resources.window_id=AcquireString(""); 13673 (void) FormatLocaleString(background_resources.window_id,MagickPathExtent, 13674 "0x%lx",windows->image.id); 13675 background_resources.backdrop=MagickTrue; 13676 /* 13677 Read each image and convert them to a tile. 13678 */ 13679 backdrop=((windows->visual_info->klass == TrueColor) || 13680 (windows->visual_info->klass == DirectColor)) ? MagickTrue : MagickFalse; 13681 read_info=CloneImageInfo(resource_info->image_info); 13682 (void) SetImageOption(read_info,"jpeg:size","120x120"); 13683 (void) CloneString(&read_info->size,DefaultTileGeometry); 13684 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 13685 (void *) NULL); 13686 images=NewImageList(); 13687 XSetCursorState(display,windows,MagickTrue); 13688 XCheckRefreshWindows(display,windows); 13689 for (i=0; i < (int) number_files; i++) 13690 { 13691 (void) CopyMagickString(read_info->filename,filelist[i],MagickPathExtent); 13692 filelist[i]=DestroyString(filelist[i]); 13693 *read_info->magick='\0'; 13694 next_image=ReadImage(read_info,exception); 13695 CatchException(exception); 13696 if (next_image != (Image *) NULL) 13697 { 13698 (void) DeleteImageProperty(next_image,"label"); 13699 (void) SetImageProperty(next_image,"label",InterpretImageProperties( 13700 read_info,next_image,DefaultTileLabel,exception),exception); 13701 (void) ParseRegionGeometry(next_image,read_info->size,&geometry, 13702 exception); 13703 thumbnail_image=ThumbnailImage(next_image,geometry.width, 13704 geometry.height,exception); 13705 if (thumbnail_image != (Image *) NULL) 13706 { 13707 next_image=DestroyImage(next_image); 13708 next_image=thumbnail_image; 13709 } 13710 if (backdrop) 13711 { 13712 (void) XDisplayBackgroundImage(display,&background_resources, 13713 next_image,exception); 13714 XSetCursorState(display,windows,MagickTrue); 13715 } 13716 AppendImageToList(&images,next_image); 13717 if (images->progress_monitor != (MagickProgressMonitor) NULL) 13718 { 13719 MagickBooleanType 13720 proceed; 13721 13722 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i, 13723 (MagickSizeType) number_files); 13724 if (proceed == MagickFalse) 13725 break; 13726 } 13727 } 13728 } 13729 filelist=(char **) RelinquishMagickMemory(filelist); 13730 if (images == (Image *) NULL) 13731 { 13732 read_info=DestroyImageInfo(read_info); 13733 XSetCursorState(display,windows,MagickFalse); 13734 ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames); 13735 return((Image *) NULL); 13736 } 13737 /* 13738 Create the Visual Image Directory. 13739 */ 13740 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL); 13741 montage_info->pointsize=10; 13742 if (resource_info->font != (char *) NULL) 13743 (void) CloneString(&montage_info->font,resource_info->font); 13744 (void) CopyMagickString(montage_info->filename,filename,MagickPathExtent); 13745 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList( 13746 images),exception); 13747 images=DestroyImageList(images); 13748 montage_info=DestroyMontageInfo(montage_info); 13749 read_info=DestroyImageInfo(read_info); 13750 XSetCursorState(display,windows,MagickFalse); 13751 if (montage_image == (Image *) NULL) 13752 return(montage_image); 13753 XClientMessage(display,windows->image.id,windows->im_protocols, 13754 windows->im_next_image,CurrentTime); 13755 return(montage_image); 13756} 13757 13758/* 13759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13760% % 13761% % 13762% % 13763% X D i s p l a y B a c k g r o u n d I m a g e % 13764% % 13765% % 13766% % 13767%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13768% 13769% XDisplayBackgroundImage() displays an image in the background of a window. 13770% 13771% The format of the XDisplayBackgroundImage method is: 13772% 13773% MagickBooleanType XDisplayBackgroundImage(Display *display, 13774% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13775% 13776% A description of each parameter follows: 13777% 13778% o display: Specifies a connection to an X server; returned from 13779% XOpenDisplay. 13780% 13781% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13782% 13783% o image: the image. 13784% 13785% o exception: return any errors or warnings in this structure. 13786% 13787*/ 13788MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display, 13789 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13790{ 13791 char 13792 geometry[MagickPathExtent], 13793 visual_type[MagickPathExtent]; 13794 13795 int 13796 height, 13797 status, 13798 width; 13799 13800 RectangleInfo 13801 geometry_info; 13802 13803 static XPixelInfo 13804 pixel; 13805 13806 static XStandardColormap 13807 *map_info; 13808 13809 static XVisualInfo 13810 *visual_info = (XVisualInfo *) NULL; 13811 13812 static XWindowInfo 13813 window_info; 13814 13815 size_t 13816 delay; 13817 13818 Window 13819 root_window; 13820 13821 XGCValues 13822 context_values; 13823 13824 XResourceInfo 13825 resources; 13826 13827 XWindowAttributes 13828 window_attributes; 13829 13830 /* 13831 Determine target window. 13832 */ 13833 assert(image != (Image *) NULL); 13834 assert(image->signature == MagickCoreSignature); 13835 if (image->debug != MagickFalse ) 13836 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 13837 resources=(*resource_info); 13838 window_info.id=(Window) NULL; 13839 root_window=XRootWindow(display,XDefaultScreen(display)); 13840 if (LocaleCompare(resources.window_id,"root") == 0) 13841 window_info.id=root_window; 13842 else 13843 { 13844 if (isdigit((int) ((unsigned char) *resources.window_id)) != 0) 13845 window_info.id=XWindowByID(display,root_window, 13846 (Window) strtol((char *) resources.window_id,(char **) NULL,0)); 13847 if (window_info.id == (Window) NULL) 13848 window_info.id=XWindowByName(display,root_window,resources.window_id); 13849 } 13850 if (window_info.id == (Window) NULL) 13851 { 13852 ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists", 13853 resources.window_id); 13854 return(MagickFalse); 13855 } 13856 /* 13857 Determine window visual id. 13858 */ 13859 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); 13860 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); 13861 (void) CopyMagickString(visual_type,"default",MagickPathExtent); 13862 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13863 if (status != 0) 13864 (void) FormatLocaleString(visual_type,MagickPathExtent,"0x%lx", 13865 XVisualIDFromVisual(window_attributes.visual)); 13866 if (visual_info == (XVisualInfo *) NULL) 13867 { 13868 /* 13869 Allocate standard colormap. 13870 */ 13871 map_info=XAllocStandardColormap(); 13872 if (map_info == (XStandardColormap *) NULL) 13873 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", 13874 image->filename); 13875 map_info->colormap=(Colormap) NULL; 13876 pixel.pixels=(unsigned long *) NULL; 13877 /* 13878 Initialize visual info. 13879 */ 13880 resources.map_type=(char *) NULL; 13881 resources.visual_type=visual_type; 13882 visual_info=XBestVisualInfo(display,map_info,&resources); 13883 if (visual_info == (XVisualInfo *) NULL) 13884 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", 13885 resources.visual_type); 13886 /* 13887 Initialize window info. 13888 */ 13889 window_info.ximage=(XImage *) NULL; 13890 window_info.matte_image=(XImage *) NULL; 13891 window_info.pixmap=(Pixmap) NULL; 13892 window_info.matte_pixmap=(Pixmap) NULL; 13893 } 13894 /* 13895 Free previous root colors. 13896 */ 13897 if (window_info.id == root_window) 13898 (void) XDestroyWindowColors(display,root_window); 13899 /* 13900 Initialize Standard Colormap. 13901 */ 13902 resources.colormap=SharedColormap; 13903 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel, 13904 exception); 13905 /* 13906 Graphic context superclass. 13907 */ 13908 context_values.background=pixel.background_color.pixel; 13909 context_values.foreground=pixel.foreground_color.pixel; 13910 pixel.annotate_context=XCreateGC(display,window_info.id, 13911 (size_t) (GCBackground | GCForeground),&context_values); 13912 if (pixel.annotate_context == (GC) NULL) 13913 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 13914 image->filename); 13915 /* 13916 Initialize Image window attributes. 13917 */ 13918 window_info.name=AcquireString("\0"); 13919 window_info.icon_name=AcquireString("\0"); 13920 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, 13921 &resources,&window_info); 13922 /* 13923 Create the X image. 13924 */ 13925 window_info.width=(unsigned int) image->columns; 13926 window_info.height=(unsigned int) image->rows; 13927 if ((image->columns != window_info.width) || 13928 (image->rows != window_info.height)) 13929 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13930 image->filename); 13931 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>", 13932 window_attributes.width,window_attributes.height); 13933 geometry_info.width=window_info.width; 13934 geometry_info.height=window_info.height; 13935 geometry_info.x=(ssize_t) window_info.x; 13936 geometry_info.y=(ssize_t) window_info.y; 13937 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 13938 &geometry_info.width,&geometry_info.height); 13939 window_info.width=(unsigned int) geometry_info.width; 13940 window_info.height=(unsigned int) geometry_info.height; 13941 window_info.x=(int) geometry_info.x; 13942 window_info.y=(int) geometry_info.y; 13943 status=XMakeImage(display,&resources,&window_info,image,window_info.width, 13944 window_info.height,exception); 13945 if (status == MagickFalse) 13946 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13947 image->filename); 13948 window_info.x=0; 13949 window_info.y=0; 13950 if (image->debug != MagickFalse ) 13951 { 13952 (void) LogMagickEvent(X11Event,GetMagickModule(), 13953 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene, 13954 (double) image->columns,(double) image->rows); 13955 if (image->colors != 0) 13956 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 13957 image->colors); 13958 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick); 13959 } 13960 /* 13961 Adjust image dimensions as specified by backdrop or geometry options. 13962 */ 13963 width=(int) window_info.width; 13964 height=(int) window_info.height; 13965 if (resources.backdrop != MagickFalse ) 13966 { 13967 /* 13968 Center image on window. 13969 */ 13970 window_info.x=(window_attributes.width/2)- 13971 (window_info.ximage->width/2); 13972 window_info.y=(window_attributes.height/2)- 13973 (window_info.ximage->height/2); 13974 width=window_attributes.width; 13975 height=window_attributes.height; 13976 } 13977 if ((resources.image_geometry != (char *) NULL) && 13978 (*resources.image_geometry != '\0')) 13979 { 13980 char 13981 default_geometry[MagickPathExtent]; 13982 13983 int 13984 flags, 13985 gravity; 13986 13987 XSizeHints 13988 *size_hints; 13989 13990 /* 13991 User specified geometry. 13992 */ 13993 size_hints=XAllocSizeHints(); 13994 if (size_hints == (XSizeHints *) NULL) 13995 ThrowXWindowFatalException(ResourceLimitFatalError, 13996 "MemoryAllocationFailed",image->filename); 13997 size_hints->flags=0L; 13998 (void) FormatLocaleString(default_geometry,MagickPathExtent,"%dx%d", 13999 width,height); 14000 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, 14001 default_geometry,window_info.border_width,size_hints,&window_info.x, 14002 &window_info.y,&width,&height,&gravity); 14003 if (flags & (XValue | YValue)) 14004 { 14005 width=window_attributes.width; 14006 height=window_attributes.height; 14007 } 14008 (void) XFree((void *) size_hints); 14009 } 14010 /* 14011 Create the X pixmap. 14012 */ 14013 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, 14014 (unsigned int) height,window_info.depth); 14015 if (window_info.pixmap == (Pixmap) NULL) 14016 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", 14017 image->filename); 14018 /* 14019 Display pixmap on the window. 14020 */ 14021 if (((unsigned int) width > window_info.width) || 14022 ((unsigned int) height > window_info.height)) 14023 (void) XFillRectangle(display,window_info.pixmap, 14024 window_info.annotate_context,0,0,(unsigned int) width, 14025 (unsigned int) height); 14026 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, 14027 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int) 14028 window_info.width,(unsigned int) window_info.height); 14029 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); 14030 (void) XClearWindow(display,window_info.id); 14031 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); 14032 XDelay(display,delay == 0UL ? 10UL : delay); 14033 (void) XSync(display,MagickFalse); 14034 return(window_info.id == root_window ? MagickTrue : MagickFalse); 14035} 14036 14037/* 14038%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14039% % 14040% % 14041% % 14042+ X D i s p l a y I m a g e % 14043% % 14044% % 14045% % 14046%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14047% 14048% XDisplayImage() displays an image via X11. A new image is created and 14049% returned if the user interactively transforms the displayed image. 14050% 14051% The format of the XDisplayImage method is: 14052% 14053% Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14054% char **argv,int argc,Image **image,size_t *state, 14055% ExceptionInfo *exception) 14056% 14057% A description of each parameter follows: 14058% 14059% o nexus: Method XDisplayImage returns an image when the 14060% user chooses 'Open Image' from the command menu or picks a tile 14061% from the image directory. Otherwise a null image is returned. 14062% 14063% o display: Specifies a connection to an X server; returned from 14064% XOpenDisplay. 14065% 14066% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 14067% 14068% o argv: Specifies the application's argument list. 14069% 14070% o argc: Specifies the number of arguments. 14071% 14072% o image: Specifies an address to an address of an Image structure; 14073% 14074% o exception: return any errors or warnings in this structure. 14075% 14076*/ 14077MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14078 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception) 14079{ 14080#define MagnifySize 256 /* must be a power of 2 */ 14081#define MagickMenus 10 14082#define MagickTitle "Commands" 14083 14084 static const char 14085 *CommandMenu[] = 14086 { 14087 "File", 14088 "Edit", 14089 "View", 14090 "Transform", 14091 "Enhance", 14092 "Effects", 14093 "F/X", 14094 "Image Edit", 14095 "Miscellany", 14096 "Help", 14097 (char *) NULL 14098 }, 14099 *FileMenu[] = 14100 { 14101 "Open...", 14102 "Next", 14103 "Former", 14104 "Select...", 14105 "Save...", 14106 "Print...", 14107 "Delete...", 14108 "New...", 14109 "Visual Directory...", 14110 "Quit", 14111 (char *) NULL 14112 }, 14113 *EditMenu[] = 14114 { 14115 "Undo", 14116 "Redo", 14117 "Cut", 14118 "Copy", 14119 "Paste", 14120 (char *) NULL 14121 }, 14122 *ViewMenu[] = 14123 { 14124 "Half Size", 14125 "Original Size", 14126 "Double Size", 14127 "Resize...", 14128 "Apply", 14129 "Refresh", 14130 "Restore", 14131 (char *) NULL 14132 }, 14133 *TransformMenu[] = 14134 { 14135 "Crop", 14136 "Chop", 14137 "Flop", 14138 "Flip", 14139 "Rotate Right", 14140 "Rotate Left", 14141 "Rotate...", 14142 "Shear...", 14143 "Roll...", 14144 "Trim Edges", 14145 (char *) NULL 14146 }, 14147 *EnhanceMenu[] = 14148 { 14149 "Hue...", 14150 "Saturation...", 14151 "Brightness...", 14152 "Gamma...", 14153 "Spiff", 14154 "Dull", 14155 "Contrast Stretch...", 14156 "Sigmoidal Contrast...", 14157 "Normalize", 14158 "Equalize", 14159 "Negate", 14160 "Grayscale", 14161 "Map...", 14162 "Quantize...", 14163 (char *) NULL 14164 }, 14165 *EffectsMenu[] = 14166 { 14167 "Despeckle", 14168 "Emboss", 14169 "Reduce Noise", 14170 "Add Noise...", 14171 "Sharpen...", 14172 "Blur...", 14173 "Threshold...", 14174 "Edge Detect...", 14175 "Spread...", 14176 "Shade...", 14177 "Raise...", 14178 "Segment...", 14179 (char *) NULL 14180 }, 14181 *FXMenu[] = 14182 { 14183 "Solarize...", 14184 "Sepia Tone...", 14185 "Swirl...", 14186 "Implode...", 14187 "Vignette...", 14188 "Wave...", 14189 "Oil Paint...", 14190 "Charcoal Draw...", 14191 (char *) NULL 14192 }, 14193 *ImageEditMenu[] = 14194 { 14195 "Annotate...", 14196 "Draw...", 14197 "Color...", 14198 "Matte...", 14199 "Composite...", 14200 "Add Border...", 14201 "Add Frame...", 14202 "Comment...", 14203 "Launch...", 14204 "Region of Interest...", 14205 (char *) NULL 14206 }, 14207 *MiscellanyMenu[] = 14208 { 14209 "Image Info", 14210 "Zoom Image", 14211 "Show Preview...", 14212 "Show Histogram", 14213 "Show Matte", 14214 "Background...", 14215 "Slide Show...", 14216 "Preferences...", 14217 (char *) NULL 14218 }, 14219 *HelpMenu[] = 14220 { 14221 "Overview", 14222 "Browse Documentation", 14223 "About Display", 14224 (char *) NULL 14225 }, 14226 *ShortCutsMenu[] = 14227 { 14228 "Next", 14229 "Former", 14230 "Open...", 14231 "Save...", 14232 "Print...", 14233 "Undo", 14234 "Restore", 14235 "Image Info", 14236 "Quit", 14237 (char *) NULL 14238 }, 14239 *VirtualMenu[] = 14240 { 14241 "Image Info", 14242 "Print", 14243 "Next", 14244 "Quit", 14245 (char *) NULL 14246 }; 14247 14248 static const char 14249 **Menus[MagickMenus] = 14250 { 14251 FileMenu, 14252 EditMenu, 14253 ViewMenu, 14254 TransformMenu, 14255 EnhanceMenu, 14256 EffectsMenu, 14257 FXMenu, 14258 ImageEditMenu, 14259 MiscellanyMenu, 14260 HelpMenu 14261 }; 14262 14263 static CommandType 14264 CommandMenus[] = 14265 { 14266 NullCommand, 14267 NullCommand, 14268 NullCommand, 14269 NullCommand, 14270 NullCommand, 14271 NullCommand, 14272 NullCommand, 14273 NullCommand, 14274 NullCommand, 14275 NullCommand, 14276 }, 14277 FileCommands[] = 14278 { 14279 OpenCommand, 14280 NextCommand, 14281 FormerCommand, 14282 SelectCommand, 14283 SaveCommand, 14284 PrintCommand, 14285 DeleteCommand, 14286 NewCommand, 14287 VisualDirectoryCommand, 14288 QuitCommand 14289 }, 14290 EditCommands[] = 14291 { 14292 UndoCommand, 14293 RedoCommand, 14294 CutCommand, 14295 CopyCommand, 14296 PasteCommand 14297 }, 14298 ViewCommands[] = 14299 { 14300 HalfSizeCommand, 14301 OriginalSizeCommand, 14302 DoubleSizeCommand, 14303 ResizeCommand, 14304 ApplyCommand, 14305 RefreshCommand, 14306 RestoreCommand 14307 }, 14308 TransformCommands[] = 14309 { 14310 CropCommand, 14311 ChopCommand, 14312 FlopCommand, 14313 FlipCommand, 14314 RotateRightCommand, 14315 RotateLeftCommand, 14316 RotateCommand, 14317 ShearCommand, 14318 RollCommand, 14319 TrimCommand 14320 }, 14321 EnhanceCommands[] = 14322 { 14323 HueCommand, 14324 SaturationCommand, 14325 BrightnessCommand, 14326 GammaCommand, 14327 SpiffCommand, 14328 DullCommand, 14329 ContrastStretchCommand, 14330 SigmoidalContrastCommand, 14331 NormalizeCommand, 14332 EqualizeCommand, 14333 NegateCommand, 14334 GrayscaleCommand, 14335 MapCommand, 14336 QuantizeCommand 14337 }, 14338 EffectsCommands[] = 14339 { 14340 DespeckleCommand, 14341 EmbossCommand, 14342 ReduceNoiseCommand, 14343 AddNoiseCommand, 14344 SharpenCommand, 14345 BlurCommand, 14346 ThresholdCommand, 14347 EdgeDetectCommand, 14348 SpreadCommand, 14349 ShadeCommand, 14350 RaiseCommand, 14351 SegmentCommand 14352 }, 14353 FXCommands[] = 14354 { 14355 SolarizeCommand, 14356 SepiaToneCommand, 14357 SwirlCommand, 14358 ImplodeCommand, 14359 VignetteCommand, 14360 WaveCommand, 14361 OilPaintCommand, 14362 CharcoalDrawCommand 14363 }, 14364 ImageEditCommands[] = 14365 { 14366 AnnotateCommand, 14367 DrawCommand, 14368 ColorCommand, 14369 MatteCommand, 14370 CompositeCommand, 14371 AddBorderCommand, 14372 AddFrameCommand, 14373 CommentCommand, 14374 LaunchCommand, 14375 RegionofInterestCommand 14376 }, 14377 MiscellanyCommands[] = 14378 { 14379 InfoCommand, 14380 ZoomCommand, 14381 ShowPreviewCommand, 14382 ShowHistogramCommand, 14383 ShowMatteCommand, 14384 BackgroundCommand, 14385 SlideShowCommand, 14386 PreferencesCommand 14387 }, 14388 HelpCommands[] = 14389 { 14390 HelpCommand, 14391 BrowseDocumentationCommand, 14392 VersionCommand 14393 }, 14394 ShortCutsCommands[] = 14395 { 14396 NextCommand, 14397 FormerCommand, 14398 OpenCommand, 14399 SaveCommand, 14400 PrintCommand, 14401 UndoCommand, 14402 RestoreCommand, 14403 InfoCommand, 14404 QuitCommand 14405 }, 14406 VirtualCommands[] = 14407 { 14408 InfoCommand, 14409 PrintCommand, 14410 NextCommand, 14411 QuitCommand 14412 }; 14413 14414 static CommandType 14415 *Commands[MagickMenus] = 14416 { 14417 FileCommands, 14418 EditCommands, 14419 ViewCommands, 14420 TransformCommands, 14421 EnhanceCommands, 14422 EffectsCommands, 14423 FXCommands, 14424 ImageEditCommands, 14425 MiscellanyCommands, 14426 HelpCommands 14427 }; 14428 14429 char 14430 command[MagickPathExtent], 14431 *directory, 14432 geometry[MagickPathExtent], 14433 resource_name[MagickPathExtent]; 14434 14435 CommandType 14436 command_type; 14437 14438 Image 14439 *display_image, 14440 *nexus; 14441 14442 int 14443 entry, 14444 id; 14445 14446 KeySym 14447 key_symbol; 14448 14449 MagickStatusType 14450 context_mask, 14451 status; 14452 14453 RectangleInfo 14454 geometry_info; 14455 14456 register int 14457 i; 14458 14459 static char 14460 working_directory[MagickPathExtent]; 14461 14462 static XPoint 14463 vid_info; 14464 14465 static XWindowInfo 14466 *magick_windows[MaxXWindows]; 14467 14468 static unsigned int 14469 number_windows; 14470 14471 struct stat 14472 attributes; 14473 14474 time_t 14475 timer, 14476 timestamp, 14477 update_time; 14478 14479 unsigned int 14480 height, 14481 width; 14482 14483 size_t 14484 delay; 14485 14486 WarningHandler 14487 warning_handler; 14488 14489 Window 14490 root_window; 14491 14492 XClassHint 14493 *class_hints; 14494 14495 XEvent 14496 event; 14497 14498 XFontStruct 14499 *font_info; 14500 14501 XGCValues 14502 context_values; 14503 14504 XPixelInfo 14505 *icon_pixel, 14506 *pixel; 14507 14508 XResourceInfo 14509 *icon_resources; 14510 14511 XStandardColormap 14512 *icon_map, 14513 *map_info; 14514 14515 XVisualInfo 14516 *icon_visual, 14517 *visual_info; 14518 14519 XWindowChanges 14520 window_changes; 14521 14522 XWindows 14523 *windows; 14524 14525 XWMHints 14526 *manager_hints; 14527 14528 assert(image != (Image **) NULL); 14529 assert((*image)->signature == MagickCoreSignature); 14530 if ((*image)->debug != MagickFalse ) 14531 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 14532 display_image=(*image); 14533 warning_handler=(WarningHandler) NULL; 14534 windows=XSetWindows((XWindows *) ~0); 14535 if (windows != (XWindows *) NULL) 14536 { 14537 int 14538 status; 14539 14540 if (*working_directory == '\0') 14541 (void) CopyMagickString(working_directory,".",MagickPathExtent); 14542 status=chdir(working_directory); 14543 if (status == -1) 14544 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 14545 "UnableToOpenFile","%s",working_directory); 14546 warning_handler=resource_info->display_warnings ? 14547 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14548 warning_handler=resource_info->display_warnings ? 14549 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14550 } 14551 else 14552 { 14553 /* 14554 Allocate windows structure. 14555 */ 14556 resource_info->colors=display_image->colors; 14557 windows=XSetWindows(XInitializeWindows(display,resource_info)); 14558 if (windows == (XWindows *) NULL) 14559 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow", 14560 (*image)->filename); 14561 /* 14562 Initialize window id's. 14563 */ 14564 number_windows=0; 14565 magick_windows[number_windows++]=(&windows->icon); 14566 magick_windows[number_windows++]=(&windows->backdrop); 14567 magick_windows[number_windows++]=(&windows->image); 14568 magick_windows[number_windows++]=(&windows->info); 14569 magick_windows[number_windows++]=(&windows->command); 14570 magick_windows[number_windows++]=(&windows->widget); 14571 magick_windows[number_windows++]=(&windows->popup); 14572 magick_windows[number_windows++]=(&windows->magnify); 14573 magick_windows[number_windows++]=(&windows->pan); 14574 for (i=0; i < (int) number_windows; i++) 14575 magick_windows[i]->id=(Window) NULL; 14576 vid_info.x=0; 14577 vid_info.y=0; 14578 } 14579 /* 14580 Initialize font info. 14581 */ 14582 if (windows->font_info != (XFontStruct *) NULL) 14583 (void) XFreeFont(display,windows->font_info); 14584 windows->font_info=XBestFont(display,resource_info,MagickFalse); 14585 if (windows->font_info == (XFontStruct *) NULL) 14586 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", 14587 resource_info->font); 14588 /* 14589 Initialize Standard Colormap. 14590 */ 14591 map_info=windows->map_info; 14592 icon_map=windows->icon_map; 14593 visual_info=windows->visual_info; 14594 icon_visual=windows->icon_visual; 14595 pixel=windows->pixel_info; 14596 icon_pixel=windows->icon_pixel; 14597 font_info=windows->font_info; 14598 icon_resources=windows->icon_resources; 14599 class_hints=windows->class_hints; 14600 manager_hints=windows->manager_hints; 14601 root_window=XRootWindow(display,visual_info->screen); 14602 nexus=NewImageList(); 14603 if (display_image->debug != MagickFalse ) 14604 { 14605 (void) LogMagickEvent(X11Event,GetMagickModule(), 14606 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename, 14607 (double) display_image->scene,(double) display_image->columns, 14608 (double) display_image->rows); 14609 if (display_image->colors != 0) 14610 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 14611 display_image->colors); 14612 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", 14613 display_image->magick); 14614 } 14615 XMakeStandardColormap(display,visual_info,resource_info,display_image, 14616 map_info,pixel,exception); 14617 display_image->taint=MagickFalse; 14618 /* 14619 Initialize graphic context. 14620 */ 14621 windows->context.id=(Window) NULL; 14622 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14623 resource_info,&windows->context); 14624 (void) CloneString(&class_hints->res_name,resource_info->client_name); 14625 (void) CloneString(&class_hints->res_class,resource_info->client_name); 14626 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]); 14627 manager_hints->flags=InputHint | StateHint; 14628 manager_hints->input=MagickFalse; 14629 manager_hints->initial_state=WithdrawnState; 14630 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14631 &windows->context); 14632 if (display_image->debug != MagickFalse ) 14633 (void) LogMagickEvent(X11Event,GetMagickModule(), 14634 "Window id: 0x%lx (context)",windows->context.id); 14635 context_values.background=pixel->background_color.pixel; 14636 context_values.font=font_info->fid; 14637 context_values.foreground=pixel->foreground_color.pixel; 14638 context_values.graphics_exposures=MagickFalse; 14639 context_mask=(MagickStatusType) 14640 (GCBackground | GCFont | GCForeground | GCGraphicsExposures); 14641 if (pixel->annotate_context != (GC) NULL) 14642 (void) XFreeGC(display,pixel->annotate_context); 14643 pixel->annotate_context=XCreateGC(display,windows->context.id, 14644 context_mask,&context_values); 14645 if (pixel->annotate_context == (GC) NULL) 14646 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14647 display_image->filename); 14648 context_values.background=pixel->depth_color.pixel; 14649 if (pixel->widget_context != (GC) NULL) 14650 (void) XFreeGC(display,pixel->widget_context); 14651 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask, 14652 &context_values); 14653 if (pixel->widget_context == (GC) NULL) 14654 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14655 display_image->filename); 14656 context_values.background=pixel->foreground_color.pixel; 14657 context_values.foreground=pixel->background_color.pixel; 14658 context_values.plane_mask=context_values.background ^ 14659 context_values.foreground; 14660 if (pixel->highlight_context != (GC) NULL) 14661 (void) XFreeGC(display,pixel->highlight_context); 14662 pixel->highlight_context=XCreateGC(display,windows->context.id, 14663 (size_t) (context_mask | GCPlaneMask),&context_values); 14664 if (pixel->highlight_context == (GC) NULL) 14665 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14666 display_image->filename); 14667 (void) XDestroyWindow(display,windows->context.id); 14668 /* 14669 Initialize icon window. 14670 */ 14671 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, 14672 icon_resources,&windows->icon); 14673 windows->icon.geometry=resource_info->icon_geometry; 14674 XBestIconSize(display,&windows->icon,display_image); 14675 windows->icon.attributes.colormap=XDefaultColormap(display, 14676 icon_visual->screen); 14677 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; 14678 manager_hints->flags=InputHint | StateHint; 14679 manager_hints->input=MagickFalse; 14680 manager_hints->initial_state=IconicState; 14681 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14682 &windows->icon); 14683 if (display_image->debug != MagickFalse ) 14684 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", 14685 windows->icon.id); 14686 /* 14687 Initialize graphic context for icon window. 14688 */ 14689 if (icon_pixel->annotate_context != (GC) NULL) 14690 (void) XFreeGC(display,icon_pixel->annotate_context); 14691 context_values.background=icon_pixel->background_color.pixel; 14692 context_values.foreground=icon_pixel->foreground_color.pixel; 14693 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, 14694 (size_t) (GCBackground | GCForeground),&context_values); 14695 if (icon_pixel->annotate_context == (GC) NULL) 14696 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14697 display_image->filename); 14698 windows->icon.annotate_context=icon_pixel->annotate_context; 14699 /* 14700 Initialize Image window. 14701 */ 14702 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14703 &windows->image); 14704 windows->image.shape=MagickTrue; /* non-rectangular shape hint */ 14705 if (resource_info->use_shared_memory == MagickFalse) 14706 windows->image.shared_memory=MagickFalse; 14707 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState)) 14708 { 14709 char 14710 *title; 14711 14712 title=InterpretImageProperties(resource_info->image_info,display_image, 14713 resource_info->title,exception); 14714 (void) CopyMagickString(windows->image.name,title,MagickPathExtent); 14715 (void) CopyMagickString(windows->image.icon_name,title,MagickPathExtent); 14716 title=DestroyString(title); 14717 } 14718 else 14719 { 14720 char 14721 filename[MagickPathExtent]; 14722 14723 /* 14724 Window name is the base of the filename. 14725 */ 14726 GetPathComponent(display_image->magick_filename,TailPath,filename); 14727 if (display_image->scene == 0) 14728 (void) FormatLocaleString(windows->image.name,MagickPathExtent, 14729 "%s: %s",MagickPackageName,filename); 14730 else 14731 (void) FormatLocaleString(windows->image.name,MagickPathExtent, 14732 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename, 14733 (double) display_image->scene,(double) GetImageListLength( 14734 display_image)); 14735 (void) CopyMagickString(windows->image.icon_name,filename,MagickPathExtent); 14736 } 14737 if (resource_info->immutable) 14738 windows->image.immutable=MagickTrue; 14739 windows->image.use_pixmap=resource_info->use_pixmap; 14740 windows->image.geometry=resource_info->image_geometry; 14741 (void) FormatLocaleString(geometry,MagickPathExtent,"%ux%u+0+0>!", 14742 XDisplayWidth(display,visual_info->screen), 14743 XDisplayHeight(display,visual_info->screen)); 14744 geometry_info.width=display_image->columns; 14745 geometry_info.height=display_image->rows; 14746 geometry_info.x=0; 14747 geometry_info.y=0; 14748 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 14749 &geometry_info.width,&geometry_info.height); 14750 windows->image.width=(unsigned int) geometry_info.width; 14751 windows->image.height=(unsigned int) geometry_info.height; 14752 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14753 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14754 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14755 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; 14756 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14757 resource_info,&windows->backdrop); 14758 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) 14759 { 14760 /* 14761 Initialize backdrop window. 14762 */ 14763 windows->backdrop.x=0; 14764 windows->backdrop.y=0; 14765 (void) CloneString(&windows->backdrop.name,"Backdrop"); 14766 windows->backdrop.flags=(size_t) (USSize | USPosition); 14767 windows->backdrop.width=(unsigned int) 14768 XDisplayWidth(display,visual_info->screen); 14769 windows->backdrop.height=(unsigned int) 14770 XDisplayHeight(display,visual_info->screen); 14771 windows->backdrop.border_width=0; 14772 windows->backdrop.immutable=MagickTrue; 14773 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | 14774 ButtonReleaseMask; 14775 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | 14776 StructureNotifyMask; 14777 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14778 manager_hints->icon_window=windows->icon.id; 14779 manager_hints->input=MagickTrue; 14780 manager_hints->initial_state=resource_info->iconic ? IconicState : 14781 NormalState; 14782 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14783 &windows->backdrop); 14784 if (display_image->debug != MagickFalse ) 14785 (void) LogMagickEvent(X11Event,GetMagickModule(), 14786 "Window id: 0x%lx (backdrop)",windows->backdrop.id); 14787 (void) XMapWindow(display,windows->backdrop.id); 14788 (void) XClearWindow(display,windows->backdrop.id); 14789 if (windows->image.id != (Window) NULL) 14790 { 14791 (void) XDestroyWindow(display,windows->image.id); 14792 windows->image.id=(Window) NULL; 14793 } 14794 /* 14795 Position image in the center the backdrop. 14796 */ 14797 windows->image.flags|=USPosition; 14798 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- 14799 (windows->image.width/2); 14800 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- 14801 (windows->image.height/2); 14802 } 14803 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14804 manager_hints->icon_window=windows->icon.id; 14805 manager_hints->input=MagickTrue; 14806 manager_hints->initial_state=resource_info->iconic ? IconicState : 14807 NormalState; 14808 if (windows->group_leader.id != (Window) NULL) 14809 { 14810 /* 14811 Follow the leader. 14812 */ 14813 manager_hints->flags|=WindowGroupHint; 14814 manager_hints->window_group=windows->group_leader.id; 14815 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); 14816 if (display_image->debug != MagickFalse ) 14817 (void) LogMagickEvent(X11Event,GetMagickModule(), 14818 "Window id: 0x%lx (group leader)",windows->group_leader.id); 14819 } 14820 XMakeWindow(display, 14821 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), 14822 argv,argc,class_hints,manager_hints,&windows->image); 14823 (void) XChangeProperty(display,windows->image.id,windows->im_protocols, 14824 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); 14825 if (windows->group_leader.id != (Window) NULL) 14826 (void) XSetTransientForHint(display,windows->image.id, 14827 windows->group_leader.id); 14828 if (display_image->debug != MagickFalse ) 14829 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", 14830 windows->image.id); 14831 /* 14832 Initialize Info widget. 14833 */ 14834 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14835 &windows->info); 14836 (void) CloneString(&windows->info.name,"Info"); 14837 (void) CloneString(&windows->info.icon_name,"Info"); 14838 windows->info.border_width=1; 14839 windows->info.x=2; 14840 windows->info.y=2; 14841 windows->info.flags|=PPosition; 14842 windows->info.attributes.win_gravity=UnmapGravity; 14843 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | 14844 StructureNotifyMask; 14845 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14846 manager_hints->input=MagickFalse; 14847 manager_hints->initial_state=NormalState; 14848 manager_hints->window_group=windows->image.id; 14849 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, 14850 &windows->info); 14851 windows->info.highlight_stipple=XCreateBitmapFromData(display, 14852 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14853 windows->info.shadow_stipple=XCreateBitmapFromData(display, 14854 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14855 (void) XSetTransientForHint(display,windows->info.id,windows->image.id); 14856 if (windows->image.mapped != MagickFalse ) 14857 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14858 if (display_image->debug != MagickFalse ) 14859 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", 14860 windows->info.id); 14861 /* 14862 Initialize Command widget. 14863 */ 14864 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14865 resource_info,&windows->command); 14866 windows->command.data=MagickMenus; 14867 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); 14868 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.command", 14869 resource_info->client_name); 14870 windows->command.geometry=XGetResourceClass(resource_info->resource_database, 14871 resource_name,"geometry",(char *) NULL); 14872 (void) CloneString(&windows->command.name,MagickTitle); 14873 windows->command.border_width=0; 14874 windows->command.flags|=PPosition; 14875 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14876 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | 14877 OwnerGrabButtonMask | StructureNotifyMask; 14878 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14879 manager_hints->input=MagickTrue; 14880 manager_hints->initial_state=NormalState; 14881 manager_hints->window_group=windows->image.id; 14882 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14883 &windows->command); 14884 windows->command.highlight_stipple=XCreateBitmapFromData(display, 14885 windows->command.id,(char *) HighlightBitmap,HighlightWidth, 14886 HighlightHeight); 14887 windows->command.shadow_stipple=XCreateBitmapFromData(display, 14888 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14889 (void) XSetTransientForHint(display,windows->command.id,windows->image.id); 14890 if (windows->command.mapped != MagickFalse ) 14891 (void) XMapRaised(display,windows->command.id); 14892 if (display_image->debug != MagickFalse ) 14893 (void) LogMagickEvent(X11Event,GetMagickModule(), 14894 "Window id: 0x%lx (command)",windows->command.id); 14895 /* 14896 Initialize Widget window. 14897 */ 14898 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14899 resource_info,&windows->widget); 14900 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.widget", 14901 resource_info->client_name); 14902 windows->widget.geometry=XGetResourceClass(resource_info->resource_database, 14903 resource_name,"geometry",(char *) NULL); 14904 windows->widget.border_width=0; 14905 windows->widget.flags|=PPosition; 14906 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14907 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14908 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14909 StructureNotifyMask; 14910 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14911 manager_hints->input=MagickTrue; 14912 manager_hints->initial_state=NormalState; 14913 manager_hints->window_group=windows->image.id; 14914 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14915 &windows->widget); 14916 windows->widget.highlight_stipple=XCreateBitmapFromData(display, 14917 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14918 windows->widget.shadow_stipple=XCreateBitmapFromData(display, 14919 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14920 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); 14921 if (display_image->debug != MagickFalse ) 14922 (void) LogMagickEvent(X11Event,GetMagickModule(), 14923 "Window id: 0x%lx (widget)",windows->widget.id); 14924 /* 14925 Initialize popup window. 14926 */ 14927 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14928 resource_info,&windows->popup); 14929 windows->popup.border_width=0; 14930 windows->popup.flags|=PPosition; 14931 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14932 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14933 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask; 14934 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14935 manager_hints->input=MagickTrue; 14936 manager_hints->initial_state=NormalState; 14937 manager_hints->window_group=windows->image.id; 14938 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14939 &windows->popup); 14940 windows->popup.highlight_stipple=XCreateBitmapFromData(display, 14941 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14942 windows->popup.shadow_stipple=XCreateBitmapFromData(display, 14943 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14944 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); 14945 if (display_image->debug != MagickFalse ) 14946 (void) LogMagickEvent(X11Event,GetMagickModule(), 14947 "Window id: 0x%lx (pop up)",windows->popup.id); 14948 /* 14949 Initialize Magnify window and cursor. 14950 */ 14951 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14952 resource_info,&windows->magnify); 14953 if (resource_info->use_shared_memory == MagickFalse) 14954 windows->magnify.shared_memory=MagickFalse; 14955 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.magnify", 14956 resource_info->client_name); 14957 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database, 14958 resource_name,"geometry",(char *) NULL); 14959 (void) FormatLocaleString(windows->magnify.name,MagickPathExtent,"Magnify %uX", 14960 resource_info->magnify); 14961 if (windows->magnify.cursor != (Cursor) NULL) 14962 (void) XFreeCursor(display,windows->magnify.cursor); 14963 windows->magnify.cursor=XMakeCursor(display,windows->image.id, 14964 map_info->colormap,resource_info->background_color, 14965 resource_info->foreground_color); 14966 if (windows->magnify.cursor == (Cursor) NULL) 14967 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor", 14968 display_image->filename); 14969 windows->magnify.width=MagnifySize; 14970 windows->magnify.height=MagnifySize; 14971 windows->magnify.flags|=PPosition; 14972 windows->magnify.min_width=MagnifySize; 14973 windows->magnify.min_height=MagnifySize; 14974 windows->magnify.width_inc=MagnifySize; 14975 windows->magnify.height_inc=MagnifySize; 14976 windows->magnify.data=resource_info->magnify; 14977 windows->magnify.attributes.cursor=windows->magnify.cursor; 14978 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask | 14979 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask | 14980 StructureNotifyMask; 14981 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14982 manager_hints->input=MagickTrue; 14983 manager_hints->initial_state=NormalState; 14984 manager_hints->window_group=windows->image.id; 14985 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14986 &windows->magnify); 14987 if (display_image->debug != MagickFalse ) 14988 (void) LogMagickEvent(X11Event,GetMagickModule(), 14989 "Window id: 0x%lx (magnify)",windows->magnify.id); 14990 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id); 14991 /* 14992 Initialize panning window. 14993 */ 14994 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14995 resource_info,&windows->pan); 14996 (void) CloneString(&windows->pan.name,"Pan Icon"); 14997 windows->pan.width=windows->icon.width; 14998 windows->pan.height=windows->icon.height; 14999 (void) FormatLocaleString(resource_name,MagickPathExtent,"%s.pan", 15000 resource_info->client_name); 15001 windows->pan.geometry=XGetResourceClass(resource_info->resource_database, 15002 resource_name,"geometry",(char *) NULL); 15003 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 15004 &windows->pan.width,&windows->pan.height); 15005 windows->pan.flags|=PPosition; 15006 windows->pan.immutable=MagickTrue; 15007 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 15008 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask | 15009 StructureNotifyMask; 15010 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 15011 manager_hints->input=MagickFalse; 15012 manager_hints->initial_state=NormalState; 15013 manager_hints->window_group=windows->image.id; 15014 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 15015 &windows->pan); 15016 if (display_image->debug != MagickFalse ) 15017 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)", 15018 windows->pan.id); 15019 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id); 15020 if (windows->info.mapped != MagickFalse ) 15021 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15022 if ((windows->image.mapped == MagickFalse) || 15023 (windows->backdrop.id != (Window) NULL)) 15024 (void) XMapWindow(display,windows->image.id); 15025 /* 15026 Set our progress monitor and warning handlers. 15027 */ 15028 if (warning_handler == (WarningHandler) NULL) 15029 { 15030 warning_handler=resource_info->display_warnings ? 15031 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 15032 warning_handler=resource_info->display_warnings ? 15033 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 15034 } 15035 /* 15036 Initialize Image and Magnify X images. 15037 */ 15038 windows->image.x=0; 15039 windows->image.y=0; 15040 windows->magnify.shape=MagickFalse; 15041 width=(unsigned int) display_image->columns; 15042 height=(unsigned int) display_image->rows; 15043 if ((display_image->columns != width) || (display_image->rows != height)) 15044 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15045 display_image->filename); 15046 status=XMakeImage(display,resource_info,&windows->image,display_image, 15047 width,height,exception); 15048 if (status == MagickFalse) 15049 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15050 display_image->filename); 15051 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL, 15052 windows->magnify.width,windows->magnify.height,exception); 15053 if (status == MagickFalse) 15054 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15055 display_image->filename); 15056 if (windows->magnify.mapped != MagickFalse ) 15057 (void) XMapRaised(display,windows->magnify.id); 15058 if (windows->pan.mapped != MagickFalse ) 15059 (void) XMapRaised(display,windows->pan.id); 15060 windows->image.window_changes.width=(int) display_image->columns; 15061 windows->image.window_changes.height=(int) display_image->rows; 15062 (void) XConfigureImage(display,resource_info,windows,display_image,exception); 15063 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15064 (void) XSync(display,MagickFalse); 15065 /* 15066 Respond to events. 15067 */ 15068 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L); 15069 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15070 update_time=0; 15071 if (resource_info->update != MagickFalse ) 15072 { 15073 MagickBooleanType 15074 status; 15075 15076 /* 15077 Determine when file data was last modified. 15078 */ 15079 status=GetPathAttributes(display_image->filename,&attributes); 15080 if (status != MagickFalse ) 15081 update_time=attributes.st_mtime; 15082 } 15083 *state&=(~FormerImageState); 15084 *state&=(~MontageImageState); 15085 *state&=(~NextImageState); 15086 do 15087 { 15088 /* 15089 Handle a window event. 15090 */ 15091 if (windows->image.mapped != MagickFalse ) 15092 if ((display_image->delay != 0) || (resource_info->update != 0)) 15093 { 15094 if (timer < time((time_t *) NULL)) 15095 { 15096 if (resource_info->update == MagickFalse) 15097 *state|=NextImageState | ExitState; 15098 else 15099 { 15100 MagickBooleanType 15101 status; 15102 15103 /* 15104 Determine if image file was modified. 15105 */ 15106 status=GetPathAttributes(display_image->filename,&attributes); 15107 if (status != MagickFalse ) 15108 if (update_time != attributes.st_mtime) 15109 { 15110 /* 15111 Redisplay image. 15112 */ 15113 (void) FormatLocaleString( 15114 resource_info->image_info->filename,MagickPathExtent, 15115 "%s:%s",display_image->magick, 15116 display_image->filename); 15117 nexus=ReadImage(resource_info->image_info,exception); 15118 if (nexus != (Image *) NULL) 15119 *state|=NextImageState | ExitState; 15120 } 15121 delay=display_image->delay/MagickMax( 15122 display_image->ticks_per_second,1L); 15123 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15124 } 15125 } 15126 if (XEventsQueued(display,QueuedAfterFlush) == 0) 15127 { 15128 /* 15129 Do not block if delay > 0. 15130 */ 15131 XDelay(display,SuspendTime << 2); 15132 continue; 15133 } 15134 } 15135 timestamp=time((time_t *) NULL); 15136 (void) XNextEvent(display,&event); 15137 if ((windows->image.stasis == MagickFalse) || 15138 (windows->magnify.stasis == MagickFalse)) 15139 { 15140 if ((time((time_t *) NULL)-timestamp) > 0) 15141 { 15142 windows->image.stasis=MagickTrue; 15143 windows->magnify.stasis=MagickTrue; 15144 } 15145 } 15146 if (event.xany.window == windows->command.id) 15147 { 15148 /* 15149 Select a command from the Command widget. 15150 */ 15151 id=XCommandWidget(display,windows,CommandMenu,&event); 15152 if (id < 0) 15153 continue; 15154 (void) CopyMagickString(command,CommandMenu[id],MagickPathExtent); 15155 command_type=CommandMenus[id]; 15156 if (id < MagickMenus) 15157 { 15158 /* 15159 Select a command from a pop-up menu. 15160 */ 15161 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15162 command); 15163 if (entry < 0) 15164 continue; 15165 (void) CopyMagickString(command,Menus[id][entry],MagickPathExtent); 15166 command_type=Commands[id][entry]; 15167 } 15168 if (command_type != NullCommand) 15169 nexus=XMagickCommand(display,resource_info,windows,command_type, 15170 &display_image,exception); 15171 continue; 15172 } 15173 switch (event.type) 15174 { 15175 case ButtonPress: 15176 { 15177 if (display_image->debug != MagickFalse ) 15178 (void) LogMagickEvent(X11Event,GetMagickModule(), 15179 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15180 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15181 if ((event.xbutton.button == Button3) && 15182 (event.xbutton.state & Mod1Mask)) 15183 { 15184 /* 15185 Convert Alt-Button3 to Button2. 15186 */ 15187 event.xbutton.button=Button2; 15188 event.xbutton.state&=(~Mod1Mask); 15189 } 15190 if (event.xbutton.window == windows->backdrop.id) 15191 { 15192 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15193 event.xbutton.time); 15194 break; 15195 } 15196 if (event.xbutton.window == windows->image.id) 15197 { 15198 switch (event.xbutton.button) 15199 { 15200 case Button1: 15201 { 15202 if (resource_info->immutable) 15203 { 15204 /* 15205 Select a command from the Virtual menu. 15206 */ 15207 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15208 command); 15209 if (entry >= 0) 15210 nexus=XMagickCommand(display,resource_info,windows, 15211 VirtualCommands[entry],&display_image,exception); 15212 break; 15213 } 15214 /* 15215 Map/unmap Command widget. 15216 */ 15217 if (windows->command.mapped != MagickFalse ) 15218 (void) XWithdrawWindow(display,windows->command.id, 15219 windows->command.screen); 15220 else 15221 { 15222 (void) XCommandWidget(display,windows,CommandMenu, 15223 (XEvent *) NULL); 15224 (void) XMapRaised(display,windows->command.id); 15225 } 15226 break; 15227 } 15228 case Button2: 15229 { 15230 /* 15231 User pressed the image magnify button. 15232 */ 15233 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15234 &display_image,exception); 15235 XMagnifyImage(display,windows,&event,exception); 15236 break; 15237 } 15238 case Button3: 15239 { 15240 if (resource_info->immutable) 15241 { 15242 /* 15243 Select a command from the Virtual menu. 15244 */ 15245 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15246 command); 15247 if (entry >= 0) 15248 nexus=XMagickCommand(display,resource_info,windows, 15249 VirtualCommands[entry],&display_image,exception); 15250 break; 15251 } 15252 if (display_image->montage != (char *) NULL) 15253 { 15254 /* 15255 Open or delete a tile from a visual image directory. 15256 */ 15257 nexus=XTileImage(display,resource_info,windows, 15258 display_image,&event,exception); 15259 if (nexus != (Image *) NULL) 15260 *state|=MontageImageState | NextImageState | ExitState; 15261 vid_info.x=(short int) windows->image.x; 15262 vid_info.y=(short int) windows->image.y; 15263 break; 15264 } 15265 /* 15266 Select a command from the Short Cuts menu. 15267 */ 15268 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15269 command); 15270 if (entry >= 0) 15271 nexus=XMagickCommand(display,resource_info,windows, 15272 ShortCutsCommands[entry],&display_image,exception); 15273 break; 15274 } 15275 case Button4: 15276 { 15277 /* 15278 Wheel up. 15279 */ 15280 XTranslateImage(display,windows,*image,XK_Up); 15281 break; 15282 } 15283 case Button5: 15284 { 15285 /* 15286 Wheel down. 15287 */ 15288 XTranslateImage(display,windows,*image,XK_Down); 15289 break; 15290 } 15291 default: 15292 break; 15293 } 15294 break; 15295 } 15296 if (event.xbutton.window == windows->magnify.id) 15297 { 15298 int 15299 factor; 15300 15301 static const char 15302 *MagnifyMenu[] = 15303 { 15304 "2", 15305 "4", 15306 "5", 15307 "6", 15308 "7", 15309 "8", 15310 "9", 15311 "3", 15312 (char *) NULL, 15313 }; 15314 15315 static KeySym 15316 MagnifyCommands[] = 15317 { 15318 XK_2, 15319 XK_4, 15320 XK_5, 15321 XK_6, 15322 XK_7, 15323 XK_8, 15324 XK_9, 15325 XK_3 15326 }; 15327 15328 /* 15329 Select a magnify factor from the pop-up menu. 15330 */ 15331 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15332 if (factor >= 0) 15333 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor], 15334 exception); 15335 break; 15336 } 15337 if (event.xbutton.window == windows->pan.id) 15338 { 15339 switch (event.xbutton.button) 15340 { 15341 case Button4: 15342 { 15343 /* 15344 Wheel up. 15345 */ 15346 XTranslateImage(display,windows,*image,XK_Up); 15347 break; 15348 } 15349 case Button5: 15350 { 15351 /* 15352 Wheel down. 15353 */ 15354 XTranslateImage(display,windows,*image,XK_Down); 15355 break; 15356 } 15357 default: 15358 { 15359 XPanImage(display,windows,&event,exception); 15360 break; 15361 } 15362 } 15363 break; 15364 } 15365 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15366 1L); 15367 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15368 break; 15369 } 15370 case ButtonRelease: 15371 { 15372 if (display_image->debug != MagickFalse ) 15373 (void) LogMagickEvent(X11Event,GetMagickModule(), 15374 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15375 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15376 break; 15377 } 15378 case ClientMessage: 15379 { 15380 if (display_image->debug != MagickFalse ) 15381 (void) LogMagickEvent(X11Event,GetMagickModule(), 15382 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15383 event.xclient.message_type,event.xclient.format,(unsigned long) 15384 event.xclient.data.l[0]); 15385 if (event.xclient.message_type == windows->im_protocols) 15386 { 15387 if (*event.xclient.data.l == (long) windows->im_update_widget) 15388 { 15389 (void) CloneString(&windows->command.name,MagickTitle); 15390 windows->command.data=MagickMenus; 15391 (void) XCommandWidget(display,windows,CommandMenu, 15392 (XEvent *) NULL); 15393 break; 15394 } 15395 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15396 { 15397 /* 15398 Update graphic context and window colormap. 15399 */ 15400 for (i=0; i < (int) number_windows; i++) 15401 { 15402 if (magick_windows[i]->id == windows->icon.id) 15403 continue; 15404 context_values.background=pixel->background_color.pixel; 15405 context_values.foreground=pixel->foreground_color.pixel; 15406 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15407 context_mask,&context_values); 15408 (void) XChangeGC(display,magick_windows[i]->widget_context, 15409 context_mask,&context_values); 15410 context_values.background=pixel->foreground_color.pixel; 15411 context_values.foreground=pixel->background_color.pixel; 15412 context_values.plane_mask=context_values.background ^ 15413 context_values.foreground; 15414 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15415 (size_t) (context_mask | GCPlaneMask), 15416 &context_values); 15417 magick_windows[i]->attributes.background_pixel= 15418 pixel->background_color.pixel; 15419 magick_windows[i]->attributes.border_pixel= 15420 pixel->border_color.pixel; 15421 magick_windows[i]->attributes.colormap=map_info->colormap; 15422 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15423 (unsigned long) magick_windows[i]->mask, 15424 &magick_windows[i]->attributes); 15425 } 15426 if (windows->pan.mapped != MagickFalse ) 15427 { 15428 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15429 windows->pan.pixmap); 15430 (void) XClearWindow(display,windows->pan.id); 15431 XDrawPanRectangle(display,windows); 15432 } 15433 if (windows->backdrop.id != (Window) NULL) 15434 (void) XInstallColormap(display,map_info->colormap); 15435 break; 15436 } 15437 if (*event.xclient.data.l == (long) windows->im_former_image) 15438 { 15439 *state|=FormerImageState | ExitState; 15440 break; 15441 } 15442 if (*event.xclient.data.l == (long) windows->im_next_image) 15443 { 15444 *state|=NextImageState | ExitState; 15445 break; 15446 } 15447 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15448 { 15449 *state|=RetainColorsState; 15450 break; 15451 } 15452 if (*event.xclient.data.l == (long) windows->im_exit) 15453 { 15454 *state|=ExitState; 15455 break; 15456 } 15457 break; 15458 } 15459 if (event.xclient.message_type == windows->dnd_protocols) 15460 { 15461 Atom 15462 selection, 15463 type; 15464 15465 int 15466 format, 15467 status; 15468 15469 unsigned char 15470 *data; 15471 15472 unsigned long 15473 after, 15474 length; 15475 15476 /* 15477 Display image named by the Drag-and-Drop selection. 15478 */ 15479 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15480 break; 15481 selection=XInternAtom(display,"DndSelection",MagickFalse); 15482 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15483 MagickPathExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15484 &length,&after,&data); 15485 if ((status != Success) || (length == 0)) 15486 break; 15487 if (*event.xclient.data.l == 2) 15488 { 15489 /* 15490 Offix DND. 15491 */ 15492 (void) CopyMagickString(resource_info->image_info->filename, 15493 (char *) data,MagickPathExtent); 15494 } 15495 else 15496 { 15497 /* 15498 XDND. 15499 */ 15500 if (strncmp((char *) data, "file:", 5) != 0) 15501 { 15502 (void) XFree((void *) data); 15503 break; 15504 } 15505 (void) CopyMagickString(resource_info->image_info->filename, 15506 ((char *) data)+5,MagickPathExtent); 15507 } 15508 nexus=ReadImage(resource_info->image_info,exception); 15509 CatchException(exception); 15510 if (nexus != (Image *) NULL) 15511 *state|=NextImageState | ExitState; 15512 (void) XFree((void *) data); 15513 break; 15514 } 15515 /* 15516 If client window delete message, exit. 15517 */ 15518 if (event.xclient.message_type != windows->wm_protocols) 15519 break; 15520 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15521 break; 15522 (void) XWithdrawWindow(display,event.xclient.window, 15523 visual_info->screen); 15524 if (event.xclient.window == windows->image.id) 15525 { 15526 *state|=ExitState; 15527 break; 15528 } 15529 if (event.xclient.window == windows->pan.id) 15530 { 15531 /* 15532 Restore original image size when pan window is deleted. 15533 */ 15534 windows->image.window_changes.width=windows->image.ximage->width; 15535 windows->image.window_changes.height=windows->image.ximage->height; 15536 (void) XConfigureImage(display,resource_info,windows, 15537 display_image,exception); 15538 } 15539 break; 15540 } 15541 case ConfigureNotify: 15542 { 15543 if (display_image->debug != MagickFalse ) 15544 (void) LogMagickEvent(X11Event,GetMagickModule(), 15545 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15546 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15547 event.xconfigure.y,event.xconfigure.send_event); 15548 if (event.xconfigure.window == windows->image.id) 15549 { 15550 /* 15551 Image window has a new configuration. 15552 */ 15553 if (event.xconfigure.send_event != 0) 15554 { 15555 XWindowChanges 15556 window_changes; 15557 15558 /* 15559 Position the transient windows relative of the Image window. 15560 */ 15561 if (windows->command.geometry == (char *) NULL) 15562 if (windows->command.mapped == MagickFalse) 15563 { 15564 windows->command.x=event.xconfigure.x- 15565 windows->command.width-25; 15566 windows->command.y=event.xconfigure.y; 15567 XConstrainWindowPosition(display,&windows->command); 15568 window_changes.x=windows->command.x; 15569 window_changes.y=windows->command.y; 15570 (void) XReconfigureWMWindow(display,windows->command.id, 15571 windows->command.screen,(unsigned int) (CWX | CWY), 15572 &window_changes); 15573 } 15574 if (windows->widget.geometry == (char *) NULL) 15575 if (windows->widget.mapped == MagickFalse) 15576 { 15577 windows->widget.x=event.xconfigure.x+ 15578 event.xconfigure.width/10; 15579 windows->widget.y=event.xconfigure.y+ 15580 event.xconfigure.height/10; 15581 XConstrainWindowPosition(display,&windows->widget); 15582 window_changes.x=windows->widget.x; 15583 window_changes.y=windows->widget.y; 15584 (void) XReconfigureWMWindow(display,windows->widget.id, 15585 windows->widget.screen,(unsigned int) (CWX | CWY), 15586 &window_changes); 15587 } 15588 if (windows->magnify.geometry == (char *) NULL) 15589 if (windows->magnify.mapped == MagickFalse) 15590 { 15591 windows->magnify.x=event.xconfigure.x+ 15592 event.xconfigure.width+25; 15593 windows->magnify.y=event.xconfigure.y; 15594 XConstrainWindowPosition(display,&windows->magnify); 15595 window_changes.x=windows->magnify.x; 15596 window_changes.y=windows->magnify.y; 15597 (void) XReconfigureWMWindow(display,windows->magnify.id, 15598 windows->magnify.screen,(unsigned int) (CWX | CWY), 15599 &window_changes); 15600 } 15601 if (windows->pan.geometry == (char *) NULL) 15602 if (windows->pan.mapped == MagickFalse) 15603 { 15604 windows->pan.x=event.xconfigure.x+ 15605 event.xconfigure.width+25; 15606 windows->pan.y=event.xconfigure.y+ 15607 windows->magnify.height+50; 15608 XConstrainWindowPosition(display,&windows->pan); 15609 window_changes.x=windows->pan.x; 15610 window_changes.y=windows->pan.y; 15611 (void) XReconfigureWMWindow(display,windows->pan.id, 15612 windows->pan.screen,(unsigned int) (CWX | CWY), 15613 &window_changes); 15614 } 15615 } 15616 if ((event.xconfigure.width == (int) windows->image.width) && 15617 (event.xconfigure.height == (int) windows->image.height)) 15618 break; 15619 windows->image.width=(unsigned int) event.xconfigure.width; 15620 windows->image.height=(unsigned int) event.xconfigure.height; 15621 windows->image.x=0; 15622 windows->image.y=0; 15623 if (display_image->montage != (char *) NULL) 15624 { 15625 windows->image.x=vid_info.x; 15626 windows->image.y=vid_info.y; 15627 } 15628 if (windows->image.mapped != MagickFalse && 15629 windows->image.stasis != MagickFalse ) 15630 { 15631 /* 15632 Update image window configuration. 15633 */ 15634 windows->image.window_changes.width=event.xconfigure.width; 15635 windows->image.window_changes.height=event.xconfigure.height; 15636 (void) XConfigureImage(display,resource_info,windows, 15637 display_image,exception); 15638 } 15639 /* 15640 Update pan window configuration. 15641 */ 15642 if ((event.xconfigure.width < windows->image.ximage->width) || 15643 (event.xconfigure.height < windows->image.ximage->height)) 15644 { 15645 (void) XMapRaised(display,windows->pan.id); 15646 XDrawPanRectangle(display,windows); 15647 } 15648 else 15649 if (windows->pan.mapped != MagickFalse ) 15650 (void) XWithdrawWindow(display,windows->pan.id, 15651 windows->pan.screen); 15652 break; 15653 } 15654 if (event.xconfigure.window == windows->magnify.id) 15655 { 15656 unsigned int 15657 magnify; 15658 15659 /* 15660 Magnify window has a new configuration. 15661 */ 15662 windows->magnify.width=(unsigned int) event.xconfigure.width; 15663 windows->magnify.height=(unsigned int) event.xconfigure.height; 15664 if (windows->magnify.mapped == MagickFalse) 15665 break; 15666 magnify=1; 15667 while ((int) magnify <= event.xconfigure.width) 15668 magnify<<=1; 15669 while ((int) magnify <= event.xconfigure.height) 15670 magnify<<=1; 15671 magnify>>=1; 15672 if (((int) magnify != event.xconfigure.width) || 15673 ((int) magnify != event.xconfigure.height)) 15674 { 15675 window_changes.width=(int) magnify; 15676 window_changes.height=(int) magnify; 15677 (void) XReconfigureWMWindow(display,windows->magnify.id, 15678 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15679 &window_changes); 15680 break; 15681 } 15682 if (windows->magnify.mapped != MagickFalse && 15683 windows->magnify.stasis != MagickFalse ) 15684 { 15685 status=XMakeImage(display,resource_info,&windows->magnify, 15686 display_image,windows->magnify.width,windows->magnify.height, 15687 exception); 15688 XMakeMagnifyImage(display,windows,exception); 15689 } 15690 break; 15691 } 15692 if (windows->magnify.mapped != MagickFalse && 15693 (event.xconfigure.window == windows->pan.id)) 15694 { 15695 /* 15696 Pan icon window has a new configuration. 15697 */ 15698 if (event.xconfigure.send_event != 0) 15699 { 15700 windows->pan.x=event.xconfigure.x; 15701 windows->pan.y=event.xconfigure.y; 15702 } 15703 windows->pan.width=(unsigned int) event.xconfigure.width; 15704 windows->pan.height=(unsigned int) event.xconfigure.height; 15705 break; 15706 } 15707 if (event.xconfigure.window == windows->icon.id) 15708 { 15709 /* 15710 Icon window has a new configuration. 15711 */ 15712 windows->icon.width=(unsigned int) event.xconfigure.width; 15713 windows->icon.height=(unsigned int) event.xconfigure.height; 15714 break; 15715 } 15716 break; 15717 } 15718 case DestroyNotify: 15719 { 15720 /* 15721 Group leader has exited. 15722 */ 15723 if (display_image->debug != MagickFalse ) 15724 (void) LogMagickEvent(X11Event,GetMagickModule(), 15725 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15726 if (event.xdestroywindow.window == windows->group_leader.id) 15727 { 15728 *state|=ExitState; 15729 break; 15730 } 15731 break; 15732 } 15733 case EnterNotify: 15734 { 15735 /* 15736 Selectively install colormap. 15737 */ 15738 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15739 if (event.xcrossing.mode != NotifyUngrab) 15740 XInstallColormap(display,map_info->colormap); 15741 break; 15742 } 15743 case Expose: 15744 { 15745 if (display_image->debug != MagickFalse ) 15746 (void) LogMagickEvent(X11Event,GetMagickModule(), 15747 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15748 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15749 event.xexpose.y); 15750 /* 15751 Refresh windows that are now exposed. 15752 */ 15753 if ((event.xexpose.window == windows->image.id) && 15754 windows->image.mapped != MagickFalse ) 15755 { 15756 XRefreshWindow(display,&windows->image,&event); 15757 delay=display_image->delay/MagickMax( 15758 display_image->ticks_per_second,1L); 15759 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15760 break; 15761 } 15762 if ((event.xexpose.window == windows->magnify.id) && 15763 windows->magnify.mapped != MagickFalse) 15764 { 15765 XMakeMagnifyImage(display,windows,exception); 15766 break; 15767 } 15768 if (event.xexpose.window == windows->pan.id) 15769 { 15770 XDrawPanRectangle(display,windows); 15771 break; 15772 } 15773 if (event.xexpose.window == windows->icon.id) 15774 { 15775 XRefreshWindow(display,&windows->icon,&event); 15776 break; 15777 } 15778 break; 15779 } 15780 case KeyPress: 15781 { 15782 int 15783 length; 15784 15785 /* 15786 Respond to a user key press. 15787 */ 15788 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15789 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15790 *(command+length)='\0'; 15791 if (display_image->debug != MagickFalse ) 15792 (void) LogMagickEvent(X11Event,GetMagickModule(), 15793 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15794 key_symbol,command); 15795 if (event.xkey.window == windows->image.id) 15796 { 15797 command_type=XImageWindowCommand(display,resource_info,windows, 15798 event.xkey.state,key_symbol,&display_image,exception); 15799 if (command_type != NullCommand) 15800 nexus=XMagickCommand(display,resource_info,windows,command_type, 15801 &display_image,exception); 15802 } 15803 if (event.xkey.window == windows->magnify.id) 15804 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol, 15805 exception); 15806 if (event.xkey.window == windows->pan.id) 15807 { 15808 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15809 (void) XWithdrawWindow(display,windows->pan.id, 15810 windows->pan.screen); 15811 else 15812 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15813 XTextViewWidget(display,resource_info,windows,MagickFalse, 15814 "Help Viewer - Image Pan",ImagePanHelp); 15815 else 15816 XTranslateImage(display,windows,*image,key_symbol); 15817 } 15818 delay=display_image->delay/MagickMax( 15819 display_image->ticks_per_second,1L); 15820 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15821 break; 15822 } 15823 case KeyRelease: 15824 { 15825 /* 15826 Respond to a user key release. 15827 */ 15828 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15829 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15830 if (display_image->debug != MagickFalse ) 15831 (void) LogMagickEvent(X11Event,GetMagickModule(), 15832 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15833 break; 15834 } 15835 case LeaveNotify: 15836 { 15837 /* 15838 Selectively uninstall colormap. 15839 */ 15840 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15841 if (event.xcrossing.mode != NotifyUngrab) 15842 XUninstallColormap(display,map_info->colormap); 15843 break; 15844 } 15845 case MapNotify: 15846 { 15847 if (display_image->debug != MagickFalse ) 15848 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15849 event.xmap.window); 15850 if (event.xmap.window == windows->backdrop.id) 15851 { 15852 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15853 CurrentTime); 15854 windows->backdrop.mapped=MagickTrue; 15855 break; 15856 } 15857 if (event.xmap.window == windows->image.id) 15858 { 15859 if (windows->backdrop.id != (Window) NULL) 15860 (void) XInstallColormap(display,map_info->colormap); 15861 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15862 { 15863 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15864 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15865 } 15866 if (((int) windows->image.width < windows->image.ximage->width) || 15867 ((int) windows->image.height < windows->image.ximage->height)) 15868 (void) XMapRaised(display,windows->pan.id); 15869 windows->image.mapped=MagickTrue; 15870 break; 15871 } 15872 if (event.xmap.window == windows->magnify.id) 15873 { 15874 XMakeMagnifyImage(display,windows,exception); 15875 windows->magnify.mapped=MagickTrue; 15876 (void) XWithdrawWindow(display,windows->info.id, 15877 windows->info.screen); 15878 break; 15879 } 15880 if (event.xmap.window == windows->pan.id) 15881 { 15882 XMakePanImage(display,resource_info,windows,display_image, 15883 exception); 15884 windows->pan.mapped=MagickTrue; 15885 break; 15886 } 15887 if (event.xmap.window == windows->info.id) 15888 { 15889 windows->info.mapped=MagickTrue; 15890 break; 15891 } 15892 if (event.xmap.window == windows->icon.id) 15893 { 15894 MagickBooleanType 15895 taint; 15896 15897 /* 15898 Create an icon image. 15899 */ 15900 taint=display_image->taint; 15901 XMakeStandardColormap(display,icon_visual,icon_resources, 15902 display_image,icon_map,icon_pixel,exception); 15903 (void) XMakeImage(display,icon_resources,&windows->icon, 15904 display_image,windows->icon.width,windows->icon.height, 15905 exception); 15906 display_image->taint=taint; 15907 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15908 windows->icon.pixmap); 15909 (void) XClearWindow(display,windows->icon.id); 15910 (void) XWithdrawWindow(display,windows->info.id, 15911 windows->info.screen); 15912 windows->icon.mapped=MagickTrue; 15913 break; 15914 } 15915 if (event.xmap.window == windows->command.id) 15916 { 15917 windows->command.mapped=MagickTrue; 15918 break; 15919 } 15920 if (event.xmap.window == windows->popup.id) 15921 { 15922 windows->popup.mapped=MagickTrue; 15923 break; 15924 } 15925 if (event.xmap.window == windows->widget.id) 15926 { 15927 windows->widget.mapped=MagickTrue; 15928 break; 15929 } 15930 break; 15931 } 15932 case MappingNotify: 15933 { 15934 (void) XRefreshKeyboardMapping(&event.xmapping); 15935 break; 15936 } 15937 case NoExpose: 15938 break; 15939 case PropertyNotify: 15940 { 15941 Atom 15942 type; 15943 15944 int 15945 format, 15946 status; 15947 15948 unsigned char 15949 *data; 15950 15951 unsigned long 15952 after, 15953 length; 15954 15955 if (display_image->debug != MagickFalse ) 15956 (void) LogMagickEvent(X11Event,GetMagickModule(), 15957 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15958 event.xproperty.atom,event.xproperty.state); 15959 if (event.xproperty.atom != windows->im_remote_command) 15960 break; 15961 /* 15962 Display image named by the remote command protocol. 15963 */ 15964 status=XGetWindowProperty(display,event.xproperty.window, 15965 event.xproperty.atom,0L,(long) MagickPathExtent,MagickFalse,(Atom) 15966 AnyPropertyType,&type,&format,&length,&after,&data); 15967 if ((status != Success) || (length == 0)) 15968 break; 15969 if (LocaleCompare((char *) data,"-quit") == 0) 15970 { 15971 XClientMessage(display,windows->image.id,windows->im_protocols, 15972 windows->im_exit,CurrentTime); 15973 (void) XFree((void *) data); 15974 break; 15975 } 15976 (void) CopyMagickString(resource_info->image_info->filename, 15977 (char *) data,MagickPathExtent); 15978 (void) XFree((void *) data); 15979 nexus=ReadImage(resource_info->image_info,exception); 15980 CatchException(exception); 15981 if (nexus != (Image *) NULL) 15982 *state|=NextImageState | ExitState; 15983 break; 15984 } 15985 case ReparentNotify: 15986 { 15987 if (display_image->debug != MagickFalse ) 15988 (void) LogMagickEvent(X11Event,GetMagickModule(), 15989 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 15990 event.xreparent.window); 15991 break; 15992 } 15993 case UnmapNotify: 15994 { 15995 if (display_image->debug != MagickFalse ) 15996 (void) LogMagickEvent(X11Event,GetMagickModule(), 15997 "Unmap Notify: 0x%lx",event.xunmap.window); 15998 if (event.xunmap.window == windows->backdrop.id) 15999 { 16000 windows->backdrop.mapped=MagickFalse; 16001 break; 16002 } 16003 if (event.xunmap.window == windows->image.id) 16004 { 16005 windows->image.mapped=MagickFalse; 16006 break; 16007 } 16008 if (event.xunmap.window == windows->magnify.id) 16009 { 16010 windows->magnify.mapped=MagickFalse; 16011 break; 16012 } 16013 if (event.xunmap.window == windows->pan.id) 16014 { 16015 windows->pan.mapped=MagickFalse; 16016 break; 16017 } 16018 if (event.xunmap.window == windows->info.id) 16019 { 16020 windows->info.mapped=MagickFalse; 16021 break; 16022 } 16023 if (event.xunmap.window == windows->icon.id) 16024 { 16025 if (map_info->colormap == icon_map->colormap) 16026 XConfigureImageColormap(display,resource_info,windows, 16027 display_image,exception); 16028 (void) XFreeStandardColormap(display,icon_visual,icon_map, 16029 icon_pixel); 16030 windows->icon.mapped=MagickFalse; 16031 break; 16032 } 16033 if (event.xunmap.window == windows->command.id) 16034 { 16035 windows->command.mapped=MagickFalse; 16036 break; 16037 } 16038 if (event.xunmap.window == windows->popup.id) 16039 { 16040 if (windows->backdrop.id != (Window) NULL) 16041 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16042 CurrentTime); 16043 windows->popup.mapped=MagickFalse; 16044 break; 16045 } 16046 if (event.xunmap.window == windows->widget.id) 16047 { 16048 if (windows->backdrop.id != (Window) NULL) 16049 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16050 CurrentTime); 16051 windows->widget.mapped=MagickFalse; 16052 break; 16053 } 16054 break; 16055 } 16056 default: 16057 { 16058 if (display_image->debug != MagickFalse ) 16059 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 16060 event.type); 16061 break; 16062 } 16063 } 16064 } while (!(*state & ExitState)); 16065 if ((*state & ExitState) == 0) 16066 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 16067 &display_image,exception); 16068 else 16069 if (resource_info->confirm_edit != MagickFalse ) 16070 { 16071 /* 16072 Query user if image has changed. 16073 */ 16074 if ((resource_info->immutable == MagickFalse) && 16075 display_image->taint != MagickFalse) 16076 { 16077 int 16078 status; 16079 16080 status=XConfirmWidget(display,windows,"Your image changed.", 16081 "Do you want to save it"); 16082 if (status == 0) 16083 *state&=(~ExitState); 16084 else 16085 if (status > 0) 16086 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 16087 &display_image,exception); 16088 } 16089 } 16090 if ((windows->visual_info->klass == GrayScale) || 16091 (windows->visual_info->klass == PseudoColor) || 16092 (windows->visual_info->klass == DirectColor)) 16093 { 16094 /* 16095 Withdraw pan and Magnify window. 16096 */ 16097 if (windows->info.mapped != MagickFalse ) 16098 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 16099 if (windows->magnify.mapped != MagickFalse ) 16100 (void) XWithdrawWindow(display,windows->magnify.id, 16101 windows->magnify.screen); 16102 if (windows->command.mapped != MagickFalse ) 16103 (void) XWithdrawWindow(display,windows->command.id, 16104 windows->command.screen); 16105 } 16106 if (windows->pan.mapped != MagickFalse ) 16107 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 16108 if (resource_info->backdrop == MagickFalse) 16109 if (windows->backdrop.mapped) 16110 { 16111 (void) XWithdrawWindow(display,windows->backdrop.id, 16112 windows->backdrop.screen); 16113 (void) XDestroyWindow(display,windows->backdrop.id); 16114 windows->backdrop.id=(Window) NULL; 16115 (void) XWithdrawWindow(display,windows->image.id, 16116 windows->image.screen); 16117 (void) XDestroyWindow(display,windows->image.id); 16118 windows->image.id=(Window) NULL; 16119 } 16120 XSetCursorState(display,windows,MagickTrue); 16121 XCheckRefreshWindows(display,windows); 16122 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 16123 *state&=(~ExitState); 16124 if (*state & ExitState) 16125 { 16126 /* 16127 Free Standard Colormap. 16128 */ 16129 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 16130 if (resource_info->map_type == (char *) NULL) 16131 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 16132 /* 16133 Free X resources. 16134 */ 16135 if (resource_info->copy_image != (Image *) NULL) 16136 { 16137 resource_info->copy_image=DestroyImage(resource_info->copy_image); 16138 resource_info->copy_image=NewImageList(); 16139 } 16140 DestroyXResources(); 16141 } 16142 (void) XSync(display,MagickFalse); 16143 /* 16144 Restore our progress monitor and warning handlers. 16145 */ 16146 (void) SetErrorHandler(warning_handler); 16147 (void) SetWarningHandler(warning_handler); 16148 /* 16149 Change to home directory. 16150 */ 16151 directory=getcwd(working_directory,MagickPathExtent); 16152 (void) directory; 16153 { 16154 int 16155 status; 16156 16157 if (*resource_info->home_directory == '\0') 16158 (void) CopyMagickString(resource_info->home_directory,".",MagickPathExtent); 16159 status=chdir(resource_info->home_directory); 16160 if (status == -1) 16161 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 16162 "UnableToOpenFile","%s",resource_info->home_directory); 16163 } 16164 *image=display_image; 16165 return(nexus); 16166} 16167#else 16168 16169/* 16170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16171% % 16172% % 16173% % 16174+ D i s p l a y I m a g e s % 16175% % 16176% % 16177% % 16178%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16179% 16180% DisplayImages() displays an image sequence to any X window screen. It 16181% returns a value other than 0 if successful. Check the exception member 16182% of image to determine the reason for any failure. 16183% 16184% The format of the DisplayImages method is: 16185% 16186% MagickBooleanType DisplayImages(const ImageInfo *image_info, 16187% Image *images,ExceptionInfo *exception) 16188% 16189% A description of each parameter follows: 16190% 16191% o image_info: the image info. 16192% 16193% o image: the image. 16194% 16195% o exception: return any errors or warnings in this structure. 16196% 16197*/ 16198MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16199 Image *image,ExceptionInfo *exception) 16200{ 16201 assert(image_info != (const ImageInfo *) NULL); 16202 assert(image_info->signature == MagickCoreSignature); 16203 assert(image != (Image *) NULL); 16204 assert(image->signature == MagickCoreSignature); 16205 (void) image_info; 16206 if (image->debug != MagickFalse ) 16207 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16208 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16209 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image->filename); 16210 return(MagickFalse); 16211} 16212 16213/* 16214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16215% % 16216% % 16217% % 16218+ R e m o t e D i s p l a y C o m m a n d % 16219% % 16220% % 16221% % 16222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16223% 16224% RemoteDisplayCommand() encourages a remote display program to display the 16225% specified image filename. 16226% 16227% The format of the RemoteDisplayCommand method is: 16228% 16229% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16230% const char *window,const char *filename,ExceptionInfo *exception) 16231% 16232% A description of each parameter follows: 16233% 16234% o image_info: the image info. 16235% 16236% o window: Specifies the name or id of an X window. 16237% 16238% o filename: the name of the image filename to display. 16239% 16240% o exception: return any errors or warnings in this structure. 16241% 16242*/ 16243MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16244 const char *window,const char *filename,ExceptionInfo *exception) 16245{ 16246 assert(image_info != (const ImageInfo *) NULL); 16247 assert(image_info->signature == MagickCoreSignature); 16248 assert(filename != (char *) NULL); 16249 (void) window; 16250 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16251 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16252 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image_info->filename); 16253 return(MagickFalse); 16254} 16255#endif 16256