display.c revision 8a5d7f45b2ba420c8ea1e51bec48d3172814def3
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% DDDD IIIII SSSSS PPPP L AAA Y Y % 7% D D I SS P P L A A Y Y % 8% D D I SSS PPPP L AAAAA Y % 9% D D I SS P L A A Y % 10% DDDD IIIII SSSSS P LLLLL A A Y % 11% % 12% % 13% MagickCore Methods to Interactively Display and Edit an Image % 14% % 15% Software Design % 16% John Cristy % 17% July 1992 % 18% % 19% % 20% Copyright 1999-2013 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/client.h" 49#include "MagickCore/color.h" 50#include "MagickCore/colorspace.h" 51#include "MagickCore/composite.h" 52#include "MagickCore/constitute.h" 53#include "MagickCore/decorate.h" 54#include "MagickCore/delegate.h" 55#include "MagickCore/display.h" 56#include "MagickCore/display-private.h" 57#include "MagickCore/distort.h" 58#include "MagickCore/draw.h" 59#include "MagickCore/effect.h" 60#include "MagickCore/enhance.h" 61#include "MagickCore/exception.h" 62#include "MagickCore/exception-private.h" 63#include "MagickCore/fx.h" 64#include "MagickCore/geometry.h" 65#include "MagickCore/image.h" 66#include "MagickCore/image-private.h" 67#include "MagickCore/list.h" 68#include "MagickCore/log.h" 69#include "MagickCore/magick.h" 70#include "MagickCore/memory_.h" 71#include "MagickCore/monitor.h" 72#include "MagickCore/monitor-private.h" 73#include "MagickCore/montage.h" 74#include "MagickCore/option.h" 75#include "MagickCore/paint.h" 76#include "MagickCore/pixel.h" 77#include "MagickCore/pixel-accessor.h" 78#include "MagickCore/PreRvIcccm.h" 79#include "MagickCore/property.h" 80#include "MagickCore/quantum.h" 81#include "MagickCore/quantum-private.h" 82#include "MagickCore/resize.h" 83#include "MagickCore/resource_.h" 84#include "MagickCore/shear.h" 85#include "MagickCore/segment.h" 86#include "MagickCore/statistic.h" 87#include "MagickCore/string_.h" 88#include "MagickCore/string-private.h" 89#include "MagickCore/transform.h" 90#include "MagickCore/threshold.h" 91#include "MagickCore/utility.h" 92#include "MagickCore/utility-private.h" 93#include "MagickCore/version.h" 94#include "MagickCore/widget.h" 95#include "MagickCore/widget-private.h" 96#include "MagickCore/xwindow.h" 97#include "MagickCore/xwindow-private.h" 98 99#if defined(MAGICKCORE_X11_DELEGATE) 100/* 101 Define declarations. 102*/ 103#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L) 104 105/* 106 Constant declarations. 107*/ 108static const unsigned char 109 HighlightBitmap[8] = 110 { 111 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 112 }, 113 OpaqueBitmap[8] = 114 { 115 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 116 }, 117 ShadowBitmap[8] = 118 { 119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 120 }; 121 122static const char 123 *PageSizes[] = 124 { 125 "Letter", 126 "Tabloid", 127 "Ledger", 128 "Legal", 129 "Statement", 130 "Executive", 131 "A3", 132 "A4", 133 "A5", 134 "B4", 135 "B5", 136 "Folio", 137 "Quarto", 138 "10x14", 139 (char *) NULL 140 }; 141 142/* 143 Help widget declarations. 144*/ 145static const char 146 *ImageAnnotateHelp[] = 147 { 148 "In annotate mode, the Command widget has these options:", 149 "", 150 " Font Name", 151 " fixed", 152 " variable", 153 " 5x8", 154 " 6x10", 155 " 7x13bold", 156 " 8x13bold", 157 " 9x15bold", 158 " 10x20", 159 " 12x24", 160 " Browser...", 161 " Font Color", 162 " black", 163 " blue", 164 " cyan", 165 " green", 166 " gray", 167 " red", 168 " magenta", 169 " yellow", 170 " white", 171 " transparent", 172 " Browser...", 173 " Font Color", 174 " black", 175 " blue", 176 " cyan", 177 " green", 178 " gray", 179 " red", 180 " magenta", 181 " yellow", 182 " white", 183 " transparent", 184 " Browser...", 185 " Rotate Text", 186 " -90", 187 " -45", 188 " -30", 189 " 0", 190 " 30", 191 " 45", 192 " 90", 193 " 180", 194 " Dialog...", 195 " Help", 196 " Dismiss", 197 "", 198 "Choose a font name from the Font Name sub-menu. Additional", 199 "font names can be specified with the font browser. You can", 200 "change the menu names by setting the X resources font1", 201 "through font9.", 202 "", 203 "Choose a font color from the Font Color sub-menu.", 204 "Additional font colors can be specified with the color", 205 "browser. You can change the menu colors by setting the X", 206 "resources pen1 through pen9.", 207 "", 208 "If you select the color browser and press Grab, you can", 209 "choose the font color by moving the pointer to the desired", 210 "color on the screen and press any button.", 211 "", 212 "If you choose to rotate the text, choose Rotate Text from the", 213 "menu and select an angle. Typically you will only want to", 214 "rotate one line of text at a time. Depending on the angle you", 215 "choose, subsequent lines may end up overwriting each other.", 216 "", 217 "Choosing a font and its color is optional. The default font", 218 "is fixed and the default color is black. However, you must", 219 "choose a location to begin entering text and press button 1.", 220 "An underscore character will appear at the location of the", 221 "pointer. The cursor changes to a pencil to indicate you are", 222 "in text mode. To exit immediately, press Dismiss.", 223 "", 224 "In text mode, any key presses will display the character at", 225 "the location of the underscore and advance the underscore", 226 "cursor. Enter your text and once completed press Apply to", 227 "finish your image annotation. To correct errors press BACK", 228 "SPACE. To delete an entire line of text, press DELETE. Any", 229 "text that exceeds the boundaries of the image window is", 230 "automagically continued onto the next line.", 231 "", 232 "The actual color you request for the font is saved in the", 233 "image. However, the color that appears in your image window", 234 "may be different. For example, on a monochrome screen the", 235 "text will appear black or white even if you choose the color", 236 "red as the font color. However, the image saved to a file", 237 "with -write is written with red lettering. To assure the", 238 "correct color text in the final image, any PseudoClass image", 239 "is promoted to DirectClass (see miff(5)). To force a", 240 "PseudoClass image to remain PseudoClass, use -colors.", 241 (char *) NULL, 242 }, 243 *ImageChopHelp[] = 244 { 245 "In chop mode, the Command widget has these options:", 246 "", 247 " Direction", 248 " horizontal", 249 " vertical", 250 " Help", 251 " Dismiss", 252 "", 253 "If the you choose the horizontal direction (this the", 254 "default), the area of the image between the two horizontal", 255 "endpoints of the chop line is removed. Otherwise, the area", 256 "of the image between the two vertical endpoints of the chop", 257 "line is removed.", 258 "", 259 "Select a location within the image window to begin your chop,", 260 "press and hold any button. Next, move the pointer to", 261 "another location in the image. As you move a line will", 262 "connect the initial location and the pointer. When you", 263 "release the button, the area within the image to chop is", 264 "determined by which direction you choose from the Command", 265 "widget.", 266 "", 267 "To cancel the image chopping, move the pointer back to the", 268 "starting point of the line and release the button.", 269 (char *) NULL, 270 }, 271 *ImageColorEditHelp[] = 272 { 273 "In color edit mode, the Command widget has these options:", 274 "", 275 " Method", 276 " point", 277 " replace", 278 " floodfill", 279 " filltoborder", 280 " reset", 281 " Pixel Color", 282 " black", 283 " blue", 284 " cyan", 285 " green", 286 " gray", 287 " red", 288 " magenta", 289 " yellow", 290 " white", 291 " Browser...", 292 " Border Color", 293 " black", 294 " blue", 295 " cyan", 296 " green", 297 " gray", 298 " red", 299 " magenta", 300 " yellow", 301 " white", 302 " Browser...", 303 " Fuzz", 304 " 0%", 305 " 2%", 306 " 5%", 307 " 10%", 308 " 15%", 309 " Dialog...", 310 " Undo", 311 " Help", 312 " Dismiss", 313 "", 314 "Choose a color editing method from the Method sub-menu", 315 "of the Command widget. The point method recolors any pixel", 316 "selected with the pointer until the button is released. The", 317 "replace method recolors any pixel that matches the color of", 318 "the pixel you select with a button press. Floodfill recolors", 319 "any pixel that matches the color of the pixel you select with", 320 "a button press and is a neighbor. Whereas filltoborder recolors", 321 "any neighbor pixel that is not the border color. Finally reset", 322 "changes the entire image to the designated color.", 323 "", 324 "Next, choose a pixel color from the Pixel Color sub-menu.", 325 "Additional pixel colors can be specified with the color", 326 "browser. You can change the menu colors by setting the X", 327 "resources pen1 through pen9.", 328 "", 329 "Now press button 1 to select a pixel within the image window", 330 "to change its color. Additional pixels may be recolored as", 331 "prescribed by the method you choose.", 332 "", 333 "If the Magnify widget is mapped, it can be helpful in positioning", 334 "your pointer within the image (refer to button 2).", 335 "", 336 "The actual color you request for the pixels is saved in the", 337 "image. However, the color that appears in your image window", 338 "may be different. For example, on a monochrome screen the", 339 "pixel will appear black or white even if you choose the", 340 "color red as the pixel color. However, the image saved to a", 341 "file with -write is written with red pixels. To assure the", 342 "correct color text in the final image, any PseudoClass image", 343 "is promoted to DirectClass (see miff(5)). To force a", 344 "PseudoClass image to remain PseudoClass, use -colors.", 345 (char *) NULL, 346 }, 347 *ImageCompositeHelp[] = 348 { 349 "First a widget window is displayed requesting you to enter an", 350 "image name. Press Composite, Grab or type a file name.", 351 "Press Cancel if you choose not to create a composite image.", 352 "When you choose Grab, move the pointer to the desired window", 353 "and press any button.", 354 "", 355 "If the Composite image does not have any matte information,", 356 "you are informed and the file browser is displayed again.", 357 "Enter the name of a mask image. The image is typically", 358 "grayscale and the same size as the composite image. If the", 359 "image is not grayscale, it is converted to grayscale and the", 360 "resulting intensities are used as matte information.", 361 "", 362 "A small window appears showing the location of the cursor in", 363 "the image window. You are now in composite mode. To exit", 364 "immediately, press Dismiss. In composite mode, the Command", 365 "widget has these options:", 366 "", 367 " Operators", 368 " Over", 369 " In", 370 " Out", 371 " Atop", 372 " Xor", 373 " Plus", 374 " Minus", 375 " Add", 376 " Subtract", 377 " Difference", 378 " Multiply", 379 " Bumpmap", 380 " Copy", 381 " CopyRed", 382 " CopyGreen", 383 " CopyBlue", 384 " CopyOpacity", 385 " Clear", 386 " Dissolve", 387 " Displace", 388 " Help", 389 " Dismiss", 390 "", 391 "Choose a composite operation from the Operators sub-menu of", 392 "the Command widget. How each operator behaves is described", 393 "below. Image window is the image currently displayed on", 394 "your X server and image is the image obtained with the File", 395 "Browser widget.", 396 "", 397 "Over The result is the union of the two image shapes,", 398 " with image obscuring image window in the region of", 399 " overlap.", 400 "", 401 "In The result is simply image cut by the shape of", 402 " image window. None of the image data of image", 403 " window is in the result.", 404 "", 405 "Out The resulting image is image with the shape of", 406 " image window cut out.", 407 "", 408 "Atop The result is the same shape as image image window,", 409 " with image obscuring image window where the image", 410 " shapes overlap. Note this differs from over", 411 " because the portion of image outside image window's", 412 " shape does not appear in the result.", 413 "", 414 "Xor The result is the image data from both image and", 415 " image window that is outside the overlap region.", 416 " The overlap region is blank.", 417 "", 418 "Plus The result is just the sum of the image data.", 419 " Output values are cropped to QuantumRange (no overflow).", 420 "", 421 "Minus The result of image - image window, with underflow", 422 " cropped to zero.", 423 "", 424 "Add The result of image + image window, with overflow", 425 " wrapping around (mod 256).", 426 "", 427 "Subtract The result of image - image window, with underflow", 428 " wrapping around (mod 256). The add and subtract", 429 " operators can be used to perform reversible", 430 " transformations.", 431 "", 432 "Difference", 433 " The result of abs(image - image window). This", 434 " useful for comparing two very similar images.", 435 "", 436 "Multiply", 437 " The result of image * image window. This", 438 " useful for the creation of drop-shadows.", 439 "", 440 "Bumpmap The result of surface normals from image * image", 441 " window.", 442 "", 443 "Copy The resulting image is image window replaced with", 444 " image. Here the matte information is ignored.", 445 "", 446 "CopyRed The red layer of the image window is replace with", 447 " the red layer of the image. The other layers are", 448 " untouched.", 449 "", 450 "CopyGreen", 451 " The green layer of the image window is replace with", 452 " the green layer of the image. The other layers are", 453 " untouched.", 454 "", 455 "CopyBlue The blue layer of the image window is replace with", 456 " the blue layer of the image. The other layers are", 457 " untouched.", 458 "", 459 "CopyOpacity", 460 " The matte layer of the image window is replace with", 461 " the matte layer of the image. The other layers are", 462 " untouched.", 463 "", 464 "The image compositor requires a matte, or alpha channel in", 465 "the image for some operations. This extra channel usually", 466 "defines a mask which represents a sort of a cookie-cutter", 467 "for the image. This the case when matte is opaque (full", 468 "coverage) for pixels inside the shape, zero outside, and", 469 "between 0 and QuantumRange on the boundary. If image does not", 470 "have a matte channel, it is initialized with 0 for any pixel", 471 "matching in color to pixel location (0,0), otherwise QuantumRange.", 472 "", 473 "If you choose Dissolve, the composite operator becomes Over. The", 474 "image matte channel percent transparency is initialized to factor.", 475 "The image window is initialized to (100-factor). Where factor is the", 476 "value you specify in the Dialog widget.", 477 "", 478 "Displace shifts the image pixels as defined by a displacement", 479 "map. With this option, image is used as a displacement map.", 480 "Black, within the displacement map, is a maximum positive", 481 "displacement. White is a maximum negative displacement and", 482 "middle gray is neutral. The displacement is scaled to determine", 483 "the pixel shift. By default, the displacement applies in both the", 484 "horizontal and vertical directions. However, if you specify a mask,", 485 "image is the horizontal X displacement and mask the vertical Y", 486 "displacement.", 487 "", 488 "Note that matte information for image window is not retained", 489 "for colormapped X server visuals (e.g. StaticColor,", 490 "StaticColor, GrayScale, PseudoColor). Correct compositing", 491 "behavior may require a TrueColor or DirectColor visual or a", 492 "Standard Colormap.", 493 "", 494 "Choosing a composite operator is optional. The default", 495 "operator is replace. However, you must choose a location to", 496 "composite your image and press button 1. Press and hold the", 497 "button before releasing and an outline of the image will", 498 "appear to help you identify your location.", 499 "", 500 "The actual colors of the composite image is saved. However,", 501 "the color that appears in image window may be different.", 502 "For example, on a monochrome screen image window will appear", 503 "black or white even though your composited image may have", 504 "many colors. If the image is saved to a file it is written", 505 "with the correct colors. To assure the correct colors are", 506 "saved in the final image, any PseudoClass image is promoted", 507 "to DirectClass (see miff(5)). To force a PseudoClass image", 508 "to remain PseudoClass, use -colors.", 509 (char *) NULL, 510 }, 511 *ImageCutHelp[] = 512 { 513 "In cut mode, the Command widget has these options:", 514 "", 515 " Help", 516 " Dismiss", 517 "", 518 "To define a cut region, press button 1 and drag. The", 519 "cut region is defined by a highlighted rectangle that", 520 "expands or contracts as it follows the pointer. Once you", 521 "are satisfied with the cut region, release the button.", 522 "You are now in rectify mode. In rectify mode, the Command", 523 "widget has these options:", 524 "", 525 " Cut", 526 " Help", 527 " Dismiss", 528 "", 529 "You can make adjustments by moving the pointer to one of the", 530 "cut rectangle corners, pressing a button, and dragging.", 531 "Finally, press Cut to commit your copy region. To", 532 "exit without cutting the image, press Dismiss.", 533 (char *) NULL, 534 }, 535 *ImageCopyHelp[] = 536 { 537 "In copy mode, the Command widget has these options:", 538 "", 539 " Help", 540 " Dismiss", 541 "", 542 "To define a copy region, press button 1 and drag. The", 543 "copy region is defined by a highlighted rectangle that", 544 "expands or contracts as it follows the pointer. Once you", 545 "are satisfied with the copy region, release the button.", 546 "You are now in rectify mode. In rectify mode, the Command", 547 "widget has these options:", 548 "", 549 " Copy", 550 " Help", 551 " Dismiss", 552 "", 553 "You can make adjustments by moving the pointer to one of the", 554 "copy rectangle corners, pressing a button, and dragging.", 555 "Finally, press Copy to commit your copy region. To", 556 "exit without copying the image, press Dismiss.", 557 (char *) NULL, 558 }, 559 *ImageCropHelp[] = 560 { 561 "In crop mode, the Command widget has these options:", 562 "", 563 " Help", 564 " Dismiss", 565 "", 566 "To define a cropping region, press button 1 and drag. The", 567 "cropping region is defined by a highlighted rectangle that", 568 "expands or contracts as it follows the pointer. Once you", 569 "are satisfied with the cropping region, release the button.", 570 "You are now in rectify mode. In rectify mode, the Command", 571 "widget has these options:", 572 "", 573 " Crop", 574 " Help", 575 " Dismiss", 576 "", 577 "You can make adjustments by moving the pointer to one of the", 578 "cropping rectangle corners, pressing a button, and dragging.", 579 "Finally, press Crop to commit your cropping region. To", 580 "exit without cropping the image, press Dismiss.", 581 (char *) NULL, 582 }, 583 *ImageDrawHelp[] = 584 { 585 "The cursor changes to a crosshair to indicate you are in", 586 "draw mode. To exit immediately, press Dismiss. In draw mode,", 587 "the Command widget has these options:", 588 "", 589 " Element", 590 " point", 591 " line", 592 " rectangle", 593 " fill rectangle", 594 " circle", 595 " fill circle", 596 " ellipse", 597 " fill ellipse", 598 " polygon", 599 " fill polygon", 600 " Color", 601 " black", 602 " blue", 603 " cyan", 604 " green", 605 " gray", 606 " red", 607 " magenta", 608 " yellow", 609 " white", 610 " transparent", 611 " Browser...", 612 " Stipple", 613 " Brick", 614 " Diagonal", 615 " Scales", 616 " Vertical", 617 " Wavy", 618 " Translucent", 619 " Opaque", 620 " Open...", 621 " Width", 622 " 1", 623 " 2", 624 " 4", 625 " 8", 626 " 16", 627 " Dialog...", 628 " Undo", 629 " Help", 630 " Dismiss", 631 "", 632 "Choose a drawing primitive from the Element sub-menu.", 633 "", 634 "Choose a color from the Color sub-menu. Additional", 635 "colors can be specified with the color browser.", 636 "", 637 "If you choose the color browser and press Grab, you can", 638 "select the color by moving the pointer to the desired", 639 "color on the screen and press any button. The transparent", 640 "color updates the image matte channel and is useful for", 641 "image compositing.", 642 "", 643 "Choose a stipple, if appropriate, from the Stipple sub-menu.", 644 "Additional stipples can be specified with the file browser.", 645 "Stipples obtained from the file browser must be on disk in the", 646 "X11 bitmap format.", 647 "", 648 "Choose a width, if appropriate, from the Width sub-menu. To", 649 "choose a specific width select the Dialog widget.", 650 "", 651 "Choose a point in the Image window and press button 1 and", 652 "hold. Next, move the pointer to another location in the", 653 "image. As you move, a line connects the initial location and", 654 "the pointer. When you release the button, the image is", 655 "updated with the primitive you just drew. For polygons, the", 656 "image is updated when you press and release the button without", 657 "moving the pointer.", 658 "", 659 "To cancel image drawing, move the pointer back to the", 660 "starting point of the line and release the button.", 661 (char *) NULL, 662 }, 663 *DisplayHelp[] = 664 { 665 "BUTTONS", 666 " The effects of each button press is described below. Three", 667 " buttons are required. If you have a two button mouse,", 668 " button 1 and 3 are returned. Press ALT and button 3 to", 669 " simulate button 2.", 670 "", 671 " 1 Press this button to map or unmap the Command widget.", 672 "", 673 " 2 Press and drag to define a region of the image to", 674 " magnify.", 675 "", 676 " 3 Press and drag to choose from a select set of commands.", 677 " This button behaves differently if the image being", 678 " displayed is a visual image directory. Here, choose a", 679 " particular tile of the directory and press this button and", 680 " drag to select a command from a pop-up menu. Choose from", 681 " these menu items:", 682 "", 683 " Open", 684 " Next", 685 " Former", 686 " Delete", 687 " Update", 688 "", 689 " If you choose Open, the image represented by the tile is", 690 " displayed. To return to the visual image directory, choose", 691 " Next from the Command widget. Next and Former moves to the", 692 " next or former image respectively. Choose Delete to delete", 693 " a particular image tile. Finally, choose Update to", 694 " synchronize all the image tiles with their respective", 695 " images.", 696 "", 697 "COMMAND WIDGET", 698 " The Command widget lists a number of sub-menus and commands.", 699 " They are", 700 "", 701 " File", 702 " Open...", 703 " Next", 704 " Former", 705 " Select...", 706 " Save...", 707 " Print...", 708 " Delete...", 709 " New...", 710 " Visual Directory...", 711 " Quit", 712 " Edit", 713 " Undo", 714 " Redo", 715 " Cut", 716 " Copy", 717 " Paste", 718 " View", 719 " Half Size", 720 " Original Size", 721 " Double Size", 722 " Resize...", 723 " Apply", 724 " Refresh", 725 " Restore", 726 " Transform", 727 " Crop", 728 " Chop", 729 " Flop", 730 " Flip", 731 " Rotate Right", 732 " Rotate Left", 733 " Rotate...", 734 " Shear...", 735 " Roll...", 736 " Trim Edges", 737 " Enhance", 738 " Brightness...", 739 " Saturation...", 740 " Hue...", 741 " Gamma...", 742 " Sharpen...", 743 " Dull", 744 " Contrast Stretch...", 745 " Sigmoidal Contrast...", 746 " Normalize", 747 " Equalize", 748 " Negate", 749 " Grayscale", 750 " Map...", 751 " Quantize...", 752 " Effects", 753 " Despeckle", 754 " Emboss", 755 " Reduce Noise", 756 " Add Noise", 757 " Sharpen...", 758 " Blur...", 759 " Threshold...", 760 " Edge Detect...", 761 " Spread...", 762 " Shade...", 763 " Painting...", 764 " Segment...", 765 " F/X", 766 " Solarize...", 767 " Sepia Tone...", 768 " Swirl...", 769 " Implode...", 770 " Vignette...", 771 " Wave...", 772 " Oil Painting...", 773 " Charcoal Drawing...", 774 " Image Edit", 775 " Annotate...", 776 " Draw...", 777 " Color...", 778 " Matte...", 779 " Composite...", 780 " Add Border...", 781 " Add Frame...", 782 " Comment...", 783 " Launch...", 784 " Region of Interest...", 785 " Miscellany", 786 " Image Info", 787 " Zoom Image", 788 " Show Preview...", 789 " Show Histogram", 790 " Show Matte", 791 " Background...", 792 " Slide Show", 793 " Preferences...", 794 " Help", 795 " Overview", 796 " Browse Documentation", 797 " About Display", 798 "", 799 " Menu items with a indented triangle have a sub-menu. They", 800 " are represented above as the indented items. To access a", 801 " sub-menu item, move the pointer to the appropriate menu and", 802 " press a button and drag. When you find the desired sub-menu", 803 " item, release the button and the command is executed. Move", 804 " the pointer away from the sub-menu if you decide not to", 805 " execute a particular command.", 806 "", 807 "KEYBOARD ACCELERATORS", 808 " Accelerators are one or two key presses that effect a", 809 " particular command. The keyboard accelerators that", 810 " display(1) understands is:", 811 "", 812 " Ctl+O Press to open an image from a file.", 813 "", 814 " space Press to display the next image.", 815 "", 816 " If the image is a multi-paged document such as a Postscript", 817 " document, you can skip ahead several pages by preceding", 818 " this command with a number. For example to display the", 819 " third page beyond the current page, press 3<space>.", 820 "", 821 " backspace Press to display the former image.", 822 "", 823 " If the image is a multi-paged document such as a Postscript", 824 " document, you can skip behind several pages by preceding", 825 " this command with a number. For example to display the", 826 " third page preceding the current page, press 3<backspace>.", 827 "", 828 " Ctl+S Press to write the image to a file.", 829 "", 830 " Ctl+P Press to print the image to a Postscript printer.", 831 "", 832 " Ctl+D Press to delete an image file.", 833 "", 834 " Ctl+N Press to create a blank canvas.", 835 "", 836 " Ctl+Q Press to discard all images and exit program.", 837 "", 838 " Ctl+Z Press to undo last image transformation.", 839 "", 840 " Ctl+R Press to redo last image transformation.", 841 "", 842 " Ctl+X Press to cut a region of the image.", 843 "", 844 " Ctl+C Press to copy a region of the image.", 845 "", 846 " Ctl+V Press to paste a region to the image.", 847 "", 848 " < Press to half the image size.", 849 "", 850 " - Press to return to the original image size.", 851 "", 852 " > Press to double the image size.", 853 "", 854 " % Press to resize the image to a width and height you", 855 " specify.", 856 "", 857 "Cmd-A Press to make any image transformations permanent." 858 "", 859 " By default, any image size transformations are applied", 860 " to the original image to create the image displayed on", 861 " the X server. However, the transformations are not", 862 " permanent (i.e. the original image does not change", 863 " size only the X image does). For example, if you", 864 " press > the X image will appear to double in size,", 865 " but the original image will in fact remain the same size.", 866 " To force the original image to double in size, press >", 867 " followed by Cmd-A.", 868 "", 869 " @ Press to refresh the image window.", 870 "", 871 " C Press to cut out a rectangular region of the image.", 872 "", 873 " [ Press to chop the image.", 874 "", 875 " H Press to flop image in the horizontal direction.", 876 "", 877 " V Press to flip image in the vertical direction.", 878 "", 879 " / Press to rotate the image 90 degrees clockwise.", 880 "", 881 " \\ Press to rotate the image 90 degrees counter-clockwise.", 882 "", 883 " * Press to rotate the image the number of degrees you", 884 " specify.", 885 "", 886 " S Press to shear the image the number of degrees you", 887 " specify.", 888 "", 889 " R Press to roll the image.", 890 "", 891 " T Press to trim the image edges.", 892 "", 893 " Shft-H Press to vary the image hue.", 894 "", 895 " Shft-S Press to vary the color saturation.", 896 "", 897 " Shft-L Press to vary the color brightness.", 898 "", 899 " Shft-G Press to gamma correct the image.", 900 "", 901 " Shft-C Press to sharpen the image contrast.", 902 "", 903 " Shft-Z Press to dull the image contrast.", 904 "", 905 " = Press to perform histogram equalization on the image.", 906 "", 907 " Shft-N Press to perform histogram normalization on the image.", 908 "", 909 " Shft-~ Press to negate the colors of the image.", 910 "", 911 " . Press to convert the image colors to gray.", 912 "", 913 " Shft-# Press to set the maximum number of unique colors in the", 914 " image.", 915 "", 916 " F2 Press to reduce the speckles in an image.", 917 "", 918 " F3 Press to eliminate peak noise from an image.", 919 "", 920 " F4 Press to add noise to an image.", 921 "", 922 " F5 Press to sharpen an image.", 923 "", 924 " F6 Press to delete an image file.", 925 "", 926 " F7 Press to threshold the image.", 927 "", 928 " F8 Press to detect edges within an image.", 929 "", 930 " F9 Press to emboss an image.", 931 "", 932 " F10 Press to displace pixels by a random amount.", 933 "", 934 " F11 Press to negate all pixels above the threshold level.", 935 "", 936 " F12 Press to shade the image using a distant light source.", 937 "", 938 " F13 Press to lighten or darken image edges to create a 3-D effect.", 939 "", 940 " F14 Press to segment the image by color.", 941 "", 942 " Meta-S Press to swirl image pixels about the center.", 943 "", 944 " Meta-I Press to implode image pixels about the center.", 945 "", 946 " Meta-W Press to alter an image along a sine wave.", 947 "", 948 " Meta-P Press to simulate an oil painting.", 949 "", 950 " Meta-C Press to simulate a charcoal drawing.", 951 "", 952 " Alt-A Press to annotate the image with text.", 953 "", 954 " Alt-D Press to draw on an image.", 955 "", 956 " Alt-P Press to edit an image pixel color.", 957 "", 958 " Alt-M Press to edit the image matte information.", 959 "", 960 " Alt-V Press to composite the image with another.", 961 "", 962 " Alt-B Press to add a border to the image.", 963 "", 964 " Alt-F Press to add an ornamental border to the image.", 965 "", 966 " Alt-Shft-!", 967 " Press to add an image comment.", 968 "", 969 " Ctl-A Press to apply image processing techniques to a region", 970 " of interest.", 971 "", 972 " Shft-? Press to display information about the image.", 973 "", 974 " Shft-+ Press to map the zoom image window.", 975 "", 976 " Shft-P Press to preview an image enhancement, effect, or f/x.", 977 "", 978 " F1 Press to display helpful information about display(1).", 979 "", 980 " Find Press to browse documentation about ImageMagick.", 981 "", 982 " 1-9 Press to change the level of magnification.", 983 "", 984 " Use the arrow keys to move the image one pixel up, down,", 985 " left, or right within the magnify window. Be sure to first", 986 " map the magnify window by pressing button 2.", 987 "", 988 " Press ALT and one of the arrow keys to trim off one pixel", 989 " from any side of the image.", 990 (char *) NULL, 991 }, 992 *ImageMatteEditHelp[] = 993 { 994 "Matte information within an image is useful for some", 995 "operations such as image compositing (See IMAGE", 996 "COMPOSITING). This extra channel usually defines a mask", 997 "which represents a sort of a cookie-cutter for the image.", 998 "This the case when matte is opaque (full coverage) for", 999 "pixels inside the shape, zero outside, and between 0 and", 1000 "QuantumRange on the boundary.", 1001 "", 1002 "A small window appears showing the location of the cursor in", 1003 "the image window. You are now in matte edit mode. To exit", 1004 "immediately, press Dismiss. In matte edit mode, the Command", 1005 "widget has these options:", 1006 "", 1007 " Method", 1008 " point", 1009 " replace", 1010 " floodfill", 1011 " filltoborder", 1012 " reset", 1013 " Border Color", 1014 " black", 1015 " blue", 1016 " cyan", 1017 " green", 1018 " gray", 1019 " red", 1020 " magenta", 1021 " yellow", 1022 " white", 1023 " Browser...", 1024 " Fuzz", 1025 " 0%", 1026 " 2%", 1027 " 5%", 1028 " 10%", 1029 " 15%", 1030 " Dialog...", 1031 " Matte", 1032 " Opaque", 1033 " Transparent", 1034 " Dialog...", 1035 " Undo", 1036 " Help", 1037 " Dismiss", 1038 "", 1039 "Choose a matte editing method from the Method sub-menu of", 1040 "the Command widget. The point method changes the matte value", 1041 "of any pixel selected with the pointer until the button is", 1042 "is released. The replace method changes the matte value of", 1043 "any pixel that matches the color of the pixel you select with", 1044 "a button press. Floodfill changes the matte value of any pixel", 1045 "that matches the color of the pixel you select with a button", 1046 "press and is a neighbor. Whereas filltoborder changes the matte", 1047 "value any neighbor pixel that is not the border color. Finally", 1048 "reset changes the entire image to the designated matte value.", 1049 "", 1050 "Choose Matte Value and pick Opaque or Transarent. For other values", 1051 "select the Dialog entry. Here a dialog appears requesting a matte", 1052 "value. The value you select is assigned as the opacity value of the", 1053 "selected pixel or pixels.", 1054 "", 1055 "Now, press any button to select a pixel within the image", 1056 "window to change its matte value.", 1057 "", 1058 "If the Magnify widget is mapped, it can be helpful in positioning", 1059 "your pointer within the image (refer to button 2).", 1060 "", 1061 "Matte information is only valid in a DirectClass image.", 1062 "Therefore, any PseudoClass image is promoted to DirectClass", 1063 "(see miff(5)). Note that matte information for PseudoClass", 1064 "is not retained for colormapped X server visuals (e.g.", 1065 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you", 1066 "immediately save your image to a file (refer to Write).", 1067 "Correct matte editing behavior may require a TrueColor or", 1068 "DirectColor visual or a Standard Colormap.", 1069 (char *) NULL, 1070 }, 1071 *ImagePanHelp[] = 1072 { 1073 "When an image exceeds the width or height of the X server", 1074 "screen, display maps a small panning icon. The rectangle", 1075 "within the panning icon shows the area that is currently", 1076 "displayed in the image window. To pan about the image,", 1077 "press any button and drag the pointer within the panning", 1078 "icon. The pan rectangle moves with the pointer and the", 1079 "image window is updated to reflect the location of the", 1080 "rectangle within the panning icon. When you have selected", 1081 "the area of the image you wish to view, release the button.", 1082 "", 1083 "Use the arrow keys to pan the image one pixel up, down,", 1084 "left, or right within the image window.", 1085 "", 1086 "The panning icon is withdrawn if the image becomes smaller", 1087 "than the dimensions of the X server screen.", 1088 (char *) NULL, 1089 }, 1090 *ImagePasteHelp[] = 1091 { 1092 "A small window appears showing the location of the cursor in", 1093 "the image window. You are now in paste mode. To exit", 1094 "immediately, press Dismiss. In paste mode, the Command", 1095 "widget has these options:", 1096 "", 1097 " Operators", 1098 " over", 1099 " in", 1100 " out", 1101 " atop", 1102 " xor", 1103 " plus", 1104 " minus", 1105 " add", 1106 " subtract", 1107 " difference", 1108 " replace", 1109 " Help", 1110 " Dismiss", 1111 "", 1112 "Choose a composite operation from the Operators sub-menu of", 1113 "the Command widget. How each operator behaves is described", 1114 "below. Image window is the image currently displayed on", 1115 "your X server and image is the image obtained with the File", 1116 "Browser widget.", 1117 "", 1118 "Over The result is the union of the two image shapes,", 1119 " with image obscuring image window in the region of", 1120 " overlap.", 1121 "", 1122 "In The result is simply image cut by the shape of", 1123 " image window. None of the image data of image", 1124 " window is in the result.", 1125 "", 1126 "Out The resulting image is image with the shape of", 1127 " image window cut out.", 1128 "", 1129 "Atop The result is the same shape as image image window,", 1130 " with image obscuring image window where the image", 1131 " shapes overlap. Note this differs from over", 1132 " because the portion of image outside image window's", 1133 " shape does not appear in the result.", 1134 "", 1135 "Xor The result is the image data from both image and", 1136 " image window that is outside the overlap region.", 1137 " The overlap region is blank.", 1138 "", 1139 "Plus The result is just the sum of the image data.", 1140 " Output values are cropped to QuantumRange (no overflow).", 1141 " This operation is independent of the matte", 1142 " channels.", 1143 "", 1144 "Minus The result of image - image window, with underflow", 1145 " cropped to zero.", 1146 "", 1147 "Add The result of image + image window, with overflow", 1148 " wrapping around (mod 256).", 1149 "", 1150 "Subtract The result of image - image window, with underflow", 1151 " wrapping around (mod 256). The add and subtract", 1152 " operators can be used to perform reversible", 1153 " transformations.", 1154 "", 1155 "Difference", 1156 " The result of abs(image - image window). This", 1157 " useful for comparing two very similar images.", 1158 "", 1159 "Copy The resulting image is image window replaced with", 1160 " image. Here the matte information is ignored.", 1161 "", 1162 "CopyRed The red layer of the image window is replace with", 1163 " the red layer of the image. The other layers are", 1164 " untouched.", 1165 "", 1166 "CopyGreen", 1167 " The green layer of the image window is replace with", 1168 " the green layer of the image. The other layers are", 1169 " untouched.", 1170 "", 1171 "CopyBlue The blue layer of the image window is replace with", 1172 " the blue layer of the image. The other layers are", 1173 " untouched.", 1174 "", 1175 "CopyOpacity", 1176 " The matte layer of the image window is replace with", 1177 " the matte layer of the image. The other layers are", 1178 " untouched.", 1179 "", 1180 "The image compositor requires a matte, or alpha channel in", 1181 "the image for some operations. This extra channel usually", 1182 "defines a mask which represents a sort of a cookie-cutter", 1183 "for the image. This the case when matte is opaque (full", 1184 "coverage) for pixels inside the shape, zero outside, and", 1185 "between 0 and QuantumRange on the boundary. If image does not", 1186 "have a matte channel, it is initialized with 0 for any pixel", 1187 "matching in color to pixel location (0,0), otherwise QuantumRange.", 1188 "", 1189 "Note that matte information for image window is not retained", 1190 "for colormapped X server visuals (e.g. StaticColor,", 1191 "StaticColor, GrayScale, PseudoColor). Correct compositing", 1192 "behavior may require a TrueColor or DirectColor visual or a", 1193 "Standard Colormap.", 1194 "", 1195 "Choosing a composite operator is optional. The default", 1196 "operator is replace. However, you must choose a location to", 1197 "paste your image and press button 1. Press and hold the", 1198 "button before releasing and an outline of the image will", 1199 "appear to help you identify your location.", 1200 "", 1201 "The actual colors of the pasted image is saved. However,", 1202 "the color that appears in image window may be different.", 1203 "For example, on a monochrome screen image window will appear", 1204 "black or white even though your pasted image may have", 1205 "many colors. If the image is saved to a file it is written", 1206 "with the correct colors. To assure the correct colors are", 1207 "saved in the final image, any PseudoClass image is promoted", 1208 "to DirectClass (see miff(5)). To force a PseudoClass image", 1209 "to remain PseudoClass, use -colors.", 1210 (char *) NULL, 1211 }, 1212 *ImageROIHelp[] = 1213 { 1214 "In region of interest mode, the Command widget has these", 1215 "options:", 1216 "", 1217 " Help", 1218 " Dismiss", 1219 "", 1220 "To define a region of interest, press button 1 and drag.", 1221 "The region of interest is defined by a highlighted rectangle", 1222 "that expands or contracts as it follows the pointer. Once", 1223 "you are satisfied with the region of interest, release the", 1224 "button. You are now in apply mode. In apply mode the", 1225 "Command widget has these options:", 1226 "", 1227 " File", 1228 " Save...", 1229 " Print...", 1230 " Edit", 1231 " Undo", 1232 " Redo", 1233 " Transform", 1234 " Flop", 1235 " Flip", 1236 " Rotate Right", 1237 " Rotate Left", 1238 " Enhance", 1239 " Hue...", 1240 " Saturation...", 1241 " Brightness...", 1242 " Gamma...", 1243 " Spiff", 1244 " Dull", 1245 " Contrast Stretch", 1246 " Sigmoidal Contrast...", 1247 " Normalize", 1248 " Equalize", 1249 " Negate", 1250 " Grayscale", 1251 " Map...", 1252 " Quantize...", 1253 " Effects", 1254 " Despeckle", 1255 " Emboss", 1256 " Reduce Noise", 1257 " Sharpen...", 1258 " Blur...", 1259 " Threshold...", 1260 " Edge Detect...", 1261 " Spread...", 1262 " Shade...", 1263 " Raise...", 1264 " Segment...", 1265 " F/X", 1266 " Solarize...", 1267 " Sepia Tone...", 1268 " Swirl...", 1269 " Implode...", 1270 " Vignette...", 1271 " Wave...", 1272 " Oil Painting...", 1273 " Charcoal Drawing...", 1274 " Miscellany", 1275 " Image Info", 1276 " Zoom Image", 1277 " Show Preview...", 1278 " Show Histogram", 1279 " Show Matte", 1280 " Help", 1281 " Dismiss", 1282 "", 1283 "You can make adjustments to the region of interest by moving", 1284 "the pointer to one of the rectangle corners, pressing a", 1285 "button, and dragging. Finally, choose an image processing", 1286 "technique from the Command widget. You can choose more than", 1287 "one image processing technique to apply to an area.", 1288 "Alternatively, you can move the region of interest before", 1289 "applying another image processing technique. To exit, press", 1290 "Dismiss.", 1291 (char *) NULL, 1292 }, 1293 *ImageRotateHelp[] = 1294 { 1295 "In rotate mode, the Command widget has these options:", 1296 "", 1297 " Pixel Color", 1298 " black", 1299 " blue", 1300 " cyan", 1301 " green", 1302 " gray", 1303 " red", 1304 " magenta", 1305 " yellow", 1306 " white", 1307 " Browser...", 1308 " Direction", 1309 " horizontal", 1310 " vertical", 1311 " Help", 1312 " Dismiss", 1313 "", 1314 "Choose a background color from the Pixel Color sub-menu.", 1315 "Additional background colors can be specified with the color", 1316 "browser. You can change the menu colors by setting the X", 1317 "resources pen1 through pen9.", 1318 "", 1319 "If you choose the color browser and press Grab, you can", 1320 "select the background color by moving the pointer to the", 1321 "desired color on the screen and press any button.", 1322 "", 1323 "Choose a point in the image window and press this button and", 1324 "hold. Next, move the pointer to another location in the", 1325 "image. As you move a line connects the initial location and", 1326 "the pointer. When you release the button, the degree of", 1327 "image rotation is determined by the slope of the line you", 1328 "just drew. The slope is relative to the direction you", 1329 "choose from the Direction sub-menu of the Command widget.", 1330 "", 1331 "To cancel the image rotation, move the pointer back to the", 1332 "starting point of the line and release the button.", 1333 (char *) NULL, 1334 }; 1335 1336/* 1337 Enumeration declarations. 1338*/ 1339typedef enum 1340{ 1341 CopyMode, 1342 CropMode, 1343 CutMode 1344} ClipboardMode; 1345 1346typedef enum 1347{ 1348 OpenCommand, 1349 NextCommand, 1350 FormerCommand, 1351 SelectCommand, 1352 SaveCommand, 1353 PrintCommand, 1354 DeleteCommand, 1355 NewCommand, 1356 VisualDirectoryCommand, 1357 QuitCommand, 1358 UndoCommand, 1359 RedoCommand, 1360 CutCommand, 1361 CopyCommand, 1362 PasteCommand, 1363 HalfSizeCommand, 1364 OriginalSizeCommand, 1365 DoubleSizeCommand, 1366 ResizeCommand, 1367 ApplyCommand, 1368 RefreshCommand, 1369 RestoreCommand, 1370 CropCommand, 1371 ChopCommand, 1372 FlopCommand, 1373 FlipCommand, 1374 RotateRightCommand, 1375 RotateLeftCommand, 1376 RotateCommand, 1377 ShearCommand, 1378 RollCommand, 1379 TrimCommand, 1380 HueCommand, 1381 SaturationCommand, 1382 BrightnessCommand, 1383 GammaCommand, 1384 SpiffCommand, 1385 DullCommand, 1386 ContrastStretchCommand, 1387 SigmoidalContrastCommand, 1388 NormalizeCommand, 1389 EqualizeCommand, 1390 NegateCommand, 1391 GrayscaleCommand, 1392 MapCommand, 1393 QuantizeCommand, 1394 DespeckleCommand, 1395 EmbossCommand, 1396 ReduceNoiseCommand, 1397 AddNoiseCommand, 1398 SharpenCommand, 1399 BlurCommand, 1400 ThresholdCommand, 1401 EdgeDetectCommand, 1402 SpreadCommand, 1403 ShadeCommand, 1404 RaiseCommand, 1405 SegmentCommand, 1406 SolarizeCommand, 1407 SepiaToneCommand, 1408 SwirlCommand, 1409 ImplodeCommand, 1410 VignetteCommand, 1411 WaveCommand, 1412 OilPaintCommand, 1413 CharcoalDrawCommand, 1414 AnnotateCommand, 1415 DrawCommand, 1416 ColorCommand, 1417 MatteCommand, 1418 CompositeCommand, 1419 AddBorderCommand, 1420 AddFrameCommand, 1421 CommentCommand, 1422 LaunchCommand, 1423 RegionofInterestCommand, 1424 ROIHelpCommand, 1425 ROIDismissCommand, 1426 InfoCommand, 1427 ZoomCommand, 1428 ShowPreviewCommand, 1429 ShowHistogramCommand, 1430 ShowMatteCommand, 1431 BackgroundCommand, 1432 SlideShowCommand, 1433 PreferencesCommand, 1434 HelpCommand, 1435 BrowseDocumentationCommand, 1436 VersionCommand, 1437 SaveToUndoBufferCommand, 1438 FreeBuffersCommand, 1439 NullCommand 1440} CommandType; 1441 1442typedef enum 1443{ 1444 AnnotateNameCommand, 1445 AnnotateFontColorCommand, 1446 AnnotateBackgroundColorCommand, 1447 AnnotateRotateCommand, 1448 AnnotateHelpCommand, 1449 AnnotateDismissCommand, 1450 TextHelpCommand, 1451 TextApplyCommand, 1452 ChopDirectionCommand, 1453 ChopHelpCommand, 1454 ChopDismissCommand, 1455 HorizontalChopCommand, 1456 VerticalChopCommand, 1457 ColorEditMethodCommand, 1458 ColorEditColorCommand, 1459 ColorEditBorderCommand, 1460 ColorEditFuzzCommand, 1461 ColorEditUndoCommand, 1462 ColorEditHelpCommand, 1463 ColorEditDismissCommand, 1464 CompositeOperatorsCommand, 1465 CompositeDissolveCommand, 1466 CompositeDisplaceCommand, 1467 CompositeHelpCommand, 1468 CompositeDismissCommand, 1469 CropHelpCommand, 1470 CropDismissCommand, 1471 RectifyCopyCommand, 1472 RectifyHelpCommand, 1473 RectifyDismissCommand, 1474 DrawElementCommand, 1475 DrawColorCommand, 1476 DrawStippleCommand, 1477 DrawWidthCommand, 1478 DrawUndoCommand, 1479 DrawHelpCommand, 1480 DrawDismissCommand, 1481 MatteEditMethod, 1482 MatteEditBorderCommand, 1483 MatteEditFuzzCommand, 1484 MatteEditValueCommand, 1485 MatteEditUndoCommand, 1486 MatteEditHelpCommand, 1487 MatteEditDismissCommand, 1488 PasteOperatorsCommand, 1489 PasteHelpCommand, 1490 PasteDismissCommand, 1491 RotateColorCommand, 1492 RotateDirectionCommand, 1493 RotateCropCommand, 1494 RotateSharpenCommand, 1495 RotateHelpCommand, 1496 RotateDismissCommand, 1497 HorizontalRotateCommand, 1498 VerticalRotateCommand, 1499 TileLoadCommand, 1500 TileNextCommand, 1501 TileFormerCommand, 1502 TileDeleteCommand, 1503 TileUpdateCommand 1504} ModeType; 1505 1506/* 1507 Stipples. 1508*/ 1509#define BricksWidth 20 1510#define BricksHeight 20 1511#define DiagonalWidth 16 1512#define DiagonalHeight 16 1513#define HighlightWidth 8 1514#define HighlightHeight 8 1515#define OpaqueWidth 8 1516#define OpaqueHeight 8 1517#define ScalesWidth 16 1518#define ScalesHeight 16 1519#define ShadowWidth 8 1520#define ShadowHeight 8 1521#define VerticalWidth 16 1522#define VerticalHeight 16 1523#define WavyWidth 16 1524#define WavyHeight 16 1525 1526/* 1527 Constant declaration. 1528*/ 1529static const int 1530 RoiDelta = 8; 1531 1532static const unsigned char 1533 BricksBitmap[] = 1534 { 1535 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 1536 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 1537 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 1538 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 1539 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01 1540 }, 1541 DiagonalBitmap[] = 1542 { 1543 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 1544 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 1545 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22 1546 }, 1547 ScalesBitmap[] = 1548 { 1549 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80, 1550 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 1551 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e 1552 }, 1553 VerticalBitmap[] = 1554 { 1555 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1556 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1557 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 1558 }, 1559 WavyBitmap[] = 1560 { 1561 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff, 1562 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf, 1563 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f 1564 }; 1565 1566/* 1567 Function prototypes. 1568*/ 1569static CommandType 1570 XImageWindowCommand(Display *,XResourceInfo *,XWindows *, 1571 const MagickStatusType,KeySym,Image **,ExceptionInfo *); 1572 1573static Image 1574 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType, 1575 Image **,ExceptionInfo *), 1576 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType), 1577 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *, 1578 ExceptionInfo *), 1579 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *, 1580 ExceptionInfo *); 1581 1582static MagickBooleanType 1583 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *, 1584 ExceptionInfo *), 1585 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **, 1586 ExceptionInfo *), 1587 XChopImage(Display *,XResourceInfo *,XWindows *,Image **, 1588 ExceptionInfo *), 1589 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode, 1590 ExceptionInfo *), 1591 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1592 ExceptionInfo *), 1593 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *, 1594 ExceptionInfo *), 1595 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1596 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1597 ExceptionInfo *), 1598 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1599 ExceptionInfo *), 1600 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1601 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1602 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **, 1603 ExceptionInfo *), 1604 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *), 1605 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1606 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *); 1607 1608static void 1609 XDrawPanRectangle(Display *,XWindows *), 1610 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **, 1611 ExceptionInfo *), 1612 XMagnifyImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1613 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1614 XPanImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1615 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType, 1616 const KeySym,ExceptionInfo *), 1617 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *), 1618 XScreenEvent(Display *,XWindows *,XEvent *,ExceptionInfo *), 1619 XTranslateImage(Display *,XWindows *,Image *,const KeySym); 1620 1621/* 1622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1623% % 1624% % 1625% % 1626% D i s p l a y I m a g e s % 1627% % 1628% % 1629% % 1630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1631% 1632% DisplayImages() displays an image sequence to any X window screen. It 1633% returns a value other than 0 if successful. Check the exception member 1634% of image to determine the reason for any failure. 1635% 1636% The format of the DisplayImages method is: 1637% 1638% MagickBooleanType DisplayImages(const ImageInfo *image_info, 1639% Image *images,ExceptionInfo *exception) 1640% 1641% A description of each parameter follows: 1642% 1643% o image_info: the image info. 1644% 1645% o image: the image. 1646% 1647% o exception: return any errors or warnings in this structure. 1648% 1649*/ 1650MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 1651 Image *images,ExceptionInfo *exception) 1652{ 1653 char 1654 *argv[1]; 1655 1656 Display 1657 *display; 1658 1659 Image 1660 *image; 1661 1662 register ssize_t 1663 i; 1664 1665 size_t 1666 state; 1667 1668 XrmDatabase 1669 resource_database; 1670 1671 XResourceInfo 1672 resource_info; 1673 1674 assert(image_info != (const ImageInfo *) NULL); 1675 assert(image_info->signature == MagickSignature); 1676 assert(images != (Image *) NULL); 1677 assert(images->signature == MagickSignature); 1678 if( IfMagickTrue(images->debug) ) 1679 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 1680 display=XOpenDisplay(image_info->server_name); 1681 if (display == (Display *) NULL) 1682 { 1683 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1684 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1685 return(MagickFalse); 1686 } 1687 if (exception->severity != UndefinedException) 1688 CatchException(exception); 1689 (void) XSetErrorHandler(XError); 1690 resource_database=XGetResourceDatabase(display,GetClientName()); 1691 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info)); 1692 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info); 1693 if (image_info->page != (char *) NULL) 1694 resource_info.image_geometry=AcquireString(image_info->page); 1695 resource_info.immutable=MagickTrue; 1696 argv[0]=AcquireString(GetClientName()); 1697 state=DefaultState; 1698 for (i=0; (state & ExitState) == 0; i++) 1699 { 1700 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations)) 1701 break; 1702 image=GetImageFromList(images,i % GetImageListLength(images)); 1703 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception); 1704 } 1705 (void) SetErrorHandler((ErrorHandler) NULL); 1706 (void) SetWarningHandler((WarningHandler) NULL); 1707 argv[0]=DestroyString(argv[0]); 1708 (void) XCloseDisplay(display); 1709 XDestroyResourceInfo(&resource_info); 1710 if (exception->severity != UndefinedException) 1711 return(MagickFalse); 1712 return(MagickTrue); 1713} 1714 1715/* 1716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1717% % 1718% % 1719% % 1720% R e m o t e D i s p l a y C o m m a n d % 1721% % 1722% % 1723% % 1724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1725% 1726% RemoteDisplayCommand() encourages a remote display program to display the 1727% specified image filename. 1728% 1729% The format of the RemoteDisplayCommand method is: 1730% 1731% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1732% const char *window,const char *filename,ExceptionInfo *exception) 1733% 1734% A description of each parameter follows: 1735% 1736% o image_info: the image info. 1737% 1738% o window: Specifies the name or id of an X window. 1739% 1740% o filename: the name of the image filename to display. 1741% 1742% o exception: return any errors or warnings in this structure. 1743% 1744*/ 1745MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1746 const char *window,const char *filename,ExceptionInfo *exception) 1747{ 1748 Display 1749 *display; 1750 1751 MagickStatusType 1752 status; 1753 1754 assert(image_info != (const ImageInfo *) NULL); 1755 assert(image_info->signature == MagickSignature); 1756 assert(filename != (char *) NULL); 1757 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 1758 display=XOpenDisplay(image_info->server_name); 1759 if (display == (Display *) NULL) 1760 { 1761 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1762 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1763 return(MagickFalse); 1764 } 1765 (void) XSetErrorHandler(XError); 1766 status=XRemoteCommand(display,window,filename); 1767 (void) XCloseDisplay(display); 1768 return(IsMagickTrue(status)); 1769} 1770 1771/* 1772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1773% % 1774% % 1775% % 1776+ X A n n o t a t e E d i t I m a g e % 1777% % 1778% % 1779% % 1780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1781% 1782% XAnnotateEditImage() annotates the image with text. 1783% 1784% The format of the XAnnotateEditImage method is: 1785% 1786% MagickBooleanType XAnnotateEditImage(Display *display, 1787% XResourceInfo *resource_info,XWindows *windows,Image *image, 1788% ExceptionInfo *exception) 1789% 1790% A description of each parameter follows: 1791% 1792% o display: Specifies a connection to an X server; returned from 1793% XOpenDisplay. 1794% 1795% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 1796% 1797% o windows: Specifies a pointer to a XWindows structure. 1798% 1799% o image: the image; returned from ReadImage. 1800% 1801*/ 1802 1803static inline ssize_t MagickMax(const ssize_t x,const ssize_t y) 1804{ 1805 if (x > y) 1806 return(x); 1807 return(y); 1808} 1809 1810static inline ssize_t MagickMin(const ssize_t x,const ssize_t y) 1811{ 1812 if (x < y) 1813 return(x); 1814 return(y); 1815} 1816 1817static MagickBooleanType XAnnotateEditImage(Display *display, 1818 XResourceInfo *resource_info,XWindows *windows,Image *image, 1819 ExceptionInfo *exception) 1820{ 1821 static const char 1822 *AnnotateMenu[] = 1823 { 1824 "Font Name", 1825 "Font Color", 1826 "Box Color", 1827 "Rotate Text", 1828 "Help", 1829 "Dismiss", 1830 (char *) NULL 1831 }, 1832 *TextMenu[] = 1833 { 1834 "Help", 1835 "Apply", 1836 (char *) NULL 1837 }; 1838 1839 static const ModeType 1840 AnnotateCommands[] = 1841 { 1842 AnnotateNameCommand, 1843 AnnotateFontColorCommand, 1844 AnnotateBackgroundColorCommand, 1845 AnnotateRotateCommand, 1846 AnnotateHelpCommand, 1847 AnnotateDismissCommand 1848 }, 1849 TextCommands[] = 1850 { 1851 TextHelpCommand, 1852 TextApplyCommand 1853 }; 1854 1855 static MagickBooleanType 1856 transparent_box = MagickTrue, 1857 transparent_pen = MagickFalse; 1858 1859 static double 1860 degrees = 0.0; 1861 1862 static unsigned int 1863 box_id = MaxNumberPens-2, 1864 font_id = 0, 1865 pen_id = 0; 1866 1867 char 1868 command[MaxTextExtent], 1869 text[MaxTextExtent]; 1870 1871 const char 1872 *ColorMenu[MaxNumberPens+1]; 1873 1874 Cursor 1875 cursor; 1876 1877 GC 1878 annotate_context; 1879 1880 int 1881 id, 1882 pen_number, 1883 status, 1884 x, 1885 y; 1886 1887 KeySym 1888 key_symbol; 1889 1890 register char 1891 *p; 1892 1893 register ssize_t 1894 i; 1895 1896 unsigned int 1897 height, 1898 width; 1899 1900 size_t 1901 state; 1902 1903 XAnnotateInfo 1904 *annotate_info, 1905 *previous_info; 1906 1907 XColor 1908 color; 1909 1910 XFontStruct 1911 *font_info; 1912 1913 XEvent 1914 event, 1915 text_event; 1916 1917 /* 1918 Map Command widget. 1919 */ 1920 (void) CloneString(&windows->command.name,"Annotate"); 1921 windows->command.data=4; 1922 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL); 1923 (void) XMapRaised(display,windows->command.id); 1924 XClientMessage(display,windows->image.id,windows->im_protocols, 1925 windows->im_update_widget,CurrentTime); 1926 /* 1927 Track pointer until button 1 is pressed. 1928 */ 1929 XQueryPosition(display,windows->image.id,&x,&y); 1930 (void) XSelectInput(display,windows->image.id, 1931 windows->image.attributes.event_mask | PointerMotionMask); 1932 cursor=XCreateFontCursor(display,XC_left_side); 1933 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1934 state=DefaultState; 1935 do 1936 { 1937 if( IfMagickTrue(windows->info.mapped) ) 1938 { 1939 /* 1940 Display pointer position. 1941 */ 1942 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 1943 x+windows->image.x,y+windows->image.y); 1944 XInfoWidget(display,windows,text); 1945 } 1946 /* 1947 Wait for next event. 1948 */ 1949 XScreenEvent(display,windows,&event,exception); 1950 if (event.xany.window == windows->command.id) 1951 { 1952 /* 1953 Select a command from the Command widget. 1954 */ 1955 id=XCommandWidget(display,windows,AnnotateMenu,&event); 1956 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1957 if (id < 0) 1958 continue; 1959 switch (AnnotateCommands[id]) 1960 { 1961 case AnnotateNameCommand: 1962 { 1963 const char 1964 *FontMenu[MaxNumberFonts]; 1965 1966 int 1967 font_number; 1968 1969 /* 1970 Initialize menu selections. 1971 */ 1972 for (i=0; i < MaxNumberFonts; i++) 1973 FontMenu[i]=resource_info->font_name[i]; 1974 FontMenu[MaxNumberFonts-2]="Browser..."; 1975 FontMenu[MaxNumberFonts-1]=(const char *) NULL; 1976 /* 1977 Select a font name from the pop-up menu. 1978 */ 1979 font_number=XMenuWidget(display,windows,AnnotateMenu[id], 1980 (const char **) FontMenu,command); 1981 if (font_number < 0) 1982 break; 1983 if (font_number == (MaxNumberFonts-2)) 1984 { 1985 static char 1986 font_name[MaxTextExtent] = "fixed"; 1987 1988 /* 1989 Select a font name from a browser. 1990 */ 1991 resource_info->font_name[font_number]=font_name; 1992 XFontBrowserWidget(display,windows,"Select",font_name); 1993 if (*font_name == '\0') 1994 break; 1995 } 1996 /* 1997 Initialize font info. 1998 */ 1999 font_info=XLoadQueryFont(display,resource_info->font_name[ 2000 font_number]); 2001 if (font_info == (XFontStruct *) NULL) 2002 { 2003 XNoticeWidget(display,windows,"Unable to load font:", 2004 resource_info->font_name[font_number]); 2005 break; 2006 } 2007 font_id=(unsigned int) font_number; 2008 (void) XFreeFont(display,font_info); 2009 break; 2010 } 2011 case AnnotateFontColorCommand: 2012 { 2013 /* 2014 Initialize menu selections. 2015 */ 2016 for (i=0; i < (int) (MaxNumberPens-2); i++) 2017 ColorMenu[i]=resource_info->pen_colors[i]; 2018 ColorMenu[MaxNumberPens-2]="transparent"; 2019 ColorMenu[MaxNumberPens-1]="Browser..."; 2020 ColorMenu[MaxNumberPens]=(const char *) NULL; 2021 /* 2022 Select a pen color from the pop-up menu. 2023 */ 2024 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2025 (const char **) ColorMenu,command); 2026 if (pen_number < 0) 2027 break; 2028 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue : 2029 MagickFalse; 2030 if( IfMagickTrue(transparent_pen) ) 2031 break; 2032 if (pen_number == (MaxNumberPens-1)) 2033 { 2034 static char 2035 color_name[MaxTextExtent] = "gray"; 2036 2037 /* 2038 Select a pen color from a dialog. 2039 */ 2040 resource_info->pen_colors[pen_number]=color_name; 2041 XColorBrowserWidget(display,windows,"Select",color_name); 2042 if (*color_name == '\0') 2043 break; 2044 } 2045 /* 2046 Set pen color. 2047 */ 2048 (void) XParseColor(display,windows->map_info->colormap, 2049 resource_info->pen_colors[pen_number],&color); 2050 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2051 (unsigned int) MaxColors,&color); 2052 windows->pixel_info->pen_colors[pen_number]=color; 2053 pen_id=(unsigned int) pen_number; 2054 break; 2055 } 2056 case AnnotateBackgroundColorCommand: 2057 { 2058 /* 2059 Initialize menu selections. 2060 */ 2061 for (i=0; i < (int) (MaxNumberPens-2); i++) 2062 ColorMenu[i]=resource_info->pen_colors[i]; 2063 ColorMenu[MaxNumberPens-2]="transparent"; 2064 ColorMenu[MaxNumberPens-1]="Browser..."; 2065 ColorMenu[MaxNumberPens]=(const char *) NULL; 2066 /* 2067 Select a pen color from the pop-up menu. 2068 */ 2069 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2070 (const char **) ColorMenu,command); 2071 if (pen_number < 0) 2072 break; 2073 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue : 2074 MagickFalse; 2075 if( IfMagickTrue(transparent_box) ) 2076 break; 2077 if (pen_number == (MaxNumberPens-1)) 2078 { 2079 static char 2080 color_name[MaxTextExtent] = "gray"; 2081 2082 /* 2083 Select a pen color from a dialog. 2084 */ 2085 resource_info->pen_colors[pen_number]=color_name; 2086 XColorBrowserWidget(display,windows,"Select",color_name); 2087 if (*color_name == '\0') 2088 break; 2089 } 2090 /* 2091 Set pen color. 2092 */ 2093 (void) XParseColor(display,windows->map_info->colormap, 2094 resource_info->pen_colors[pen_number],&color); 2095 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2096 (unsigned int) MaxColors,&color); 2097 windows->pixel_info->pen_colors[pen_number]=color; 2098 box_id=(unsigned int) pen_number; 2099 break; 2100 } 2101 case AnnotateRotateCommand: 2102 { 2103 int 2104 entry; 2105 2106 static char 2107 angle[MaxTextExtent] = "30.0"; 2108 2109 static const char 2110 *RotateMenu[] = 2111 { 2112 "-90", 2113 "-45", 2114 "-30", 2115 "0", 2116 "30", 2117 "45", 2118 "90", 2119 "180", 2120 "Dialog...", 2121 (char *) NULL, 2122 }; 2123 2124 /* 2125 Select a command from the pop-up menu. 2126 */ 2127 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu, 2128 command); 2129 if (entry < 0) 2130 break; 2131 if (entry != 8) 2132 { 2133 degrees=StringToDouble(RotateMenu[entry],(char **) NULL); 2134 break; 2135 } 2136 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:", 2137 angle); 2138 if (*angle == '\0') 2139 break; 2140 degrees=StringToDouble(angle,(char **) NULL); 2141 break; 2142 } 2143 case AnnotateHelpCommand: 2144 { 2145 XTextViewWidget(display,resource_info,windows,MagickFalse, 2146 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2147 break; 2148 } 2149 case AnnotateDismissCommand: 2150 { 2151 /* 2152 Prematurely exit. 2153 */ 2154 state|=EscapeState; 2155 state|=ExitState; 2156 break; 2157 } 2158 default: 2159 break; 2160 } 2161 continue; 2162 } 2163 switch (event.type) 2164 { 2165 case ButtonPress: 2166 { 2167 if (event.xbutton.button != Button1) 2168 break; 2169 if (event.xbutton.window != windows->image.id) 2170 break; 2171 /* 2172 Change to text entering mode. 2173 */ 2174 x=event.xbutton.x; 2175 y=event.xbutton.y; 2176 state|=ExitState; 2177 break; 2178 } 2179 case ButtonRelease: 2180 break; 2181 case Expose: 2182 break; 2183 case KeyPress: 2184 { 2185 if (event.xkey.window != windows->image.id) 2186 break; 2187 /* 2188 Respond to a user key press. 2189 */ 2190 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2191 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2192 switch ((int) key_symbol) 2193 { 2194 case XK_Escape: 2195 case XK_F20: 2196 { 2197 /* 2198 Prematurely exit. 2199 */ 2200 state|=EscapeState; 2201 state|=ExitState; 2202 break; 2203 } 2204 case XK_F1: 2205 case XK_Help: 2206 { 2207 XTextViewWidget(display,resource_info,windows,MagickFalse, 2208 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2209 break; 2210 } 2211 default: 2212 { 2213 (void) XBell(display,0); 2214 break; 2215 } 2216 } 2217 break; 2218 } 2219 case MotionNotify: 2220 { 2221 /* 2222 Map and unmap Info widget as cursor crosses its boundaries. 2223 */ 2224 x=event.xmotion.x; 2225 y=event.xmotion.y; 2226 if( IfMagickTrue(windows->info.mapped) ) 2227 { 2228 if ((x < (int) (windows->info.x+windows->info.width)) && 2229 (y < (int) (windows->info.y+windows->info.height))) 2230 (void) XWithdrawWindow(display,windows->info.id, 2231 windows->info.screen); 2232 } 2233 else 2234 if ((x > (int) (windows->info.x+windows->info.width)) || 2235 (y > (int) (windows->info.y+windows->info.height))) 2236 (void) XMapWindow(display,windows->info.id); 2237 break; 2238 } 2239 default: 2240 break; 2241 } 2242 } while ((state & ExitState) == 0); 2243 (void) XSelectInput(display,windows->image.id, 2244 windows->image.attributes.event_mask); 2245 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 2246 if ((state & EscapeState) != 0) 2247 return(MagickTrue); 2248 /* 2249 Set font info and check boundary conditions. 2250 */ 2251 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]); 2252 if (font_info == (XFontStruct *) NULL) 2253 { 2254 XNoticeWidget(display,windows,"Unable to load font:", 2255 resource_info->font_name[font_id]); 2256 font_info=windows->font_info; 2257 } 2258 if ((x+font_info->max_bounds.width) >= (int) windows->image.width) 2259 x=(int) windows->image.width-font_info->max_bounds.width; 2260 if (y < (int) (font_info->ascent+font_info->descent)) 2261 y=(int) font_info->ascent+font_info->descent; 2262 if (((int) font_info->max_bounds.width > (int) windows->image.width) || 2263 ((font_info->ascent+font_info->descent) >= (int) windows->image.height)) 2264 return(MagickFalse); 2265 /* 2266 Initialize annotate structure. 2267 */ 2268 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info)); 2269 if (annotate_info == (XAnnotateInfo *) NULL) 2270 return(MagickFalse); 2271 XGetAnnotateInfo(annotate_info); 2272 annotate_info->x=x; 2273 annotate_info->y=y; 2274 if( IfMagickFalse(transparent_box) && IfMagickFalse(transparent_pen)) 2275 annotate_info->stencil=OpaqueStencil; 2276 else 2277 if( IfMagickFalse(transparent_box) ) 2278 annotate_info->stencil=BackgroundStencil; 2279 else 2280 annotate_info->stencil=ForegroundStencil; 2281 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent; 2282 annotate_info->degrees=degrees; 2283 annotate_info->font_info=font_info; 2284 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2285 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL, 2286 sizeof(*annotate_info->text)); 2287 if (annotate_info->text == (char *) NULL) 2288 return(MagickFalse); 2289 /* 2290 Create cursor and set graphic context. 2291 */ 2292 cursor=XCreateFontCursor(display,XC_pencil); 2293 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2294 annotate_context=windows->image.annotate_context; 2295 (void) XSetFont(display,annotate_context,font_info->fid); 2296 (void) XSetBackground(display,annotate_context, 2297 windows->pixel_info->pen_colors[box_id].pixel); 2298 (void) XSetForeground(display,annotate_context, 2299 windows->pixel_info->pen_colors[pen_id].pixel); 2300 /* 2301 Begin annotating the image with text. 2302 */ 2303 (void) CloneString(&windows->command.name,"Text"); 2304 windows->command.data=0; 2305 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL); 2306 state=DefaultState; 2307 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2308 text_event.xexpose.width=(int) font_info->max_bounds.width; 2309 text_event.xexpose.height=font_info->max_bounds.ascent+ 2310 font_info->max_bounds.descent; 2311 p=annotate_info->text; 2312 do 2313 { 2314 /* 2315 Display text cursor. 2316 */ 2317 *p='\0'; 2318 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2319 /* 2320 Wait for next event. 2321 */ 2322 XScreenEvent(display,windows,&event,exception); 2323 if (event.xany.window == windows->command.id) 2324 { 2325 /* 2326 Select a command from the Command widget. 2327 */ 2328 (void) XSetBackground(display,annotate_context, 2329 windows->pixel_info->background_color.pixel); 2330 (void) XSetForeground(display,annotate_context, 2331 windows->pixel_info->foreground_color.pixel); 2332 id=XCommandWidget(display,windows,AnnotateMenu,&event); 2333 (void) XSetBackground(display,annotate_context, 2334 windows->pixel_info->pen_colors[box_id].pixel); 2335 (void) XSetForeground(display,annotate_context, 2336 windows->pixel_info->pen_colors[pen_id].pixel); 2337 if (id < 0) 2338 continue; 2339 switch (TextCommands[id]) 2340 { 2341 case TextHelpCommand: 2342 { 2343 XTextViewWidget(display,resource_info,windows,MagickFalse, 2344 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2345 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2346 break; 2347 } 2348 case TextApplyCommand: 2349 { 2350 /* 2351 Finished annotating. 2352 */ 2353 annotate_info->width=(unsigned int) XTextWidth(font_info, 2354 annotate_info->text,(int) strlen(annotate_info->text)); 2355 XRefreshWindow(display,&windows->image,&text_event); 2356 state|=ExitState; 2357 break; 2358 } 2359 default: 2360 break; 2361 } 2362 continue; 2363 } 2364 /* 2365 Erase text cursor. 2366 */ 2367 text_event.xexpose.x=x; 2368 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2369 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y, 2370 (unsigned int) text_event.xexpose.width,(unsigned int) 2371 text_event.xexpose.height,MagickFalse); 2372 XRefreshWindow(display,&windows->image,&text_event); 2373 switch (event.type) 2374 { 2375 case ButtonPress: 2376 { 2377 if (event.xbutton.window != windows->image.id) 2378 break; 2379 if (event.xbutton.button == Button2) 2380 { 2381 /* 2382 Request primary selection. 2383 */ 2384 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, 2385 windows->image.id,CurrentTime); 2386 break; 2387 } 2388 break; 2389 } 2390 case Expose: 2391 { 2392 if (event.xexpose.count == 0) 2393 { 2394 XAnnotateInfo 2395 *text_info; 2396 2397 /* 2398 Refresh Image window. 2399 */ 2400 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 2401 text_info=annotate_info; 2402 while (text_info != (XAnnotateInfo *) NULL) 2403 { 2404 if (annotate_info->stencil == ForegroundStencil) 2405 (void) XDrawString(display,windows->image.id,annotate_context, 2406 text_info->x,text_info->y,text_info->text, 2407 (int) strlen(text_info->text)); 2408 else 2409 (void) XDrawImageString(display,windows->image.id, 2410 annotate_context,text_info->x,text_info->y,text_info->text, 2411 (int) strlen(text_info->text)); 2412 text_info=text_info->previous; 2413 } 2414 (void) XDrawString(display,windows->image.id,annotate_context, 2415 x,y,"_",1); 2416 } 2417 break; 2418 } 2419 case KeyPress: 2420 { 2421 int 2422 length; 2423 2424 if (event.xkey.window != windows->image.id) 2425 break; 2426 /* 2427 Respond to a user key press. 2428 */ 2429 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 2430 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2431 *(command+length)='\0'; 2432 if (((event.xkey.state & ControlMask) != 0) || 2433 ((event.xkey.state & Mod1Mask) != 0)) 2434 state|=ModifierState; 2435 if ((state & ModifierState) != 0) 2436 switch ((int) key_symbol) 2437 { 2438 case XK_u: 2439 case XK_U: 2440 { 2441 key_symbol=DeleteCommand; 2442 break; 2443 } 2444 default: 2445 break; 2446 } 2447 switch ((int) key_symbol) 2448 { 2449 case XK_BackSpace: 2450 { 2451 /* 2452 Erase one character. 2453 */ 2454 if (p == annotate_info->text) 2455 { 2456 if (annotate_info->previous == (XAnnotateInfo *) NULL) 2457 break; 2458 else 2459 { 2460 /* 2461 Go to end of the previous line of text. 2462 */ 2463 annotate_info=annotate_info->previous; 2464 p=annotate_info->text; 2465 x=annotate_info->x+annotate_info->width; 2466 y=annotate_info->y; 2467 if (annotate_info->width != 0) 2468 p+=strlen(annotate_info->text); 2469 break; 2470 } 2471 } 2472 p--; 2473 x-=XTextWidth(font_info,p,1); 2474 text_event.xexpose.x=x; 2475 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2476 XRefreshWindow(display,&windows->image,&text_event); 2477 break; 2478 } 2479 case XK_bracketleft: 2480 { 2481 key_symbol=XK_Escape; 2482 break; 2483 } 2484 case DeleteCommand: 2485 { 2486 /* 2487 Erase the entire line of text. 2488 */ 2489 while (p != annotate_info->text) 2490 { 2491 p--; 2492 x-=XTextWidth(font_info,p,1); 2493 text_event.xexpose.x=x; 2494 XRefreshWindow(display,&windows->image,&text_event); 2495 } 2496 break; 2497 } 2498 case XK_Escape: 2499 case XK_F20: 2500 { 2501 /* 2502 Finished annotating. 2503 */ 2504 annotate_info->width=(unsigned int) XTextWidth(font_info, 2505 annotate_info->text,(int) strlen(annotate_info->text)); 2506 XRefreshWindow(display,&windows->image,&text_event); 2507 state|=ExitState; 2508 break; 2509 } 2510 default: 2511 { 2512 /* 2513 Draw a single character on the Image window. 2514 */ 2515 if ((state & ModifierState) != 0) 2516 break; 2517 if (*command == '\0') 2518 break; 2519 *p=(*command); 2520 if (annotate_info->stencil == ForegroundStencil) 2521 (void) XDrawString(display,windows->image.id,annotate_context, 2522 x,y,p,1); 2523 else 2524 (void) XDrawImageString(display,windows->image.id, 2525 annotate_context,x,y,p,1); 2526 x+=XTextWidth(font_info,p,1); 2527 p++; 2528 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2529 break; 2530 } 2531 case XK_Return: 2532 case XK_KP_Enter: 2533 { 2534 /* 2535 Advance to the next line of text. 2536 */ 2537 *p='\0'; 2538 annotate_info->width=(unsigned int) XTextWidth(font_info, 2539 annotate_info->text,(int) strlen(annotate_info->text)); 2540 if (annotate_info->next != (XAnnotateInfo *) NULL) 2541 { 2542 /* 2543 Line of text already exists. 2544 */ 2545 annotate_info=annotate_info->next; 2546 x=annotate_info->x; 2547 y=annotate_info->y; 2548 p=annotate_info->text; 2549 break; 2550 } 2551 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2552 sizeof(*annotate_info->next)); 2553 if (annotate_info->next == (XAnnotateInfo *) NULL) 2554 return(MagickFalse); 2555 *annotate_info->next=(*annotate_info); 2556 annotate_info->next->previous=annotate_info; 2557 annotate_info=annotate_info->next; 2558 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2559 windows->image.width/MagickMax((ssize_t) 2560 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2561 if (annotate_info->text == (char *) NULL) 2562 return(MagickFalse); 2563 annotate_info->y+=annotate_info->height; 2564 if (annotate_info->y > (int) windows->image.height) 2565 annotate_info->y=(int) annotate_info->height; 2566 annotate_info->next=(XAnnotateInfo *) NULL; 2567 x=annotate_info->x; 2568 y=annotate_info->y; 2569 p=annotate_info->text; 2570 break; 2571 } 2572 } 2573 break; 2574 } 2575 case KeyRelease: 2576 { 2577 /* 2578 Respond to a user key release. 2579 */ 2580 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2581 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2582 state&=(~ModifierState); 2583 break; 2584 } 2585 case SelectionNotify: 2586 { 2587 Atom 2588 type; 2589 2590 int 2591 format; 2592 2593 unsigned char 2594 *data; 2595 2596 unsigned long 2597 after, 2598 length; 2599 2600 /* 2601 Obtain response from primary selection. 2602 */ 2603 if (event.xselection.property == (Atom) None) 2604 break; 2605 status=XGetWindowProperty(display,event.xselection.requestor, 2606 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING, 2607 &type,&format,&length,&after,&data); 2608 if ((status != Success) || (type != XA_STRING) || (format == 32) || 2609 (length == 0)) 2610 break; 2611 /* 2612 Annotate Image window with primary selection. 2613 */ 2614 for (i=0; i < (ssize_t) length; i++) 2615 { 2616 if ((char) data[i] != '\n') 2617 { 2618 /* 2619 Draw a single character on the Image window. 2620 */ 2621 *p=(char) data[i]; 2622 (void) XDrawString(display,windows->image.id,annotate_context, 2623 x,y,p,1); 2624 x+=XTextWidth(font_info,p,1); 2625 p++; 2626 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2627 continue; 2628 } 2629 /* 2630 Advance to the next line of text. 2631 */ 2632 *p='\0'; 2633 annotate_info->width=(unsigned int) XTextWidth(font_info, 2634 annotate_info->text,(int) strlen(annotate_info->text)); 2635 if (annotate_info->next != (XAnnotateInfo *) NULL) 2636 { 2637 /* 2638 Line of text already exists. 2639 */ 2640 annotate_info=annotate_info->next; 2641 x=annotate_info->x; 2642 y=annotate_info->y; 2643 p=annotate_info->text; 2644 continue; 2645 } 2646 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2647 sizeof(*annotate_info->next)); 2648 if (annotate_info->next == (XAnnotateInfo *) NULL) 2649 return(MagickFalse); 2650 *annotate_info->next=(*annotate_info); 2651 annotate_info->next->previous=annotate_info; 2652 annotate_info=annotate_info->next; 2653 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2654 windows->image.width/MagickMax((ssize_t) 2655 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2656 if (annotate_info->text == (char *) NULL) 2657 return(MagickFalse); 2658 annotate_info->y+=annotate_info->height; 2659 if (annotate_info->y > (int) windows->image.height) 2660 annotate_info->y=(int) annotate_info->height; 2661 annotate_info->next=(XAnnotateInfo *) NULL; 2662 x=annotate_info->x; 2663 y=annotate_info->y; 2664 p=annotate_info->text; 2665 } 2666 (void) XFree((void *) data); 2667 break; 2668 } 2669 default: 2670 break; 2671 } 2672 } while ((state & ExitState) == 0); 2673 (void) XFreeCursor(display,cursor); 2674 /* 2675 Annotation is relative to image configuration. 2676 */ 2677 width=(unsigned int) image->columns; 2678 height=(unsigned int) image->rows; 2679 x=0; 2680 y=0; 2681 if (windows->image.crop_geometry != (char *) NULL) 2682 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 2683 /* 2684 Initialize annotated image. 2685 */ 2686 XSetCursorState(display,windows,MagickTrue); 2687 XCheckRefreshWindows(display,windows); 2688 while (annotate_info != (XAnnotateInfo *) NULL) 2689 { 2690 if (annotate_info->width == 0) 2691 { 2692 /* 2693 No text on this line-- go to the next line of text. 2694 */ 2695 previous_info=annotate_info->previous; 2696 annotate_info->text=(char *) 2697 RelinquishMagickMemory(annotate_info->text); 2698 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2699 annotate_info=previous_info; 2700 continue; 2701 } 2702 /* 2703 Determine pixel index for box and pen color. 2704 */ 2705 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id]; 2706 if (windows->pixel_info->colors != 0) 2707 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2708 if (windows->pixel_info->pixels[i] == 2709 windows->pixel_info->pen_colors[box_id].pixel) 2710 { 2711 windows->pixel_info->box_index=(unsigned short) i; 2712 break; 2713 } 2714 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 2715 if (windows->pixel_info->colors != 0) 2716 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2717 if (windows->pixel_info->pixels[i] == 2718 windows->pixel_info->pen_colors[pen_id].pixel) 2719 { 2720 windows->pixel_info->pen_index=(unsigned short) i; 2721 break; 2722 } 2723 /* 2724 Define the annotate geometry string. 2725 */ 2726 annotate_info->x=(int) 2727 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width; 2728 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+ 2729 windows->image.y)/windows->image.ximage->height; 2730 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent, 2731 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width, 2732 height*annotate_info->height/windows->image.ximage->height, 2733 annotate_info->x+x,annotate_info->y+y); 2734 /* 2735 Annotate image with text. 2736 */ 2737 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image, 2738 exception); 2739 if (status == 0) 2740 return(MagickFalse); 2741 /* 2742 Free up memory. 2743 */ 2744 previous_info=annotate_info->previous; 2745 annotate_info->text=DestroyString(annotate_info->text); 2746 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2747 annotate_info=previous_info; 2748 } 2749 (void) XSetForeground(display,annotate_context, 2750 windows->pixel_info->foreground_color.pixel); 2751 (void) XSetBackground(display,annotate_context, 2752 windows->pixel_info->background_color.pixel); 2753 (void) XSetFont(display,annotate_context,windows->font_info->fid); 2754 XSetCursorState(display,windows,MagickFalse); 2755 (void) XFreeFont(display,font_info); 2756 /* 2757 Update image configuration. 2758 */ 2759 XConfigureImageColormap(display,resource_info,windows,image,exception); 2760 (void) XConfigureImage(display,resource_info,windows,image,exception); 2761 return(MagickTrue); 2762} 2763 2764/* 2765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2766% % 2767% % 2768% % 2769+ X B a c k g r o u n d I m a g e % 2770% % 2771% % 2772% % 2773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2774% 2775% XBackgroundImage() displays the image in the background of a window. 2776% 2777% The format of the XBackgroundImage method is: 2778% 2779% MagickBooleanType XBackgroundImage(Display *display, 2780% XResourceInfo *resource_info,XWindows *windows,Image **image, 2781% ExceptionInfo *exception) 2782% 2783% A description of each parameter follows: 2784% 2785% o display: Specifies a connection to an X server; returned from 2786% XOpenDisplay. 2787% 2788% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2789% 2790% o windows: Specifies a pointer to a XWindows structure. 2791% 2792% o image: the image. 2793% 2794% o exception: return any errors or warnings in this structure. 2795% 2796*/ 2797static MagickBooleanType XBackgroundImage(Display *display, 2798 XResourceInfo *resource_info,XWindows *windows,Image **image, 2799 ExceptionInfo *exception) 2800{ 2801#define BackgroundImageTag "Background/Image" 2802 2803 int 2804 status; 2805 2806 static char 2807 window_id[MaxTextExtent] = "root"; 2808 2809 XResourceInfo 2810 background_resources; 2811 2812 /* 2813 Put image in background. 2814 */ 2815 status=XDialogWidget(display,windows,"Background", 2816 "Enter window id (id 0x00 selects window with pointer):",window_id); 2817 if (*window_id == '\0') 2818 return(MagickFalse); 2819 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 2820 exception); 2821 XInfoWidget(display,windows,BackgroundImageTag); 2822 XSetCursorState(display,windows,MagickTrue); 2823 XCheckRefreshWindows(display,windows); 2824 background_resources=(*resource_info); 2825 background_resources.window_id=window_id; 2826 background_resources.backdrop=IsMagickTrue(status); 2827 status=XDisplayBackgroundImage(display,&background_resources,*image, 2828 exception); 2829 if (IfMagickTrue(status)) 2830 XClientMessage(display,windows->image.id,windows->im_protocols, 2831 windows->im_retain_colors,CurrentTime); 2832 XSetCursorState(display,windows,MagickFalse); 2833 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image, 2834 exception); 2835 return(MagickTrue); 2836} 2837 2838/* 2839%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2840% % 2841% % 2842% % 2843+ X C h o p I m a g e % 2844% % 2845% % 2846% % 2847%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2848% 2849% XChopImage() chops the X image. 2850% 2851% The format of the XChopImage method is: 2852% 2853% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info, 2854% XWindows *windows,Image **image,ExceptionInfo *exception) 2855% 2856% A description of each parameter follows: 2857% 2858% o display: Specifies a connection to an X server; returned from 2859% XOpenDisplay. 2860% 2861% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2862% 2863% o windows: Specifies a pointer to a XWindows structure. 2864% 2865% o image: the image. 2866% 2867% o exception: return any errors or warnings in this structure. 2868% 2869*/ 2870static MagickBooleanType XChopImage(Display *display, 2871 XResourceInfo *resource_info,XWindows *windows,Image **image, 2872 ExceptionInfo *exception) 2873{ 2874 static const char 2875 *ChopMenu[] = 2876 { 2877 "Direction", 2878 "Help", 2879 "Dismiss", 2880 (char *) NULL 2881 }; 2882 2883 static ModeType 2884 direction = HorizontalChopCommand; 2885 2886 static const ModeType 2887 ChopCommands[] = 2888 { 2889 ChopDirectionCommand, 2890 ChopHelpCommand, 2891 ChopDismissCommand 2892 }, 2893 DirectionCommands[] = 2894 { 2895 HorizontalChopCommand, 2896 VerticalChopCommand 2897 }; 2898 2899 char 2900 text[MaxTextExtent]; 2901 2902 Image 2903 *chop_image; 2904 2905 int 2906 id, 2907 x, 2908 y; 2909 2910 double 2911 scale_factor; 2912 2913 RectangleInfo 2914 chop_info; 2915 2916 unsigned int 2917 distance, 2918 height, 2919 width; 2920 2921 size_t 2922 state; 2923 2924 XEvent 2925 event; 2926 2927 XSegment 2928 segment_info; 2929 2930 /* 2931 Map Command widget. 2932 */ 2933 (void) CloneString(&windows->command.name,"Chop"); 2934 windows->command.data=1; 2935 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL); 2936 (void) XMapRaised(display,windows->command.id); 2937 XClientMessage(display,windows->image.id,windows->im_protocols, 2938 windows->im_update_widget,CurrentTime); 2939 /* 2940 Track pointer until button 1 is pressed. 2941 */ 2942 XQueryPosition(display,windows->image.id,&x,&y); 2943 (void) XSelectInput(display,windows->image.id, 2944 windows->image.attributes.event_mask | PointerMotionMask); 2945 state=DefaultState; 2946 do 2947 { 2948 if( IfMagickTrue(windows->info.mapped) ) 2949 { 2950 /* 2951 Display pointer position. 2952 */ 2953 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 2954 x+windows->image.x,y+windows->image.y); 2955 XInfoWidget(display,windows,text); 2956 } 2957 /* 2958 Wait for next event. 2959 */ 2960 XScreenEvent(display,windows,&event,exception); 2961 if (event.xany.window == windows->command.id) 2962 { 2963 /* 2964 Select a command from the Command widget. 2965 */ 2966 id=XCommandWidget(display,windows,ChopMenu,&event); 2967 if (id < 0) 2968 continue; 2969 switch (ChopCommands[id]) 2970 { 2971 case ChopDirectionCommand: 2972 { 2973 char 2974 command[MaxTextExtent]; 2975 2976 static const char 2977 *Directions[] = 2978 { 2979 "horizontal", 2980 "vertical", 2981 (char *) NULL, 2982 }; 2983 2984 /* 2985 Select a command from the pop-up menu. 2986 */ 2987 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 2988 if (id >= 0) 2989 direction=DirectionCommands[id]; 2990 break; 2991 } 2992 case ChopHelpCommand: 2993 { 2994 XTextViewWidget(display,resource_info,windows,MagickFalse, 2995 "Help Viewer - Image Chop",ImageChopHelp); 2996 break; 2997 } 2998 case ChopDismissCommand: 2999 { 3000 /* 3001 Prematurely exit. 3002 */ 3003 state|=EscapeState; 3004 state|=ExitState; 3005 break; 3006 } 3007 default: 3008 break; 3009 } 3010 continue; 3011 } 3012 switch (event.type) 3013 { 3014 case ButtonPress: 3015 { 3016 if (event.xbutton.button != Button1) 3017 break; 3018 if (event.xbutton.window != windows->image.id) 3019 break; 3020 /* 3021 User has committed to start point of chopping line. 3022 */ 3023 segment_info.x1=(short int) event.xbutton.x; 3024 segment_info.x2=(short int) event.xbutton.x; 3025 segment_info.y1=(short int) event.xbutton.y; 3026 segment_info.y2=(short int) event.xbutton.y; 3027 state|=ExitState; 3028 break; 3029 } 3030 case ButtonRelease: 3031 break; 3032 case Expose: 3033 break; 3034 case KeyPress: 3035 { 3036 char 3037 command[MaxTextExtent]; 3038 3039 KeySym 3040 key_symbol; 3041 3042 if (event.xkey.window != windows->image.id) 3043 break; 3044 /* 3045 Respond to a user key press. 3046 */ 3047 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3048 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3049 switch ((int) key_symbol) 3050 { 3051 case XK_Escape: 3052 case XK_F20: 3053 { 3054 /* 3055 Prematurely exit. 3056 */ 3057 state|=EscapeState; 3058 state|=ExitState; 3059 break; 3060 } 3061 case XK_F1: 3062 case XK_Help: 3063 { 3064 (void) XSetFunction(display,windows->image.highlight_context, 3065 GXcopy); 3066 XTextViewWidget(display,resource_info,windows,MagickFalse, 3067 "Help Viewer - Image Chop",ImageChopHelp); 3068 (void) XSetFunction(display,windows->image.highlight_context, 3069 GXinvert); 3070 break; 3071 } 3072 default: 3073 { 3074 (void) XBell(display,0); 3075 break; 3076 } 3077 } 3078 break; 3079 } 3080 case MotionNotify: 3081 { 3082 /* 3083 Map and unmap Info widget as text cursor crosses its boundaries. 3084 */ 3085 x=event.xmotion.x; 3086 y=event.xmotion.y; 3087 if( IfMagickTrue(windows->info.mapped) ) 3088 { 3089 if ((x < (int) (windows->info.x+windows->info.width)) && 3090 (y < (int) (windows->info.y+windows->info.height))) 3091 (void) XWithdrawWindow(display,windows->info.id, 3092 windows->info.screen); 3093 } 3094 else 3095 if ((x > (int) (windows->info.x+windows->info.width)) || 3096 (y > (int) (windows->info.y+windows->info.height))) 3097 (void) XMapWindow(display,windows->info.id); 3098 } 3099 } 3100 } while ((state & ExitState) == 0); 3101 (void) XSelectInput(display,windows->image.id, 3102 windows->image.attributes.event_mask); 3103 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3104 if ((state & EscapeState) != 0) 3105 return(MagickTrue); 3106 /* 3107 Draw line as pointer moves until the mouse button is released. 3108 */ 3109 chop_info.width=0; 3110 chop_info.height=0; 3111 chop_info.x=0; 3112 chop_info.y=0; 3113 distance=0; 3114 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3115 state=DefaultState; 3116 do 3117 { 3118 if (distance > 9) 3119 { 3120 /* 3121 Display info and draw chopping line. 3122 */ 3123 if( IfMagickFalse(windows->info.mapped) ) 3124 (void) XMapWindow(display,windows->info.id); 3125 (void) FormatLocaleString(text,MaxTextExtent, 3126 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 3127 chop_info.height,(double) chop_info.x,(double) chop_info.y); 3128 XInfoWidget(display,windows,text); 3129 XHighlightLine(display,windows->image.id, 3130 windows->image.highlight_context,&segment_info); 3131 } 3132 else 3133 if( IfMagickTrue(windows->info.mapped) ) 3134 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3135 /* 3136 Wait for next event. 3137 */ 3138 XScreenEvent(display,windows,&event,exception); 3139 if (distance > 9) 3140 XHighlightLine(display,windows->image.id, 3141 windows->image.highlight_context,&segment_info); 3142 switch (event.type) 3143 { 3144 case ButtonPress: 3145 { 3146 segment_info.x2=(short int) event.xmotion.x; 3147 segment_info.y2=(short int) event.xmotion.y; 3148 break; 3149 } 3150 case ButtonRelease: 3151 { 3152 /* 3153 User has committed to chopping line. 3154 */ 3155 segment_info.x2=(short int) event.xbutton.x; 3156 segment_info.y2=(short int) event.xbutton.y; 3157 state|=ExitState; 3158 break; 3159 } 3160 case Expose: 3161 break; 3162 case MotionNotify: 3163 { 3164 segment_info.x2=(short int) event.xmotion.x; 3165 segment_info.y2=(short int) event.xmotion.y; 3166 } 3167 default: 3168 break; 3169 } 3170 /* 3171 Check boundary conditions. 3172 */ 3173 if (segment_info.x2 < 0) 3174 segment_info.x2=0; 3175 else 3176 if (segment_info.x2 > windows->image.ximage->width) 3177 segment_info.x2=windows->image.ximage->width; 3178 if (segment_info.y2 < 0) 3179 segment_info.y2=0; 3180 else 3181 if (segment_info.y2 > windows->image.ximage->height) 3182 segment_info.y2=windows->image.ximage->height; 3183 distance=(unsigned int) 3184 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 3185 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 3186 /* 3187 Compute chopping geometry. 3188 */ 3189 if (direction == HorizontalChopCommand) 3190 { 3191 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 3192 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 3193 chop_info.height=0; 3194 chop_info.y=0; 3195 if (segment_info.x1 > (int) segment_info.x2) 3196 { 3197 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 3198 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 3199 } 3200 } 3201 else 3202 { 3203 chop_info.width=0; 3204 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 3205 chop_info.x=0; 3206 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 3207 if (segment_info.y1 > segment_info.y2) 3208 { 3209 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 3210 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 3211 } 3212 } 3213 } while ((state & ExitState) == 0); 3214 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 3215 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3216 if (distance <= 9) 3217 return(MagickTrue); 3218 /* 3219 Image chopping is relative to image configuration. 3220 */ 3221 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 3222 exception); 3223 XSetCursorState(display,windows,MagickTrue); 3224 XCheckRefreshWindows(display,windows); 3225 windows->image.window_changes.width=windows->image.ximage->width- 3226 (unsigned int) chop_info.width; 3227 windows->image.window_changes.height=windows->image.ximage->height- 3228 (unsigned int) chop_info.height; 3229 width=(unsigned int) (*image)->columns; 3230 height=(unsigned int) (*image)->rows; 3231 x=0; 3232 y=0; 3233 if (windows->image.crop_geometry != (char *) NULL) 3234 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 3235 scale_factor=(double) width/windows->image.ximage->width; 3236 chop_info.x+=x; 3237 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 3238 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 3239 scale_factor=(double) height/windows->image.ximage->height; 3240 chop_info.y+=y; 3241 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 3242 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 3243 /* 3244 Chop image. 3245 */ 3246 chop_image=ChopImage(*image,&chop_info,exception); 3247 XSetCursorState(display,windows,MagickFalse); 3248 if (chop_image == (Image *) NULL) 3249 return(MagickFalse); 3250 *image=DestroyImage(*image); 3251 *image=chop_image; 3252 /* 3253 Update image configuration. 3254 */ 3255 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3256 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3257 return(MagickTrue); 3258} 3259 3260/* 3261%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3262% % 3263% % 3264% % 3265+ X C o l o r E d i t I m a g e % 3266% % 3267% % 3268% % 3269%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3270% 3271% XColorEditImage() allows the user to interactively change the color of one 3272% pixel for a DirectColor image or one colormap entry for a PseudoClass image. 3273% 3274% The format of the XColorEditImage method is: 3275% 3276% MagickBooleanType XColorEditImage(Display *display, 3277% XResourceInfo *resource_info,XWindows *windows,Image **image, 3278% ExceptionInfo *exception) 3279% 3280% A description of each parameter follows: 3281% 3282% o display: Specifies a connection to an X server; returned from 3283% XOpenDisplay. 3284% 3285% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3286% 3287% o windows: Specifies a pointer to a XWindows structure. 3288% 3289% o image: the image; returned from ReadImage. 3290% 3291% o exception: return any errors or warnings in this structure. 3292% 3293*/ 3294static MagickBooleanType XColorEditImage(Display *display, 3295 XResourceInfo *resource_info,XWindows *windows,Image **image, 3296 ExceptionInfo *exception) 3297{ 3298 static const char 3299 *ColorEditMenu[] = 3300 { 3301 "Method", 3302 "Pixel Color", 3303 "Border Color", 3304 "Fuzz", 3305 "Undo", 3306 "Help", 3307 "Dismiss", 3308 (char *) NULL 3309 }; 3310 3311 static const ModeType 3312 ColorEditCommands[] = 3313 { 3314 ColorEditMethodCommand, 3315 ColorEditColorCommand, 3316 ColorEditBorderCommand, 3317 ColorEditFuzzCommand, 3318 ColorEditUndoCommand, 3319 ColorEditHelpCommand, 3320 ColorEditDismissCommand 3321 }; 3322 3323 static PaintMethod 3324 method = PointMethod; 3325 3326 static unsigned int 3327 pen_id = 0; 3328 3329 static XColor 3330 border_color = { 0, 0, 0, 0, 0, 0 }; 3331 3332 char 3333 command[MaxTextExtent], 3334 text[MaxTextExtent]; 3335 3336 Cursor 3337 cursor; 3338 3339 int 3340 entry, 3341 id, 3342 x, 3343 x_offset, 3344 y, 3345 y_offset; 3346 3347 register Quantum 3348 *q; 3349 3350 register ssize_t 3351 i; 3352 3353 unsigned int 3354 height, 3355 width; 3356 3357 size_t 3358 state; 3359 3360 XColor 3361 color; 3362 3363 XEvent 3364 event; 3365 3366 /* 3367 Map Command widget. 3368 */ 3369 (void) CloneString(&windows->command.name,"Color Edit"); 3370 windows->command.data=4; 3371 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 3372 (void) XMapRaised(display,windows->command.id); 3373 XClientMessage(display,windows->image.id,windows->im_protocols, 3374 windows->im_update_widget,CurrentTime); 3375 /* 3376 Make cursor. 3377 */ 3378 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 3379 resource_info->background_color,resource_info->foreground_color); 3380 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3381 /* 3382 Track pointer until button 1 is pressed. 3383 */ 3384 XQueryPosition(display,windows->image.id,&x,&y); 3385 (void) XSelectInput(display,windows->image.id, 3386 windows->image.attributes.event_mask | PointerMotionMask); 3387 state=DefaultState; 3388 do 3389 { 3390 if( IfMagickTrue(windows->info.mapped) ) 3391 { 3392 /* 3393 Display pointer position. 3394 */ 3395 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 3396 x+windows->image.x,y+windows->image.y); 3397 XInfoWidget(display,windows,text); 3398 } 3399 /* 3400 Wait for next event. 3401 */ 3402 XScreenEvent(display,windows,&event,exception); 3403 if (event.xany.window == windows->command.id) 3404 { 3405 /* 3406 Select a command from the Command widget. 3407 */ 3408 id=XCommandWidget(display,windows,ColorEditMenu,&event); 3409 if (id < 0) 3410 { 3411 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3412 continue; 3413 } 3414 switch (ColorEditCommands[id]) 3415 { 3416 case ColorEditMethodCommand: 3417 { 3418 char 3419 **methods; 3420 3421 /* 3422 Select a method from the pop-up menu. 3423 */ 3424 methods=(char **) GetCommandOptions(MagickMethodOptions); 3425 if (methods == (char **) NULL) 3426 break; 3427 entry=XMenuWidget(display,windows,ColorEditMenu[id], 3428 (const char **) methods,command); 3429 if (entry >= 0) 3430 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 3431 MagickFalse,methods[entry]); 3432 methods=DestroyStringList(methods); 3433 break; 3434 } 3435 case ColorEditColorCommand: 3436 { 3437 const char 3438 *ColorMenu[MaxNumberPens]; 3439 3440 int 3441 pen_number; 3442 3443 /* 3444 Initialize menu selections. 3445 */ 3446 for (i=0; i < (int) (MaxNumberPens-2); i++) 3447 ColorMenu[i]=resource_info->pen_colors[i]; 3448 ColorMenu[MaxNumberPens-2]="Browser..."; 3449 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3450 /* 3451 Select a pen color from the pop-up menu. 3452 */ 3453 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3454 (const char **) ColorMenu,command); 3455 if (pen_number < 0) 3456 break; 3457 if (pen_number == (MaxNumberPens-2)) 3458 { 3459 static char 3460 color_name[MaxTextExtent] = "gray"; 3461 3462 /* 3463 Select a pen color from a dialog. 3464 */ 3465 resource_info->pen_colors[pen_number]=color_name; 3466 XColorBrowserWidget(display,windows,"Select",color_name); 3467 if (*color_name == '\0') 3468 break; 3469 } 3470 /* 3471 Set pen color. 3472 */ 3473 (void) XParseColor(display,windows->map_info->colormap, 3474 resource_info->pen_colors[pen_number],&color); 3475 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 3476 (unsigned int) MaxColors,&color); 3477 windows->pixel_info->pen_colors[pen_number]=color; 3478 pen_id=(unsigned int) pen_number; 3479 break; 3480 } 3481 case ColorEditBorderCommand: 3482 { 3483 const char 3484 *ColorMenu[MaxNumberPens]; 3485 3486 int 3487 pen_number; 3488 3489 /* 3490 Initialize menu selections. 3491 */ 3492 for (i=0; i < (int) (MaxNumberPens-2); i++) 3493 ColorMenu[i]=resource_info->pen_colors[i]; 3494 ColorMenu[MaxNumberPens-2]="Browser..."; 3495 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3496 /* 3497 Select a pen color from the pop-up menu. 3498 */ 3499 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3500 (const char **) ColorMenu,command); 3501 if (pen_number < 0) 3502 break; 3503 if (pen_number == (MaxNumberPens-2)) 3504 { 3505 static char 3506 color_name[MaxTextExtent] = "gray"; 3507 3508 /* 3509 Select a pen color from a dialog. 3510 */ 3511 resource_info->pen_colors[pen_number]=color_name; 3512 XColorBrowserWidget(display,windows,"Select",color_name); 3513 if (*color_name == '\0') 3514 break; 3515 } 3516 /* 3517 Set border color. 3518 */ 3519 (void) XParseColor(display,windows->map_info->colormap, 3520 resource_info->pen_colors[pen_number],&border_color); 3521 break; 3522 } 3523 case ColorEditFuzzCommand: 3524 { 3525 static char 3526 fuzz[MaxTextExtent]; 3527 3528 static const char 3529 *FuzzMenu[] = 3530 { 3531 "0%", 3532 "2%", 3533 "5%", 3534 "10%", 3535 "15%", 3536 "Dialog...", 3537 (char *) NULL, 3538 }; 3539 3540 /* 3541 Select a command from the pop-up menu. 3542 */ 3543 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 3544 command); 3545 if (entry < 0) 3546 break; 3547 if (entry != 5) 3548 { 3549 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 3550 QuantumRange+1.0); 3551 break; 3552 } 3553 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 3554 (void) XDialogWidget(display,windows,"Ok", 3555 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 3556 if (*fuzz == '\0') 3557 break; 3558 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 3559 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 3560 1.0); 3561 break; 3562 } 3563 case ColorEditUndoCommand: 3564 { 3565 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 3566 image,exception); 3567 break; 3568 } 3569 case ColorEditHelpCommand: 3570 default: 3571 { 3572 XTextViewWidget(display,resource_info,windows,MagickFalse, 3573 "Help Viewer - Image Annotation",ImageColorEditHelp); 3574 break; 3575 } 3576 case ColorEditDismissCommand: 3577 { 3578 /* 3579 Prematurely exit. 3580 */ 3581 state|=EscapeState; 3582 state|=ExitState; 3583 break; 3584 } 3585 } 3586 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3587 continue; 3588 } 3589 switch (event.type) 3590 { 3591 case ButtonPress: 3592 { 3593 if (event.xbutton.button != Button1) 3594 break; 3595 if ((event.xbutton.window != windows->image.id) && 3596 (event.xbutton.window != windows->magnify.id)) 3597 break; 3598 /* 3599 exit loop. 3600 */ 3601 x=event.xbutton.x; 3602 y=event.xbutton.y; 3603 (void) XMagickCommand(display,resource_info,windows, 3604 SaveToUndoBufferCommand,image,exception); 3605 state|=UpdateConfigurationState; 3606 break; 3607 } 3608 case ButtonRelease: 3609 { 3610 if (event.xbutton.button != Button1) 3611 break; 3612 if ((event.xbutton.window != windows->image.id) && 3613 (event.xbutton.window != windows->magnify.id)) 3614 break; 3615 /* 3616 Update colormap information. 3617 */ 3618 x=event.xbutton.x; 3619 y=event.xbutton.y; 3620 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3621 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3622 XInfoWidget(display,windows,text); 3623 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3624 state&=(~UpdateConfigurationState); 3625 break; 3626 } 3627 case Expose: 3628 break; 3629 case KeyPress: 3630 { 3631 KeySym 3632 key_symbol; 3633 3634 if (event.xkey.window == windows->magnify.id) 3635 { 3636 Window 3637 window; 3638 3639 window=windows->magnify.id; 3640 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 3641 } 3642 if (event.xkey.window != windows->image.id) 3643 break; 3644 /* 3645 Respond to a user key press. 3646 */ 3647 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3648 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3649 switch ((int) key_symbol) 3650 { 3651 case XK_Escape: 3652 case XK_F20: 3653 { 3654 /* 3655 Prematurely exit. 3656 */ 3657 state|=ExitState; 3658 break; 3659 } 3660 case XK_F1: 3661 case XK_Help: 3662 { 3663 XTextViewWidget(display,resource_info,windows,MagickFalse, 3664 "Help Viewer - Image Annotation",ImageColorEditHelp); 3665 break; 3666 } 3667 default: 3668 { 3669 (void) XBell(display,0); 3670 break; 3671 } 3672 } 3673 break; 3674 } 3675 case MotionNotify: 3676 { 3677 /* 3678 Map and unmap Info widget as cursor crosses its boundaries. 3679 */ 3680 x=event.xmotion.x; 3681 y=event.xmotion.y; 3682 if( IfMagickTrue(windows->info.mapped) ) 3683 { 3684 if ((x < (int) (windows->info.x+windows->info.width)) && 3685 (y < (int) (windows->info.y+windows->info.height))) 3686 (void) XWithdrawWindow(display,windows->info.id, 3687 windows->info.screen); 3688 } 3689 else 3690 if ((x > (int) (windows->info.x+windows->info.width)) || 3691 (y > (int) (windows->info.y+windows->info.height))) 3692 (void) XMapWindow(display,windows->info.id); 3693 break; 3694 } 3695 default: 3696 break; 3697 } 3698 if (event.xany.window == windows->magnify.id) 3699 { 3700 x=windows->magnify.x-windows->image.x; 3701 y=windows->magnify.y-windows->image.y; 3702 } 3703 x_offset=x; 3704 y_offset=y; 3705 if ((state & UpdateConfigurationState) != 0) 3706 { 3707 CacheView 3708 *image_view; 3709 3710 int 3711 x, 3712 y; 3713 3714 /* 3715 Pixel edit is relative to image configuration. 3716 */ 3717 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 3718 MagickTrue); 3719 color=windows->pixel_info->pen_colors[pen_id]; 3720 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 3721 width=(unsigned int) (*image)->columns; 3722 height=(unsigned int) (*image)->rows; 3723 x=0; 3724 y=0; 3725 if (windows->image.crop_geometry != (char *) NULL) 3726 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 3727 &width,&height); 3728 x_offset=(int) 3729 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 3730 y_offset=(int) 3731 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 3732 if ((x_offset < 0) || (y_offset < 0)) 3733 continue; 3734 if ((x_offset >= (int) (*image)->columns) || 3735 (y_offset >= (int) (*image)->rows)) 3736 continue; 3737 image_view=AcquireAuthenticCacheView(*image,exception); 3738 switch (method) 3739 { 3740 case PointMethod: 3741 default: 3742 { 3743 /* 3744 Update color information using point algorithm. 3745 */ 3746 if( IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) ) 3747 return(MagickFalse); 3748 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 3749 (ssize_t) y_offset,1,1,exception); 3750 if (q == (Quantum *) NULL) 3751 break; 3752 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3753 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3754 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3755 (void) SyncCacheViewAuthenticPixels(image_view,exception); 3756 break; 3757 } 3758 case ReplaceMethod: 3759 { 3760 PixelInfo 3761 pixel, 3762 target; 3763 3764 /* 3765 Update color information using replace algorithm. 3766 */ 3767 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t) 3768 x_offset,(ssize_t) y_offset,&target,exception); 3769 if ((*image)->storage_class == DirectClass) 3770 { 3771 for (y=0; y < (int) (*image)->rows; y++) 3772 { 3773 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3774 (*image)->columns,1,exception); 3775 if (q == (Quantum *) NULL) 3776 break; 3777 for (x=0; x < (int) (*image)->columns; x++) 3778 { 3779 GetPixelInfoPixel(*image,q,&pixel); 3780 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 3781 { 3782 SetPixelRed(*image,ScaleShortToQuantum( 3783 color.red),q); 3784 SetPixelGreen(*image,ScaleShortToQuantum( 3785 color.green),q); 3786 SetPixelBlue(*image,ScaleShortToQuantum( 3787 color.blue),q); 3788 } 3789 q+=GetPixelChannels(*image); 3790 } 3791 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 3792 break; 3793 } 3794 } 3795 else 3796 { 3797 for (i=0; i < (ssize_t) (*image)->colors; i++) 3798 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target)) 3799 { 3800 (*image)->colormap[i].red=(double) ScaleShortToQuantum( 3801 color.red); 3802 (*image)->colormap[i].green=(double) ScaleShortToQuantum( 3803 color.green); 3804 (*image)->colormap[i].blue=(double) ScaleShortToQuantum( 3805 color.blue); 3806 } 3807 (void) SyncImage(*image,exception); 3808 } 3809 break; 3810 } 3811 case FloodfillMethod: 3812 case FillToBorderMethod: 3813 { 3814 DrawInfo 3815 *draw_info; 3816 3817 PixelInfo 3818 target; 3819 3820 /* 3821 Update color information using floodfill algorithm. 3822 */ 3823 (void) GetOneVirtualPixelInfo(*image, 3824 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 3825 y_offset,&target,exception); 3826 if (method == FillToBorderMethod) 3827 { 3828 target.red=(double) 3829 ScaleShortToQuantum(border_color.red); 3830 target.green=(double) 3831 ScaleShortToQuantum(border_color.green); 3832 target.blue=(double) 3833 ScaleShortToQuantum(border_color.blue); 3834 } 3835 draw_info=CloneDrawInfo(resource_info->image_info, 3836 (DrawInfo *) NULL); 3837 (void) QueryColorCompliance(resource_info->pen_colors[pen_id], 3838 AllCompliance,&draw_info->fill,exception); 3839 (void) FloodfillPaintImage(*image,draw_info,&target, 3840 (ssize_t)x_offset,(ssize_t)y_offset, 3841 IsMagickFalse(method == FloodfillMethod),exception); 3842 draw_info=DestroyDrawInfo(draw_info); 3843 break; 3844 } 3845 case ResetMethod: 3846 { 3847 /* 3848 Update color information using reset algorithm. 3849 */ 3850 if( IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) ) 3851 return(MagickFalse); 3852 for (y=0; y < (int) (*image)->rows; y++) 3853 { 3854 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3855 (*image)->columns,1,exception); 3856 if (q == (Quantum *) NULL) 3857 break; 3858 for (x=0; x < (int) (*image)->columns; x++) 3859 { 3860 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3861 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3862 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3863 q+=GetPixelChannels(*image); 3864 } 3865 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 3866 break; 3867 } 3868 break; 3869 } 3870 } 3871 image_view=DestroyCacheView(image_view); 3872 state&=(~UpdateConfigurationState); 3873 } 3874 } while ((state & ExitState) == 0); 3875 (void) XSelectInput(display,windows->image.id, 3876 windows->image.attributes.event_mask); 3877 XSetCursorState(display,windows,MagickFalse); 3878 (void) XFreeCursor(display,cursor); 3879 return(MagickTrue); 3880} 3881 3882/* 3883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3884% % 3885% % 3886% % 3887+ X C o m p o s i t e I m a g e % 3888% % 3889% % 3890% % 3891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3892% 3893% XCompositeImage() requests an image name from the user, reads the image and 3894% composites it with the X window image at a location the user chooses with 3895% the pointer. 3896% 3897% The format of the XCompositeImage method is: 3898% 3899% MagickBooleanType XCompositeImage(Display *display, 3900% XResourceInfo *resource_info,XWindows *windows,Image *image, 3901% ExceptionInfo *exception) 3902% 3903% A description of each parameter follows: 3904% 3905% o display: Specifies a connection to an X server; returned from 3906% XOpenDisplay. 3907% 3908% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3909% 3910% o windows: Specifies a pointer to a XWindows structure. 3911% 3912% o image: the image; returned from ReadImage. 3913% 3914% o exception: return any errors or warnings in this structure. 3915% 3916*/ 3917static MagickBooleanType XCompositeImage(Display *display, 3918 XResourceInfo *resource_info,XWindows *windows,Image *image, 3919 ExceptionInfo *exception) 3920{ 3921 static char 3922 displacement_geometry[MaxTextExtent] = "30x30", 3923 filename[MaxTextExtent] = "\0"; 3924 3925 static const char 3926 *CompositeMenu[] = 3927 { 3928 "Operators", 3929 "Dissolve", 3930 "Displace", 3931 "Help", 3932 "Dismiss", 3933 (char *) NULL 3934 }; 3935 3936 static CompositeOperator 3937 compose = CopyCompositeOp; 3938 3939 static const ModeType 3940 CompositeCommands[] = 3941 { 3942 CompositeOperatorsCommand, 3943 CompositeDissolveCommand, 3944 CompositeDisplaceCommand, 3945 CompositeHelpCommand, 3946 CompositeDismissCommand 3947 }; 3948 3949 char 3950 text[MaxTextExtent]; 3951 3952 Cursor 3953 cursor; 3954 3955 Image 3956 *composite_image; 3957 3958 int 3959 entry, 3960 id, 3961 x, 3962 y; 3963 3964 double 3965 blend, 3966 scale_factor; 3967 3968 RectangleInfo 3969 highlight_info, 3970 composite_info; 3971 3972 unsigned int 3973 height, 3974 width; 3975 3976 size_t 3977 state; 3978 3979 XEvent 3980 event; 3981 3982 /* 3983 Request image file name from user. 3984 */ 3985 XFileBrowserWidget(display,windows,"Composite",filename); 3986 if (*filename == '\0') 3987 return(MagickTrue); 3988 /* 3989 Read image. 3990 */ 3991 XSetCursorState(display,windows,MagickTrue); 3992 XCheckRefreshWindows(display,windows); 3993 (void) CopyMagickString(resource_info->image_info->filename,filename, 3994 MaxTextExtent); 3995 composite_image=ReadImage(resource_info->image_info,exception); 3996 CatchException(exception); 3997 XSetCursorState(display,windows,MagickFalse); 3998 if (composite_image == (Image *) NULL) 3999 return(MagickFalse); 4000 /* 4001 Map Command widget. 4002 */ 4003 (void) CloneString(&windows->command.name,"Composite"); 4004 windows->command.data=1; 4005 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 4006 (void) XMapRaised(display,windows->command.id); 4007 XClientMessage(display,windows->image.id,windows->im_protocols, 4008 windows->im_update_widget,CurrentTime); 4009 /* 4010 Track pointer until button 1 is pressed. 4011 */ 4012 XQueryPosition(display,windows->image.id,&x,&y); 4013 (void) XSelectInput(display,windows->image.id, 4014 windows->image.attributes.event_mask | PointerMotionMask); 4015 composite_info.x=(ssize_t) windows->image.x+x; 4016 composite_info.y=(ssize_t) windows->image.y+y; 4017 composite_info.width=0; 4018 composite_info.height=0; 4019 cursor=XCreateFontCursor(display,XC_ul_angle); 4020 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4021 blend=0.0; 4022 state=DefaultState; 4023 do 4024 { 4025 if( IfMagickTrue(windows->info.mapped) ) 4026 { 4027 /* 4028 Display pointer position. 4029 */ 4030 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4031 (long) composite_info.x,(long) composite_info.y); 4032 XInfoWidget(display,windows,text); 4033 } 4034 highlight_info=composite_info; 4035 highlight_info.x=composite_info.x-windows->image.x; 4036 highlight_info.y=composite_info.y-windows->image.y; 4037 XHighlightRectangle(display,windows->image.id, 4038 windows->image.highlight_context,&highlight_info); 4039 /* 4040 Wait for next event. 4041 */ 4042 XScreenEvent(display,windows,&event,exception); 4043 XHighlightRectangle(display,windows->image.id, 4044 windows->image.highlight_context,&highlight_info); 4045 if (event.xany.window == windows->command.id) 4046 { 4047 /* 4048 Select a command from the Command widget. 4049 */ 4050 id=XCommandWidget(display,windows,CompositeMenu,&event); 4051 if (id < 0) 4052 continue; 4053 switch (CompositeCommands[id]) 4054 { 4055 case CompositeOperatorsCommand: 4056 { 4057 char 4058 command[MaxTextExtent], 4059 **operators; 4060 4061 /* 4062 Select a command from the pop-up menu. 4063 */ 4064 operators=GetCommandOptions(MagickComposeOptions); 4065 if (operators == (char **) NULL) 4066 break; 4067 entry=XMenuWidget(display,windows,CompositeMenu[id], 4068 (const char **) operators,command); 4069 if (entry >= 0) 4070 compose=(CompositeOperator) ParseCommandOption( 4071 MagickComposeOptions,MagickFalse,operators[entry]); 4072 operators=DestroyStringList(operators); 4073 break; 4074 } 4075 case CompositeDissolveCommand: 4076 { 4077 static char 4078 factor[MaxTextExtent] = "20.0"; 4079 4080 /* 4081 Dissolve the two images a given percent. 4082 */ 4083 (void) XSetFunction(display,windows->image.highlight_context, 4084 GXcopy); 4085 (void) XDialogWidget(display,windows,"Dissolve", 4086 "Enter the blend factor (0.0 - 99.9%):",factor); 4087 (void) XSetFunction(display,windows->image.highlight_context, 4088 GXinvert); 4089 if (*factor == '\0') 4090 break; 4091 blend=StringToDouble(factor,(char **) NULL); 4092 compose=DissolveCompositeOp; 4093 break; 4094 } 4095 case CompositeDisplaceCommand: 4096 { 4097 /* 4098 Get horizontal and vertical scale displacement geometry. 4099 */ 4100 (void) XSetFunction(display,windows->image.highlight_context, 4101 GXcopy); 4102 (void) XDialogWidget(display,windows,"Displace", 4103 "Enter the horizontal and vertical scale:",displacement_geometry); 4104 (void) XSetFunction(display,windows->image.highlight_context, 4105 GXinvert); 4106 if (*displacement_geometry == '\0') 4107 break; 4108 compose=DisplaceCompositeOp; 4109 break; 4110 } 4111 case CompositeHelpCommand: 4112 { 4113 (void) XSetFunction(display,windows->image.highlight_context, 4114 GXcopy); 4115 XTextViewWidget(display,resource_info,windows,MagickFalse, 4116 "Help Viewer - Image Composite",ImageCompositeHelp); 4117 (void) XSetFunction(display,windows->image.highlight_context, 4118 GXinvert); 4119 break; 4120 } 4121 case CompositeDismissCommand: 4122 { 4123 /* 4124 Prematurely exit. 4125 */ 4126 state|=EscapeState; 4127 state|=ExitState; 4128 break; 4129 } 4130 default: 4131 break; 4132 } 4133 continue; 4134 } 4135 switch (event.type) 4136 { 4137 case ButtonPress: 4138 { 4139 if( IfMagickTrue(image->debug) ) 4140 (void) LogMagickEvent(X11Event,GetMagickModule(), 4141 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 4142 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4143 if (event.xbutton.button != Button1) 4144 break; 4145 if (event.xbutton.window != windows->image.id) 4146 break; 4147 /* 4148 Change cursor. 4149 */ 4150 composite_info.width=composite_image->columns; 4151 composite_info.height=composite_image->rows; 4152 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4153 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4154 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4155 break; 4156 } 4157 case ButtonRelease: 4158 { 4159 if( IfMagickTrue(image->debug) ) 4160 (void) LogMagickEvent(X11Event,GetMagickModule(), 4161 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 4162 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4163 if (event.xbutton.button != Button1) 4164 break; 4165 if (event.xbutton.window != windows->image.id) 4166 break; 4167 if ((composite_info.width != 0) && (composite_info.height != 0)) 4168 { 4169 /* 4170 User has selected the location of the composite image. 4171 */ 4172 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4173 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4174 state|=ExitState; 4175 } 4176 break; 4177 } 4178 case Expose: 4179 break; 4180 case KeyPress: 4181 { 4182 char 4183 command[MaxTextExtent]; 4184 4185 KeySym 4186 key_symbol; 4187 4188 int 4189 length; 4190 4191 if (event.xkey.window != windows->image.id) 4192 break; 4193 /* 4194 Respond to a user key press. 4195 */ 4196 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 4197 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4198 *(command+length)='\0'; 4199 if( IfMagickTrue(image->debug) ) 4200 (void) LogMagickEvent(X11Event,GetMagickModule(), 4201 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 4202 switch ((int) key_symbol) 4203 { 4204 case XK_Escape: 4205 case XK_F20: 4206 { 4207 /* 4208 Prematurely exit. 4209 */ 4210 composite_image=DestroyImage(composite_image); 4211 state|=EscapeState; 4212 state|=ExitState; 4213 break; 4214 } 4215 case XK_F1: 4216 case XK_Help: 4217 { 4218 (void) XSetFunction(display,windows->image.highlight_context, 4219 GXcopy); 4220 XTextViewWidget(display,resource_info,windows,MagickFalse, 4221 "Help Viewer - Image Composite",ImageCompositeHelp); 4222 (void) XSetFunction(display,windows->image.highlight_context, 4223 GXinvert); 4224 break; 4225 } 4226 default: 4227 { 4228 (void) XBell(display,0); 4229 break; 4230 } 4231 } 4232 break; 4233 } 4234 case MotionNotify: 4235 { 4236 /* 4237 Map and unmap Info widget as text cursor crosses its boundaries. 4238 */ 4239 x=event.xmotion.x; 4240 y=event.xmotion.y; 4241 if( IfMagickTrue(windows->info.mapped) ) 4242 { 4243 if ((x < (int) (windows->info.x+windows->info.width)) && 4244 (y < (int) (windows->info.y+windows->info.height))) 4245 (void) XWithdrawWindow(display,windows->info.id, 4246 windows->info.screen); 4247 } 4248 else 4249 if ((x > (int) (windows->info.x+windows->info.width)) || 4250 (y > (int) (windows->info.y+windows->info.height))) 4251 (void) XMapWindow(display,windows->info.id); 4252 composite_info.x=(ssize_t) windows->image.x+x; 4253 composite_info.y=(ssize_t) windows->image.y+y; 4254 break; 4255 } 4256 default: 4257 { 4258 if( IfMagickTrue(image->debug) ) 4259 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 4260 event.type); 4261 break; 4262 } 4263 } 4264 } while ((state & ExitState) == 0); 4265 (void) XSelectInput(display,windows->image.id, 4266 windows->image.attributes.event_mask); 4267 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4268 XSetCursorState(display,windows,MagickFalse); 4269 (void) XFreeCursor(display,cursor); 4270 if ((state & EscapeState) != 0) 4271 return(MagickTrue); 4272 /* 4273 Image compositing is relative to image configuration. 4274 */ 4275 XSetCursorState(display,windows,MagickTrue); 4276 XCheckRefreshWindows(display,windows); 4277 width=(unsigned int) image->columns; 4278 height=(unsigned int) image->rows; 4279 x=0; 4280 y=0; 4281 if (windows->image.crop_geometry != (char *) NULL) 4282 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 4283 scale_factor=(double) width/windows->image.ximage->width; 4284 composite_info.x+=x; 4285 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 4286 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 4287 scale_factor=(double) height/windows->image.ximage->height; 4288 composite_info.y+=y; 4289 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 4290 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 4291 if ((composite_info.width != composite_image->columns) || 4292 (composite_info.height != composite_image->rows)) 4293 { 4294 Image 4295 *resize_image; 4296 4297 /* 4298 Scale composite image. 4299 */ 4300 resize_image=ResizeImage(composite_image,composite_info.width, 4301 composite_info.height,composite_image->filter,exception); 4302 composite_image=DestroyImage(composite_image); 4303 if (resize_image == (Image *) NULL) 4304 { 4305 XSetCursorState(display,windows,MagickFalse); 4306 return(MagickFalse); 4307 } 4308 composite_image=resize_image; 4309 } 4310 if (compose == DisplaceCompositeOp) 4311 (void) SetImageArtifact(composite_image,"compose:args", 4312 displacement_geometry); 4313 if (blend != 0.0) 4314 { 4315 CacheView 4316 *image_view; 4317 4318 int 4319 y; 4320 4321 Quantum 4322 opacity; 4323 4324 register int 4325 x; 4326 4327 register Quantum 4328 *q; 4329 4330 /* 4331 Create mattes for blending. 4332 */ 4333 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception); 4334 opacity=(Quantum) (ScaleQuantumToChar(QuantumRange)- 4335 ((ssize_t) ScaleQuantumToChar(QuantumRange)*blend)/100); 4336 if( IfMagickFalse(SetImageStorageClass(image,DirectClass,exception)) ) 4337 return(MagickFalse); 4338 image->alpha_trait=BlendPixelTrait; 4339 image_view=AcquireAuthenticCacheView(image,exception); 4340 for (y=0; y < (int) image->rows; y++) 4341 { 4342 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 4343 exception); 4344 if (q == (Quantum *) NULL) 4345 break; 4346 for (x=0; x < (int) image->columns; x++) 4347 { 4348 SetPixelAlpha(image,opacity,q); 4349 q+=GetPixelChannels(image); 4350 } 4351 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 4352 break; 4353 } 4354 image_view=DestroyCacheView(image_view); 4355 } 4356 /* 4357 Composite image with X Image window. 4358 */ 4359 (void) CompositeImage(image,composite_image,compose,MagickTrue, 4360 composite_info.x,composite_info.y,exception); 4361 composite_image=DestroyImage(composite_image); 4362 XSetCursorState(display,windows,MagickFalse); 4363 /* 4364 Update image configuration. 4365 */ 4366 XConfigureImageColormap(display,resource_info,windows,image,exception); 4367 (void) XConfigureImage(display,resource_info,windows,image,exception); 4368 return(MagickTrue); 4369} 4370 4371/* 4372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4373% % 4374% % 4375% % 4376+ X C o n f i g u r e I m a g e % 4377% % 4378% % 4379% % 4380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4381% 4382% XConfigureImage() creates a new X image. It also notifies the window 4383% manager of the new image size and configures the transient widows. 4384% 4385% The format of the XConfigureImage method is: 4386% 4387% MagickBooleanType XConfigureImage(Display *display, 4388% XResourceInfo *resource_info,XWindows *windows,Image *image, 4389% ExceptionInfo *exception) 4390% 4391% A description of each parameter follows: 4392% 4393% o display: Specifies a connection to an X server; returned from 4394% XOpenDisplay. 4395% 4396% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4397% 4398% o windows: Specifies a pointer to a XWindows structure. 4399% 4400% o image: the image. 4401% 4402% o exception: return any errors or warnings in this structure. 4403% 4404% o exception: return any errors or warnings in this structure. 4405% 4406*/ 4407static MagickBooleanType XConfigureImage(Display *display, 4408 XResourceInfo *resource_info,XWindows *windows,Image *image, 4409 ExceptionInfo *exception) 4410{ 4411 char 4412 geometry[MaxTextExtent]; 4413 4414 MagickStatusType 4415 status; 4416 4417 size_t 4418 mask, 4419 height, 4420 width; 4421 4422 ssize_t 4423 x, 4424 y; 4425 4426 XSizeHints 4427 *size_hints; 4428 4429 XWindowChanges 4430 window_changes; 4431 4432 /* 4433 Dismiss if window dimensions are zero. 4434 */ 4435 width=(unsigned int) windows->image.window_changes.width; 4436 height=(unsigned int) windows->image.window_changes.height; 4437 if( IfMagickTrue(image->debug) ) 4438 (void) LogMagickEvent(X11Event,GetMagickModule(), 4439 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 4440 windows->image.ximage->height,(double) width,(double) height); 4441 if ((width*height) == 0) 4442 return(MagickTrue); 4443 x=0; 4444 y=0; 4445 /* 4446 Resize image to fit Image window dimensions. 4447 */ 4448 XSetCursorState(display,windows,MagickTrue); 4449 (void) XFlush(display); 4450 if (((int) width != windows->image.ximage->width) || 4451 ((int) height != windows->image.ximage->height)) 4452 image->taint=MagickTrue; 4453 windows->magnify.x=(int) 4454 width*windows->magnify.x/windows->image.ximage->width; 4455 windows->magnify.y=(int) 4456 height*windows->magnify.y/windows->image.ximage->height; 4457 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 4458 windows->image.y=(int) 4459 (height*windows->image.y/windows->image.ximage->height); 4460 status=XMakeImage(display,resource_info,&windows->image,image, 4461 (unsigned int) width,(unsigned int) height,exception); 4462 if( IfMagickFalse(status) ) 4463 XNoticeWidget(display,windows,"Unable to configure X image:", 4464 windows->image.name); 4465 /* 4466 Notify window manager of the new configuration. 4467 */ 4468 if (resource_info->image_geometry != (char *) NULL) 4469 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!", 4470 resource_info->image_geometry); 4471 else 4472 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 4473 XDisplayWidth(display,windows->image.screen), 4474 XDisplayHeight(display,windows->image.screen)); 4475 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 4476 window_changes.width=(int) width; 4477 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 4478 window_changes.width=XDisplayWidth(display,windows->image.screen); 4479 window_changes.height=(int) height; 4480 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 4481 window_changes.height=XDisplayHeight(display,windows->image.screen); 4482 mask=(size_t) (CWWidth | CWHeight); 4483 if (resource_info->backdrop) 4484 { 4485 mask|=CWX | CWY; 4486 window_changes.x=(int) 4487 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 4488 window_changes.y=(int) 4489 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 4490 } 4491 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 4492 (unsigned int) mask,&window_changes); 4493 (void) XClearWindow(display,windows->image.id); 4494 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 4495 /* 4496 Update Magnify window configuration. 4497 */ 4498 if( IfMagickTrue(windows->magnify.mapped) ) 4499 XMakeMagnifyImage(display,windows,exception); 4500 windows->pan.crop_geometry=windows->image.crop_geometry; 4501 XBestIconSize(display,&windows->pan,image); 4502 while (((windows->pan.width << 1) < MaxIconSize) && 4503 ((windows->pan.height << 1) < MaxIconSize)) 4504 { 4505 windows->pan.width<<=1; 4506 windows->pan.height<<=1; 4507 } 4508 if (windows->pan.geometry != (char *) NULL) 4509 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 4510 &windows->pan.width,&windows->pan.height); 4511 window_changes.width=(int) windows->pan.width; 4512 window_changes.height=(int) windows->pan.height; 4513 size_hints=XAllocSizeHints(); 4514 if (size_hints != (XSizeHints *) NULL) 4515 { 4516 /* 4517 Set new size hints. 4518 */ 4519 size_hints->flags=PSize | PMinSize | PMaxSize; 4520 size_hints->width=window_changes.width; 4521 size_hints->height=window_changes.height; 4522 size_hints->min_width=size_hints->width; 4523 size_hints->min_height=size_hints->height; 4524 size_hints->max_width=size_hints->width; 4525 size_hints->max_height=size_hints->height; 4526 (void) XSetNormalHints(display,windows->pan.id,size_hints); 4527 (void) XFree((void *) size_hints); 4528 } 4529 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 4530 (unsigned int) (CWWidth | CWHeight),&window_changes); 4531 /* 4532 Update icon window configuration. 4533 */ 4534 windows->icon.crop_geometry=windows->image.crop_geometry; 4535 XBestIconSize(display,&windows->icon,image); 4536 window_changes.width=(int) windows->icon.width; 4537 window_changes.height=(int) windows->icon.height; 4538 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 4539 (unsigned int) (CWWidth | CWHeight),&window_changes); 4540 XSetCursorState(display,windows,MagickFalse); 4541 return(IsMagickTrue(status)); 4542} 4543 4544/* 4545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4546% % 4547% % 4548% % 4549+ X C r o p I m a g e % 4550% % 4551% % 4552% % 4553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4554% 4555% XCropImage() allows the user to select a region of the image and crop, copy, 4556% or cut it. For copy or cut, the image can subsequently be composited onto 4557% the image with XPasteImage. 4558% 4559% The format of the XCropImage method is: 4560% 4561% MagickBooleanType XCropImage(Display *display, 4562% XResourceInfo *resource_info,XWindows *windows,Image *image, 4563% const ClipboardMode mode,ExceptionInfo *exception) 4564% 4565% A description of each parameter follows: 4566% 4567% o display: Specifies a connection to an X server; returned from 4568% XOpenDisplay. 4569% 4570% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4571% 4572% o windows: Specifies a pointer to a XWindows structure. 4573% 4574% o image: the image; returned from ReadImage. 4575% 4576% o mode: This unsigned value specified whether the image should be 4577% cropped, copied, or cut. 4578% 4579% o exception: return any errors or warnings in this structure. 4580% 4581*/ 4582static MagickBooleanType XCropImage(Display *display, 4583 XResourceInfo *resource_info,XWindows *windows,Image *image, 4584 const ClipboardMode mode,ExceptionInfo *exception) 4585{ 4586 static const char 4587 *CropModeMenu[] = 4588 { 4589 "Help", 4590 "Dismiss", 4591 (char *) NULL 4592 }, 4593 *RectifyModeMenu[] = 4594 { 4595 "Crop", 4596 "Help", 4597 "Dismiss", 4598 (char *) NULL 4599 }; 4600 4601 static const ModeType 4602 CropCommands[] = 4603 { 4604 CropHelpCommand, 4605 CropDismissCommand 4606 }, 4607 RectifyCommands[] = 4608 { 4609 RectifyCopyCommand, 4610 RectifyHelpCommand, 4611 RectifyDismissCommand 4612 }; 4613 4614 CacheView 4615 *image_view; 4616 4617 char 4618 command[MaxTextExtent], 4619 text[MaxTextExtent]; 4620 4621 Cursor 4622 cursor; 4623 4624 int 4625 id, 4626 x, 4627 y; 4628 4629 KeySym 4630 key_symbol; 4631 4632 Image 4633 *crop_image; 4634 4635 double 4636 scale_factor; 4637 4638 RectangleInfo 4639 crop_info, 4640 highlight_info; 4641 4642 register Quantum 4643 *q; 4644 4645 unsigned int 4646 height, 4647 width; 4648 4649 size_t 4650 state; 4651 4652 XEvent 4653 event; 4654 4655 /* 4656 Map Command widget. 4657 */ 4658 switch (mode) 4659 { 4660 case CopyMode: 4661 { 4662 (void) CloneString(&windows->command.name,"Copy"); 4663 break; 4664 } 4665 case CropMode: 4666 { 4667 (void) CloneString(&windows->command.name,"Crop"); 4668 break; 4669 } 4670 case CutMode: 4671 { 4672 (void) CloneString(&windows->command.name,"Cut"); 4673 break; 4674 } 4675 } 4676 RectifyModeMenu[0]=windows->command.name; 4677 windows->command.data=0; 4678 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 4679 (void) XMapRaised(display,windows->command.id); 4680 XClientMessage(display,windows->image.id,windows->im_protocols, 4681 windows->im_update_widget,CurrentTime); 4682 /* 4683 Track pointer until button 1 is pressed. 4684 */ 4685 XQueryPosition(display,windows->image.id,&x,&y); 4686 (void) XSelectInput(display,windows->image.id, 4687 windows->image.attributes.event_mask | PointerMotionMask); 4688 crop_info.x=(ssize_t) windows->image.x+x; 4689 crop_info.y=(ssize_t) windows->image.y+y; 4690 crop_info.width=0; 4691 crop_info.height=0; 4692 cursor=XCreateFontCursor(display,XC_fleur); 4693 state=DefaultState; 4694 do 4695 { 4696 if( IfMagickTrue(windows->info.mapped) ) 4697 { 4698 /* 4699 Display pointer position. 4700 */ 4701 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4702 (long) crop_info.x,(long) crop_info.y); 4703 XInfoWidget(display,windows,text); 4704 } 4705 /* 4706 Wait for next event. 4707 */ 4708 XScreenEvent(display,windows,&event,exception); 4709 if (event.xany.window == windows->command.id) 4710 { 4711 /* 4712 Select a command from the Command widget. 4713 */ 4714 id=XCommandWidget(display,windows,CropModeMenu,&event); 4715 if (id < 0) 4716 continue; 4717 switch (CropCommands[id]) 4718 { 4719 case CropHelpCommand: 4720 { 4721 switch (mode) 4722 { 4723 case CopyMode: 4724 { 4725 XTextViewWidget(display,resource_info,windows,MagickFalse, 4726 "Help Viewer - Image Copy",ImageCopyHelp); 4727 break; 4728 } 4729 case CropMode: 4730 { 4731 XTextViewWidget(display,resource_info,windows,MagickFalse, 4732 "Help Viewer - Image Crop",ImageCropHelp); 4733 break; 4734 } 4735 case CutMode: 4736 { 4737 XTextViewWidget(display,resource_info,windows,MagickFalse, 4738 "Help Viewer - Image Cut",ImageCutHelp); 4739 break; 4740 } 4741 } 4742 break; 4743 } 4744 case CropDismissCommand: 4745 { 4746 /* 4747 Prematurely exit. 4748 */ 4749 state|=EscapeState; 4750 state|=ExitState; 4751 break; 4752 } 4753 default: 4754 break; 4755 } 4756 continue; 4757 } 4758 switch (event.type) 4759 { 4760 case ButtonPress: 4761 { 4762 if (event.xbutton.button != Button1) 4763 break; 4764 if (event.xbutton.window != windows->image.id) 4765 break; 4766 /* 4767 Note first corner of cropping rectangle-- exit loop. 4768 */ 4769 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4770 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4771 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4772 state|=ExitState; 4773 break; 4774 } 4775 case ButtonRelease: 4776 break; 4777 case Expose: 4778 break; 4779 case KeyPress: 4780 { 4781 if (event.xkey.window != windows->image.id) 4782 break; 4783 /* 4784 Respond to a user key press. 4785 */ 4786 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 4787 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4788 switch ((int) key_symbol) 4789 { 4790 case XK_Escape: 4791 case XK_F20: 4792 { 4793 /* 4794 Prematurely exit. 4795 */ 4796 state|=EscapeState; 4797 state|=ExitState; 4798 break; 4799 } 4800 case XK_F1: 4801 case XK_Help: 4802 { 4803 switch (mode) 4804 { 4805 case CopyMode: 4806 { 4807 XTextViewWidget(display,resource_info,windows,MagickFalse, 4808 "Help Viewer - Image Copy",ImageCopyHelp); 4809 break; 4810 } 4811 case CropMode: 4812 { 4813 XTextViewWidget(display,resource_info,windows,MagickFalse, 4814 "Help Viewer - Image Crop",ImageCropHelp); 4815 break; 4816 } 4817 case CutMode: 4818 { 4819 XTextViewWidget(display,resource_info,windows,MagickFalse, 4820 "Help Viewer - Image Cut",ImageCutHelp); 4821 break; 4822 } 4823 } 4824 break; 4825 } 4826 default: 4827 { 4828 (void) XBell(display,0); 4829 break; 4830 } 4831 } 4832 break; 4833 } 4834 case MotionNotify: 4835 { 4836 if (event.xmotion.window != windows->image.id) 4837 break; 4838 /* 4839 Map and unmap Info widget as text cursor crosses its boundaries. 4840 */ 4841 x=event.xmotion.x; 4842 y=event.xmotion.y; 4843 if( IfMagickTrue(windows->info.mapped) ) 4844 { 4845 if ((x < (int) (windows->info.x+windows->info.width)) && 4846 (y < (int) (windows->info.y+windows->info.height))) 4847 (void) XWithdrawWindow(display,windows->info.id, 4848 windows->info.screen); 4849 } 4850 else 4851 if ((x > (int) (windows->info.x+windows->info.width)) || 4852 (y > (int) (windows->info.y+windows->info.height))) 4853 (void) XMapWindow(display,windows->info.id); 4854 crop_info.x=(ssize_t) windows->image.x+x; 4855 crop_info.y=(ssize_t) windows->image.y+y; 4856 break; 4857 } 4858 default: 4859 break; 4860 } 4861 } while ((state & ExitState) == 0); 4862 (void) XSelectInput(display,windows->image.id, 4863 windows->image.attributes.event_mask); 4864 if ((state & EscapeState) != 0) 4865 { 4866 /* 4867 User want to exit without cropping. 4868 */ 4869 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4870 (void) XFreeCursor(display,cursor); 4871 return(MagickTrue); 4872 } 4873 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4874 do 4875 { 4876 /* 4877 Size rectangle as pointer moves until the mouse button is released. 4878 */ 4879 x=(int) crop_info.x; 4880 y=(int) crop_info.y; 4881 crop_info.width=0; 4882 crop_info.height=0; 4883 state=DefaultState; 4884 do 4885 { 4886 highlight_info=crop_info; 4887 highlight_info.x=crop_info.x-windows->image.x; 4888 highlight_info.y=crop_info.y-windows->image.y; 4889 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4890 { 4891 /* 4892 Display info and draw cropping rectangle. 4893 */ 4894 if( IfMagickFalse(windows->info.mapped) ) 4895 (void) XMapWindow(display,windows->info.id); 4896 (void) FormatLocaleString(text,MaxTextExtent, 4897 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4898 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4899 XInfoWidget(display,windows,text); 4900 XHighlightRectangle(display,windows->image.id, 4901 windows->image.highlight_context,&highlight_info); 4902 } 4903 else 4904 if( IfMagickTrue(windows->info.mapped) ) 4905 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4906 /* 4907 Wait for next event. 4908 */ 4909 XScreenEvent(display,windows,&event,exception); 4910 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4911 XHighlightRectangle(display,windows->image.id, 4912 windows->image.highlight_context,&highlight_info); 4913 switch (event.type) 4914 { 4915 case ButtonPress: 4916 { 4917 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4918 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4919 break; 4920 } 4921 case ButtonRelease: 4922 { 4923 /* 4924 User has committed to cropping rectangle. 4925 */ 4926 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4927 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4928 XSetCursorState(display,windows,MagickFalse); 4929 state|=ExitState; 4930 windows->command.data=0; 4931 (void) XCommandWidget(display,windows,RectifyModeMenu, 4932 (XEvent *) NULL); 4933 break; 4934 } 4935 case Expose: 4936 break; 4937 case MotionNotify: 4938 { 4939 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 4940 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 4941 } 4942 default: 4943 break; 4944 } 4945 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 4946 ((state & ExitState) != 0)) 4947 { 4948 /* 4949 Check boundary conditions. 4950 */ 4951 if (crop_info.x < 0) 4952 crop_info.x=0; 4953 else 4954 if (crop_info.x > (ssize_t) windows->image.ximage->width) 4955 crop_info.x=(ssize_t) windows->image.ximage->width; 4956 if ((int) crop_info.x < x) 4957 crop_info.width=(unsigned int) (x-crop_info.x); 4958 else 4959 { 4960 crop_info.width=(unsigned int) (crop_info.x-x); 4961 crop_info.x=(ssize_t) x; 4962 } 4963 if (crop_info.y < 0) 4964 crop_info.y=0; 4965 else 4966 if (crop_info.y > (ssize_t) windows->image.ximage->height) 4967 crop_info.y=(ssize_t) windows->image.ximage->height; 4968 if ((int) crop_info.y < y) 4969 crop_info.height=(unsigned int) (y-crop_info.y); 4970 else 4971 { 4972 crop_info.height=(unsigned int) (crop_info.y-y); 4973 crop_info.y=(ssize_t) y; 4974 } 4975 } 4976 } while ((state & ExitState) == 0); 4977 /* 4978 Wait for user to grab a corner of the rectangle or press return. 4979 */ 4980 state=DefaultState; 4981 (void) XMapWindow(display,windows->info.id); 4982 do 4983 { 4984 if( IfMagickTrue(windows->info.mapped) ) 4985 { 4986 /* 4987 Display pointer position. 4988 */ 4989 (void) FormatLocaleString(text,MaxTextExtent, 4990 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4991 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4992 XInfoWidget(display,windows,text); 4993 } 4994 highlight_info=crop_info; 4995 highlight_info.x=crop_info.x-windows->image.x; 4996 highlight_info.y=crop_info.y-windows->image.y; 4997 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 4998 { 4999 state|=EscapeState; 5000 state|=ExitState; 5001 break; 5002 } 5003 XHighlightRectangle(display,windows->image.id, 5004 windows->image.highlight_context,&highlight_info); 5005 XScreenEvent(display,windows,&event,exception); 5006 if (event.xany.window == windows->command.id) 5007 { 5008 /* 5009 Select a command from the Command widget. 5010 */ 5011 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5012 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 5013 (void) XSetFunction(display,windows->image.highlight_context, 5014 GXinvert); 5015 XHighlightRectangle(display,windows->image.id, 5016 windows->image.highlight_context,&highlight_info); 5017 if (id >= 0) 5018 switch (RectifyCommands[id]) 5019 { 5020 case RectifyCopyCommand: 5021 { 5022 state|=ExitState; 5023 break; 5024 } 5025 case RectifyHelpCommand: 5026 { 5027 (void) XSetFunction(display,windows->image.highlight_context, 5028 GXcopy); 5029 switch (mode) 5030 { 5031 case CopyMode: 5032 { 5033 XTextViewWidget(display,resource_info,windows,MagickFalse, 5034 "Help Viewer - Image Copy",ImageCopyHelp); 5035 break; 5036 } 5037 case CropMode: 5038 { 5039 XTextViewWidget(display,resource_info,windows,MagickFalse, 5040 "Help Viewer - Image Crop",ImageCropHelp); 5041 break; 5042 } 5043 case CutMode: 5044 { 5045 XTextViewWidget(display,resource_info,windows,MagickFalse, 5046 "Help Viewer - Image Cut",ImageCutHelp); 5047 break; 5048 } 5049 } 5050 (void) XSetFunction(display,windows->image.highlight_context, 5051 GXinvert); 5052 break; 5053 } 5054 case RectifyDismissCommand: 5055 { 5056 /* 5057 Prematurely exit. 5058 */ 5059 state|=EscapeState; 5060 state|=ExitState; 5061 break; 5062 } 5063 default: 5064 break; 5065 } 5066 continue; 5067 } 5068 XHighlightRectangle(display,windows->image.id, 5069 windows->image.highlight_context,&highlight_info); 5070 switch (event.type) 5071 { 5072 case ButtonPress: 5073 { 5074 if (event.xbutton.button != Button1) 5075 break; 5076 if (event.xbutton.window != windows->image.id) 5077 break; 5078 x=windows->image.x+event.xbutton.x; 5079 y=windows->image.y+event.xbutton.y; 5080 if ((x < (int) (crop_info.x+RoiDelta)) && 5081 (x > (int) (crop_info.x-RoiDelta)) && 5082 (y < (int) (crop_info.y+RoiDelta)) && 5083 (y > (int) (crop_info.y-RoiDelta))) 5084 { 5085 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5086 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5087 state|=UpdateConfigurationState; 5088 break; 5089 } 5090 if ((x < (int) (crop_info.x+RoiDelta)) && 5091 (x > (int) (crop_info.x-RoiDelta)) && 5092 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5093 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5094 { 5095 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5096 state|=UpdateConfigurationState; 5097 break; 5098 } 5099 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5100 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5101 (y < (int) (crop_info.y+RoiDelta)) && 5102 (y > (int) (crop_info.y-RoiDelta))) 5103 { 5104 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5105 state|=UpdateConfigurationState; 5106 break; 5107 } 5108 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5109 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5110 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5111 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5112 { 5113 state|=UpdateConfigurationState; 5114 break; 5115 } 5116 } 5117 case ButtonRelease: 5118 { 5119 if (event.xbutton.window == windows->pan.id) 5120 if ((highlight_info.x != crop_info.x-windows->image.x) || 5121 (highlight_info.y != crop_info.y-windows->image.y)) 5122 XHighlightRectangle(display,windows->image.id, 5123 windows->image.highlight_context,&highlight_info); 5124 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5125 event.xbutton.time); 5126 break; 5127 } 5128 case Expose: 5129 { 5130 if (event.xexpose.window == windows->image.id) 5131 if (event.xexpose.count == 0) 5132 { 5133 event.xexpose.x=(int) highlight_info.x; 5134 event.xexpose.y=(int) highlight_info.y; 5135 event.xexpose.width=(int) highlight_info.width; 5136 event.xexpose.height=(int) highlight_info.height; 5137 XRefreshWindow(display,&windows->image,&event); 5138 } 5139 if (event.xexpose.window == windows->info.id) 5140 if (event.xexpose.count == 0) 5141 XInfoWidget(display,windows,text); 5142 break; 5143 } 5144 case KeyPress: 5145 { 5146 if (event.xkey.window != windows->image.id) 5147 break; 5148 /* 5149 Respond to a user key press. 5150 */ 5151 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5152 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5153 switch ((int) key_symbol) 5154 { 5155 case XK_Escape: 5156 case XK_F20: 5157 state|=EscapeState; 5158 case XK_Return: 5159 { 5160 state|=ExitState; 5161 break; 5162 } 5163 case XK_Home: 5164 case XK_KP_Home: 5165 { 5166 crop_info.x=(ssize_t) (windows->image.width/2L- 5167 crop_info.width/2L); 5168 crop_info.y=(ssize_t) (windows->image.height/2L- 5169 crop_info.height/2L); 5170 break; 5171 } 5172 case XK_Left: 5173 case XK_KP_Left: 5174 { 5175 crop_info.x--; 5176 break; 5177 } 5178 case XK_Up: 5179 case XK_KP_Up: 5180 case XK_Next: 5181 { 5182 crop_info.y--; 5183 break; 5184 } 5185 case XK_Right: 5186 case XK_KP_Right: 5187 { 5188 crop_info.x++; 5189 break; 5190 } 5191 case XK_Prior: 5192 case XK_Down: 5193 case XK_KP_Down: 5194 { 5195 crop_info.y++; 5196 break; 5197 } 5198 case XK_F1: 5199 case XK_Help: 5200 { 5201 (void) XSetFunction(display,windows->image.highlight_context, 5202 GXcopy); 5203 switch (mode) 5204 { 5205 case CopyMode: 5206 { 5207 XTextViewWidget(display,resource_info,windows,MagickFalse, 5208 "Help Viewer - Image Copy",ImageCopyHelp); 5209 break; 5210 } 5211 case CropMode: 5212 { 5213 XTextViewWidget(display,resource_info,windows,MagickFalse, 5214 "Help Viewer - Image Cropg",ImageCropHelp); 5215 break; 5216 } 5217 case CutMode: 5218 { 5219 XTextViewWidget(display,resource_info,windows,MagickFalse, 5220 "Help Viewer - Image Cutg",ImageCutHelp); 5221 break; 5222 } 5223 } 5224 (void) XSetFunction(display,windows->image.highlight_context, 5225 GXinvert); 5226 break; 5227 } 5228 default: 5229 { 5230 (void) XBell(display,0); 5231 break; 5232 } 5233 } 5234 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5235 event.xkey.time); 5236 break; 5237 } 5238 case KeyRelease: 5239 break; 5240 case MotionNotify: 5241 { 5242 if (event.xmotion.window != windows->image.id) 5243 break; 5244 /* 5245 Map and unmap Info widget as text cursor crosses its boundaries. 5246 */ 5247 x=event.xmotion.x; 5248 y=event.xmotion.y; 5249 if( IfMagickTrue(windows->info.mapped) ) 5250 { 5251 if ((x < (int) (windows->info.x+windows->info.width)) && 5252 (y < (int) (windows->info.y+windows->info.height))) 5253 (void) XWithdrawWindow(display,windows->info.id, 5254 windows->info.screen); 5255 } 5256 else 5257 if ((x > (int) (windows->info.x+windows->info.width)) || 5258 (y > (int) (windows->info.y+windows->info.height))) 5259 (void) XMapWindow(display,windows->info.id); 5260 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 5261 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 5262 break; 5263 } 5264 case SelectionRequest: 5265 { 5266 XSelectionEvent 5267 notify; 5268 5269 XSelectionRequestEvent 5270 *request; 5271 5272 /* 5273 Set primary selection. 5274 */ 5275 (void) FormatLocaleString(text,MaxTextExtent, 5276 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 5277 crop_info.height,(double) crop_info.x,(double) crop_info.y); 5278 request=(&(event.xselectionrequest)); 5279 (void) XChangeProperty(request->display,request->requestor, 5280 request->property,request->target,8,PropModeReplace, 5281 (unsigned char *) text,(int) strlen(text)); 5282 notify.type=SelectionNotify; 5283 notify.display=request->display; 5284 notify.requestor=request->requestor; 5285 notify.selection=request->selection; 5286 notify.target=request->target; 5287 notify.time=request->time; 5288 if (request->property == None) 5289 notify.property=request->target; 5290 else 5291 notify.property=request->property; 5292 (void) XSendEvent(request->display,request->requestor,False,0, 5293 (XEvent *) ¬ify); 5294 } 5295 default: 5296 break; 5297 } 5298 if ((state & UpdateConfigurationState) != 0) 5299 { 5300 (void) XPutBackEvent(display,&event); 5301 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5302 break; 5303 } 5304 } while ((state & ExitState) == 0); 5305 } while ((state & ExitState) == 0); 5306 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5307 XSetCursorState(display,windows,MagickFalse); 5308 if ((state & EscapeState) != 0) 5309 return(MagickTrue); 5310 if (mode == CropMode) 5311 if (((int) crop_info.width != windows->image.ximage->width) || 5312 ((int) crop_info.height != windows->image.ximage->height)) 5313 { 5314 /* 5315 Reconfigure Image window as defined by cropping rectangle. 5316 */ 5317 XSetCropGeometry(display,windows,&crop_info,image); 5318 windows->image.window_changes.width=(int) crop_info.width; 5319 windows->image.window_changes.height=(int) crop_info.height; 5320 (void) XConfigureImage(display,resource_info,windows,image,exception); 5321 return(MagickTrue); 5322 } 5323 /* 5324 Copy image before applying image transforms. 5325 */ 5326 XSetCursorState(display,windows,MagickTrue); 5327 XCheckRefreshWindows(display,windows); 5328 width=(unsigned int) image->columns; 5329 height=(unsigned int) image->rows; 5330 x=0; 5331 y=0; 5332 if (windows->image.crop_geometry != (char *) NULL) 5333 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 5334 scale_factor=(double) width/windows->image.ximage->width; 5335 crop_info.x+=x; 5336 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 5337 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 5338 scale_factor=(double) height/windows->image.ximage->height; 5339 crop_info.y+=y; 5340 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 5341 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5); 5342 crop_image=CropImage(image,&crop_info,exception); 5343 XSetCursorState(display,windows,MagickFalse); 5344 if (crop_image == (Image *) NULL) 5345 return(MagickFalse); 5346 if (resource_info->copy_image != (Image *) NULL) 5347 resource_info->copy_image=DestroyImage(resource_info->copy_image); 5348 resource_info->copy_image=crop_image; 5349 if (mode == CopyMode) 5350 { 5351 (void) XConfigureImage(display,resource_info,windows,image,exception); 5352 return(MagickTrue); 5353 } 5354 /* 5355 Cut image. 5356 */ 5357 if( IfMagickFalse(SetImageStorageClass(image,DirectClass,exception)) ) 5358 return(MagickFalse); 5359 image->alpha_trait=BlendPixelTrait; 5360 image_view=AcquireAuthenticCacheView(image,exception); 5361 for (y=0; y < (int) crop_info.height; y++) 5362 { 5363 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y, 5364 crop_info.width,1,exception); 5365 if (q == (Quantum *) NULL) 5366 break; 5367 for (x=0; x < (int) crop_info.width; x++) 5368 { 5369 SetPixelAlpha(image,TransparentAlpha,q); 5370 q+=GetPixelChannels(image); 5371 } 5372 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 5373 break; 5374 } 5375 image_view=DestroyCacheView(image_view); 5376 /* 5377 Update image configuration. 5378 */ 5379 XConfigureImageColormap(display,resource_info,windows,image,exception); 5380 (void) XConfigureImage(display,resource_info,windows,image,exception); 5381 return(MagickTrue); 5382} 5383 5384/* 5385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5386% % 5387% % 5388% % 5389+ X D r a w I m a g e % 5390% % 5391% % 5392% % 5393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5394% 5395% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on 5396% the image. 5397% 5398% The format of the XDrawEditImage method is: 5399% 5400% MagickBooleanType XDrawEditImage(Display *display, 5401% XResourceInfo *resource_info,XWindows *windows,Image **image, 5402% ExceptionInfo *exception) 5403% 5404% A description of each parameter follows: 5405% 5406% o display: Specifies a connection to an X server; returned from 5407% XOpenDisplay. 5408% 5409% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 5410% 5411% o windows: Specifies a pointer to a XWindows structure. 5412% 5413% o image: the image. 5414% 5415% o exception: return any errors or warnings in this structure. 5416% 5417*/ 5418static MagickBooleanType XDrawEditImage(Display *display, 5419 XResourceInfo *resource_info,XWindows *windows,Image **image, 5420 ExceptionInfo *exception) 5421{ 5422 static const char 5423 *DrawMenu[] = 5424 { 5425 "Element", 5426 "Color", 5427 "Stipple", 5428 "Width", 5429 "Undo", 5430 "Help", 5431 "Dismiss", 5432 (char *) NULL 5433 }; 5434 5435 static ElementType 5436 element = PointElement; 5437 5438 static const ModeType 5439 DrawCommands[] = 5440 { 5441 DrawElementCommand, 5442 DrawColorCommand, 5443 DrawStippleCommand, 5444 DrawWidthCommand, 5445 DrawUndoCommand, 5446 DrawHelpCommand, 5447 DrawDismissCommand 5448 }; 5449 5450 static Pixmap 5451 stipple = (Pixmap) NULL; 5452 5453 static unsigned int 5454 pen_id = 0, 5455 line_width = 1; 5456 5457 char 5458 command[MaxTextExtent], 5459 text[MaxTextExtent]; 5460 5461 Cursor 5462 cursor; 5463 5464 int 5465 entry, 5466 id, 5467 number_coordinates, 5468 x, 5469 y; 5470 5471 double 5472 degrees; 5473 5474 MagickStatusType 5475 status; 5476 5477 RectangleInfo 5478 rectangle_info; 5479 5480 register int 5481 i; 5482 5483 unsigned int 5484 distance, 5485 height, 5486 max_coordinates, 5487 width; 5488 5489 size_t 5490 state; 5491 5492 Window 5493 root_window; 5494 5495 XDrawInfo 5496 draw_info; 5497 5498 XEvent 5499 event; 5500 5501 XPoint 5502 *coordinate_info; 5503 5504 XSegment 5505 line_info; 5506 5507 /* 5508 Allocate polygon info. 5509 */ 5510 max_coordinates=2048; 5511 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates, 5512 sizeof(*coordinate_info)); 5513 if (coordinate_info == (XPoint *) NULL) 5514 { 5515 (void) ThrowMagickException(exception,GetMagickModule(), 5516 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 5517 return(MagickFalse); 5518 } 5519 /* 5520 Map Command widget. 5521 */ 5522 (void) CloneString(&windows->command.name,"Draw"); 5523 windows->command.data=4; 5524 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL); 5525 (void) XMapRaised(display,windows->command.id); 5526 XClientMessage(display,windows->image.id,windows->im_protocols, 5527 windows->im_update_widget,CurrentTime); 5528 /* 5529 Wait for first button press. 5530 */ 5531 root_window=XRootWindow(display,XDefaultScreen(display)); 5532 draw_info.stencil=OpaqueStencil; 5533 status=MagickTrue; 5534 cursor=XCreateFontCursor(display,XC_tcross); 5535 for ( ; ; ) 5536 { 5537 XQueryPosition(display,windows->image.id,&x,&y); 5538 (void) XSelectInput(display,windows->image.id, 5539 windows->image.attributes.event_mask | PointerMotionMask); 5540 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5541 state=DefaultState; 5542 do 5543 { 5544 if( IfMagickTrue(windows->info.mapped) ) 5545 { 5546 /* 5547 Display pointer position. 5548 */ 5549 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 5550 x+windows->image.x,y+windows->image.y); 5551 XInfoWidget(display,windows,text); 5552 } 5553 /* 5554 Wait for next event. 5555 */ 5556 XScreenEvent(display,windows,&event,exception); 5557 if (event.xany.window == windows->command.id) 5558 { 5559 /* 5560 Select a command from the Command widget. 5561 */ 5562 id=XCommandWidget(display,windows,DrawMenu,&event); 5563 if (id < 0) 5564 continue; 5565 switch (DrawCommands[id]) 5566 { 5567 case DrawElementCommand: 5568 { 5569 static const char 5570 *Elements[] = 5571 { 5572 "point", 5573 "line", 5574 "rectangle", 5575 "fill rectangle", 5576 "circle", 5577 "fill circle", 5578 "ellipse", 5579 "fill ellipse", 5580 "polygon", 5581 "fill polygon", 5582 (char *) NULL, 5583 }; 5584 5585 /* 5586 Select a command from the pop-up menu. 5587 */ 5588 element=(ElementType) (XMenuWidget(display,windows, 5589 DrawMenu[id],Elements,command)+1); 5590 break; 5591 } 5592 case DrawColorCommand: 5593 { 5594 const char 5595 *ColorMenu[MaxNumberPens+1]; 5596 5597 int 5598 pen_number; 5599 5600 MagickBooleanType 5601 transparent; 5602 5603 XColor 5604 color; 5605 5606 /* 5607 Initialize menu selections. 5608 */ 5609 for (i=0; i < (int) (MaxNumberPens-2); i++) 5610 ColorMenu[i]=resource_info->pen_colors[i]; 5611 ColorMenu[MaxNumberPens-2]="transparent"; 5612 ColorMenu[MaxNumberPens-1]="Browser..."; 5613 ColorMenu[MaxNumberPens]=(char *) NULL; 5614 /* 5615 Select a pen color from the pop-up menu. 5616 */ 5617 pen_number=XMenuWidget(display,windows,DrawMenu[id], 5618 (const char **) ColorMenu,command); 5619 if (pen_number < 0) 5620 break; 5621 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue : 5622 MagickFalse; 5623 if( IfMagickTrue(transparent) ) 5624 { 5625 draw_info.stencil=TransparentStencil; 5626 break; 5627 } 5628 if (pen_number == (MaxNumberPens-1)) 5629 { 5630 static char 5631 color_name[MaxTextExtent] = "gray"; 5632 5633 /* 5634 Select a pen color from a dialog. 5635 */ 5636 resource_info->pen_colors[pen_number]=color_name; 5637 XColorBrowserWidget(display,windows,"Select",color_name); 5638 if (*color_name == '\0') 5639 break; 5640 } 5641 /* 5642 Set pen color. 5643 */ 5644 (void) XParseColor(display,windows->map_info->colormap, 5645 resource_info->pen_colors[pen_number],&color); 5646 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 5647 (unsigned int) MaxColors,&color); 5648 windows->pixel_info->pen_colors[pen_number]=color; 5649 pen_id=(unsigned int) pen_number; 5650 draw_info.stencil=OpaqueStencil; 5651 break; 5652 } 5653 case DrawStippleCommand: 5654 { 5655 Image 5656 *stipple_image; 5657 5658 ImageInfo 5659 *image_info; 5660 5661 int 5662 status; 5663 5664 static char 5665 filename[MaxTextExtent] = "\0"; 5666 5667 static const char 5668 *StipplesMenu[] = 5669 { 5670 "Brick", 5671 "Diagonal", 5672 "Scales", 5673 "Vertical", 5674 "Wavy", 5675 "Translucent", 5676 "Opaque", 5677 (char *) NULL, 5678 (char *) NULL, 5679 }; 5680 5681 /* 5682 Select a command from the pop-up menu. 5683 */ 5684 StipplesMenu[7]="Open..."; 5685 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu, 5686 command); 5687 if (entry < 0) 5688 break; 5689 if (stipple != (Pixmap) NULL) 5690 (void) XFreePixmap(display,stipple); 5691 stipple=(Pixmap) NULL; 5692 if (entry != 7) 5693 { 5694 switch (entry) 5695 { 5696 case 0: 5697 { 5698 stipple=XCreateBitmapFromData(display,root_window, 5699 (char *) BricksBitmap,BricksWidth,BricksHeight); 5700 break; 5701 } 5702 case 1: 5703 { 5704 stipple=XCreateBitmapFromData(display,root_window, 5705 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight); 5706 break; 5707 } 5708 case 2: 5709 { 5710 stipple=XCreateBitmapFromData(display,root_window, 5711 (char *) ScalesBitmap,ScalesWidth,ScalesHeight); 5712 break; 5713 } 5714 case 3: 5715 { 5716 stipple=XCreateBitmapFromData(display,root_window, 5717 (char *) VerticalBitmap,VerticalWidth,VerticalHeight); 5718 break; 5719 } 5720 case 4: 5721 { 5722 stipple=XCreateBitmapFromData(display,root_window, 5723 (char *) WavyBitmap,WavyWidth,WavyHeight); 5724 break; 5725 } 5726 case 5: 5727 { 5728 stipple=XCreateBitmapFromData(display,root_window, 5729 (char *) HighlightBitmap,HighlightWidth, 5730 HighlightHeight); 5731 break; 5732 } 5733 case 6: 5734 default: 5735 { 5736 stipple=XCreateBitmapFromData(display,root_window, 5737 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight); 5738 break; 5739 } 5740 } 5741 break; 5742 } 5743 XFileBrowserWidget(display,windows,"Stipple",filename); 5744 if (*filename == '\0') 5745 break; 5746 /* 5747 Read image. 5748 */ 5749 XSetCursorState(display,windows,MagickTrue); 5750 XCheckRefreshWindows(display,windows); 5751 image_info=AcquireImageInfo(); 5752 (void) CopyMagickString(image_info->filename,filename, 5753 MaxTextExtent); 5754 stipple_image=ReadImage(image_info,exception); 5755 CatchException(exception); 5756 XSetCursorState(display,windows,MagickFalse); 5757 if (stipple_image == (Image *) NULL) 5758 break; 5759 (void) AcquireUniqueFileResource(filename); 5760 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent, 5761 "xbm:%s",filename); 5762 (void) WriteImage(image_info,stipple_image,exception); 5763 stipple_image=DestroyImage(stipple_image); 5764 image_info=DestroyImageInfo(image_info); 5765 status=XReadBitmapFile(display,root_window,filename,&width, 5766 &height,&stipple,&x,&y); 5767 (void) RelinquishUniqueFileResource(filename); 5768 if ((status != BitmapSuccess) != 0) 5769 XNoticeWidget(display,windows,"Unable to read X bitmap image:", 5770 filename); 5771 break; 5772 } 5773 case DrawWidthCommand: 5774 { 5775 static char 5776 width[MaxTextExtent] = "0"; 5777 5778 static const char 5779 *WidthsMenu[] = 5780 { 5781 "1", 5782 "2", 5783 "4", 5784 "8", 5785 "16", 5786 "Dialog...", 5787 (char *) NULL, 5788 }; 5789 5790 /* 5791 Select a command from the pop-up menu. 5792 */ 5793 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu, 5794 command); 5795 if (entry < 0) 5796 break; 5797 if (entry != 5) 5798 { 5799 line_width=(unsigned int) StringToUnsignedLong( 5800 WidthsMenu[entry]); 5801 break; 5802 } 5803 (void) XDialogWidget(display,windows,"Ok","Enter line width:", 5804 width); 5805 if (*width == '\0') 5806 break; 5807 line_width=(unsigned int) StringToUnsignedLong(width); 5808 break; 5809 } 5810 case DrawUndoCommand: 5811 { 5812 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 5813 image,exception); 5814 break; 5815 } 5816 case DrawHelpCommand: 5817 { 5818 XTextViewWidget(display,resource_info,windows,MagickFalse, 5819 "Help Viewer - Image Rotation",ImageDrawHelp); 5820 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5821 break; 5822 } 5823 case DrawDismissCommand: 5824 { 5825 /* 5826 Prematurely exit. 5827 */ 5828 state|=EscapeState; 5829 state|=ExitState; 5830 break; 5831 } 5832 default: 5833 break; 5834 } 5835 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5836 continue; 5837 } 5838 switch (event.type) 5839 { 5840 case ButtonPress: 5841 { 5842 if (event.xbutton.button != Button1) 5843 break; 5844 if (event.xbutton.window != windows->image.id) 5845 break; 5846 /* 5847 exit loop. 5848 */ 5849 x=event.xbutton.x; 5850 y=event.xbutton.y; 5851 state|=ExitState; 5852 break; 5853 } 5854 case ButtonRelease: 5855 break; 5856 case Expose: 5857 break; 5858 case KeyPress: 5859 { 5860 KeySym 5861 key_symbol; 5862 5863 if (event.xkey.window != windows->image.id) 5864 break; 5865 /* 5866 Respond to a user key press. 5867 */ 5868 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5869 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5870 switch ((int) key_symbol) 5871 { 5872 case XK_Escape: 5873 case XK_F20: 5874 { 5875 /* 5876 Prematurely exit. 5877 */ 5878 state|=EscapeState; 5879 state|=ExitState; 5880 break; 5881 } 5882 case XK_F1: 5883 case XK_Help: 5884 { 5885 XTextViewWidget(display,resource_info,windows,MagickFalse, 5886 "Help Viewer - Image Rotation",ImageDrawHelp); 5887 break; 5888 } 5889 default: 5890 { 5891 (void) XBell(display,0); 5892 break; 5893 } 5894 } 5895 break; 5896 } 5897 case MotionNotify: 5898 { 5899 /* 5900 Map and unmap Info widget as text cursor crosses its boundaries. 5901 */ 5902 x=event.xmotion.x; 5903 y=event.xmotion.y; 5904 if( IfMagickTrue(windows->info.mapped) ) 5905 { 5906 if ((x < (int) (windows->info.x+windows->info.width)) && 5907 (y < (int) (windows->info.y+windows->info.height))) 5908 (void) XWithdrawWindow(display,windows->info.id, 5909 windows->info.screen); 5910 } 5911 else 5912 if ((x > (int) (windows->info.x+windows->info.width)) || 5913 (y > (int) (windows->info.y+windows->info.height))) 5914 (void) XMapWindow(display,windows->info.id); 5915 break; 5916 } 5917 } 5918 } while ((state & ExitState) == 0); 5919 (void) XSelectInput(display,windows->image.id, 5920 windows->image.attributes.event_mask); 5921 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 5922 if ((state & EscapeState) != 0) 5923 break; 5924 /* 5925 Draw element as pointer moves until the button is released. 5926 */ 5927 distance=0; 5928 degrees=0.0; 5929 line_info.x1=x; 5930 line_info.y1=y; 5931 line_info.x2=x; 5932 line_info.y2=y; 5933 rectangle_info.x=(ssize_t) x; 5934 rectangle_info.y=(ssize_t) y; 5935 rectangle_info.width=0; 5936 rectangle_info.height=0; 5937 number_coordinates=1; 5938 coordinate_info->x=x; 5939 coordinate_info->y=y; 5940 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 5941 state=DefaultState; 5942 do 5943 { 5944 switch (element) 5945 { 5946 case PointElement: 5947 default: 5948 { 5949 if (number_coordinates > 1) 5950 { 5951 (void) XDrawLines(display,windows->image.id, 5952 windows->image.highlight_context,coordinate_info, 5953 number_coordinates,CoordModeOrigin); 5954 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d", 5955 coordinate_info[number_coordinates-1].x, 5956 coordinate_info[number_coordinates-1].y); 5957 XInfoWidget(display,windows,text); 5958 } 5959 break; 5960 } 5961 case LineElement: 5962 { 5963 if (distance > 9) 5964 { 5965 /* 5966 Display angle of the line. 5967 */ 5968 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 5969 line_info.y1),(double) (line_info.x2-line_info.x1))); 5970 (void) FormatLocaleString(text,MaxTextExtent," %g", 5971 (double) degrees); 5972 XInfoWidget(display,windows,text); 5973 XHighlightLine(display,windows->image.id, 5974 windows->image.highlight_context,&line_info); 5975 } 5976 else 5977 if( IfMagickTrue(windows->info.mapped) ) 5978 (void) XWithdrawWindow(display,windows->info.id, 5979 windows->info.screen); 5980 break; 5981 } 5982 case RectangleElement: 5983 case FillRectangleElement: 5984 { 5985 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5986 { 5987 /* 5988 Display info and draw drawing rectangle. 5989 */ 5990 (void) FormatLocaleString(text,MaxTextExtent, 5991 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5992 (double) rectangle_info.height,(double) rectangle_info.x, 5993 (double) rectangle_info.y); 5994 XInfoWidget(display,windows,text); 5995 XHighlightRectangle(display,windows->image.id, 5996 windows->image.highlight_context,&rectangle_info); 5997 } 5998 else 5999 if( IfMagickTrue(windows->info.mapped) ) 6000 (void) XWithdrawWindow(display,windows->info.id, 6001 windows->info.screen); 6002 break; 6003 } 6004 case CircleElement: 6005 case FillCircleElement: 6006 case EllipseElement: 6007 case FillEllipseElement: 6008 { 6009 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6010 { 6011 /* 6012 Display info and draw drawing rectangle. 6013 */ 6014 (void) FormatLocaleString(text,MaxTextExtent, 6015 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 6016 (double) rectangle_info.height,(double) rectangle_info.x, 6017 (double) rectangle_info.y); 6018 XInfoWidget(display,windows,text); 6019 XHighlightEllipse(display,windows->image.id, 6020 windows->image.highlight_context,&rectangle_info); 6021 } 6022 else 6023 if( IfMagickTrue(windows->info.mapped) ) 6024 (void) XWithdrawWindow(display,windows->info.id, 6025 windows->info.screen); 6026 break; 6027 } 6028 case PolygonElement: 6029 case FillPolygonElement: 6030 { 6031 if (number_coordinates > 1) 6032 (void) XDrawLines(display,windows->image.id, 6033 windows->image.highlight_context,coordinate_info, 6034 number_coordinates,CoordModeOrigin); 6035 if (distance > 9) 6036 { 6037 /* 6038 Display angle of the line. 6039 */ 6040 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 6041 line_info.y1),(double) (line_info.x2-line_info.x1))); 6042 (void) FormatLocaleString(text,MaxTextExtent," %g", 6043 (double) degrees); 6044 XInfoWidget(display,windows,text); 6045 XHighlightLine(display,windows->image.id, 6046 windows->image.highlight_context,&line_info); 6047 } 6048 else 6049 if( IfMagickTrue(windows->info.mapped) ) 6050 (void) XWithdrawWindow(display,windows->info.id, 6051 windows->info.screen); 6052 break; 6053 } 6054 } 6055 /* 6056 Wait for next event. 6057 */ 6058 XScreenEvent(display,windows,&event,exception); 6059 switch (element) 6060 { 6061 case PointElement: 6062 default: 6063 { 6064 if (number_coordinates > 1) 6065 (void) XDrawLines(display,windows->image.id, 6066 windows->image.highlight_context,coordinate_info, 6067 number_coordinates,CoordModeOrigin); 6068 break; 6069 } 6070 case LineElement: 6071 { 6072 if (distance > 9) 6073 XHighlightLine(display,windows->image.id, 6074 windows->image.highlight_context,&line_info); 6075 break; 6076 } 6077 case RectangleElement: 6078 case FillRectangleElement: 6079 { 6080 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6081 XHighlightRectangle(display,windows->image.id, 6082 windows->image.highlight_context,&rectangle_info); 6083 break; 6084 } 6085 case CircleElement: 6086 case FillCircleElement: 6087 case EllipseElement: 6088 case FillEllipseElement: 6089 { 6090 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6091 XHighlightEllipse(display,windows->image.id, 6092 windows->image.highlight_context,&rectangle_info); 6093 break; 6094 } 6095 case PolygonElement: 6096 case FillPolygonElement: 6097 { 6098 if (number_coordinates > 1) 6099 (void) XDrawLines(display,windows->image.id, 6100 windows->image.highlight_context,coordinate_info, 6101 number_coordinates,CoordModeOrigin); 6102 if (distance > 9) 6103 XHighlightLine(display,windows->image.id, 6104 windows->image.highlight_context,&line_info); 6105 break; 6106 } 6107 } 6108 switch (event.type) 6109 { 6110 case ButtonPress: 6111 break; 6112 case ButtonRelease: 6113 { 6114 /* 6115 User has committed to element. 6116 */ 6117 line_info.x2=event.xbutton.x; 6118 line_info.y2=event.xbutton.y; 6119 rectangle_info.x=(ssize_t) event.xbutton.x; 6120 rectangle_info.y=(ssize_t) event.xbutton.y; 6121 coordinate_info[number_coordinates].x=event.xbutton.x; 6122 coordinate_info[number_coordinates].y=event.xbutton.y; 6123 if (((element != PolygonElement) && 6124 (element != FillPolygonElement)) || (distance <= 9)) 6125 { 6126 state|=ExitState; 6127 break; 6128 } 6129 number_coordinates++; 6130 if (number_coordinates < (int) max_coordinates) 6131 { 6132 line_info.x1=event.xbutton.x; 6133 line_info.y1=event.xbutton.y; 6134 break; 6135 } 6136 max_coordinates<<=1; 6137 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6138 max_coordinates,sizeof(*coordinate_info)); 6139 if (coordinate_info == (XPoint *) NULL) 6140 (void) ThrowMagickException(exception,GetMagickModule(), 6141 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6142 break; 6143 } 6144 case Expose: 6145 break; 6146 case MotionNotify: 6147 { 6148 if (event.xmotion.window != windows->image.id) 6149 break; 6150 if (element != PointElement) 6151 { 6152 line_info.x2=event.xmotion.x; 6153 line_info.y2=event.xmotion.y; 6154 rectangle_info.x=(ssize_t) event.xmotion.x; 6155 rectangle_info.y=(ssize_t) event.xmotion.y; 6156 break; 6157 } 6158 coordinate_info[number_coordinates].x=event.xbutton.x; 6159 coordinate_info[number_coordinates].y=event.xbutton.y; 6160 number_coordinates++; 6161 if (number_coordinates < (int) max_coordinates) 6162 break; 6163 max_coordinates<<=1; 6164 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6165 max_coordinates,sizeof(*coordinate_info)); 6166 if (coordinate_info == (XPoint *) NULL) 6167 (void) ThrowMagickException(exception,GetMagickModule(), 6168 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6169 break; 6170 } 6171 default: 6172 break; 6173 } 6174 /* 6175 Check boundary conditions. 6176 */ 6177 if (line_info.x2 < 0) 6178 line_info.x2=0; 6179 else 6180 if (line_info.x2 > (int) windows->image.width) 6181 line_info.x2=(short) windows->image.width; 6182 if (line_info.y2 < 0) 6183 line_info.y2=0; 6184 else 6185 if (line_info.y2 > (int) windows->image.height) 6186 line_info.y2=(short) windows->image.height; 6187 distance=(unsigned int) 6188 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+ 6189 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1))); 6190 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) || 6191 ((state & ExitState) != 0)) 6192 { 6193 if (rectangle_info.x < 0) 6194 rectangle_info.x=0; 6195 else 6196 if (rectangle_info.x > (ssize_t) windows->image.width) 6197 rectangle_info.x=(ssize_t) windows->image.width; 6198 if ((int) rectangle_info.x < x) 6199 rectangle_info.width=(unsigned int) (x-rectangle_info.x); 6200 else 6201 { 6202 rectangle_info.width=(unsigned int) (rectangle_info.x-x); 6203 rectangle_info.x=(ssize_t) x; 6204 } 6205 if (rectangle_info.y < 0) 6206 rectangle_info.y=0; 6207 else 6208 if (rectangle_info.y > (ssize_t) windows->image.height) 6209 rectangle_info.y=(ssize_t) windows->image.height; 6210 if ((int) rectangle_info.y < y) 6211 rectangle_info.height=(unsigned int) (y-rectangle_info.y); 6212 else 6213 { 6214 rectangle_info.height=(unsigned int) (rectangle_info.y-y); 6215 rectangle_info.y=(ssize_t) y; 6216 } 6217 } 6218 } while ((state & ExitState) == 0); 6219 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 6220 if ((element == PointElement) || (element == PolygonElement) || 6221 (element == FillPolygonElement)) 6222 { 6223 /* 6224 Determine polygon bounding box. 6225 */ 6226 rectangle_info.x=(ssize_t) coordinate_info->x; 6227 rectangle_info.y=(ssize_t) coordinate_info->y; 6228 x=coordinate_info->x; 6229 y=coordinate_info->y; 6230 for (i=1; i < number_coordinates; i++) 6231 { 6232 if (coordinate_info[i].x > x) 6233 x=coordinate_info[i].x; 6234 if (coordinate_info[i].y > y) 6235 y=coordinate_info[i].y; 6236 if ((ssize_t) coordinate_info[i].x < rectangle_info.x) 6237 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0); 6238 if ((ssize_t) coordinate_info[i].y < rectangle_info.y) 6239 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0); 6240 } 6241 rectangle_info.width=(size_t) (x-rectangle_info.x); 6242 rectangle_info.height=(size_t) (y-rectangle_info.y); 6243 for (i=0; i < number_coordinates; i++) 6244 { 6245 coordinate_info[i].x-=rectangle_info.x; 6246 coordinate_info[i].y-=rectangle_info.y; 6247 } 6248 } 6249 else 6250 if (distance <= 9) 6251 continue; 6252 else 6253 if ((element == RectangleElement) || 6254 (element == CircleElement) || (element == EllipseElement)) 6255 { 6256 rectangle_info.width--; 6257 rectangle_info.height--; 6258 } 6259 /* 6260 Drawing is relative to image configuration. 6261 */ 6262 draw_info.x=(int) rectangle_info.x; 6263 draw_info.y=(int) rectangle_info.y; 6264 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand, 6265 image,exception); 6266 width=(unsigned int) (*image)->columns; 6267 height=(unsigned int) (*image)->rows; 6268 x=0; 6269 y=0; 6270 if (windows->image.crop_geometry != (char *) NULL) 6271 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 6272 draw_info.x+=windows->image.x-(line_width/2); 6273 if (draw_info.x < 0) 6274 draw_info.x=0; 6275 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width); 6276 draw_info.y+=windows->image.y-(line_width/2); 6277 if (draw_info.y < 0) 6278 draw_info.y=0; 6279 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height; 6280 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1); 6281 if (draw_info.width > (unsigned int) (*image)->columns) 6282 draw_info.width=(unsigned int) (*image)->columns; 6283 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1); 6284 if (draw_info.height > (unsigned int) (*image)->rows) 6285 draw_info.height=(unsigned int) (*image)->rows; 6286 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d", 6287 width*draw_info.width/windows->image.ximage->width, 6288 height*draw_info.height/windows->image.ximage->height, 6289 draw_info.x+x,draw_info.y+y); 6290 /* 6291 Initialize drawing attributes. 6292 */ 6293 draw_info.degrees=0.0; 6294 draw_info.element=element; 6295 draw_info.stipple=stipple; 6296 draw_info.line_width=line_width; 6297 draw_info.line_info=line_info; 6298 if (line_info.x1 > (int) (line_width/2)) 6299 draw_info.line_info.x1=(short) line_width/2; 6300 if (line_info.y1 > (int) (line_width/2)) 6301 draw_info.line_info.y1=(short) line_width/2; 6302 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2)); 6303 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2)); 6304 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0)) 6305 { 6306 draw_info.line_info.x2=(-draw_info.line_info.x2); 6307 draw_info.line_info.y2=(-draw_info.line_info.y2); 6308 } 6309 if (draw_info.line_info.x2 < 0) 6310 { 6311 draw_info.line_info.x2=(-draw_info.line_info.x2); 6312 Swap(draw_info.line_info.x1,draw_info.line_info.x2); 6313 } 6314 if (draw_info.line_info.y2 < 0) 6315 { 6316 draw_info.line_info.y2=(-draw_info.line_info.y2); 6317 Swap(draw_info.line_info.y1,draw_info.line_info.y2); 6318 } 6319 draw_info.rectangle_info=rectangle_info; 6320 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2)) 6321 draw_info.rectangle_info.x=(ssize_t) line_width/2; 6322 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2)) 6323 draw_info.rectangle_info.y=(ssize_t) line_width/2; 6324 draw_info.number_coordinates=(unsigned int) number_coordinates; 6325 draw_info.coordinate_info=coordinate_info; 6326 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 6327 /* 6328 Draw element on image. 6329 */ 6330 XSetCursorState(display,windows,MagickTrue); 6331 XCheckRefreshWindows(display,windows); 6332 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception); 6333 XSetCursorState(display,windows,MagickFalse); 6334 /* 6335 Update image colormap and return to image drawing. 6336 */ 6337 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6338 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6339 } 6340 XSetCursorState(display,windows,MagickFalse); 6341 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info); 6342 return(IsMagickTrue(status)); 6343} 6344 6345/* 6346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6347% % 6348% % 6349% % 6350+ X D r a w P a n R e c t a n g l e % 6351% % 6352% % 6353% % 6354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6355% 6356% XDrawPanRectangle() draws a rectangle in the pan window. The pan window 6357% displays a zoom image and the rectangle shows which portion of the image is 6358% displayed in the Image window. 6359% 6360% The format of the XDrawPanRectangle method is: 6361% 6362% XDrawPanRectangle(Display *display,XWindows *windows) 6363% 6364% A description of each parameter follows: 6365% 6366% o display: Specifies a connection to an X server; returned from 6367% XOpenDisplay. 6368% 6369% o windows: Specifies a pointer to a XWindows structure. 6370% 6371*/ 6372static void XDrawPanRectangle(Display *display,XWindows *windows) 6373{ 6374 double 6375 scale_factor; 6376 6377 RectangleInfo 6378 highlight_info; 6379 6380 /* 6381 Determine dimensions of the panning rectangle. 6382 */ 6383 scale_factor=(double) windows->pan.width/windows->image.ximage->width; 6384 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5); 6385 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5); 6386 scale_factor=(double) 6387 windows->pan.height/windows->image.ximage->height; 6388 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5); 6389 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5); 6390 /* 6391 Display the panning rectangle. 6392 */ 6393 (void) XClearWindow(display,windows->pan.id); 6394 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context, 6395 &highlight_info); 6396} 6397 6398/* 6399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6400% % 6401% % 6402% % 6403+ X I m a g e C a c h e % 6404% % 6405% % 6406% % 6407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6408% 6409% XImageCache() handles the creation, manipulation, and destruction of the 6410% image cache (undo and redo buffers). 6411% 6412% The format of the XImageCache method is: 6413% 6414% void XImageCache(Display *display,XResourceInfo *resource_info, 6415% XWindows *windows,const CommandType command,Image **image, 6416% ExceptionInfo *exception) 6417% 6418% A description of each parameter follows: 6419% 6420% o display: Specifies a connection to an X server; returned from 6421% XOpenDisplay. 6422% 6423% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6424% 6425% o windows: Specifies a pointer to a XWindows structure. 6426% 6427% o command: Specifies a command to perform. 6428% 6429% o image: the image; XImageCache may transform the image and return a new 6430% image pointer. 6431% 6432% o exception: return any errors or warnings in this structure. 6433% 6434*/ 6435static void XImageCache(Display *display,XResourceInfo *resource_info, 6436 XWindows *windows,const CommandType command,Image **image, 6437 ExceptionInfo *exception) 6438{ 6439 Image 6440 *cache_image; 6441 6442 static Image 6443 *redo_image = (Image *) NULL, 6444 *undo_image = (Image *) NULL; 6445 6446 switch (command) 6447 { 6448 case FreeBuffersCommand: 6449 { 6450 /* 6451 Free memory from the undo and redo cache. 6452 */ 6453 while (undo_image != (Image *) NULL) 6454 { 6455 cache_image=undo_image; 6456 undo_image=GetPreviousImageInList(undo_image); 6457 cache_image->list=DestroyImage(cache_image->list); 6458 cache_image=DestroyImage(cache_image); 6459 } 6460 undo_image=NewImageList(); 6461 if (redo_image != (Image *) NULL) 6462 redo_image=DestroyImage(redo_image); 6463 redo_image=NewImageList(); 6464 return; 6465 } 6466 case UndoCommand: 6467 { 6468 char 6469 image_geometry[MaxTextExtent]; 6470 6471 /* 6472 Undo the last image transformation. 6473 */ 6474 if (undo_image == (Image *) NULL) 6475 { 6476 (void) XBell(display,0); 6477 return; 6478 } 6479 cache_image=undo_image; 6480 undo_image=GetPreviousImageInList(undo_image); 6481 windows->image.window_changes.width=(int) cache_image->columns; 6482 windows->image.window_changes.height=(int) cache_image->rows; 6483 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 6484 windows->image.ximage->width,windows->image.ximage->height); 6485 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 6486 exception); 6487 if (windows->image.crop_geometry != (char *) NULL) 6488 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 6489 windows->image.crop_geometry); 6490 windows->image.crop_geometry=cache_image->geometry; 6491 if (redo_image != (Image *) NULL) 6492 redo_image=DestroyImage(redo_image); 6493 redo_image=(*image); 6494 *image=cache_image->list; 6495 cache_image=DestroyImage(cache_image); 6496 if( IfMagickTrue(windows->image.orphan) ) 6497 return; 6498 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6499 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6500 return; 6501 } 6502 case CutCommand: 6503 case PasteCommand: 6504 case ApplyCommand: 6505 case HalfSizeCommand: 6506 case OriginalSizeCommand: 6507 case DoubleSizeCommand: 6508 case ResizeCommand: 6509 case TrimCommand: 6510 case CropCommand: 6511 case ChopCommand: 6512 case FlipCommand: 6513 case FlopCommand: 6514 case RotateRightCommand: 6515 case RotateLeftCommand: 6516 case RotateCommand: 6517 case ShearCommand: 6518 case RollCommand: 6519 case NegateCommand: 6520 case ContrastStretchCommand: 6521 case SigmoidalContrastCommand: 6522 case NormalizeCommand: 6523 case EqualizeCommand: 6524 case HueCommand: 6525 case SaturationCommand: 6526 case BrightnessCommand: 6527 case GammaCommand: 6528 case SpiffCommand: 6529 case DullCommand: 6530 case GrayscaleCommand: 6531 case MapCommand: 6532 case QuantizeCommand: 6533 case DespeckleCommand: 6534 case EmbossCommand: 6535 case ReduceNoiseCommand: 6536 case AddNoiseCommand: 6537 case SharpenCommand: 6538 case BlurCommand: 6539 case ThresholdCommand: 6540 case EdgeDetectCommand: 6541 case SpreadCommand: 6542 case ShadeCommand: 6543 case RaiseCommand: 6544 case SegmentCommand: 6545 case SolarizeCommand: 6546 case SepiaToneCommand: 6547 case SwirlCommand: 6548 case ImplodeCommand: 6549 case VignetteCommand: 6550 case WaveCommand: 6551 case OilPaintCommand: 6552 case CharcoalDrawCommand: 6553 case AnnotateCommand: 6554 case AddBorderCommand: 6555 case AddFrameCommand: 6556 case CompositeCommand: 6557 case CommentCommand: 6558 case LaunchCommand: 6559 case RegionofInterestCommand: 6560 case SaveToUndoBufferCommand: 6561 case RedoCommand: 6562 { 6563 Image 6564 *previous_image; 6565 6566 ssize_t 6567 bytes; 6568 6569 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo)); 6570 if (undo_image != (Image *) NULL) 6571 { 6572 /* 6573 Ensure the undo cache has enough memory available. 6574 */ 6575 previous_image=undo_image; 6576 while (previous_image != (Image *) NULL) 6577 { 6578 bytes+=previous_image->list->columns*previous_image->list->rows* 6579 sizeof(PixelInfo); 6580 if (bytes <= (ssize_t) (resource_info->undo_cache << 20)) 6581 { 6582 previous_image=GetPreviousImageInList(previous_image); 6583 continue; 6584 } 6585 bytes-=previous_image->list->columns*previous_image->list->rows* 6586 sizeof(PixelInfo); 6587 if (previous_image == undo_image) 6588 undo_image=NewImageList(); 6589 else 6590 previous_image->next->previous=NewImageList(); 6591 break; 6592 } 6593 while (previous_image != (Image *) NULL) 6594 { 6595 /* 6596 Delete any excess memory from undo cache. 6597 */ 6598 cache_image=previous_image; 6599 previous_image=GetPreviousImageInList(previous_image); 6600 cache_image->list=DestroyImage(cache_image->list); 6601 cache_image=DestroyImage(cache_image); 6602 } 6603 } 6604 if (bytes > (ssize_t) (resource_info->undo_cache << 20)) 6605 break; 6606 /* 6607 Save image before transformations are applied. 6608 */ 6609 cache_image=AcquireImage((ImageInfo *) NULL,exception); 6610 if (cache_image == (Image *) NULL) 6611 break; 6612 XSetCursorState(display,windows,MagickTrue); 6613 XCheckRefreshWindows(display,windows); 6614 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception); 6615 XSetCursorState(display,windows,MagickFalse); 6616 if (cache_image->list == (Image *) NULL) 6617 { 6618 cache_image=DestroyImage(cache_image); 6619 break; 6620 } 6621 cache_image->columns=(size_t) windows->image.ximage->width; 6622 cache_image->rows=(size_t) windows->image.ximage->height; 6623 cache_image->geometry=windows->image.crop_geometry; 6624 if (windows->image.crop_geometry != (char *) NULL) 6625 { 6626 cache_image->geometry=AcquireString((char *) NULL); 6627 (void) CopyMagickString(cache_image->geometry, 6628 windows->image.crop_geometry,MaxTextExtent); 6629 } 6630 if (undo_image == (Image *) NULL) 6631 { 6632 undo_image=cache_image; 6633 break; 6634 } 6635 undo_image->next=cache_image; 6636 undo_image->next->previous=undo_image; 6637 undo_image=undo_image->next; 6638 break; 6639 } 6640 default: 6641 break; 6642 } 6643 if (command == RedoCommand) 6644 { 6645 /* 6646 Redo the last image transformation. 6647 */ 6648 if (redo_image == (Image *) NULL) 6649 { 6650 (void) XBell(display,0); 6651 return; 6652 } 6653 windows->image.window_changes.width=(int) redo_image->columns; 6654 windows->image.window_changes.height=(int) redo_image->rows; 6655 if (windows->image.crop_geometry != (char *) NULL) 6656 windows->image.crop_geometry=(char *) 6657 RelinquishMagickMemory(windows->image.crop_geometry); 6658 windows->image.crop_geometry=redo_image->geometry; 6659 *image=DestroyImage(*image); 6660 *image=redo_image; 6661 redo_image=NewImageList(); 6662 if( IfMagickTrue(windows->image.orphan) ) 6663 return; 6664 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6665 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6666 return; 6667 } 6668 if (command != InfoCommand) 6669 return; 6670 /* 6671 Display image info. 6672 */ 6673 XSetCursorState(display,windows,MagickTrue); 6674 XCheckRefreshWindows(display,windows); 6675 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception); 6676 XSetCursorState(display,windows,MagickFalse); 6677} 6678 6679/* 6680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6681% % 6682% % 6683% % 6684+ X I m a g e W i n d o w C o m m a n d % 6685% % 6686% % 6687% % 6688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6689% 6690% XImageWindowCommand() makes a transform to the image or Image window as 6691% specified by a user menu button or keyboard command. 6692% 6693% The format of the XImageWindowCommand method is: 6694% 6695% CommandType XImageWindowCommand(Display *display, 6696% XResourceInfo *resource_info,XWindows *windows, 6697% const MagickStatusType state,KeySym key_symbol,Image **image, 6698% ExceptionInfo *exception) 6699% 6700% A description of each parameter follows: 6701% 6702% o nexus: Method XImageWindowCommand returns an image when the 6703% user chooses 'Open Image' from the command menu. Otherwise a null 6704% image is returned. 6705% 6706% o display: Specifies a connection to an X server; returned from 6707% XOpenDisplay. 6708% 6709% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6710% 6711% o windows: Specifies a pointer to a XWindows structure. 6712% 6713% o state: key mask. 6714% 6715% o key_symbol: Specifies a command to perform. 6716% 6717% o image: the image; XImageWIndowCommand may transform the image and 6718% return a new image pointer. 6719% 6720% o exception: return any errors or warnings in this structure. 6721% 6722*/ 6723static CommandType XImageWindowCommand(Display *display, 6724 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state, 6725 KeySym key_symbol,Image **image,ExceptionInfo *exception) 6726{ 6727 static char 6728 delta[MaxTextExtent] = ""; 6729 6730 static const char 6731 Digits[] = "01234567890"; 6732 6733 static KeySym 6734 last_symbol = XK_0; 6735 6736 if ((key_symbol >= XK_0) && (key_symbol <= XK_9)) 6737 { 6738 if (((last_symbol < XK_0) || (last_symbol > XK_9))) 6739 { 6740 *delta='\0'; 6741 resource_info->quantum=1; 6742 } 6743 last_symbol=key_symbol; 6744 delta[strlen(delta)+1]='\0'; 6745 delta[strlen(delta)]=Digits[key_symbol-XK_0]; 6746 resource_info->quantum=StringToLong(delta); 6747 return(NullCommand); 6748 } 6749 last_symbol=key_symbol; 6750 if (resource_info->immutable) 6751 { 6752 /* 6753 Virtual image window has a restricted command set. 6754 */ 6755 switch (key_symbol) 6756 { 6757 case XK_question: 6758 return(InfoCommand); 6759 case XK_p: 6760 case XK_Print: 6761 return(PrintCommand); 6762 case XK_space: 6763 return(NextCommand); 6764 case XK_q: 6765 case XK_Escape: 6766 return(QuitCommand); 6767 default: 6768 break; 6769 } 6770 return(NullCommand); 6771 } 6772 switch ((int) key_symbol) 6773 { 6774 case XK_o: 6775 { 6776 if ((state & ControlMask) == 0) 6777 break; 6778 return(OpenCommand); 6779 } 6780 case XK_space: 6781 return(NextCommand); 6782 case XK_BackSpace: 6783 return(FormerCommand); 6784 case XK_s: 6785 { 6786 if ((state & Mod1Mask) != 0) 6787 return(SwirlCommand); 6788 if ((state & ControlMask) == 0) 6789 return(ShearCommand); 6790 return(SaveCommand); 6791 } 6792 case XK_p: 6793 case XK_Print: 6794 { 6795 if ((state & Mod1Mask) != 0) 6796 return(OilPaintCommand); 6797 if ((state & Mod4Mask) != 0) 6798 return(ColorCommand); 6799 if ((state & ControlMask) == 0) 6800 return(NullCommand); 6801 return(PrintCommand); 6802 } 6803 case XK_d: 6804 { 6805 if ((state & Mod4Mask) != 0) 6806 return(DrawCommand); 6807 if ((state & ControlMask) == 0) 6808 return(NullCommand); 6809 return(DeleteCommand); 6810 } 6811 case XK_Select: 6812 { 6813 if ((state & ControlMask) == 0) 6814 return(NullCommand); 6815 return(SelectCommand); 6816 } 6817 case XK_n: 6818 { 6819 if ((state & ControlMask) == 0) 6820 return(NullCommand); 6821 return(NewCommand); 6822 } 6823 case XK_q: 6824 case XK_Escape: 6825 return(QuitCommand); 6826 case XK_z: 6827 case XK_Undo: 6828 { 6829 if ((state & ControlMask) == 0) 6830 return(NullCommand); 6831 return(UndoCommand); 6832 } 6833 case XK_r: 6834 case XK_Redo: 6835 { 6836 if ((state & ControlMask) == 0) 6837 return(RollCommand); 6838 return(RedoCommand); 6839 } 6840 case XK_x: 6841 { 6842 if ((state & ControlMask) == 0) 6843 return(NullCommand); 6844 return(CutCommand); 6845 } 6846 case XK_c: 6847 { 6848 if ((state & Mod1Mask) != 0) 6849 return(CharcoalDrawCommand); 6850 if ((state & ControlMask) == 0) 6851 return(CropCommand); 6852 return(CopyCommand); 6853 } 6854 case XK_v: 6855 case XK_Insert: 6856 { 6857 if ((state & Mod4Mask) != 0) 6858 return(CompositeCommand); 6859 if ((state & ControlMask) == 0) 6860 return(FlipCommand); 6861 return(PasteCommand); 6862 } 6863 case XK_less: 6864 return(HalfSizeCommand); 6865 case XK_minus: 6866 return(OriginalSizeCommand); 6867 case XK_greater: 6868 return(DoubleSizeCommand); 6869 case XK_percent: 6870 return(ResizeCommand); 6871 case XK_at: 6872 return(RefreshCommand); 6873 case XK_bracketleft: 6874 return(ChopCommand); 6875 case XK_h: 6876 return(FlopCommand); 6877 case XK_slash: 6878 return(RotateRightCommand); 6879 case XK_backslash: 6880 return(RotateLeftCommand); 6881 case XK_asterisk: 6882 return(RotateCommand); 6883 case XK_t: 6884 return(TrimCommand); 6885 case XK_H: 6886 return(HueCommand); 6887 case XK_S: 6888 return(SaturationCommand); 6889 case XK_L: 6890 return(BrightnessCommand); 6891 case XK_G: 6892 return(GammaCommand); 6893 case XK_C: 6894 return(SpiffCommand); 6895 case XK_Z: 6896 return(DullCommand); 6897 case XK_N: 6898 return(NormalizeCommand); 6899 case XK_equal: 6900 return(EqualizeCommand); 6901 case XK_asciitilde: 6902 return(NegateCommand); 6903 case XK_period: 6904 return(GrayscaleCommand); 6905 case XK_numbersign: 6906 return(QuantizeCommand); 6907 case XK_F2: 6908 return(DespeckleCommand); 6909 case XK_F3: 6910 return(EmbossCommand); 6911 case XK_F4: 6912 return(ReduceNoiseCommand); 6913 case XK_F5: 6914 return(AddNoiseCommand); 6915 case XK_F6: 6916 return(SharpenCommand); 6917 case XK_F7: 6918 return(BlurCommand); 6919 case XK_F8: 6920 return(ThresholdCommand); 6921 case XK_F9: 6922 return(EdgeDetectCommand); 6923 case XK_F10: 6924 return(SpreadCommand); 6925 case XK_F11: 6926 return(ShadeCommand); 6927 case XK_F12: 6928 return(RaiseCommand); 6929 case XK_F13: 6930 return(SegmentCommand); 6931 case XK_i: 6932 { 6933 if ((state & Mod1Mask) == 0) 6934 return(NullCommand); 6935 return(ImplodeCommand); 6936 } 6937 case XK_w: 6938 { 6939 if ((state & Mod1Mask) == 0) 6940 return(NullCommand); 6941 return(WaveCommand); 6942 } 6943 case XK_m: 6944 { 6945 if ((state & Mod4Mask) == 0) 6946 return(NullCommand); 6947 return(MatteCommand); 6948 } 6949 case XK_b: 6950 { 6951 if ((state & Mod4Mask) == 0) 6952 return(NullCommand); 6953 return(AddBorderCommand); 6954 } 6955 case XK_f: 6956 { 6957 if ((state & Mod4Mask) == 0) 6958 return(NullCommand); 6959 return(AddFrameCommand); 6960 } 6961 case XK_exclam: 6962 { 6963 if ((state & Mod4Mask) == 0) 6964 return(NullCommand); 6965 return(CommentCommand); 6966 } 6967 case XK_a: 6968 { 6969 if ((state & Mod1Mask) != 0) 6970 return(ApplyCommand); 6971 if ((state & Mod4Mask) != 0) 6972 return(AnnotateCommand); 6973 if ((state & ControlMask) == 0) 6974 return(NullCommand); 6975 return(RegionofInterestCommand); 6976 } 6977 case XK_question: 6978 return(InfoCommand); 6979 case XK_plus: 6980 return(ZoomCommand); 6981 case XK_P: 6982 { 6983 if ((state & ShiftMask) == 0) 6984 return(NullCommand); 6985 return(ShowPreviewCommand); 6986 } 6987 case XK_Execute: 6988 return(LaunchCommand); 6989 case XK_F1: 6990 return(HelpCommand); 6991 case XK_Find: 6992 return(BrowseDocumentationCommand); 6993 case XK_Menu: 6994 { 6995 (void) XMapRaised(display,windows->command.id); 6996 return(NullCommand); 6997 } 6998 case XK_Next: 6999 case XK_Prior: 7000 case XK_Home: 7001 case XK_KP_Home: 7002 { 7003 XTranslateImage(display,windows,*image,key_symbol); 7004 return(NullCommand); 7005 } 7006 case XK_Up: 7007 case XK_KP_Up: 7008 case XK_Down: 7009 case XK_KP_Down: 7010 case XK_Left: 7011 case XK_KP_Left: 7012 case XK_Right: 7013 case XK_KP_Right: 7014 { 7015 if ((state & Mod1Mask) != 0) 7016 { 7017 RectangleInfo 7018 crop_info; 7019 7020 /* 7021 Trim one pixel from edge of image. 7022 */ 7023 crop_info.x=0; 7024 crop_info.y=0; 7025 crop_info.width=(size_t) windows->image.ximage->width; 7026 crop_info.height=(size_t) windows->image.ximage->height; 7027 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up)) 7028 { 7029 if (resource_info->quantum >= (int) crop_info.height) 7030 resource_info->quantum=(int) crop_info.height-1; 7031 crop_info.height-=resource_info->quantum; 7032 } 7033 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down)) 7034 { 7035 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y)) 7036 resource_info->quantum=(int) (crop_info.height-crop_info.y-1); 7037 crop_info.y+=resource_info->quantum; 7038 crop_info.height-=resource_info->quantum; 7039 } 7040 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left)) 7041 { 7042 if (resource_info->quantum >= (int) crop_info.width) 7043 resource_info->quantum=(int) crop_info.width-1; 7044 crop_info.width-=resource_info->quantum; 7045 } 7046 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right)) 7047 { 7048 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x)) 7049 resource_info->quantum=(int) (crop_info.width-crop_info.x-1); 7050 crop_info.x+=resource_info->quantum; 7051 crop_info.width-=resource_info->quantum; 7052 } 7053 if ((int) (windows->image.x+windows->image.width) > 7054 (int) crop_info.width) 7055 windows->image.x=(int) (crop_info.width-windows->image.width); 7056 if ((int) (windows->image.y+windows->image.height) > 7057 (int) crop_info.height) 7058 windows->image.y=(int) (crop_info.height-windows->image.height); 7059 XSetCropGeometry(display,windows,&crop_info,*image); 7060 windows->image.window_changes.width=(int) crop_info.width; 7061 windows->image.window_changes.height=(int) crop_info.height; 7062 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None); 7063 (void) XConfigureImage(display,resource_info,windows,*image, 7064 exception); 7065 return(NullCommand); 7066 } 7067 XTranslateImage(display,windows,*image,key_symbol); 7068 return(NullCommand); 7069 } 7070 default: 7071 return(NullCommand); 7072 } 7073 return(NullCommand); 7074} 7075 7076/* 7077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7078% % 7079% % 7080% % 7081+ X M a g i c k C o m m a n d % 7082% % 7083% % 7084% % 7085%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7086% 7087% XMagickCommand() makes a transform to the image or Image window as 7088% specified by a user menu button or keyboard command. 7089% 7090% The format of the XMagickCommand method is: 7091% 7092% Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7093% XWindows *windows,const CommandType command,Image **image, 7094% ExceptionInfo *exception) 7095% 7096% A description of each parameter follows: 7097% 7098% o display: Specifies a connection to an X server; returned from 7099% XOpenDisplay. 7100% 7101% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 7102% 7103% o windows: Specifies a pointer to a XWindows structure. 7104% 7105% o command: Specifies a command to perform. 7106% 7107% o image: the image; XMagickCommand may transform the image and return a 7108% new image pointer. 7109% 7110% o exception: return any errors or warnings in this structure. 7111% 7112*/ 7113static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7114 XWindows *windows,const CommandType command,Image **image, 7115 ExceptionInfo *exception) 7116{ 7117 char 7118 filename[MaxTextExtent], 7119 geometry[MaxTextExtent], 7120 modulate_factors[MaxTextExtent]; 7121 7122 GeometryInfo 7123 geometry_info; 7124 7125 Image 7126 *nexus; 7127 7128 ImageInfo 7129 *image_info; 7130 7131 int 7132 x, 7133 y; 7134 7135 MagickStatusType 7136 flags, 7137 status; 7138 7139 QuantizeInfo 7140 quantize_info; 7141 7142 RectangleInfo 7143 page_geometry; 7144 7145 register int 7146 i; 7147 7148 static char 7149 color[MaxTextExtent] = "gray"; 7150 7151 unsigned int 7152 height, 7153 width; 7154 7155 /* 7156 Process user command. 7157 */ 7158 XCheckRefreshWindows(display,windows); 7159 XImageCache(display,resource_info,windows,command,image,exception); 7160 nexus=NewImageList(); 7161 windows->image.window_changes.width=windows->image.ximage->width; 7162 windows->image.window_changes.height=windows->image.ximage->height; 7163 image_info=CloneImageInfo(resource_info->image_info); 7164 SetGeometryInfo(&geometry_info); 7165 GetQuantizeInfo(&quantize_info); 7166 switch (command) 7167 { 7168 case OpenCommand: 7169 { 7170 /* 7171 Load image. 7172 */ 7173 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 7174 break; 7175 } 7176 case NextCommand: 7177 { 7178 /* 7179 Display next image. 7180 */ 7181 for (i=0; i < resource_info->quantum; i++) 7182 XClientMessage(display,windows->image.id,windows->im_protocols, 7183 windows->im_next_image,CurrentTime); 7184 break; 7185 } 7186 case FormerCommand: 7187 { 7188 /* 7189 Display former image. 7190 */ 7191 for (i=0; i < resource_info->quantum; i++) 7192 XClientMessage(display,windows->image.id,windows->im_protocols, 7193 windows->im_former_image,CurrentTime); 7194 break; 7195 } 7196 case SelectCommand: 7197 { 7198 int 7199 status; 7200 7201 /* 7202 Select image. 7203 */ 7204 if (*resource_info->home_directory == '\0') 7205 (void) CopyMagickString(resource_info->home_directory,".", 7206 MaxTextExtent); 7207 status=chdir(resource_info->home_directory); 7208 if (status == -1) 7209 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 7210 "UnableToOpenFile","%s",resource_info->home_directory); 7211 nexus=XOpenImage(display,resource_info,windows,MagickTrue); 7212 break; 7213 } 7214 case SaveCommand: 7215 { 7216 /* 7217 Save image. 7218 */ 7219 status=XSaveImage(display,resource_info,windows,*image,exception); 7220 if( IfMagickFalse(status) ) 7221 { 7222 char 7223 message[MaxTextExtent]; 7224 7225 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7226 exception->reason != (char *) NULL ? exception->reason : "", 7227 exception->description != (char *) NULL ? exception->description : 7228 ""); 7229 XNoticeWidget(display,windows,"Unable to save file:",message); 7230 break; 7231 } 7232 break; 7233 } 7234 case PrintCommand: 7235 { 7236 /* 7237 Print image. 7238 */ 7239 status=XPrintImage(display,resource_info,windows,*image,exception); 7240 if( IfMagickFalse(status) ) 7241 { 7242 char 7243 message[MaxTextExtent]; 7244 7245 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7246 exception->reason != (char *) NULL ? exception->reason : "", 7247 exception->description != (char *) NULL ? exception->description : 7248 ""); 7249 XNoticeWidget(display,windows,"Unable to print file:",message); 7250 break; 7251 } 7252 break; 7253 } 7254 case DeleteCommand: 7255 { 7256 static char 7257 filename[MaxTextExtent] = "\0"; 7258 7259 /* 7260 Delete image file. 7261 */ 7262 XFileBrowserWidget(display,windows,"Delete",filename); 7263 if (*filename == '\0') 7264 break; 7265 status=IsMagickTrue(remove_utf8(filename)); 7266 if( IfMagickTrue(status) ) 7267 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7268 break; 7269 } 7270 case NewCommand: 7271 { 7272 int 7273 status; 7274 7275 static char 7276 color[MaxTextExtent] = "gray", 7277 geometry[MaxTextExtent] = "640x480"; 7278 7279 static const char 7280 *format = "gradient"; 7281 7282 /* 7283 Query user for canvas geometry. 7284 */ 7285 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7286 geometry); 7287 if (*geometry == '\0') 7288 break; 7289 if (status == 0) 7290 format="xc"; 7291 XColorBrowserWidget(display,windows,"Select",color); 7292 if (*color == '\0') 7293 break; 7294 /* 7295 Create canvas. 7296 */ 7297 (void) FormatLocaleString(image_info->filename,MaxTextExtent, 7298 "%s:%s",format,color); 7299 (void) CloneString(&image_info->size,geometry); 7300 nexus=ReadImage(image_info,exception); 7301 CatchException(exception); 7302 XClientMessage(display,windows->image.id,windows->im_protocols, 7303 windows->im_next_image,CurrentTime); 7304 break; 7305 } 7306 case VisualDirectoryCommand: 7307 { 7308 /* 7309 Visual Image directory. 7310 */ 7311 nexus=XVisualDirectoryImage(display,resource_info,windows,exception); 7312 break; 7313 } 7314 case QuitCommand: 7315 { 7316 /* 7317 exit program. 7318 */ 7319 if( IfMagickFalse(resource_info->confirm_exit) ) 7320 XClientMessage(display,windows->image.id,windows->im_protocols, 7321 windows->im_exit,CurrentTime); 7322 else 7323 { 7324 int 7325 status; 7326 7327 /* 7328 Confirm program exit. 7329 */ 7330 status=XConfirmWidget(display,windows,"Do you really want to exit", 7331 resource_info->client_name); 7332 if (status > 0) 7333 XClientMessage(display,windows->image.id,windows->im_protocols, 7334 windows->im_exit,CurrentTime); 7335 } 7336 break; 7337 } 7338 case CutCommand: 7339 { 7340 /* 7341 Cut image. 7342 */ 7343 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception); 7344 break; 7345 } 7346 case CopyCommand: 7347 { 7348 /* 7349 Copy image. 7350 */ 7351 (void) XCropImage(display,resource_info,windows,*image,CopyMode, 7352 exception); 7353 break; 7354 } 7355 case PasteCommand: 7356 { 7357 /* 7358 Paste image. 7359 */ 7360 status=XPasteImage(display,resource_info,windows,*image,exception); 7361 if( IfMagickFalse(status) ) 7362 { 7363 XNoticeWidget(display,windows,"Unable to paste X image", 7364 (*image)->filename); 7365 break; 7366 } 7367 break; 7368 } 7369 case HalfSizeCommand: 7370 { 7371 /* 7372 Half image size. 7373 */ 7374 windows->image.window_changes.width=windows->image.ximage->width/2; 7375 windows->image.window_changes.height=windows->image.ximage->height/2; 7376 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7377 break; 7378 } 7379 case OriginalSizeCommand: 7380 { 7381 /* 7382 Original image size. 7383 */ 7384 windows->image.window_changes.width=(int) (*image)->columns; 7385 windows->image.window_changes.height=(int) (*image)->rows; 7386 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7387 break; 7388 } 7389 case DoubleSizeCommand: 7390 { 7391 /* 7392 Double the image size. 7393 */ 7394 windows->image.window_changes.width=windows->image.ximage->width << 1; 7395 windows->image.window_changes.height=windows->image.ximage->height << 1; 7396 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7397 break; 7398 } 7399 case ResizeCommand: 7400 { 7401 int 7402 status; 7403 7404 size_t 7405 height, 7406 width; 7407 7408 ssize_t 7409 x, 7410 y; 7411 7412 /* 7413 Resize image. 7414 */ 7415 width=(size_t) windows->image.ximage->width; 7416 height=(size_t) windows->image.ximage->height; 7417 x=0; 7418 y=0; 7419 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0", 7420 (double) width,(double) height); 7421 status=XDialogWidget(display,windows,"Resize", 7422 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7423 if (*geometry == '\0') 7424 break; 7425 if (status == 0) 7426 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent); 7427 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7428 windows->image.window_changes.width=(int) width; 7429 windows->image.window_changes.height=(int) height; 7430 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7431 break; 7432 } 7433 case ApplyCommand: 7434 { 7435 char 7436 image_geometry[MaxTextExtent]; 7437 7438 if ((windows->image.crop_geometry == (char *) NULL) && 7439 ((int) (*image)->columns == windows->image.ximage->width) && 7440 ((int) (*image)->rows == windows->image.ximage->height)) 7441 break; 7442 /* 7443 Apply size transforms to image. 7444 */ 7445 XSetCursorState(display,windows,MagickTrue); 7446 XCheckRefreshWindows(display,windows); 7447 /* 7448 Crop and/or scale displayed image. 7449 */ 7450 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 7451 windows->image.ximage->width,windows->image.ximage->height); 7452 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 7453 exception); 7454 if (windows->image.crop_geometry != (char *) NULL) 7455 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 7456 windows->image.crop_geometry); 7457 windows->image.x=0; 7458 windows->image.y=0; 7459 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7460 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7461 break; 7462 } 7463 case RefreshCommand: 7464 { 7465 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7466 break; 7467 } 7468 case RestoreCommand: 7469 { 7470 /* 7471 Restore Image window to its original size. 7472 */ 7473 if ((windows->image.width == (unsigned int) (*image)->columns) && 7474 (windows->image.height == (unsigned int) (*image)->rows) && 7475 (windows->image.crop_geometry == (char *) NULL)) 7476 { 7477 (void) XBell(display,0); 7478 break; 7479 } 7480 windows->image.window_changes.width=(int) (*image)->columns; 7481 windows->image.window_changes.height=(int) (*image)->rows; 7482 if (windows->image.crop_geometry != (char *) NULL) 7483 { 7484 windows->image.crop_geometry=(char *) 7485 RelinquishMagickMemory(windows->image.crop_geometry); 7486 windows->image.crop_geometry=(char *) NULL; 7487 windows->image.x=0; 7488 windows->image.y=0; 7489 } 7490 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7491 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7492 break; 7493 } 7494 case CropCommand: 7495 { 7496 /* 7497 Crop image. 7498 */ 7499 (void) XCropImage(display,resource_info,windows,*image,CropMode, 7500 exception); 7501 break; 7502 } 7503 case ChopCommand: 7504 { 7505 /* 7506 Chop image. 7507 */ 7508 status=XChopImage(display,resource_info,windows,image,exception); 7509 if( IfMagickFalse(status) ) 7510 { 7511 XNoticeWidget(display,windows,"Unable to cut X image", 7512 (*image)->filename); 7513 break; 7514 } 7515 break; 7516 } 7517 case FlopCommand: 7518 { 7519 Image 7520 *flop_image; 7521 7522 /* 7523 Flop image scanlines. 7524 */ 7525 XSetCursorState(display,windows,MagickTrue); 7526 XCheckRefreshWindows(display,windows); 7527 flop_image=FlopImage(*image,exception); 7528 if (flop_image != (Image *) NULL) 7529 { 7530 *image=DestroyImage(*image); 7531 *image=flop_image; 7532 } 7533 CatchException(exception); 7534 XSetCursorState(display,windows,MagickFalse); 7535 if (windows->image.crop_geometry != (char *) NULL) 7536 { 7537 /* 7538 Flop crop geometry. 7539 */ 7540 width=(unsigned int) (*image)->columns; 7541 height=(unsigned int) (*image)->rows; 7542 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7543 &width,&height); 7544 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7545 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7546 } 7547 if( IfMagickTrue(windows->image.orphan) ) 7548 break; 7549 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7550 break; 7551 } 7552 case FlipCommand: 7553 { 7554 Image 7555 *flip_image; 7556 7557 /* 7558 Flip image scanlines. 7559 */ 7560 XSetCursorState(display,windows,MagickTrue); 7561 XCheckRefreshWindows(display,windows); 7562 flip_image=FlipImage(*image,exception); 7563 if (flip_image != (Image *) NULL) 7564 { 7565 *image=DestroyImage(*image); 7566 *image=flip_image; 7567 } 7568 CatchException(exception); 7569 XSetCursorState(display,windows,MagickFalse); 7570 if (windows->image.crop_geometry != (char *) NULL) 7571 { 7572 /* 7573 Flip crop geometry. 7574 */ 7575 width=(unsigned int) (*image)->columns; 7576 height=(unsigned int) (*image)->rows; 7577 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7578 &width,&height); 7579 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7580 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7581 } 7582 if( IfMagickTrue(windows->image.orphan) ) 7583 break; 7584 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7585 break; 7586 } 7587 case RotateRightCommand: 7588 { 7589 /* 7590 Rotate image 90 degrees clockwise. 7591 */ 7592 status=XRotateImage(display,resource_info,windows,90.0,image,exception); 7593 if( IfMagickFalse(status) ) 7594 { 7595 XNoticeWidget(display,windows,"Unable to rotate X image", 7596 (*image)->filename); 7597 break; 7598 } 7599 break; 7600 } 7601 case RotateLeftCommand: 7602 { 7603 /* 7604 Rotate image 90 degrees counter-clockwise. 7605 */ 7606 status=XRotateImage(display,resource_info,windows,-90.0,image,exception); 7607 if( IfMagickFalse(status) ) 7608 { 7609 XNoticeWidget(display,windows,"Unable to rotate X image", 7610 (*image)->filename); 7611 break; 7612 } 7613 break; 7614 } 7615 case RotateCommand: 7616 { 7617 /* 7618 Rotate image. 7619 */ 7620 status=XRotateImage(display,resource_info,windows,0.0,image,exception); 7621 if( IfMagickFalse(status) ) 7622 { 7623 XNoticeWidget(display,windows,"Unable to rotate X image", 7624 (*image)->filename); 7625 break; 7626 } 7627 break; 7628 } 7629 case ShearCommand: 7630 { 7631 Image 7632 *shear_image; 7633 7634 static char 7635 geometry[MaxTextExtent] = "45.0x45.0"; 7636 7637 /* 7638 Query user for shear color and geometry. 7639 */ 7640 XColorBrowserWidget(display,windows,"Select",color); 7641 if (*color == '\0') 7642 break; 7643 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7644 geometry); 7645 if (*geometry == '\0') 7646 break; 7647 /* 7648 Shear image. 7649 */ 7650 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7651 exception); 7652 XSetCursorState(display,windows,MagickTrue); 7653 XCheckRefreshWindows(display,windows); 7654 (void) QueryColorCompliance(color,AllCompliance, 7655 &(*image)->background_color,exception); 7656 flags=ParseGeometry(geometry,&geometry_info); 7657 if ((flags & SigmaValue) == 0) 7658 geometry_info.sigma=geometry_info.rho; 7659 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7660 exception); 7661 if (shear_image != (Image *) NULL) 7662 { 7663 *image=DestroyImage(*image); 7664 *image=shear_image; 7665 } 7666 CatchException(exception); 7667 XSetCursorState(display,windows,MagickFalse); 7668 if( IfMagickTrue(windows->image.orphan) ) 7669 break; 7670 windows->image.window_changes.width=(int) (*image)->columns; 7671 windows->image.window_changes.height=(int) (*image)->rows; 7672 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7673 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7674 break; 7675 } 7676 case RollCommand: 7677 { 7678 Image 7679 *roll_image; 7680 7681 static char 7682 geometry[MaxTextExtent] = "+2+2"; 7683 7684 /* 7685 Query user for the roll geometry. 7686 */ 7687 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7688 geometry); 7689 if (*geometry == '\0') 7690 break; 7691 /* 7692 Roll image. 7693 */ 7694 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7695 exception); 7696 XSetCursorState(display,windows,MagickTrue); 7697 XCheckRefreshWindows(display,windows); 7698 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7699 exception); 7700 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7701 exception); 7702 if (roll_image != (Image *) NULL) 7703 { 7704 *image=DestroyImage(*image); 7705 *image=roll_image; 7706 } 7707 CatchException(exception); 7708 XSetCursorState(display,windows,MagickFalse); 7709 if( IfMagickTrue(windows->image.orphan) ) 7710 break; 7711 windows->image.window_changes.width=(int) (*image)->columns; 7712 windows->image.window_changes.height=(int) (*image)->rows; 7713 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7714 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7715 break; 7716 } 7717 case TrimCommand: 7718 { 7719 static char 7720 fuzz[MaxTextExtent]; 7721 7722 /* 7723 Query user for the fuzz factor. 7724 */ 7725 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0* 7726 (*image)->fuzz/(QuantumRange+1.0)); 7727 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7728 if (*fuzz == '\0') 7729 break; 7730 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0); 7731 /* 7732 Trim image. 7733 */ 7734 status=XTrimImage(display,resource_info,windows,*image,exception); 7735 if( IfMagickFalse(status) ) 7736 { 7737 XNoticeWidget(display,windows,"Unable to trim X image", 7738 (*image)->filename); 7739 break; 7740 } 7741 break; 7742 } 7743 case HueCommand: 7744 { 7745 static char 7746 hue_percent[MaxTextExtent] = "110"; 7747 7748 /* 7749 Query user for percent hue change. 7750 */ 7751 (void) XDialogWidget(display,windows,"Apply", 7752 "Enter percent change in image hue (0-200):",hue_percent); 7753 if (*hue_percent == '\0') 7754 break; 7755 /* 7756 Vary the image hue. 7757 */ 7758 XSetCursorState(display,windows,MagickTrue); 7759 XCheckRefreshWindows(display,windows); 7760 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent); 7761 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7762 MaxTextExtent); 7763 (void) ModulateImage(*image,modulate_factors,exception); 7764 XSetCursorState(display,windows,MagickFalse); 7765 if( IfMagickTrue(windows->image.orphan) ) 7766 break; 7767 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7768 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7769 break; 7770 } 7771 case SaturationCommand: 7772 { 7773 static char 7774 saturation_percent[MaxTextExtent] = "110"; 7775 7776 /* 7777 Query user for percent saturation change. 7778 */ 7779 (void) XDialogWidget(display,windows,"Apply", 7780 "Enter percent change in color saturation (0-200):",saturation_percent); 7781 if (*saturation_percent == '\0') 7782 break; 7783 /* 7784 Vary color saturation. 7785 */ 7786 XSetCursorState(display,windows,MagickTrue); 7787 XCheckRefreshWindows(display,windows); 7788 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent); 7789 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7790 MaxTextExtent); 7791 (void) ModulateImage(*image,modulate_factors,exception); 7792 XSetCursorState(display,windows,MagickFalse); 7793 if( IfMagickTrue(windows->image.orphan) ) 7794 break; 7795 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7796 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7797 break; 7798 } 7799 case BrightnessCommand: 7800 { 7801 static char 7802 brightness_percent[MaxTextExtent] = "110"; 7803 7804 /* 7805 Query user for percent brightness change. 7806 */ 7807 (void) XDialogWidget(display,windows,"Apply", 7808 "Enter percent change in color brightness (0-200):",brightness_percent); 7809 if (*brightness_percent == '\0') 7810 break; 7811 /* 7812 Vary the color brightness. 7813 */ 7814 XSetCursorState(display,windows,MagickTrue); 7815 XCheckRefreshWindows(display,windows); 7816 (void) CopyMagickString(modulate_factors,brightness_percent, 7817 MaxTextExtent); 7818 (void) ModulateImage(*image,modulate_factors,exception); 7819 XSetCursorState(display,windows,MagickFalse); 7820 if( IfMagickTrue(windows->image.orphan) ) 7821 break; 7822 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7823 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7824 break; 7825 } 7826 case GammaCommand: 7827 { 7828 static char 7829 factor[MaxTextExtent] = "1.6"; 7830 7831 /* 7832 Query user for gamma value. 7833 */ 7834 (void) XDialogWidget(display,windows,"Gamma", 7835 "Enter gamma value (e.g. 1.2):",factor); 7836 if (*factor == '\0') 7837 break; 7838 /* 7839 Gamma correct image. 7840 */ 7841 XSetCursorState(display,windows,MagickTrue); 7842 XCheckRefreshWindows(display,windows); 7843 (void) GammaImage(*image,atof(factor),exception); 7844 XSetCursorState(display,windows,MagickFalse); 7845 if( IfMagickTrue(windows->image.orphan) ) 7846 break; 7847 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7848 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7849 break; 7850 } 7851 case SpiffCommand: 7852 { 7853 /* 7854 Sharpen the image contrast. 7855 */ 7856 XSetCursorState(display,windows,MagickTrue); 7857 XCheckRefreshWindows(display,windows); 7858 (void) ContrastImage(*image,MagickTrue,exception); 7859 XSetCursorState(display,windows,MagickFalse); 7860 if( IfMagickTrue(windows->image.orphan) ) 7861 break; 7862 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7863 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7864 break; 7865 } 7866 case DullCommand: 7867 { 7868 /* 7869 Dull the image contrast. 7870 */ 7871 XSetCursorState(display,windows,MagickTrue); 7872 XCheckRefreshWindows(display,windows); 7873 (void) ContrastImage(*image,MagickFalse,exception); 7874 XSetCursorState(display,windows,MagickFalse); 7875 if( IfMagickTrue(windows->image.orphan) ) 7876 break; 7877 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7878 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7879 break; 7880 } 7881 case ContrastStretchCommand: 7882 { 7883 double 7884 black_point, 7885 white_point; 7886 7887 static char 7888 levels[MaxTextExtent] = "1%"; 7889 7890 /* 7891 Query user for gamma value. 7892 */ 7893 (void) XDialogWidget(display,windows,"Contrast Stretch", 7894 "Enter black and white points:",levels); 7895 if (*levels == '\0') 7896 break; 7897 /* 7898 Contrast stretch image. 7899 */ 7900 XSetCursorState(display,windows,MagickTrue); 7901 XCheckRefreshWindows(display,windows); 7902 flags=ParseGeometry(levels,&geometry_info); 7903 black_point=geometry_info.rho; 7904 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7905 if ((flags & PercentValue) != 0) 7906 { 7907 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7908 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7909 } 7910 white_point=(double) (*image)->columns*(*image)->rows-white_point; 7911 (void) ContrastStretchImage(*image,black_point,white_point, 7912 exception); 7913 XSetCursorState(display,windows,MagickFalse); 7914 if( IfMagickTrue(windows->image.orphan) ) 7915 break; 7916 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7917 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7918 break; 7919 } 7920 case SigmoidalContrastCommand: 7921 { 7922 GeometryInfo 7923 geometry_info; 7924 7925 MagickStatusType 7926 flags; 7927 7928 static char 7929 levels[MaxTextExtent] = "3x50%"; 7930 7931 /* 7932 Query user for gamma value. 7933 */ 7934 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7935 "Enter contrast and midpoint:",levels); 7936 if (*levels == '\0') 7937 break; 7938 /* 7939 Contrast stretch image. 7940 */ 7941 XSetCursorState(display,windows,MagickTrue); 7942 XCheckRefreshWindows(display,windows); 7943 flags=ParseGeometry(levels,&geometry_info); 7944 if ((flags & SigmaValue) == 0) 7945 geometry_info.sigma=1.0*QuantumRange/2.0; 7946 if ((flags & PercentValue) != 0) 7947 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0; 7948 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho, 7949 geometry_info.sigma,exception); 7950 XSetCursorState(display,windows,MagickFalse); 7951 if( IfMagickTrue(windows->image.orphan) ) 7952 break; 7953 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7954 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7955 break; 7956 } 7957 case NormalizeCommand: 7958 { 7959 /* 7960 Perform histogram normalization on the image. 7961 */ 7962 XSetCursorState(display,windows,MagickTrue); 7963 XCheckRefreshWindows(display,windows); 7964 (void) NormalizeImage(*image,exception); 7965 XSetCursorState(display,windows,MagickFalse); 7966 if( IfMagickTrue(windows->image.orphan) ) 7967 break; 7968 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7969 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7970 break; 7971 } 7972 case EqualizeCommand: 7973 { 7974 /* 7975 Perform histogram equalization on the image. 7976 */ 7977 XSetCursorState(display,windows,MagickTrue); 7978 XCheckRefreshWindows(display,windows); 7979 (void) EqualizeImage(*image,exception); 7980 XSetCursorState(display,windows,MagickFalse); 7981 if( IfMagickTrue(windows->image.orphan) ) 7982 break; 7983 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7984 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7985 break; 7986 } 7987 case NegateCommand: 7988 { 7989 /* 7990 Negate colors in image. 7991 */ 7992 XSetCursorState(display,windows,MagickTrue); 7993 XCheckRefreshWindows(display,windows); 7994 (void) NegateImage(*image,MagickFalse,exception); 7995 XSetCursorState(display,windows,MagickFalse); 7996 if( IfMagickTrue(windows->image.orphan) ) 7997 break; 7998 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7999 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8000 break; 8001 } 8002 case GrayscaleCommand: 8003 { 8004 /* 8005 Convert image to grayscale. 8006 */ 8007 XSetCursorState(display,windows,MagickTrue); 8008 XCheckRefreshWindows(display,windows); 8009 (void) SetImageType(*image,(*image)->alpha_trait != BlendPixelTrait ? 8010 GrayscaleType : GrayscaleMatteType,exception); 8011 XSetCursorState(display,windows,MagickFalse); 8012 if( IfMagickTrue(windows->image.orphan) ) 8013 break; 8014 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8015 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8016 break; 8017 } 8018 case MapCommand: 8019 { 8020 Image 8021 *affinity_image; 8022 8023 static char 8024 filename[MaxTextExtent] = "\0"; 8025 8026 /* 8027 Request image file name from user. 8028 */ 8029 XFileBrowserWidget(display,windows,"Map",filename); 8030 if (*filename == '\0') 8031 break; 8032 /* 8033 Map image. 8034 */ 8035 XSetCursorState(display,windows,MagickTrue); 8036 XCheckRefreshWindows(display,windows); 8037 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 8038 affinity_image=ReadImage(image_info,exception); 8039 if (affinity_image != (Image *) NULL) 8040 { 8041 (void) RemapImage(&quantize_info,*image,affinity_image,exception); 8042 affinity_image=DestroyImage(affinity_image); 8043 } 8044 CatchException(exception); 8045 XSetCursorState(display,windows,MagickFalse); 8046 if( IfMagickTrue(windows->image.orphan) ) 8047 break; 8048 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8049 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8050 break; 8051 } 8052 case QuantizeCommand: 8053 { 8054 int 8055 status; 8056 8057 static char 8058 colors[MaxTextExtent] = "256"; 8059 8060 /* 8061 Query user for maximum number of colors. 8062 */ 8063 status=XDialogWidget(display,windows,"Quantize", 8064 "Maximum number of colors:",colors); 8065 if (*colors == '\0') 8066 break; 8067 /* 8068 Color reduce the image. 8069 */ 8070 XSetCursorState(display,windows,MagickTrue); 8071 XCheckRefreshWindows(display,windows); 8072 quantize_info.number_colors=StringToUnsignedLong(colors); 8073 quantize_info.dither_method=status != 0 ? RiemersmaDitherMethod : 8074 NoDitherMethod; 8075 (void) QuantizeImage(&quantize_info,*image,exception); 8076 XSetCursorState(display,windows,MagickFalse); 8077 if( IfMagickTrue(windows->image.orphan) ) 8078 break; 8079 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8080 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8081 break; 8082 } 8083 case DespeckleCommand: 8084 { 8085 Image 8086 *despeckle_image; 8087 8088 /* 8089 Despeckle image. 8090 */ 8091 XSetCursorState(display,windows,MagickTrue); 8092 XCheckRefreshWindows(display,windows); 8093 despeckle_image=DespeckleImage(*image,exception); 8094 if (despeckle_image != (Image *) NULL) 8095 { 8096 *image=DestroyImage(*image); 8097 *image=despeckle_image; 8098 } 8099 CatchException(exception); 8100 XSetCursorState(display,windows,MagickFalse); 8101 if( IfMagickTrue(windows->image.orphan) ) 8102 break; 8103 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8104 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8105 break; 8106 } 8107 case EmbossCommand: 8108 { 8109 Image 8110 *emboss_image; 8111 8112 static char 8113 radius[MaxTextExtent] = "0.0x1.0"; 8114 8115 /* 8116 Query user for emboss radius. 8117 */ 8118 (void) XDialogWidget(display,windows,"Emboss", 8119 "Enter the emboss radius and standard deviation:",radius); 8120 if (*radius == '\0') 8121 break; 8122 /* 8123 Reduce noise in the image. 8124 */ 8125 XSetCursorState(display,windows,MagickTrue); 8126 XCheckRefreshWindows(display,windows); 8127 flags=ParseGeometry(radius,&geometry_info); 8128 if ((flags & SigmaValue) == 0) 8129 geometry_info.sigma=1.0; 8130 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma, 8131 exception); 8132 if (emboss_image != (Image *) NULL) 8133 { 8134 *image=DestroyImage(*image); 8135 *image=emboss_image; 8136 } 8137 CatchException(exception); 8138 XSetCursorState(display,windows,MagickFalse); 8139 if( IfMagickTrue(windows->image.orphan) ) 8140 break; 8141 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8142 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8143 break; 8144 } 8145 case ReduceNoiseCommand: 8146 { 8147 Image 8148 *noise_image; 8149 8150 static char 8151 radius[MaxTextExtent] = "0"; 8152 8153 /* 8154 Query user for noise radius. 8155 */ 8156 (void) XDialogWidget(display,windows,"Reduce Noise", 8157 "Enter the noise radius:",radius); 8158 if (*radius == '\0') 8159 break; 8160 /* 8161 Reduce noise in the image. 8162 */ 8163 XSetCursorState(display,windows,MagickTrue); 8164 XCheckRefreshWindows(display,windows); 8165 flags=ParseGeometry(radius,&geometry_info); 8166 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t) 8167 geometry_info.rho,(size_t) geometry_info.rho,exception); 8168 if (noise_image != (Image *) NULL) 8169 { 8170 *image=DestroyImage(*image); 8171 *image=noise_image; 8172 } 8173 CatchException(exception); 8174 XSetCursorState(display,windows,MagickFalse); 8175 if( IfMagickTrue(windows->image.orphan) ) 8176 break; 8177 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8178 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8179 break; 8180 } 8181 case AddNoiseCommand: 8182 { 8183 char 8184 **noises; 8185 8186 Image 8187 *noise_image; 8188 8189 static char 8190 noise_type[MaxTextExtent] = "Gaussian"; 8191 8192 /* 8193 Add noise to the image. 8194 */ 8195 noises=GetCommandOptions(MagickNoiseOptions); 8196 if (noises == (char **) NULL) 8197 break; 8198 XListBrowserWidget(display,windows,&windows->widget, 8199 (const char **) noises,"Add Noise", 8200 "Select a type of noise to add to your image:",noise_type); 8201 noises=DestroyStringList(noises); 8202 if (*noise_type == '\0') 8203 break; 8204 XSetCursorState(display,windows,MagickTrue); 8205 XCheckRefreshWindows(display,windows); 8206 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption( 8207 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception); 8208 if (noise_image != (Image *) NULL) 8209 { 8210 *image=DestroyImage(*image); 8211 *image=noise_image; 8212 } 8213 CatchException(exception); 8214 XSetCursorState(display,windows,MagickFalse); 8215 if( IfMagickTrue(windows->image.orphan) ) 8216 break; 8217 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8218 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8219 break; 8220 } 8221 case SharpenCommand: 8222 { 8223 Image 8224 *sharp_image; 8225 8226 static char 8227 radius[MaxTextExtent] = "0.0x1.0"; 8228 8229 /* 8230 Query user for sharpen radius. 8231 */ 8232 (void) XDialogWidget(display,windows,"Sharpen", 8233 "Enter the sharpen radius and standard deviation:",radius); 8234 if (*radius == '\0') 8235 break; 8236 /* 8237 Sharpen image scanlines. 8238 */ 8239 XSetCursorState(display,windows,MagickTrue); 8240 XCheckRefreshWindows(display,windows); 8241 flags=ParseGeometry(radius,&geometry_info); 8242 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma, 8243 exception); 8244 if (sharp_image != (Image *) NULL) 8245 { 8246 *image=DestroyImage(*image); 8247 *image=sharp_image; 8248 } 8249 CatchException(exception); 8250 XSetCursorState(display,windows,MagickFalse); 8251 if( IfMagickTrue(windows->image.orphan) ) 8252 break; 8253 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8254 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8255 break; 8256 } 8257 case BlurCommand: 8258 { 8259 Image 8260 *blur_image; 8261 8262 static char 8263 radius[MaxTextExtent] = "0.0x1.0"; 8264 8265 /* 8266 Query user for blur radius. 8267 */ 8268 (void) XDialogWidget(display,windows,"Blur", 8269 "Enter the blur radius and standard deviation:",radius); 8270 if (*radius == '\0') 8271 break; 8272 /* 8273 Blur an image. 8274 */ 8275 XSetCursorState(display,windows,MagickTrue); 8276 XCheckRefreshWindows(display,windows); 8277 flags=ParseGeometry(radius,&geometry_info); 8278 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma, 8279 exception); 8280 if (blur_image != (Image *) NULL) 8281 { 8282 *image=DestroyImage(*image); 8283 *image=blur_image; 8284 } 8285 CatchException(exception); 8286 XSetCursorState(display,windows,MagickFalse); 8287 if( IfMagickTrue(windows->image.orphan) ) 8288 break; 8289 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8290 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8291 break; 8292 } 8293 case ThresholdCommand: 8294 { 8295 double 8296 threshold; 8297 8298 static char 8299 factor[MaxTextExtent] = "128"; 8300 8301 /* 8302 Query user for threshold value. 8303 */ 8304 (void) XDialogWidget(display,windows,"Threshold", 8305 "Enter threshold value:",factor); 8306 if (*factor == '\0') 8307 break; 8308 /* 8309 Gamma correct image. 8310 */ 8311 XSetCursorState(display,windows,MagickTrue); 8312 XCheckRefreshWindows(display,windows); 8313 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8314 (void) BilevelImage(*image,threshold,exception); 8315 XSetCursorState(display,windows,MagickFalse); 8316 if( IfMagickTrue(windows->image.orphan) ) 8317 break; 8318 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8319 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8320 break; 8321 } 8322 case EdgeDetectCommand: 8323 { 8324 Image 8325 *edge_image; 8326 8327 static char 8328 radius[MaxTextExtent] = "0"; 8329 8330 /* 8331 Query user for edge factor. 8332 */ 8333 (void) XDialogWidget(display,windows,"Detect Edges", 8334 "Enter the edge detect radius:",radius); 8335 if (*radius == '\0') 8336 break; 8337 /* 8338 Detect edge in image. 8339 */ 8340 XSetCursorState(display,windows,MagickTrue); 8341 XCheckRefreshWindows(display,windows); 8342 flags=ParseGeometry(radius,&geometry_info); 8343 edge_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8344 exception); 8345 if (edge_image != (Image *) NULL) 8346 { 8347 *image=DestroyImage(*image); 8348 *image=edge_image; 8349 } 8350 CatchException(exception); 8351 XSetCursorState(display,windows,MagickFalse); 8352 if( IfMagickTrue(windows->image.orphan) ) 8353 break; 8354 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8355 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8356 break; 8357 } 8358 case SpreadCommand: 8359 { 8360 Image 8361 *spread_image; 8362 8363 static char 8364 amount[MaxTextExtent] = "2"; 8365 8366 /* 8367 Query user for spread amount. 8368 */ 8369 (void) XDialogWidget(display,windows,"Spread", 8370 "Enter the displacement amount:",amount); 8371 if (*amount == '\0') 8372 break; 8373 /* 8374 Displace image pixels by a random amount. 8375 */ 8376 XSetCursorState(display,windows,MagickTrue); 8377 XCheckRefreshWindows(display,windows); 8378 flags=ParseGeometry(amount,&geometry_info); 8379 spread_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8380 exception); 8381 if (spread_image != (Image *) NULL) 8382 { 8383 *image=DestroyImage(*image); 8384 *image=spread_image; 8385 } 8386 CatchException(exception); 8387 XSetCursorState(display,windows,MagickFalse); 8388 if( IfMagickTrue(windows->image.orphan) ) 8389 break; 8390 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8391 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8392 break; 8393 } 8394 case ShadeCommand: 8395 { 8396 Image 8397 *shade_image; 8398 8399 int 8400 status; 8401 8402 static char 8403 geometry[MaxTextExtent] = "30x30"; 8404 8405 /* 8406 Query user for the shade geometry. 8407 */ 8408 status=XDialogWidget(display,windows,"Shade", 8409 "Enter the azimuth and elevation of the light source:",geometry); 8410 if (*geometry == '\0') 8411 break; 8412 /* 8413 Shade image pixels. 8414 */ 8415 XSetCursorState(display,windows,MagickTrue); 8416 XCheckRefreshWindows(display,windows); 8417 flags=ParseGeometry(geometry,&geometry_info); 8418 if ((flags & SigmaValue) == 0) 8419 geometry_info.sigma=1.0; 8420 shade_image=ShadeImage(*image,IsMagickTrue(status), 8421 geometry_info.rho,geometry_info.sigma,exception); 8422 if (shade_image != (Image *) NULL) 8423 { 8424 *image=DestroyImage(*image); 8425 *image=shade_image; 8426 } 8427 CatchException(exception); 8428 XSetCursorState(display,windows,MagickFalse); 8429 if( IfMagickTrue(windows->image.orphan) ) 8430 break; 8431 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8432 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8433 break; 8434 } 8435 case RaiseCommand: 8436 { 8437 static char 8438 bevel_width[MaxTextExtent] = "10"; 8439 8440 /* 8441 Query user for bevel width. 8442 */ 8443 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8444 if (*bevel_width == '\0') 8445 break; 8446 /* 8447 Raise an image. 8448 */ 8449 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8450 exception); 8451 XSetCursorState(display,windows,MagickTrue); 8452 XCheckRefreshWindows(display,windows); 8453 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8454 exception); 8455 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception); 8456 XSetCursorState(display,windows,MagickFalse); 8457 if( IfMagickTrue(windows->image.orphan) ) 8458 break; 8459 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8460 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8461 break; 8462 } 8463 case SegmentCommand: 8464 { 8465 static char 8466 threshold[MaxTextExtent] = "1.0x1.5"; 8467 8468 /* 8469 Query user for smoothing threshold. 8470 */ 8471 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8472 threshold); 8473 if (*threshold == '\0') 8474 break; 8475 /* 8476 Segment an image. 8477 */ 8478 XSetCursorState(display,windows,MagickTrue); 8479 XCheckRefreshWindows(display,windows); 8480 flags=ParseGeometry(threshold,&geometry_info); 8481 if ((flags & SigmaValue) == 0) 8482 geometry_info.sigma=1.0; 8483 (void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho, 8484 geometry_info.sigma,exception); 8485 XSetCursorState(display,windows,MagickFalse); 8486 if( IfMagickTrue(windows->image.orphan) ) 8487 break; 8488 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8489 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8490 break; 8491 } 8492 case SepiaToneCommand: 8493 { 8494 double 8495 threshold; 8496 8497 Image 8498 *sepia_image; 8499 8500 static char 8501 factor[MaxTextExtent] = "80%"; 8502 8503 /* 8504 Query user for sepia-tone factor. 8505 */ 8506 (void) XDialogWidget(display,windows,"Sepia Tone", 8507 "Enter the sepia tone factor (0 - 99.9%):",factor); 8508 if (*factor == '\0') 8509 break; 8510 /* 8511 Sepia tone image pixels. 8512 */ 8513 XSetCursorState(display,windows,MagickTrue); 8514 XCheckRefreshWindows(display,windows); 8515 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8516 sepia_image=SepiaToneImage(*image,threshold,exception); 8517 if (sepia_image != (Image *) NULL) 8518 { 8519 *image=DestroyImage(*image); 8520 *image=sepia_image; 8521 } 8522 CatchException(exception); 8523 XSetCursorState(display,windows,MagickFalse); 8524 if( IfMagickTrue(windows->image.orphan) ) 8525 break; 8526 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8527 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8528 break; 8529 } 8530 case SolarizeCommand: 8531 { 8532 double 8533 threshold; 8534 8535 static char 8536 factor[MaxTextExtent] = "60%"; 8537 8538 /* 8539 Query user for solarize factor. 8540 */ 8541 (void) XDialogWidget(display,windows,"Solarize", 8542 "Enter the solarize factor (0 - 99.9%):",factor); 8543 if (*factor == '\0') 8544 break; 8545 /* 8546 Solarize image pixels. 8547 */ 8548 XSetCursorState(display,windows,MagickTrue); 8549 XCheckRefreshWindows(display,windows); 8550 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8551 (void) SolarizeImage(*image,threshold,exception); 8552 XSetCursorState(display,windows,MagickFalse); 8553 if( IfMagickTrue(windows->image.orphan) ) 8554 break; 8555 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8556 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8557 break; 8558 } 8559 case SwirlCommand: 8560 { 8561 Image 8562 *swirl_image; 8563 8564 static char 8565 degrees[MaxTextExtent] = "60"; 8566 8567 /* 8568 Query user for swirl angle. 8569 */ 8570 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8571 degrees); 8572 if (*degrees == '\0') 8573 break; 8574 /* 8575 Swirl image pixels about the center. 8576 */ 8577 XSetCursorState(display,windows,MagickTrue); 8578 XCheckRefreshWindows(display,windows); 8579 flags=ParseGeometry(degrees,&geometry_info); 8580 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate, 8581 exception); 8582 if (swirl_image != (Image *) NULL) 8583 { 8584 *image=DestroyImage(*image); 8585 *image=swirl_image; 8586 } 8587 CatchException(exception); 8588 XSetCursorState(display,windows,MagickFalse); 8589 if( IfMagickTrue(windows->image.orphan) ) 8590 break; 8591 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8592 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8593 break; 8594 } 8595 case ImplodeCommand: 8596 { 8597 Image 8598 *implode_image; 8599 8600 static char 8601 factor[MaxTextExtent] = "0.3"; 8602 8603 /* 8604 Query user for implode factor. 8605 */ 8606 (void) XDialogWidget(display,windows,"Implode", 8607 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8608 if (*factor == '\0') 8609 break; 8610 /* 8611 Implode image pixels about the center. 8612 */ 8613 XSetCursorState(display,windows,MagickTrue); 8614 XCheckRefreshWindows(display,windows); 8615 flags=ParseGeometry(factor,&geometry_info); 8616 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate, 8617 exception); 8618 if (implode_image != (Image *) NULL) 8619 { 8620 *image=DestroyImage(*image); 8621 *image=implode_image; 8622 } 8623 CatchException(exception); 8624 XSetCursorState(display,windows,MagickFalse); 8625 if( IfMagickTrue(windows->image.orphan) ) 8626 break; 8627 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8628 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8629 break; 8630 } 8631 case VignetteCommand: 8632 { 8633 Image 8634 *vignette_image; 8635 8636 static char 8637 geometry[MaxTextExtent] = "0x20"; 8638 8639 /* 8640 Query user for the vignette geometry. 8641 */ 8642 (void) XDialogWidget(display,windows,"Vignette", 8643 "Enter the radius, sigma, and x and y offsets:",geometry); 8644 if (*geometry == '\0') 8645 break; 8646 /* 8647 Soften the edges of the image in vignette style 8648 */ 8649 XSetCursorState(display,windows,MagickTrue); 8650 XCheckRefreshWindows(display,windows); 8651 flags=ParseGeometry(geometry,&geometry_info); 8652 if ((flags & SigmaValue) == 0) 8653 geometry_info.sigma=1.0; 8654 if ((flags & XiValue) == 0) 8655 geometry_info.xi=0.1*(*image)->columns; 8656 if ((flags & PsiValue) == 0) 8657 geometry_info.psi=0.1*(*image)->rows; 8658 vignette_image=VignetteImage(*image,geometry_info.rho,0.0,(ssize_t) 8659 ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5), 8660 exception); 8661 if (vignette_image != (Image *) NULL) 8662 { 8663 *image=DestroyImage(*image); 8664 *image=vignette_image; 8665 } 8666 CatchException(exception); 8667 XSetCursorState(display,windows,MagickFalse); 8668 if( IfMagickTrue(windows->image.orphan) ) 8669 break; 8670 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8671 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8672 break; 8673 } 8674 case WaveCommand: 8675 { 8676 Image 8677 *wave_image; 8678 8679 static char 8680 geometry[MaxTextExtent] = "25x150"; 8681 8682 /* 8683 Query user for the wave geometry. 8684 */ 8685 (void) XDialogWidget(display,windows,"Wave", 8686 "Enter the amplitude and length of the wave:",geometry); 8687 if (*geometry == '\0') 8688 break; 8689 /* 8690 Alter an image along a sine wave. 8691 */ 8692 XSetCursorState(display,windows,MagickTrue); 8693 XCheckRefreshWindows(display,windows); 8694 flags=ParseGeometry(geometry,&geometry_info); 8695 if ((flags & SigmaValue) == 0) 8696 geometry_info.sigma=1.0; 8697 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8698 (*image)->interpolate,exception); 8699 if (wave_image != (Image *) NULL) 8700 { 8701 *image=DestroyImage(*image); 8702 *image=wave_image; 8703 } 8704 CatchException(exception); 8705 XSetCursorState(display,windows,MagickFalse); 8706 if( IfMagickTrue(windows->image.orphan) ) 8707 break; 8708 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8709 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8710 break; 8711 } 8712 case OilPaintCommand: 8713 { 8714 Image 8715 *paint_image; 8716 8717 static char 8718 radius[MaxTextExtent] = "0"; 8719 8720 /* 8721 Query user for circular neighborhood radius. 8722 */ 8723 (void) XDialogWidget(display,windows,"Oil Paint", 8724 "Enter the mask radius:",radius); 8725 if (*radius == '\0') 8726 break; 8727 /* 8728 OilPaint image scanlines. 8729 */ 8730 XSetCursorState(display,windows,MagickTrue); 8731 XCheckRefreshWindows(display,windows); 8732 flags=ParseGeometry(radius,&geometry_info); 8733 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma, 8734 exception); 8735 if (paint_image != (Image *) NULL) 8736 { 8737 *image=DestroyImage(*image); 8738 *image=paint_image; 8739 } 8740 CatchException(exception); 8741 XSetCursorState(display,windows,MagickFalse); 8742 if( IfMagickTrue(windows->image.orphan) ) 8743 break; 8744 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8745 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8746 break; 8747 } 8748 case CharcoalDrawCommand: 8749 { 8750 Image 8751 *charcoal_image; 8752 8753 static char 8754 radius[MaxTextExtent] = "0x1"; 8755 8756 /* 8757 Query user for charcoal radius. 8758 */ 8759 (void) XDialogWidget(display,windows,"Charcoal Draw", 8760 "Enter the charcoal radius and sigma:",radius); 8761 if (*radius == '\0') 8762 break; 8763 /* 8764 Charcoal the image. 8765 */ 8766 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8767 exception); 8768 XSetCursorState(display,windows,MagickTrue); 8769 XCheckRefreshWindows(display,windows); 8770 flags=ParseGeometry(radius,&geometry_info); 8771 if ((flags & SigmaValue) == 0) 8772 geometry_info.sigma=geometry_info.rho; 8773 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8774 exception); 8775 if (charcoal_image != (Image *) NULL) 8776 { 8777 *image=DestroyImage(*image); 8778 *image=charcoal_image; 8779 } 8780 CatchException(exception); 8781 XSetCursorState(display,windows,MagickFalse); 8782 if( IfMagickTrue(windows->image.orphan) ) 8783 break; 8784 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8785 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8786 break; 8787 } 8788 case AnnotateCommand: 8789 { 8790 /* 8791 Annotate the image with text. 8792 */ 8793 status=XAnnotateEditImage(display,resource_info,windows,*image,exception); 8794 if( IfMagickFalse(status) ) 8795 { 8796 XNoticeWidget(display,windows,"Unable to annotate X image", 8797 (*image)->filename); 8798 break; 8799 } 8800 break; 8801 } 8802 case DrawCommand: 8803 { 8804 /* 8805 Draw image. 8806 */ 8807 status=XDrawEditImage(display,resource_info,windows,image,exception); 8808 if( IfMagickFalse(status) ) 8809 { 8810 XNoticeWidget(display,windows,"Unable to draw on the X image", 8811 (*image)->filename); 8812 break; 8813 } 8814 break; 8815 } 8816 case ColorCommand: 8817 { 8818 /* 8819 Color edit. 8820 */ 8821 status=XColorEditImage(display,resource_info,windows,image,exception); 8822 if( IfMagickFalse(status) ) 8823 { 8824 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8825 (*image)->filename); 8826 break; 8827 } 8828 break; 8829 } 8830 case MatteCommand: 8831 { 8832 /* 8833 Matte edit. 8834 */ 8835 status=XMatteEditImage(display,resource_info,windows,image,exception); 8836 if( IfMagickFalse(status) ) 8837 { 8838 XNoticeWidget(display,windows,"Unable to matte edit X image", 8839 (*image)->filename); 8840 break; 8841 } 8842 break; 8843 } 8844 case CompositeCommand: 8845 { 8846 /* 8847 Composite image. 8848 */ 8849 status=XCompositeImage(display,resource_info,windows,*image, 8850 exception); 8851 if( IfMagickFalse(status) ) 8852 { 8853 XNoticeWidget(display,windows,"Unable to composite X image", 8854 (*image)->filename); 8855 break; 8856 } 8857 break; 8858 } 8859 case AddBorderCommand: 8860 { 8861 Image 8862 *border_image; 8863 8864 static char 8865 geometry[MaxTextExtent] = "6x6"; 8866 8867 /* 8868 Query user for border color and geometry. 8869 */ 8870 XColorBrowserWidget(display,windows,"Select",color); 8871 if (*color == '\0') 8872 break; 8873 (void) XDialogWidget(display,windows,"Add Border", 8874 "Enter border geometry:",geometry); 8875 if (*geometry == '\0') 8876 break; 8877 /* 8878 Add a border to the image. 8879 */ 8880 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8881 exception); 8882 XSetCursorState(display,windows,MagickTrue); 8883 XCheckRefreshWindows(display,windows); 8884 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color, 8885 exception); 8886 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8887 exception); 8888 border_image=BorderImage(*image,&page_geometry,(*image)->compose, 8889 exception); 8890 if (border_image != (Image *) NULL) 8891 { 8892 *image=DestroyImage(*image); 8893 *image=border_image; 8894 } 8895 CatchException(exception); 8896 XSetCursorState(display,windows,MagickFalse); 8897 if( IfMagickTrue(windows->image.orphan) ) 8898 break; 8899 windows->image.window_changes.width=(int) (*image)->columns; 8900 windows->image.window_changes.height=(int) (*image)->rows; 8901 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8902 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8903 break; 8904 } 8905 case AddFrameCommand: 8906 { 8907 FrameInfo 8908 frame_info; 8909 8910 Image 8911 *frame_image; 8912 8913 static char 8914 geometry[MaxTextExtent] = "6x6"; 8915 8916 /* 8917 Query user for frame color and geometry. 8918 */ 8919 XColorBrowserWidget(display,windows,"Select",color); 8920 if (*color == '\0') 8921 break; 8922 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8923 geometry); 8924 if (*geometry == '\0') 8925 break; 8926 /* 8927 Surround image with an ornamental border. 8928 */ 8929 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8930 exception); 8931 XSetCursorState(display,windows,MagickTrue); 8932 XCheckRefreshWindows(display,windows); 8933 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color, 8934 exception); 8935 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8936 exception); 8937 frame_info.width=page_geometry.width; 8938 frame_info.height=page_geometry.height; 8939 frame_info.outer_bevel=page_geometry.x; 8940 frame_info.inner_bevel=page_geometry.y; 8941 frame_info.x=(ssize_t) frame_info.width; 8942 frame_info.y=(ssize_t) frame_info.height; 8943 frame_info.width=(*image)->columns+2*frame_info.width; 8944 frame_info.height=(*image)->rows+2*frame_info.height; 8945 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception); 8946 if (frame_image != (Image *) NULL) 8947 { 8948 *image=DestroyImage(*image); 8949 *image=frame_image; 8950 } 8951 CatchException(exception); 8952 XSetCursorState(display,windows,MagickFalse); 8953 if( IfMagickTrue(windows->image.orphan) ) 8954 break; 8955 windows->image.window_changes.width=(int) (*image)->columns; 8956 windows->image.window_changes.height=(int) (*image)->rows; 8957 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8958 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8959 break; 8960 } 8961 case CommentCommand: 8962 { 8963 const char 8964 *value; 8965 8966 FILE 8967 *file; 8968 8969 int 8970 unique_file; 8971 8972 /* 8973 Edit image comment. 8974 */ 8975 unique_file=AcquireUniqueFileResource(image_info->filename); 8976 if (unique_file == -1) 8977 XNoticeWidget(display,windows,"Unable to edit image comment", 8978 image_info->filename); 8979 value=GetImageProperty(*image,"comment",exception); 8980 if (value == (char *) NULL) 8981 unique_file=close(unique_file)-1; 8982 else 8983 { 8984 register const char 8985 *p; 8986 8987 file=fdopen(unique_file,"w"); 8988 if (file == (FILE *) NULL) 8989 { 8990 XNoticeWidget(display,windows,"Unable to edit image comment", 8991 image_info->filename); 8992 break; 8993 } 8994 for (p=value; *p != '\0'; p++) 8995 (void) fputc((int) *p,file); 8996 (void) fputc('\n',file); 8997 (void) fclose(file); 8998 } 8999 XSetCursorState(display,windows,MagickTrue); 9000 XCheckRefreshWindows(display,windows); 9001 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 9002 exception); 9003 if( IfMagickFalse(status) ) 9004 XNoticeWidget(display,windows,"Unable to edit image comment", 9005 (char *) NULL); 9006 else 9007 { 9008 char 9009 *comment; 9010 9011 comment=FileToString(image_info->filename,~0UL,exception); 9012 if (comment != (char *) NULL) 9013 { 9014 (void) SetImageProperty(*image,"comment",comment,exception); 9015 (*image)->taint=MagickTrue; 9016 } 9017 } 9018 (void) RelinquishUniqueFileResource(image_info->filename); 9019 XSetCursorState(display,windows,MagickFalse); 9020 break; 9021 } 9022 case LaunchCommand: 9023 { 9024 /* 9025 Launch program. 9026 */ 9027 XSetCursorState(display,windows,MagickTrue); 9028 XCheckRefreshWindows(display,windows); 9029 (void) AcquireUniqueFilename(filename); 9030 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s", 9031 filename); 9032 status=WriteImage(image_info,*image,exception); 9033 if( IfMagickFalse(status) ) 9034 XNoticeWidget(display,windows,"Unable to launch image editor", 9035 (char *) NULL); 9036 else 9037 { 9038 nexus=ReadImage(resource_info->image_info,exception); 9039 CatchException(exception); 9040 XClientMessage(display,windows->image.id,windows->im_protocols, 9041 windows->im_next_image,CurrentTime); 9042 } 9043 (void) RelinquishUniqueFileResource(filename); 9044 XSetCursorState(display,windows,MagickFalse); 9045 break; 9046 } 9047 case RegionofInterestCommand: 9048 { 9049 /* 9050 Apply an image processing technique to a region of interest. 9051 */ 9052 (void) XROIImage(display,resource_info,windows,image,exception); 9053 break; 9054 } 9055 case InfoCommand: 9056 break; 9057 case ZoomCommand: 9058 { 9059 /* 9060 Zoom image. 9061 */ 9062 if( IfMagickTrue(windows->magnify.mapped) ) 9063 (void) XRaiseWindow(display,windows->magnify.id); 9064 else 9065 { 9066 /* 9067 Make magnify image. 9068 */ 9069 XSetCursorState(display,windows,MagickTrue); 9070 (void) XMapRaised(display,windows->magnify.id); 9071 XSetCursorState(display,windows,MagickFalse); 9072 } 9073 break; 9074 } 9075 case ShowPreviewCommand: 9076 { 9077 char 9078 **previews; 9079 9080 Image 9081 *preview_image; 9082 9083 static char 9084 preview_type[MaxTextExtent] = "Gamma"; 9085 9086 /* 9087 Select preview type from menu. 9088 */ 9089 previews=GetCommandOptions(MagickPreviewOptions); 9090 if (previews == (char **) NULL) 9091 break; 9092 XListBrowserWidget(display,windows,&windows->widget, 9093 (const char **) previews,"Preview", 9094 "Select an enhancement, effect, or F/X:",preview_type); 9095 previews=DestroyStringList(previews); 9096 if (*preview_type == '\0') 9097 break; 9098 /* 9099 Show image preview. 9100 */ 9101 XSetCursorState(display,windows,MagickTrue); 9102 XCheckRefreshWindows(display,windows); 9103 image_info->preview_type=(PreviewType) 9104 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type); 9105 image_info->group=(ssize_t) windows->image.id; 9106 (void) DeleteImageProperty(*image,"label"); 9107 (void) SetImageProperty(*image,"label","Preview",exception); 9108 (void) AcquireUniqueFilename(filename); 9109 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s", 9110 filename); 9111 status=WriteImage(image_info,*image,exception); 9112 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9113 preview_image=ReadImage(image_info,exception); 9114 (void) RelinquishUniqueFileResource(filename); 9115 if (preview_image == (Image *) NULL) 9116 break; 9117 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s", 9118 filename); 9119 status=WriteImage(image_info,preview_image,exception); 9120 preview_image=DestroyImage(preview_image); 9121 if( IfMagickFalse(status) ) 9122 XNoticeWidget(display,windows,"Unable to show image preview", 9123 (*image)->filename); 9124 XDelay(display,1500); 9125 XSetCursorState(display,windows,MagickFalse); 9126 break; 9127 } 9128 case ShowHistogramCommand: 9129 { 9130 Image 9131 *histogram_image; 9132 9133 /* 9134 Show image histogram. 9135 */ 9136 XSetCursorState(display,windows,MagickTrue); 9137 XCheckRefreshWindows(display,windows); 9138 image_info->group=(ssize_t) windows->image.id; 9139 (void) DeleteImageProperty(*image,"label"); 9140 (void) SetImageProperty(*image,"label","Histogram",exception); 9141 (void) AcquireUniqueFilename(filename); 9142 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s", 9143 filename); 9144 status=WriteImage(image_info,*image,exception); 9145 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9146 histogram_image=ReadImage(image_info,exception); 9147 (void) RelinquishUniqueFileResource(filename); 9148 if (histogram_image == (Image *) NULL) 9149 break; 9150 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent, 9151 "show:%s",filename); 9152 status=WriteImage(image_info,histogram_image,exception); 9153 histogram_image=DestroyImage(histogram_image); 9154 if( IfMagickFalse(status) ) 9155 XNoticeWidget(display,windows,"Unable to show histogram", 9156 (*image)->filename); 9157 XDelay(display,1500); 9158 XSetCursorState(display,windows,MagickFalse); 9159 break; 9160 } 9161 case ShowMatteCommand: 9162 { 9163 Image 9164 *matte_image; 9165 9166 if ((*image)->alpha_trait != BlendPixelTrait) 9167 { 9168 XNoticeWidget(display,windows, 9169 "Image does not have any matte information",(*image)->filename); 9170 break; 9171 } 9172 /* 9173 Show image matte. 9174 */ 9175 XSetCursorState(display,windows,MagickTrue); 9176 XCheckRefreshWindows(display,windows); 9177 image_info->group=(ssize_t) windows->image.id; 9178 (void) DeleteImageProperty(*image,"label"); 9179 (void) SetImageProperty(*image,"label","Matte",exception); 9180 (void) AcquireUniqueFilename(filename); 9181 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s", 9182 filename); 9183 status=WriteImage(image_info,*image,exception); 9184 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 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,MaxTextExtent,"show:%s", 9190 filename); 9191 status=WriteImage(image_info,matte_image,exception); 9192 matte_image=DestroyImage(matte_image); 9193 if( IfMagickFalse(status) ) 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( IfMagickFalse(status) ) 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[MaxTextExtent] = "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( IfMagickFalse(status) ) 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[MaxTextExtent], 9273 *url; 9274 9275 /* 9276 Display documentation using Netscape remote control. 9277 */ 9278 url=GetMagickHomeURL(); 9279 (void) FormatLocaleString(command,MaxTextExtent, 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( IfMagickFalse(status) ) 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[MaxTextExtent]; 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( IfMagickTrue(windows->info.mapped) ) 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( IfMagickTrue(windows->info.mapped) ) 9387 { 9388 /* 9389 Display pointer position. 9390 */ 9391 (void) FormatLocaleString(text,MaxTextExtent," %+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( IfMagickFalse(status) ) 9617 ThrowXWindowFatalException(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[MaxTextExtent] = "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[MaxTextExtent], 9701 text[MaxTextExtent]; 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( IfMagickTrue(windows->info.mapped) ) 9755 { 9756 /* 9757 Display pointer position. 9758 */ 9759 (void) FormatLocaleString(text,MaxTextExtent," %+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[MaxTextExtent] = "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[MaxTextExtent]; 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%",MaxTextExtent); 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,"%",MaxTextExtent); 9877 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 9878 1.0); 9879 break; 9880 } 9881 case MatteEditValueCommand: 9882 { 9883 static char 9884 message[MaxTextExtent]; 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,MaxTextExtent,QuantumFormat, 9905 OpaqueAlpha); 9906 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9907 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9908 (Quantum) TransparentAlpha); 9909 break; 9910 } 9911 (void) FormatLocaleString(message,MaxTextExtent, 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[MaxTextExtent]; 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( IfMagickTrue(windows->info.mapped) ) 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( IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) ) 10098 return(MagickFalse); 10099 if ((*image)->alpha_trait != BlendPixelTrait) 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( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 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 IsMagickFalse(method == FloodfillMethod),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( IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) ) 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( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 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[MaxTextExtent] = "\0"; 10271 10272 /* 10273 Request file name from user. 10274 */ 10275 if( IfMagickFalse(command) ) 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 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","..."); 10298 return((Image *) NULL); 10299 } 10300 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10301 if (filelist == (char **) NULL) 10302 { 10303 ThrowXWindowFatalException(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,MaxTextExtent); 10324 exception=AcquireExceptionInfo(); 10325 (void) SetImageInfo(image_info,0,exception); 10326 if (LocaleCompare(image_info->magick,"X") == 0) 10327 { 10328 char 10329 seconds[MaxTextExtent]; 10330 10331 /* 10332 User may want to delay the X server screen grab. 10333 */ 10334 (void) CopyMagickString(seconds,"0",MaxTextExtent); 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 IfMagickTrue(magick_info->raw)) 10344 { 10345 char 10346 geometry[MaxTextExtent]; 10347 10348 /* 10349 Request image size from the user. 10350 */ 10351 (void) CopyMagickString(geometry,"512x512",MaxTextExtent); 10352 if (image_info->size != (char *) NULL) 10353 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent); 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,MaxTextExtent); 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,~0,exception); 10380 if (text == (char *) NULL) 10381 return((Image *) NULL); 10382 textlist=StringToList(text); 10383 if (textlist != (char **) NULL) 10384 { 10385 char 10386 title[MaxTextExtent]; 10387 10388 register int 10389 i; 10390 10391 (void) FormatLocaleString(title,MaxTextExtent, 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[MaxTextExtent]; 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,MaxTextExtent," %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[MaxTextExtent]; 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( IfMagickTrue(windows->info.mapped) ) 10699 { 10700 /* 10701 Display pointer position. 10702 */ 10703 (void) FormatLocaleString(text,MaxTextExtent," %+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[MaxTextExtent], 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( IfMagickTrue(image->debug) ) 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( IfMagickTrue(image->debug) ) 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[MaxTextExtent]; 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( IfMagickTrue(image->debug) ) 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( IfMagickTrue(windows->info.mapped) ) 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( IfMagickTrue(image->debug) ) 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[MaxTextExtent], 10987 geometry[MaxTextExtent]; 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,MaxTextExtent,"Letter"); 11003 if (image_info->page != (char *) NULL) 11004 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 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,MaxTextExtent,"%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,MaxTextExtent,"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(IsMagickTrue(status)); 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[MaxTextExtent], 11283 text[MaxTextExtent]; 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( IfMagickTrue(windows->info.mapped) ) 11345 { 11346 /* 11347 Display pointer position. 11348 */ 11349 (void) FormatLocaleString(text,MaxTextExtent," %+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( IfMagickTrue(windows->info.mapped) ) 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( IfMagickFalse(windows->info.mapped) ) 11506 (void) XMapWindow(display,windows->info.id); 11507 (void) FormatLocaleString(text,MaxTextExtent, 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( IfMagickTrue(windows->info.mapped) ) 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 (void) XMapWindow(display,windows->info.id); 11596 do 11597 { 11598 if( IfMagickTrue(windows->info.mapped) ) 11599 { 11600 /* 11601 Display pointer position. 11602 */ 11603 (void) FormatLocaleString(text,MaxTextExtent, 11604 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11605 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11606 XInfoWidget(display,windows,text); 11607 } 11608 highlight_info=roi_info; 11609 highlight_info.x=roi_info.x-windows->image.x; 11610 highlight_info.y=roi_info.y-windows->image.y; 11611 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11612 { 11613 state|=EscapeState; 11614 state|=ExitState; 11615 break; 11616 } 11617 if ((state & UpdateRegionState) != 0) 11618 { 11619 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11620 switch (command_type) 11621 { 11622 case UndoCommand: 11623 case RedoCommand: 11624 { 11625 (void) XMagickCommand(display,resource_info,windows,command_type, 11626 image,exception); 11627 break; 11628 } 11629 default: 11630 { 11631 /* 11632 Region of interest is relative to image configuration. 11633 */ 11634 progress_monitor=SetImageProgressMonitor(*image, 11635 (MagickProgressMonitor) NULL,(*image)->client_data); 11636 crop_info=roi_info; 11637 width=(unsigned int) (*image)->columns; 11638 height=(unsigned int) (*image)->rows; 11639 x=0; 11640 y=0; 11641 if (windows->image.crop_geometry != (char *) NULL) 11642 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11643 &width,&height); 11644 scale_factor=(double) width/windows->image.ximage->width; 11645 crop_info.x+=x; 11646 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11647 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11648 scale_factor=(double) 11649 height/windows->image.ximage->height; 11650 crop_info.y+=y; 11651 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11652 crop_info.height=(unsigned int) 11653 (scale_factor*crop_info.height+0.5); 11654 roi_image=CropImage(*image,&crop_info,exception); 11655 (void) SetImageProgressMonitor(*image,progress_monitor, 11656 (*image)->client_data); 11657 if (roi_image == (Image *) NULL) 11658 continue; 11659 /* 11660 Apply image processing technique to the region of interest. 11661 */ 11662 windows->image.orphan=MagickTrue; 11663 (void) XMagickCommand(display,resource_info,windows,command_type, 11664 &roi_image,exception); 11665 progress_monitor=SetImageProgressMonitor(*image, 11666 (MagickProgressMonitor) NULL,(*image)->client_data); 11667 (void) XMagickCommand(display,resource_info,windows, 11668 SaveToUndoBufferCommand,image,exception); 11669 windows->image.orphan=MagickFalse; 11670 (void) CompositeImage(*image,roi_image,CopyCompositeOp, 11671 MagickTrue,crop_info.x,crop_info.y,exception); 11672 roi_image=DestroyImage(roi_image); 11673 (void) SetImageProgressMonitor(*image,progress_monitor, 11674 (*image)->client_data); 11675 break; 11676 } 11677 } 11678 if (command_type != InfoCommand) 11679 { 11680 XConfigureImageColormap(display,resource_info,windows,*image, 11681 exception); 11682 (void) XConfigureImage(display,resource_info,windows,*image, 11683 exception); 11684 } 11685 XCheckRefreshWindows(display,windows); 11686 XInfoWidget(display,windows,text); 11687 (void) XSetFunction(display,windows->image.highlight_context, 11688 GXinvert); 11689 state&=(~UpdateRegionState); 11690 } 11691 XHighlightRectangle(display,windows->image.id, 11692 windows->image.highlight_context,&highlight_info); 11693 XScreenEvent(display,windows,&event,exception); 11694 if (event.xany.window == windows->command.id) 11695 { 11696 /* 11697 Select a command from the Command widget. 11698 */ 11699 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11700 command_type=NullCommand; 11701 id=XCommandWidget(display,windows,ApplyMenu,&event); 11702 if (id >= 0) 11703 { 11704 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent); 11705 command_type=ApplyCommands[id]; 11706 if (id < ApplyMenus) 11707 { 11708 /* 11709 Select a command from a pop-up menu. 11710 */ 11711 entry=XMenuWidget(display,windows,ApplyMenu[id], 11712 (const char **) Menus[id],command); 11713 if (entry >= 0) 11714 { 11715 (void) CopyMagickString(command,Menus[id][entry], 11716 MaxTextExtent); 11717 command_type=Commands[id][entry]; 11718 } 11719 } 11720 } 11721 (void) XSetFunction(display,windows->image.highlight_context, 11722 GXinvert); 11723 XHighlightRectangle(display,windows->image.id, 11724 windows->image.highlight_context,&highlight_info); 11725 if (command_type == HelpCommand) 11726 { 11727 (void) XSetFunction(display,windows->image.highlight_context, 11728 GXcopy); 11729 XTextViewWidget(display,resource_info,windows,MagickFalse, 11730 "Help Viewer - Region of Interest",ImageROIHelp); 11731 (void) XSetFunction(display,windows->image.highlight_context, 11732 GXinvert); 11733 continue; 11734 } 11735 if (command_type == QuitCommand) 11736 { 11737 /* 11738 exit. 11739 */ 11740 state|=EscapeState; 11741 state|=ExitState; 11742 continue; 11743 } 11744 if (command_type != NullCommand) 11745 state|=UpdateRegionState; 11746 continue; 11747 } 11748 XHighlightRectangle(display,windows->image.id, 11749 windows->image.highlight_context,&highlight_info); 11750 switch (event.type) 11751 { 11752 case ButtonPress: 11753 { 11754 x=windows->image.x; 11755 y=windows->image.y; 11756 if (event.xbutton.button != Button1) 11757 break; 11758 if (event.xbutton.window != windows->image.id) 11759 break; 11760 x=windows->image.x+event.xbutton.x; 11761 y=windows->image.y+event.xbutton.y; 11762 if ((x < (int) (roi_info.x+RoiDelta)) && 11763 (x > (int) (roi_info.x-RoiDelta)) && 11764 (y < (int) (roi_info.y+RoiDelta)) && 11765 (y > (int) (roi_info.y-RoiDelta))) 11766 { 11767 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11768 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11769 state|=UpdateConfigurationState; 11770 break; 11771 } 11772 if ((x < (int) (roi_info.x+RoiDelta)) && 11773 (x > (int) (roi_info.x-RoiDelta)) && 11774 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11775 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11776 { 11777 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11778 state|=UpdateConfigurationState; 11779 break; 11780 } 11781 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11782 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11783 (y < (int) (roi_info.y+RoiDelta)) && 11784 (y > (int) (roi_info.y-RoiDelta))) 11785 { 11786 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11787 state|=UpdateConfigurationState; 11788 break; 11789 } 11790 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11791 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11792 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11793 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11794 { 11795 state|=UpdateConfigurationState; 11796 break; 11797 } 11798 } 11799 case ButtonRelease: 11800 { 11801 if (event.xbutton.window == windows->pan.id) 11802 if ((highlight_info.x != crop_info.x-windows->image.x) || 11803 (highlight_info.y != crop_info.y-windows->image.y)) 11804 XHighlightRectangle(display,windows->image.id, 11805 windows->image.highlight_context,&highlight_info); 11806 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11807 event.xbutton.time); 11808 break; 11809 } 11810 case Expose: 11811 { 11812 if (event.xexpose.window == windows->image.id) 11813 if (event.xexpose.count == 0) 11814 { 11815 event.xexpose.x=(int) highlight_info.x; 11816 event.xexpose.y=(int) highlight_info.y; 11817 event.xexpose.width=(int) highlight_info.width; 11818 event.xexpose.height=(int) highlight_info.height; 11819 XRefreshWindow(display,&windows->image,&event); 11820 } 11821 if (event.xexpose.window == windows->info.id) 11822 if (event.xexpose.count == 0) 11823 XInfoWidget(display,windows,text); 11824 break; 11825 } 11826 case KeyPress: 11827 { 11828 KeySym 11829 key_symbol; 11830 11831 if (event.xkey.window != windows->image.id) 11832 break; 11833 /* 11834 Respond to a user key press. 11835 */ 11836 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11837 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11838 switch ((int) key_symbol) 11839 { 11840 case XK_Shift_L: 11841 case XK_Shift_R: 11842 break; 11843 case XK_Escape: 11844 case XK_F20: 11845 state|=EscapeState; 11846 case XK_Return: 11847 { 11848 state|=ExitState; 11849 break; 11850 } 11851 case XK_Home: 11852 case XK_KP_Home: 11853 { 11854 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11855 roi_info.y=(ssize_t) (windows->image.height/2L- 11856 roi_info.height/2L); 11857 break; 11858 } 11859 case XK_Left: 11860 case XK_KP_Left: 11861 { 11862 roi_info.x--; 11863 break; 11864 } 11865 case XK_Up: 11866 case XK_KP_Up: 11867 case XK_Next: 11868 { 11869 roi_info.y--; 11870 break; 11871 } 11872 case XK_Right: 11873 case XK_KP_Right: 11874 { 11875 roi_info.x++; 11876 break; 11877 } 11878 case XK_Prior: 11879 case XK_Down: 11880 case XK_KP_Down: 11881 { 11882 roi_info.y++; 11883 break; 11884 } 11885 case XK_F1: 11886 case XK_Help: 11887 { 11888 (void) XSetFunction(display,windows->image.highlight_context, 11889 GXcopy); 11890 XTextViewWidget(display,resource_info,windows,MagickFalse, 11891 "Help Viewer - Region of Interest",ImageROIHelp); 11892 (void) XSetFunction(display,windows->image.highlight_context, 11893 GXinvert); 11894 break; 11895 } 11896 default: 11897 { 11898 command_type=XImageWindowCommand(display,resource_info,windows, 11899 event.xkey.state,key_symbol,image,exception); 11900 if (command_type != NullCommand) 11901 state|=UpdateRegionState; 11902 break; 11903 } 11904 } 11905 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11906 event.xkey.time); 11907 break; 11908 } 11909 case KeyRelease: 11910 break; 11911 case MotionNotify: 11912 { 11913 if (event.xbutton.window != windows->image.id) 11914 break; 11915 /* 11916 Map and unmap Info widget as text cursor crosses its boundaries. 11917 */ 11918 x=event.xmotion.x; 11919 y=event.xmotion.y; 11920 if( IfMagickTrue(windows->info.mapped) ) 11921 { 11922 if ((x < (int) (windows->info.x+windows->info.width)) && 11923 (y < (int) (windows->info.y+windows->info.height))) 11924 (void) XWithdrawWindow(display,windows->info.id, 11925 windows->info.screen); 11926 } 11927 else 11928 if ((x > (int) (windows->info.x+windows->info.width)) || 11929 (y > (int) (windows->info.y+windows->info.height))) 11930 (void) XMapWindow(display,windows->info.id); 11931 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11932 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11933 break; 11934 } 11935 case SelectionRequest: 11936 { 11937 XSelectionEvent 11938 notify; 11939 11940 XSelectionRequestEvent 11941 *request; 11942 11943 /* 11944 Set primary selection. 11945 */ 11946 (void) FormatLocaleString(text,MaxTextExtent, 11947 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11948 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11949 request=(&(event.xselectionrequest)); 11950 (void) XChangeProperty(request->display,request->requestor, 11951 request->property,request->target,8,PropModeReplace, 11952 (unsigned char *) text,(int) strlen(text)); 11953 notify.type=SelectionNotify; 11954 notify.display=request->display; 11955 notify.requestor=request->requestor; 11956 notify.selection=request->selection; 11957 notify.target=request->target; 11958 notify.time=request->time; 11959 if (request->property == None) 11960 notify.property=request->target; 11961 else 11962 notify.property=request->property; 11963 (void) XSendEvent(request->display,request->requestor,False,0, 11964 (XEvent *) ¬ify); 11965 } 11966 default: 11967 break; 11968 } 11969 if ((state & UpdateConfigurationState) != 0) 11970 { 11971 (void) XPutBackEvent(display,&event); 11972 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11973 break; 11974 } 11975 } while ((state & ExitState) == 0); 11976 } while ((state & ExitState) == 0); 11977 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11978 XSetCursorState(display,windows,MagickFalse); 11979 if ((state & EscapeState) != 0) 11980 return(MagickTrue); 11981 return(MagickTrue); 11982} 11983 11984/* 11985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11986% % 11987% % 11988% % 11989+ X R o t a t e I m a g e % 11990% % 11991% % 11992% % 11993%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11994% 11995% XRotateImage() rotates the X image. If the degrees parameter if zero, the 11996% rotation angle is computed from the slope of a line drawn by the user. 11997% 11998% The format of the XRotateImage method is: 11999% 12000% MagickBooleanType XRotateImage(Display *display, 12001% XResourceInfo *resource_info,XWindows *windows,double degrees, 12002% Image **image,ExceptionInfo *exception) 12003% 12004% A description of each parameter follows: 12005% 12006% o display: Specifies a connection to an X server; returned from 12007% XOpenDisplay. 12008% 12009% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12010% 12011% o windows: Specifies a pointer to a XWindows structure. 12012% 12013% o degrees: Specifies the number of degrees to rotate the image. 12014% 12015% o image: the image. 12016% 12017% o exception: return any errors or warnings in this structure. 12018% 12019*/ 12020static MagickBooleanType XRotateImage(Display *display, 12021 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image, 12022 ExceptionInfo *exception) 12023{ 12024 static const char 12025 *RotateMenu[] = 12026 { 12027 "Pixel Color", 12028 "Direction", 12029 "Help", 12030 "Dismiss", 12031 (char *) NULL 12032 }; 12033 12034 static ModeType 12035 direction = HorizontalRotateCommand; 12036 12037 static const ModeType 12038 DirectionCommands[] = 12039 { 12040 HorizontalRotateCommand, 12041 VerticalRotateCommand 12042 }, 12043 RotateCommands[] = 12044 { 12045 RotateColorCommand, 12046 RotateDirectionCommand, 12047 RotateHelpCommand, 12048 RotateDismissCommand 12049 }; 12050 12051 static unsigned int 12052 pen_id = 0; 12053 12054 char 12055 command[MaxTextExtent], 12056 text[MaxTextExtent]; 12057 12058 Image 12059 *rotate_image; 12060 12061 int 12062 id, 12063 x, 12064 y; 12065 12066 double 12067 normalized_degrees; 12068 12069 register int 12070 i; 12071 12072 unsigned int 12073 height, 12074 rotations, 12075 width; 12076 12077 if (degrees == 0.0) 12078 { 12079 unsigned int 12080 distance; 12081 12082 size_t 12083 state; 12084 12085 XEvent 12086 event; 12087 12088 XSegment 12089 rotate_info; 12090 12091 /* 12092 Map Command widget. 12093 */ 12094 (void) CloneString(&windows->command.name,"Rotate"); 12095 windows->command.data=2; 12096 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 12097 (void) XMapRaised(display,windows->command.id); 12098 XClientMessage(display,windows->image.id,windows->im_protocols, 12099 windows->im_update_widget,CurrentTime); 12100 /* 12101 Wait for first button press. 12102 */ 12103 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12104 XQueryPosition(display,windows->image.id,&x,&y); 12105 rotate_info.x1=x; 12106 rotate_info.y1=y; 12107 rotate_info.x2=x; 12108 rotate_info.y2=y; 12109 state=DefaultState; 12110 do 12111 { 12112 XHighlightLine(display,windows->image.id, 12113 windows->image.highlight_context,&rotate_info); 12114 /* 12115 Wait for next event. 12116 */ 12117 XScreenEvent(display,windows,&event,exception); 12118 XHighlightLine(display,windows->image.id, 12119 windows->image.highlight_context,&rotate_info); 12120 if (event.xany.window == windows->command.id) 12121 { 12122 /* 12123 Select a command from the Command widget. 12124 */ 12125 id=XCommandWidget(display,windows,RotateMenu,&event); 12126 if (id < 0) 12127 continue; 12128 (void) XSetFunction(display,windows->image.highlight_context, 12129 GXcopy); 12130 switch (RotateCommands[id]) 12131 { 12132 case RotateColorCommand: 12133 { 12134 const char 12135 *ColorMenu[MaxNumberPens]; 12136 12137 int 12138 pen_number; 12139 12140 XColor 12141 color; 12142 12143 /* 12144 Initialize menu selections. 12145 */ 12146 for (i=0; i < (int) (MaxNumberPens-2); i++) 12147 ColorMenu[i]=resource_info->pen_colors[i]; 12148 ColorMenu[MaxNumberPens-2]="Browser..."; 12149 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12150 /* 12151 Select a pen color from the pop-up menu. 12152 */ 12153 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12154 (const char **) ColorMenu,command); 12155 if (pen_number < 0) 12156 break; 12157 if (pen_number == (MaxNumberPens-2)) 12158 { 12159 static char 12160 color_name[MaxTextExtent] = "gray"; 12161 12162 /* 12163 Select a pen color from a dialog. 12164 */ 12165 resource_info->pen_colors[pen_number]=color_name; 12166 XColorBrowserWidget(display,windows,"Select",color_name); 12167 if (*color_name == '\0') 12168 break; 12169 } 12170 /* 12171 Set pen color. 12172 */ 12173 (void) XParseColor(display,windows->map_info->colormap, 12174 resource_info->pen_colors[pen_number],&color); 12175 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12176 (unsigned int) MaxColors,&color); 12177 windows->pixel_info->pen_colors[pen_number]=color; 12178 pen_id=(unsigned int) pen_number; 12179 break; 12180 } 12181 case RotateDirectionCommand: 12182 { 12183 static const char 12184 *Directions[] = 12185 { 12186 "horizontal", 12187 "vertical", 12188 (char *) NULL, 12189 }; 12190 12191 /* 12192 Select a command from the pop-up menu. 12193 */ 12194 id=XMenuWidget(display,windows,RotateMenu[id], 12195 Directions,command); 12196 if (id >= 0) 12197 direction=DirectionCommands[id]; 12198 break; 12199 } 12200 case RotateHelpCommand: 12201 { 12202 XTextViewWidget(display,resource_info,windows,MagickFalse, 12203 "Help Viewer - Image Rotation",ImageRotateHelp); 12204 break; 12205 } 12206 case RotateDismissCommand: 12207 { 12208 /* 12209 Prematurely exit. 12210 */ 12211 state|=EscapeState; 12212 state|=ExitState; 12213 break; 12214 } 12215 default: 12216 break; 12217 } 12218 (void) XSetFunction(display,windows->image.highlight_context, 12219 GXinvert); 12220 continue; 12221 } 12222 switch (event.type) 12223 { 12224 case ButtonPress: 12225 { 12226 if (event.xbutton.button != Button1) 12227 break; 12228 if (event.xbutton.window != windows->image.id) 12229 break; 12230 /* 12231 exit loop. 12232 */ 12233 (void) XSetFunction(display,windows->image.highlight_context, 12234 GXcopy); 12235 rotate_info.x1=event.xbutton.x; 12236 rotate_info.y1=event.xbutton.y; 12237 state|=ExitState; 12238 break; 12239 } 12240 case ButtonRelease: 12241 break; 12242 case Expose: 12243 break; 12244 case KeyPress: 12245 { 12246 char 12247 command[MaxTextExtent]; 12248 12249 KeySym 12250 key_symbol; 12251 12252 if (event.xkey.window != windows->image.id) 12253 break; 12254 /* 12255 Respond to a user key press. 12256 */ 12257 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12258 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12259 switch ((int) key_symbol) 12260 { 12261 case XK_Escape: 12262 case XK_F20: 12263 { 12264 /* 12265 Prematurely exit. 12266 */ 12267 state|=EscapeState; 12268 state|=ExitState; 12269 break; 12270 } 12271 case XK_F1: 12272 case XK_Help: 12273 { 12274 (void) XSetFunction(display,windows->image.highlight_context, 12275 GXcopy); 12276 XTextViewWidget(display,resource_info,windows,MagickFalse, 12277 "Help Viewer - Image Rotation",ImageRotateHelp); 12278 (void) XSetFunction(display,windows->image.highlight_context, 12279 GXinvert); 12280 break; 12281 } 12282 default: 12283 { 12284 (void) XBell(display,0); 12285 break; 12286 } 12287 } 12288 break; 12289 } 12290 case MotionNotify: 12291 { 12292 rotate_info.x1=event.xmotion.x; 12293 rotate_info.y1=event.xmotion.y; 12294 } 12295 } 12296 rotate_info.x2=rotate_info.x1; 12297 rotate_info.y2=rotate_info.y1; 12298 if (direction == HorizontalRotateCommand) 12299 rotate_info.x2+=32; 12300 else 12301 rotate_info.y2-=32; 12302 } while ((state & ExitState) == 0); 12303 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12304 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12305 if ((state & EscapeState) != 0) 12306 return(MagickTrue); 12307 /* 12308 Draw line as pointer moves until the mouse button is released. 12309 */ 12310 distance=0; 12311 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12312 state=DefaultState; 12313 do 12314 { 12315 if (distance > 9) 12316 { 12317 /* 12318 Display info and draw rotation line. 12319 */ 12320 if( IfMagickFalse(windows->info.mapped) ) 12321 (void) XMapWindow(display,windows->info.id); 12322 (void) FormatLocaleString(text,MaxTextExtent," %g", 12323 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12324 XInfoWidget(display,windows,text); 12325 XHighlightLine(display,windows->image.id, 12326 windows->image.highlight_context,&rotate_info); 12327 } 12328 else 12329 if( IfMagickTrue(windows->info.mapped) ) 12330 (void) XWithdrawWindow(display,windows->info.id, 12331 windows->info.screen); 12332 /* 12333 Wait for next event. 12334 */ 12335 XScreenEvent(display,windows,&event,exception); 12336 if (distance > 9) 12337 XHighlightLine(display,windows->image.id, 12338 windows->image.highlight_context,&rotate_info); 12339 switch (event.type) 12340 { 12341 case ButtonPress: 12342 break; 12343 case ButtonRelease: 12344 { 12345 /* 12346 User has committed to rotation line. 12347 */ 12348 rotate_info.x2=event.xbutton.x; 12349 rotate_info.y2=event.xbutton.y; 12350 state|=ExitState; 12351 break; 12352 } 12353 case Expose: 12354 break; 12355 case MotionNotify: 12356 { 12357 rotate_info.x2=event.xmotion.x; 12358 rotate_info.y2=event.xmotion.y; 12359 } 12360 default: 12361 break; 12362 } 12363 /* 12364 Check boundary conditions. 12365 */ 12366 if (rotate_info.x2 < 0) 12367 rotate_info.x2=0; 12368 else 12369 if (rotate_info.x2 > (int) windows->image.width) 12370 rotate_info.x2=(short) windows->image.width; 12371 if (rotate_info.y2 < 0) 12372 rotate_info.y2=0; 12373 else 12374 if (rotate_info.y2 > (int) windows->image.height) 12375 rotate_info.y2=(short) windows->image.height; 12376 /* 12377 Compute rotation angle from the slope of the line. 12378 */ 12379 degrees=0.0; 12380 distance=(unsigned int) 12381 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12382 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12383 if (distance > 9) 12384 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12385 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12386 } while ((state & ExitState) == 0); 12387 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12388 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12389 if (distance <= 9) 12390 return(MagickTrue); 12391 } 12392 if (direction == VerticalRotateCommand) 12393 degrees-=90.0; 12394 if (degrees == 0.0) 12395 return(MagickTrue); 12396 /* 12397 Rotate image. 12398 */ 12399 normalized_degrees=degrees; 12400 while (normalized_degrees < -45.0) 12401 normalized_degrees+=360.0; 12402 for (rotations=0; normalized_degrees > 45.0; rotations++) 12403 normalized_degrees-=90.0; 12404 if (normalized_degrees != 0.0) 12405 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 12406 exception); 12407 XSetCursorState(display,windows,MagickTrue); 12408 XCheckRefreshWindows(display,windows); 12409 (*image)->background_color.red=(double) ScaleShortToQuantum( 12410 windows->pixel_info->pen_colors[pen_id].red); 12411 (*image)->background_color.green=(double) ScaleShortToQuantum( 12412 windows->pixel_info->pen_colors[pen_id].green); 12413 (*image)->background_color.blue=(double) ScaleShortToQuantum( 12414 windows->pixel_info->pen_colors[pen_id].blue); 12415 rotate_image=RotateImage(*image,degrees,exception); 12416 XSetCursorState(display,windows,MagickFalse); 12417 if (rotate_image == (Image *) NULL) 12418 return(MagickFalse); 12419 *image=DestroyImage(*image); 12420 *image=rotate_image; 12421 if (windows->image.crop_geometry != (char *) NULL) 12422 { 12423 /* 12424 Rotate crop geometry. 12425 */ 12426 width=(unsigned int) (*image)->columns; 12427 height=(unsigned int) (*image)->rows; 12428 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12429 switch (rotations % 4) 12430 { 12431 default: 12432 case 0: 12433 break; 12434 case 1: 12435 { 12436 /* 12437 Rotate 90 degrees. 12438 */ 12439 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12440 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12441 (int) height-y,x); 12442 break; 12443 } 12444 case 2: 12445 { 12446 /* 12447 Rotate 180 degrees. 12448 */ 12449 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12450 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12451 break; 12452 } 12453 case 3: 12454 { 12455 /* 12456 Rotate 270 degrees. 12457 */ 12458 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12459 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12460 break; 12461 } 12462 } 12463 } 12464 if( IfMagickTrue(windows->image.orphan) ) 12465 return(MagickTrue); 12466 if (normalized_degrees != 0.0) 12467 { 12468 /* 12469 Update image colormap. 12470 */ 12471 windows->image.window_changes.width=(int) (*image)->columns; 12472 windows->image.window_changes.height=(int) (*image)->rows; 12473 if (windows->image.crop_geometry != (char *) NULL) 12474 { 12475 /* 12476 Obtain dimensions of image from crop geometry. 12477 */ 12478 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12479 &width,&height); 12480 windows->image.window_changes.width=(int) width; 12481 windows->image.window_changes.height=(int) height; 12482 } 12483 XConfigureImageColormap(display,resource_info,windows,*image,exception); 12484 } 12485 else 12486 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12487 { 12488 windows->image.window_changes.width=windows->image.ximage->height; 12489 windows->image.window_changes.height=windows->image.ximage->width; 12490 } 12491 /* 12492 Update image configuration. 12493 */ 12494 (void) XConfigureImage(display,resource_info,windows,*image,exception); 12495 return(MagickTrue); 12496} 12497 12498/* 12499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12500% % 12501% % 12502% % 12503+ X S a v e I m a g e % 12504% % 12505% % 12506% % 12507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12508% 12509% XSaveImage() saves an image to a file. 12510% 12511% The format of the XSaveImage method is: 12512% 12513% MagickBooleanType XSaveImage(Display *display, 12514% XResourceInfo *resource_info,XWindows *windows,Image *image, 12515% ExceptionInfo *exception) 12516% 12517% A description of each parameter follows: 12518% 12519% o display: Specifies a connection to an X server; returned from 12520% XOpenDisplay. 12521% 12522% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12523% 12524% o windows: Specifies a pointer to a XWindows structure. 12525% 12526% o image: the image. 12527% 12528% o exception: return any errors or warnings in this structure. 12529% 12530*/ 12531static MagickBooleanType XSaveImage(Display *display, 12532 XResourceInfo *resource_info,XWindows *windows,Image *image, 12533 ExceptionInfo *exception) 12534{ 12535 char 12536 filename[MaxTextExtent], 12537 geometry[MaxTextExtent]; 12538 12539 Image 12540 *save_image; 12541 12542 ImageInfo 12543 *image_info; 12544 12545 MagickStatusType 12546 status; 12547 12548 /* 12549 Request file name from user. 12550 */ 12551 if (resource_info->write_filename != (char *) NULL) 12552 (void) CopyMagickString(filename,resource_info->write_filename, 12553 MaxTextExtent); 12554 else 12555 { 12556 char 12557 path[MaxTextExtent]; 12558 12559 int 12560 status; 12561 12562 GetPathComponent(image->filename,HeadPath,path); 12563 GetPathComponent(image->filename,TailPath,filename); 12564 if (*path != '\0') 12565 { 12566 if (*path == '\0') 12567 (void) CopyMagickString(path,".",MaxTextExtent); 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( IfMagickTrue(IsPathAccessible(filename)) ) 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,MaxTextExtent); 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[MaxTextExtent]; 12597 12598 int 12599 status; 12600 12601 /* 12602 Request JPEG quality from user. 12603 */ 12604 (void) FormatLocaleString(quality,MaxTextExtent,"%.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[MaxTextExtent]; 12620 12621 /* 12622 Request page geometry from user. 12623 */ 12624 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12625 if (LocaleCompare(image_info->magick,"PDF") == 0) 12626 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12627 if (image_info->page != (char *) NULL) 12628 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 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,MaxTextExtent,"%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,MaxTextExtent); 12650 status=WriteImage(image_info,save_image,exception); 12651 if( IfMagickTrue(status) ) 12652 image->taint=MagickFalse; 12653 save_image=DestroyImage(save_image); 12654 image_info=DestroyImageInfo(image_info); 12655 XSetCursorState(display,windows,MagickFalse); 12656 return(IsMagickTrue(status)); 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( IfMagickFalse(windows->magnify.mapped) ) 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( IfMagickFalse(windows->magnify.mapped) ) 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[MaxTextExtent]; 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( IfMagickTrue(windows->magnify.mapped) ) 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[MaxTextExtent]; 12969 12970 int 12971 x, 12972 y; 12973 12974 double 12975 scale_factor; 12976 12977 unsigned int 12978 height, 12979 width; 12980 12981 if( IfMagickTrue(windows->info.mapped) ) 12982 { 12983 /* 12984 Display info on cropping rectangle. 12985 */ 12986 (void) FormatLocaleString(text,MaxTextExtent," %.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,MaxTextExtent, 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[MaxTextExtent], 13086 filename[MaxTextExtent]; 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 MaxTextExtent); 13189 (void) CopyMagickString(resource_info->image_info->filename,filename, 13190 MaxTextExtent); 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( IfMagickFalse(IsPathAccessible(filename)) ) 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=IsMagickTrue(remove_utf8(filename)); 13228 if( IfMagickTrue(status) ) 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( IfMagickTrue(IsPathAccessible(filename)) ) 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 SetPixelInfoPixel(image,&pixel,s); 13286 s+=GetPixelChannels(image); 13287 } 13288 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 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[MaxTextExtent]; 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,MaxTextExtent," %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[MaxTextExtent] = "\0", 13635 filenames[MaxTextExtent] = "*"; 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 ThrowXWindowFatalException(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( IfMagickFalse(status) || (number_files == 0)) 13660 { 13661 if (number_files == 0) 13662 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames) 13663 else 13664 ThrowXWindowFatalException(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,MaxTextExtent, 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=IsMagickTrue( (windows->visual_info->klass == TrueColor) || 13680 (windows->visual_info->klass == DirectColor) ); 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],MaxTextExtent); 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( IfMagickFalse(proceed) ) 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 ThrowXWindowFatalException(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,MaxTextExtent); 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[MaxTextExtent], 13793 visual_type[MaxTextExtent]; 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 == MagickSignature); 13835 if( IfMagickTrue(image->debug) ) 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((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 ThrowXWindowFatalException(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",MaxTextExtent); 13862 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13863 if (status != 0) 13864 (void) FormatLocaleString(visual_type,MaxTextExtent,"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,MaxTextExtent,"%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( IfMagickFalse(status) ) 13946 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13947 image->filename); 13948 window_info.x=0; 13949 window_info.y=0; 13950 if( IfMagickTrue(image->debug) ) 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( IfMagickTrue(resources.backdrop) ) 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[MaxTextExtent]; 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,MaxTextExtent,"%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(IsMagickTrue(window_info.id == root_window)); 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[MaxTextExtent], 14431 *directory, 14432 geometry[MaxTextExtent], 14433 resource_name[MaxTextExtent]; 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[MaxTextExtent]; 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 == MagickSignature); 14530 if( IfMagickTrue((*image)->debug) ) 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,".",MaxTextExtent); 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( IfMagickTrue(display_image->debug) ) 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( IfMagickTrue(display_image->debug) ) 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( IfMagickTrue(display_image->debug) ) 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( IfMagickFalse(resource_info->use_shared_memory) ) 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,MaxTextExtent); 14715 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent); 14716 title=DestroyString(title); 14717 } 14718 else 14719 { 14720 char 14721 filename[MaxTextExtent]; 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,MaxTextExtent, 14729 "%s: %s",MagickPackageName,filename); 14730 else 14731 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 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,MaxTextExtent); 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,MaxTextExtent,"%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( IfMagickTrue(display_image->debug) ) 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( IfMagickTrue(display_image->debug) ) 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( IfMagickTrue(display_image->debug) ) 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( IfMagickTrue(windows->image.mapped) ) 14857 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14858 if( IfMagickTrue(display_image->debug) ) 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,MaxTextExtent,"%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( IfMagickTrue(windows->command.mapped) ) 14891 (void) XMapRaised(display,windows->command.id); 14892 if( IfMagickTrue(display_image->debug) ) 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,MaxTextExtent,"%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( IfMagickTrue(display_image->debug) ) 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( IfMagickTrue(display_image->debug) ) 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( IfMagickFalse(resource_info->use_shared_memory) ) 14954 windows->magnify.shared_memory=MagickFalse; 14955 (void) FormatLocaleString(resource_name,MaxTextExtent,"%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,MaxTextExtent,"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( IfMagickTrue(display_image->debug) ) 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,MaxTextExtent,"%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( IfMagickTrue(display_image->debug) ) 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( IfMagickTrue(windows->info.mapped) ) 15021 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15022 if( IfMagickFalse(windows->image.mapped) || 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( IfMagickFalse(status) ) 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( IfMagickFalse(status) ) 15054 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15055 display_image->filename); 15056 if( IfMagickTrue(windows->magnify.mapped) ) 15057 (void) XMapRaised(display,windows->magnify.id); 15058 if( IfMagickTrue(windows->pan.mapped) ) 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( IfMagickTrue(resource_info->update) ) 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( IfMagickTrue(status) ) 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( IfMagickTrue(windows->image.mapped) ) 15092 if ((display_image->delay != 0) || (resource_info->update != 0)) 15093 { 15094 if (timer < time((time_t *) NULL)) 15095 { 15096 if( IfMagickFalse(resource_info->update) ) 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( IfMagickTrue(status) ) 15108 if (update_time != attributes.st_mtime) 15109 { 15110 /* 15111 Redisplay image. 15112 */ 15113 (void) FormatLocaleString( 15114 resource_info->image_info->filename,MaxTextExtent, 15115 "%s:%s",display_image->magick, 15116 display_image->filename); 15117 nexus=ReadImage(resource_info->image_info,exception); 15118 if (nexus != (Image *) NULL) 15119 { 15120 nexus=DestroyImage(nexus); 15121 *state|=NextImageState | ExitState; 15122 } 15123 } 15124 delay=display_image->delay/MagickMax( 15125 display_image->ticks_per_second,1L); 15126 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15127 } 15128 } 15129 if (XEventsQueued(display,QueuedAfterFlush) == 0) 15130 { 15131 /* 15132 Do not block if delay > 0. 15133 */ 15134 XDelay(display,SuspendTime << 2); 15135 continue; 15136 } 15137 } 15138 timestamp=time((time_t *) NULL); 15139 (void) XNextEvent(display,&event); 15140 if( IfMagickFalse(windows->image.stasis) ) 15141 windows->image.stasis=IsMagickTrue((time((time_t *) NULL)-timestamp) > 0); 15142 if( IfMagickFalse(windows->magnify.stasis) ) 15143 windows->magnify.stasis=IsMagickTrue((time((time_t *) NULL)-timestamp) > 0); 15144 if (event.xany.window == windows->command.id) 15145 { 15146 /* 15147 Select a command from the Command widget. 15148 */ 15149 id=XCommandWidget(display,windows,CommandMenu,&event); 15150 if (id < 0) 15151 continue; 15152 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent); 15153 command_type=CommandMenus[id]; 15154 if (id < MagickMenus) 15155 { 15156 /* 15157 Select a command from a pop-up menu. 15158 */ 15159 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15160 command); 15161 if (entry < 0) 15162 continue; 15163 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent); 15164 command_type=Commands[id][entry]; 15165 } 15166 if (command_type != NullCommand) 15167 nexus=XMagickCommand(display,resource_info,windows,command_type, 15168 &display_image,exception); 15169 continue; 15170 } 15171 switch (event.type) 15172 { 15173 case ButtonPress: 15174 { 15175 if( IfMagickTrue(display_image->debug) ) 15176 (void) LogMagickEvent(X11Event,GetMagickModule(), 15177 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15178 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15179 if ((event.xbutton.button == Button3) && 15180 (event.xbutton.state & Mod1Mask)) 15181 { 15182 /* 15183 Convert Alt-Button3 to Button2. 15184 */ 15185 event.xbutton.button=Button2; 15186 event.xbutton.state&=(~Mod1Mask); 15187 } 15188 if (event.xbutton.window == windows->backdrop.id) 15189 { 15190 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15191 event.xbutton.time); 15192 break; 15193 } 15194 if (event.xbutton.window == windows->image.id) 15195 { 15196 switch (event.xbutton.button) 15197 { 15198 case Button1: 15199 { 15200 if (resource_info->immutable) 15201 { 15202 /* 15203 Select a command from the Virtual menu. 15204 */ 15205 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15206 command); 15207 if (entry >= 0) 15208 nexus=XMagickCommand(display,resource_info,windows, 15209 VirtualCommands[entry],&display_image,exception); 15210 break; 15211 } 15212 /* 15213 Map/unmap Command widget. 15214 */ 15215 if( IfMagickTrue(windows->command.mapped) ) 15216 (void) XWithdrawWindow(display,windows->command.id, 15217 windows->command.screen); 15218 else 15219 { 15220 (void) XCommandWidget(display,windows,CommandMenu, 15221 (XEvent *) NULL); 15222 (void) XMapRaised(display,windows->command.id); 15223 } 15224 break; 15225 } 15226 case Button2: 15227 { 15228 /* 15229 User pressed the image magnify button. 15230 */ 15231 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15232 &display_image,exception); 15233 XMagnifyImage(display,windows,&event,exception); 15234 break; 15235 } 15236 case Button3: 15237 { 15238 if (resource_info->immutable) 15239 { 15240 /* 15241 Select a command from the Virtual menu. 15242 */ 15243 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15244 command); 15245 if (entry >= 0) 15246 nexus=XMagickCommand(display,resource_info,windows, 15247 VirtualCommands[entry],&display_image,exception); 15248 break; 15249 } 15250 if (display_image->montage != (char *) NULL) 15251 { 15252 /* 15253 Open or delete a tile from a visual image directory. 15254 */ 15255 nexus=XTileImage(display,resource_info,windows, 15256 display_image,&event,exception); 15257 if (nexus != (Image *) NULL) 15258 *state|=MontageImageState | NextImageState | ExitState; 15259 vid_info.x=(short int) windows->image.x; 15260 vid_info.y=(short int) windows->image.y; 15261 break; 15262 } 15263 /* 15264 Select a command from the Short Cuts menu. 15265 */ 15266 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15267 command); 15268 if (entry >= 0) 15269 nexus=XMagickCommand(display,resource_info,windows, 15270 ShortCutsCommands[entry],&display_image,exception); 15271 break; 15272 } 15273 case Button4: 15274 { 15275 /* 15276 Wheel up. 15277 */ 15278 XTranslateImage(display,windows,*image,XK_Up); 15279 break; 15280 } 15281 case Button5: 15282 { 15283 /* 15284 Wheel down. 15285 */ 15286 XTranslateImage(display,windows,*image,XK_Down); 15287 break; 15288 } 15289 default: 15290 break; 15291 } 15292 break; 15293 } 15294 if (event.xbutton.window == windows->magnify.id) 15295 { 15296 int 15297 factor; 15298 15299 static const char 15300 *MagnifyMenu[] = 15301 { 15302 "2", 15303 "4", 15304 "5", 15305 "6", 15306 "7", 15307 "8", 15308 "9", 15309 "3", 15310 (char *) NULL, 15311 }; 15312 15313 static KeySym 15314 MagnifyCommands[] = 15315 { 15316 XK_2, 15317 XK_4, 15318 XK_5, 15319 XK_6, 15320 XK_7, 15321 XK_8, 15322 XK_9, 15323 XK_3 15324 }; 15325 15326 /* 15327 Select a magnify factor from the pop-up menu. 15328 */ 15329 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15330 if (factor >= 0) 15331 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor], 15332 exception); 15333 break; 15334 } 15335 if (event.xbutton.window == windows->pan.id) 15336 { 15337 switch (event.xbutton.button) 15338 { 15339 case Button4: 15340 { 15341 /* 15342 Wheel up. 15343 */ 15344 XTranslateImage(display,windows,*image,XK_Up); 15345 break; 15346 } 15347 case Button5: 15348 { 15349 /* 15350 Wheel down. 15351 */ 15352 XTranslateImage(display,windows,*image,XK_Down); 15353 break; 15354 } 15355 default: 15356 { 15357 XPanImage(display,windows,&event,exception); 15358 break; 15359 } 15360 } 15361 break; 15362 } 15363 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15364 1L); 15365 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15366 break; 15367 } 15368 case ButtonRelease: 15369 { 15370 if( IfMagickTrue(display_image->debug) ) 15371 (void) LogMagickEvent(X11Event,GetMagickModule(), 15372 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15373 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15374 break; 15375 } 15376 case ClientMessage: 15377 { 15378 if( IfMagickTrue(display_image->debug) ) 15379 (void) LogMagickEvent(X11Event,GetMagickModule(), 15380 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15381 event.xclient.message_type,event.xclient.format,(unsigned long) 15382 event.xclient.data.l[0]); 15383 if (event.xclient.message_type == windows->im_protocols) 15384 { 15385 if (*event.xclient.data.l == (long) windows->im_update_widget) 15386 { 15387 (void) CloneString(&windows->command.name,MagickTitle); 15388 windows->command.data=MagickMenus; 15389 (void) XCommandWidget(display,windows,CommandMenu, 15390 (XEvent *) NULL); 15391 break; 15392 } 15393 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15394 { 15395 /* 15396 Update graphic context and window colormap. 15397 */ 15398 for (i=0; i < (int) number_windows; i++) 15399 { 15400 if (magick_windows[i]->id == windows->icon.id) 15401 continue; 15402 context_values.background=pixel->background_color.pixel; 15403 context_values.foreground=pixel->foreground_color.pixel; 15404 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15405 context_mask,&context_values); 15406 (void) XChangeGC(display,magick_windows[i]->widget_context, 15407 context_mask,&context_values); 15408 context_values.background=pixel->foreground_color.pixel; 15409 context_values.foreground=pixel->background_color.pixel; 15410 context_values.plane_mask=context_values.background ^ 15411 context_values.foreground; 15412 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15413 (size_t) (context_mask | GCPlaneMask), 15414 &context_values); 15415 magick_windows[i]->attributes.background_pixel= 15416 pixel->background_color.pixel; 15417 magick_windows[i]->attributes.border_pixel= 15418 pixel->border_color.pixel; 15419 magick_windows[i]->attributes.colormap=map_info->colormap; 15420 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15421 (unsigned long) magick_windows[i]->mask, 15422 &magick_windows[i]->attributes); 15423 } 15424 if( IfMagickTrue(windows->pan.mapped) ) 15425 { 15426 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15427 windows->pan.pixmap); 15428 (void) XClearWindow(display,windows->pan.id); 15429 XDrawPanRectangle(display,windows); 15430 } 15431 if (windows->backdrop.id != (Window) NULL) 15432 (void) XInstallColormap(display,map_info->colormap); 15433 break; 15434 } 15435 if (*event.xclient.data.l == (long) windows->im_former_image) 15436 { 15437 *state|=FormerImageState | ExitState; 15438 break; 15439 } 15440 if (*event.xclient.data.l == (long) windows->im_next_image) 15441 { 15442 *state|=NextImageState | ExitState; 15443 break; 15444 } 15445 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15446 { 15447 *state|=RetainColorsState; 15448 break; 15449 } 15450 if (*event.xclient.data.l == (long) windows->im_exit) 15451 { 15452 *state|=ExitState; 15453 break; 15454 } 15455 break; 15456 } 15457 if (event.xclient.message_type == windows->dnd_protocols) 15458 { 15459 Atom 15460 selection, 15461 type; 15462 15463 int 15464 format, 15465 status; 15466 15467 unsigned char 15468 *data; 15469 15470 unsigned long 15471 after, 15472 length; 15473 15474 /* 15475 Display image named by the Drag-and-Drop selection. 15476 */ 15477 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15478 break; 15479 selection=XInternAtom(display,"DndSelection",MagickFalse); 15480 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15481 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15482 &length,&after,&data); 15483 if ((status != Success) || (length == 0)) 15484 break; 15485 if (*event.xclient.data.l == 2) 15486 { 15487 /* 15488 Offix DND. 15489 */ 15490 (void) CopyMagickString(resource_info->image_info->filename, 15491 (char *) data,MaxTextExtent); 15492 } 15493 else 15494 { 15495 /* 15496 XDND. 15497 */ 15498 if (strncmp((char *) data, "file:", 5) != 0) 15499 { 15500 (void) XFree((void *) data); 15501 break; 15502 } 15503 (void) CopyMagickString(resource_info->image_info->filename, 15504 ((char *) data)+5,MaxTextExtent); 15505 } 15506 nexus=ReadImage(resource_info->image_info,exception); 15507 CatchException(exception); 15508 if (nexus != (Image *) NULL) 15509 *state|=NextImageState | ExitState; 15510 (void) XFree((void *) data); 15511 break; 15512 } 15513 /* 15514 If client window delete message, exit. 15515 */ 15516 if (event.xclient.message_type != windows->wm_protocols) 15517 break; 15518 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15519 break; 15520 (void) XWithdrawWindow(display,event.xclient.window, 15521 visual_info->screen); 15522 if (event.xclient.window == windows->image.id) 15523 { 15524 *state|=ExitState; 15525 break; 15526 } 15527 if (event.xclient.window == windows->pan.id) 15528 { 15529 /* 15530 Restore original image size when pan window is deleted. 15531 */ 15532 windows->image.window_changes.width=windows->image.ximage->width; 15533 windows->image.window_changes.height=windows->image.ximage->height; 15534 (void) XConfigureImage(display,resource_info,windows, 15535 display_image,exception); 15536 } 15537 break; 15538 } 15539 case ConfigureNotify: 15540 { 15541 if( IfMagickTrue(display_image->debug) ) 15542 (void) LogMagickEvent(X11Event,GetMagickModule(), 15543 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15544 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15545 event.xconfigure.y,event.xconfigure.send_event); 15546 if (event.xconfigure.window == windows->image.id) 15547 { 15548 /* 15549 Image window has a new configuration. 15550 */ 15551 if (event.xconfigure.send_event != 0) 15552 { 15553 XWindowChanges 15554 window_changes; 15555 15556 /* 15557 Position the transient windows relative of the Image window. 15558 */ 15559 if (windows->command.geometry == (char *) NULL) 15560 if( IfMagickFalse(windows->command.mapped) ) 15561 { 15562 windows->command.x=event.xconfigure.x- 15563 windows->command.width-25; 15564 windows->command.y=event.xconfigure.y; 15565 XConstrainWindowPosition(display,&windows->command); 15566 window_changes.x=windows->command.x; 15567 window_changes.y=windows->command.y; 15568 (void) XReconfigureWMWindow(display,windows->command.id, 15569 windows->command.screen,(unsigned int) (CWX | CWY), 15570 &window_changes); 15571 } 15572 if (windows->widget.geometry == (char *) NULL) 15573 if( IfMagickFalse(windows->widget.mapped) ) 15574 { 15575 windows->widget.x=event.xconfigure.x+ 15576 event.xconfigure.width/10; 15577 windows->widget.y=event.xconfigure.y+ 15578 event.xconfigure.height/10; 15579 XConstrainWindowPosition(display,&windows->widget); 15580 window_changes.x=windows->widget.x; 15581 window_changes.y=windows->widget.y; 15582 (void) XReconfigureWMWindow(display,windows->widget.id, 15583 windows->widget.screen,(unsigned int) (CWX | CWY), 15584 &window_changes); 15585 } 15586 if (windows->magnify.geometry == (char *) NULL) 15587 if( IfMagickFalse(windows->magnify.mapped) ) 15588 { 15589 windows->magnify.x=event.xconfigure.x+ 15590 event.xconfigure.width+25; 15591 windows->magnify.y=event.xconfigure.y; 15592 XConstrainWindowPosition(display,&windows->magnify); 15593 window_changes.x=windows->magnify.x; 15594 window_changes.y=windows->magnify.y; 15595 (void) XReconfigureWMWindow(display,windows->magnify.id, 15596 windows->magnify.screen,(unsigned int) (CWX | CWY), 15597 &window_changes); 15598 } 15599 if (windows->pan.geometry == (char *) NULL) 15600 if( IfMagickFalse(windows->pan.mapped) ) 15601 { 15602 windows->pan.x=event.xconfigure.x+ 15603 event.xconfigure.width+25; 15604 windows->pan.y=event.xconfigure.y+ 15605 windows->magnify.height+50; 15606 XConstrainWindowPosition(display,&windows->pan); 15607 window_changes.x=windows->pan.x; 15608 window_changes.y=windows->pan.y; 15609 (void) XReconfigureWMWindow(display,windows->pan.id, 15610 windows->pan.screen,(unsigned int) (CWX | CWY), 15611 &window_changes); 15612 } 15613 } 15614 if ((event.xconfigure.width == (int) windows->image.width) && 15615 (event.xconfigure.height == (int) windows->image.height)) 15616 break; 15617 windows->image.width=(unsigned int) event.xconfigure.width; 15618 windows->image.height=(unsigned int) event.xconfigure.height; 15619 windows->image.x=0; 15620 windows->image.y=0; 15621 if (display_image->montage != (char *) NULL) 15622 { 15623 windows->image.x=vid_info.x; 15624 windows->image.y=vid_info.y; 15625 } 15626 if( IfMagickTrue(windows->image.mapped) && 15627 IfMagickTrue(windows->image.stasis) ) 15628 { 15629 /* 15630 Update image window configuration. 15631 */ 15632 windows->image.window_changes.width=event.xconfigure.width; 15633 windows->image.window_changes.height=event.xconfigure.height; 15634 (void) XConfigureImage(display,resource_info,windows, 15635 display_image,exception); 15636 } 15637 /* 15638 Update pan window configuration. 15639 */ 15640 if ((event.xconfigure.width < windows->image.ximage->width) || 15641 (event.xconfigure.height < windows->image.ximage->height)) 15642 { 15643 (void) XMapRaised(display,windows->pan.id); 15644 XDrawPanRectangle(display,windows); 15645 } 15646 else 15647 if( IfMagickTrue(windows->pan.mapped) ) 15648 (void) XWithdrawWindow(display,windows->pan.id, 15649 windows->pan.screen); 15650 break; 15651 } 15652 if (event.xconfigure.window == windows->magnify.id) 15653 { 15654 unsigned int 15655 magnify; 15656 15657 /* 15658 Magnify window has a new configuration. 15659 */ 15660 windows->magnify.width=(unsigned int) event.xconfigure.width; 15661 windows->magnify.height=(unsigned int) event.xconfigure.height; 15662 if( IfMagickFalse(windows->magnify.mapped) ) 15663 break; 15664 magnify=1; 15665 while ((int) magnify <= event.xconfigure.width) 15666 magnify<<=1; 15667 while ((int) magnify <= event.xconfigure.height) 15668 magnify<<=1; 15669 magnify>>=1; 15670 if (((int) magnify != event.xconfigure.width) || 15671 ((int) magnify != event.xconfigure.height)) 15672 { 15673 window_changes.width=(int) magnify; 15674 window_changes.height=(int) magnify; 15675 (void) XReconfigureWMWindow(display,windows->magnify.id, 15676 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15677 &window_changes); 15678 break; 15679 } 15680 if( IfMagickTrue(windows->magnify.mapped) && 15681 IfMagickTrue(windows->magnify.stasis) ) 15682 { 15683 status=XMakeImage(display,resource_info,&windows->magnify, 15684 display_image,windows->magnify.width,windows->magnify.height, 15685 exception); 15686 XMakeMagnifyImage(display,windows,exception); 15687 } 15688 break; 15689 } 15690 if( IfMagickTrue(windows->magnify.mapped) && 15691 (event.xconfigure.window == windows->pan.id)) 15692 { 15693 /* 15694 Pan icon window has a new configuration. 15695 */ 15696 if (event.xconfigure.send_event != 0) 15697 { 15698 windows->pan.x=event.xconfigure.x; 15699 windows->pan.y=event.xconfigure.y; 15700 } 15701 windows->pan.width=(unsigned int) event.xconfigure.width; 15702 windows->pan.height=(unsigned int) event.xconfigure.height; 15703 break; 15704 } 15705 if (event.xconfigure.window == windows->icon.id) 15706 { 15707 /* 15708 Icon window has a new configuration. 15709 */ 15710 windows->icon.width=(unsigned int) event.xconfigure.width; 15711 windows->icon.height=(unsigned int) event.xconfigure.height; 15712 break; 15713 } 15714 break; 15715 } 15716 case DestroyNotify: 15717 { 15718 /* 15719 Group leader has exited. 15720 */ 15721 if( IfMagickTrue(display_image->debug) ) 15722 (void) LogMagickEvent(X11Event,GetMagickModule(), 15723 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15724 if (event.xdestroywindow.window == windows->group_leader.id) 15725 { 15726 *state|=ExitState; 15727 break; 15728 } 15729 break; 15730 } 15731 case EnterNotify: 15732 { 15733 /* 15734 Selectively install colormap. 15735 */ 15736 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15737 if (event.xcrossing.mode != NotifyUngrab) 15738 XInstallColormap(display,map_info->colormap); 15739 break; 15740 } 15741 case Expose: 15742 { 15743 if( IfMagickTrue(display_image->debug) ) 15744 (void) LogMagickEvent(X11Event,GetMagickModule(), 15745 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15746 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15747 event.xexpose.y); 15748 /* 15749 Refresh windows that are now exposed. 15750 */ 15751 if ((event.xexpose.window == windows->image.id) && 15752 IfMagickTrue(windows->image.mapped) ) 15753 { 15754 XRefreshWindow(display,&windows->image,&event); 15755 delay=display_image->delay/MagickMax( 15756 display_image->ticks_per_second,1L); 15757 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15758 break; 15759 } 15760 if ((event.xexpose.window == windows->magnify.id) && 15761 IfMagickTrue(windows->magnify.mapped)) 15762 { 15763 XMakeMagnifyImage(display,windows,exception); 15764 break; 15765 } 15766 if (event.xexpose.window == windows->pan.id) 15767 { 15768 XDrawPanRectangle(display,windows); 15769 break; 15770 } 15771 if (event.xexpose.window == windows->icon.id) 15772 { 15773 XRefreshWindow(display,&windows->icon,&event); 15774 break; 15775 } 15776 break; 15777 } 15778 case KeyPress: 15779 { 15780 int 15781 length; 15782 15783 /* 15784 Respond to a user key press. 15785 */ 15786 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15787 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15788 *(command+length)='\0'; 15789 if( IfMagickTrue(display_image->debug) ) 15790 (void) LogMagickEvent(X11Event,GetMagickModule(), 15791 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15792 key_symbol,command); 15793 if (event.xkey.window == windows->image.id) 15794 { 15795 command_type=XImageWindowCommand(display,resource_info,windows, 15796 event.xkey.state,key_symbol,&display_image,exception); 15797 if (command_type != NullCommand) 15798 nexus=XMagickCommand(display,resource_info,windows,command_type, 15799 &display_image,exception); 15800 } 15801 if (event.xkey.window == windows->magnify.id) 15802 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol, 15803 exception); 15804 if (event.xkey.window == windows->pan.id) 15805 { 15806 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15807 (void) XWithdrawWindow(display,windows->pan.id, 15808 windows->pan.screen); 15809 else 15810 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15811 XTextViewWidget(display,resource_info,windows,MagickFalse, 15812 "Help Viewer - Image Pan",ImagePanHelp); 15813 else 15814 XTranslateImage(display,windows,*image,key_symbol); 15815 } 15816 delay=display_image->delay/MagickMax( 15817 display_image->ticks_per_second,1L); 15818 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15819 break; 15820 } 15821 case KeyRelease: 15822 { 15823 /* 15824 Respond to a user key release. 15825 */ 15826 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15827 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15828 if( IfMagickTrue(display_image->debug) ) 15829 (void) LogMagickEvent(X11Event,GetMagickModule(), 15830 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15831 break; 15832 } 15833 case LeaveNotify: 15834 { 15835 /* 15836 Selectively uninstall colormap. 15837 */ 15838 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15839 if (event.xcrossing.mode != NotifyUngrab) 15840 XUninstallColormap(display,map_info->colormap); 15841 break; 15842 } 15843 case MapNotify: 15844 { 15845 if( IfMagickTrue(display_image->debug) ) 15846 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15847 event.xmap.window); 15848 if (event.xmap.window == windows->backdrop.id) 15849 { 15850 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15851 CurrentTime); 15852 windows->backdrop.mapped=MagickTrue; 15853 break; 15854 } 15855 if (event.xmap.window == windows->image.id) 15856 { 15857 if (windows->backdrop.id != (Window) NULL) 15858 (void) XInstallColormap(display,map_info->colormap); 15859 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15860 { 15861 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15862 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15863 } 15864 if (((int) windows->image.width < windows->image.ximage->width) || 15865 ((int) windows->image.height < windows->image.ximage->height)) 15866 (void) XMapRaised(display,windows->pan.id); 15867 windows->image.mapped=MagickTrue; 15868 break; 15869 } 15870 if (event.xmap.window == windows->magnify.id) 15871 { 15872 XMakeMagnifyImage(display,windows,exception); 15873 windows->magnify.mapped=MagickTrue; 15874 (void) XWithdrawWindow(display,windows->info.id, 15875 windows->info.screen); 15876 break; 15877 } 15878 if (event.xmap.window == windows->pan.id) 15879 { 15880 XMakePanImage(display,resource_info,windows,display_image, 15881 exception); 15882 windows->pan.mapped=MagickTrue; 15883 break; 15884 } 15885 if (event.xmap.window == windows->info.id) 15886 { 15887 windows->info.mapped=MagickTrue; 15888 break; 15889 } 15890 if (event.xmap.window == windows->icon.id) 15891 { 15892 MagickBooleanType 15893 taint; 15894 15895 /* 15896 Create an icon image. 15897 */ 15898 taint=display_image->taint; 15899 XMakeStandardColormap(display,icon_visual,icon_resources, 15900 display_image,icon_map,icon_pixel,exception); 15901 (void) XMakeImage(display,icon_resources,&windows->icon, 15902 display_image,windows->icon.width,windows->icon.height, 15903 exception); 15904 display_image->taint=taint; 15905 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15906 windows->icon.pixmap); 15907 (void) XClearWindow(display,windows->icon.id); 15908 (void) XWithdrawWindow(display,windows->info.id, 15909 windows->info.screen); 15910 windows->icon.mapped=MagickTrue; 15911 break; 15912 } 15913 if (event.xmap.window == windows->command.id) 15914 { 15915 windows->command.mapped=MagickTrue; 15916 break; 15917 } 15918 if (event.xmap.window == windows->popup.id) 15919 { 15920 windows->popup.mapped=MagickTrue; 15921 break; 15922 } 15923 if (event.xmap.window == windows->widget.id) 15924 { 15925 windows->widget.mapped=MagickTrue; 15926 break; 15927 } 15928 break; 15929 } 15930 case MappingNotify: 15931 { 15932 (void) XRefreshKeyboardMapping(&event.xmapping); 15933 break; 15934 } 15935 case NoExpose: 15936 break; 15937 case PropertyNotify: 15938 { 15939 Atom 15940 type; 15941 15942 int 15943 format, 15944 status; 15945 15946 unsigned char 15947 *data; 15948 15949 unsigned long 15950 after, 15951 length; 15952 15953 if( IfMagickTrue(display_image->debug) ) 15954 (void) LogMagickEvent(X11Event,GetMagickModule(), 15955 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15956 event.xproperty.atom,event.xproperty.state); 15957 if (event.xproperty.atom != windows->im_remote_command) 15958 break; 15959 /* 15960 Display image named by the remote command protocol. 15961 */ 15962 status=XGetWindowProperty(display,event.xproperty.window, 15963 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom) 15964 AnyPropertyType,&type,&format,&length,&after,&data); 15965 if ((status != Success) || (length == 0)) 15966 break; 15967 if (LocaleCompare((char *) data,"-quit") == 0) 15968 { 15969 XClientMessage(display,windows->image.id,windows->im_protocols, 15970 windows->im_exit,CurrentTime); 15971 (void) XFree((void *) data); 15972 break; 15973 } 15974 (void) CopyMagickString(resource_info->image_info->filename, 15975 (char *) data,MaxTextExtent); 15976 (void) XFree((void *) data); 15977 nexus=ReadImage(resource_info->image_info,exception); 15978 CatchException(exception); 15979 if (nexus != (Image *) NULL) 15980 *state|=NextImageState | ExitState; 15981 break; 15982 } 15983 case ReparentNotify: 15984 { 15985 if( IfMagickTrue(display_image->debug) ) 15986 (void) LogMagickEvent(X11Event,GetMagickModule(), 15987 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 15988 event.xreparent.window); 15989 break; 15990 } 15991 case UnmapNotify: 15992 { 15993 if( IfMagickTrue(display_image->debug) ) 15994 (void) LogMagickEvent(X11Event,GetMagickModule(), 15995 "Unmap Notify: 0x%lx",event.xunmap.window); 15996 if (event.xunmap.window == windows->backdrop.id) 15997 { 15998 windows->backdrop.mapped=MagickFalse; 15999 break; 16000 } 16001 if (event.xunmap.window == windows->image.id) 16002 { 16003 windows->image.mapped=MagickFalse; 16004 break; 16005 } 16006 if (event.xunmap.window == windows->magnify.id) 16007 { 16008 windows->magnify.mapped=MagickFalse; 16009 break; 16010 } 16011 if (event.xunmap.window == windows->pan.id) 16012 { 16013 windows->pan.mapped=MagickFalse; 16014 break; 16015 } 16016 if (event.xunmap.window == windows->info.id) 16017 { 16018 windows->info.mapped=MagickFalse; 16019 break; 16020 } 16021 if (event.xunmap.window == windows->icon.id) 16022 { 16023 if (map_info->colormap == icon_map->colormap) 16024 XConfigureImageColormap(display,resource_info,windows, 16025 display_image,exception); 16026 (void) XFreeStandardColormap(display,icon_visual,icon_map, 16027 icon_pixel); 16028 windows->icon.mapped=MagickFalse; 16029 break; 16030 } 16031 if (event.xunmap.window == windows->command.id) 16032 { 16033 windows->command.mapped=MagickFalse; 16034 break; 16035 } 16036 if (event.xunmap.window == windows->popup.id) 16037 { 16038 if (windows->backdrop.id != (Window) NULL) 16039 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16040 CurrentTime); 16041 windows->popup.mapped=MagickFalse; 16042 break; 16043 } 16044 if (event.xunmap.window == windows->widget.id) 16045 { 16046 if (windows->backdrop.id != (Window) NULL) 16047 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16048 CurrentTime); 16049 windows->widget.mapped=MagickFalse; 16050 break; 16051 } 16052 break; 16053 } 16054 default: 16055 { 16056 if( IfMagickTrue(display_image->debug) ) 16057 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 16058 event.type); 16059 break; 16060 } 16061 } 16062 } while (!(*state & ExitState)); 16063 if ((*state & ExitState) == 0) 16064 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 16065 &display_image,exception); 16066 else 16067 if( IfMagickTrue(resource_info->confirm_edit) ) 16068 { 16069 /* 16070 Query user if image has changed. 16071 */ 16072 if( IfMagickFalse(resource_info->immutable) && 16073 IfMagickTrue(display_image->taint)) 16074 { 16075 int 16076 status; 16077 16078 status=XConfirmWidget(display,windows,"Your image changed.", 16079 "Do you want to save it"); 16080 if (status == 0) 16081 *state&=(~ExitState); 16082 else 16083 if (status > 0) 16084 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 16085 &display_image,exception); 16086 } 16087 } 16088 if ((windows->visual_info->klass == GrayScale) || 16089 (windows->visual_info->klass == PseudoColor) || 16090 (windows->visual_info->klass == DirectColor)) 16091 { 16092 /* 16093 Withdraw pan and Magnify window. 16094 */ 16095 if( IfMagickTrue(windows->info.mapped) ) 16096 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 16097 if( IfMagickTrue(windows->magnify.mapped) ) 16098 (void) XWithdrawWindow(display,windows->magnify.id, 16099 windows->magnify.screen); 16100 if( IfMagickTrue(windows->command.mapped) ) 16101 (void) XWithdrawWindow(display,windows->command.id, 16102 windows->command.screen); 16103 } 16104 if( IfMagickTrue(windows->pan.mapped) ) 16105 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 16106 if( IfMagickFalse(resource_info->backdrop) ) 16107 if (windows->backdrop.mapped) 16108 { 16109 (void) XWithdrawWindow(display,windows->backdrop.id, 16110 windows->backdrop.screen); 16111 (void) XDestroyWindow(display,windows->backdrop.id); 16112 windows->backdrop.id=(Window) NULL; 16113 (void) XWithdrawWindow(display,windows->image.id, 16114 windows->image.screen); 16115 (void) XDestroyWindow(display,windows->image.id); 16116 windows->image.id=(Window) NULL; 16117 } 16118 XSetCursorState(display,windows,MagickTrue); 16119 XCheckRefreshWindows(display,windows); 16120 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 16121 *state&=(~ExitState); 16122 if (*state & ExitState) 16123 { 16124 /* 16125 Free Standard Colormap. 16126 */ 16127 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 16128 if (resource_info->map_type == (char *) NULL) 16129 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 16130 /* 16131 Free X resources. 16132 */ 16133 if (resource_info->copy_image != (Image *) NULL) 16134 { 16135 resource_info->copy_image=DestroyImage(resource_info->copy_image); 16136 resource_info->copy_image=NewImageList(); 16137 } 16138 DestroyXResources(); 16139 } 16140 (void) XSync(display,MagickFalse); 16141 /* 16142 Restore our progress monitor and warning handlers. 16143 */ 16144 (void) SetErrorHandler(warning_handler); 16145 (void) SetWarningHandler(warning_handler); 16146 /* 16147 Change to home directory. 16148 */ 16149 directory=getcwd(working_directory,MaxTextExtent); 16150 (void) directory; 16151 { 16152 int 16153 status; 16154 16155 if (*resource_info->home_directory == '\0') 16156 (void) CopyMagickString(resource_info->home_directory,".",MaxTextExtent); 16157 status=chdir(resource_info->home_directory); 16158 if (status == -1) 16159 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 16160 "UnableToOpenFile","%s",resource_info->home_directory); 16161 } 16162 *image=display_image; 16163 return(nexus); 16164} 16165#else 16166 16167/* 16168%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16169% % 16170% % 16171% % 16172+ D i s p l a y I m a g e s % 16173% % 16174% % 16175% % 16176%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16177% 16178% DisplayImages() displays an image sequence to any X window screen. It 16179% returns a value other than 0 if successful. Check the exception member 16180% of image to determine the reason for any failure. 16181% 16182% The format of the DisplayImages method is: 16183% 16184% MagickBooleanType DisplayImages(const ImageInfo *image_info, 16185% Image *images,ExceptionInfo *exception) 16186% 16187% A description of each parameter follows: 16188% 16189% o image_info: the image info. 16190% 16191% o image: the image. 16192% 16193% o exception: return any errors or warnings in this structure. 16194% 16195*/ 16196MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16197 Image *image,ExceptionInfo *exception) 16198{ 16199 assert(image_info != (const ImageInfo *) NULL); 16200 assert(image_info->signature == MagickSignature); 16201 assert(image != (Image *) NULL); 16202 assert(image->signature == MagickSignature); 16203 if( IfMagickTrue(image->debug) ) 16204 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16205 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16206 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image->filename); 16207 return(MagickFalse); 16208} 16209 16210/* 16211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16212% % 16213% % 16214% % 16215+ R e m o t e D i s p l a y C o m m a n d % 16216% % 16217% % 16218% % 16219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16220% 16221% RemoteDisplayCommand() encourages a remote display program to display the 16222% specified image filename. 16223% 16224% The format of the RemoteDisplayCommand method is: 16225% 16226% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16227% const char *window,const char *filename,ExceptionInfo *exception) 16228% 16229% A description of each parameter follows: 16230% 16231% o image_info: the image info. 16232% 16233% o window: Specifies the name or id of an X window. 16234% 16235% o filename: the name of the image filename to display. 16236% 16237% o exception: return any errors or warnings in this structure. 16238% 16239*/ 16240MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16241 const char *window,const char *filename,ExceptionInfo *exception) 16242{ 16243 assert(image_info != (const ImageInfo *) NULL); 16244 assert(image_info->signature == MagickSignature); 16245 assert(filename != (char *) NULL); 16246 (void) window; 16247 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16248 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16249 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image_info->filename); 16250 return(MagickFalse); 16251} 16252#endif 16253