display.c revision 1454be7db7a897f42cd40e4165f945d77196a6f8
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-2012 ImageMagick Studio LLC, a non-profit organization % 21% dedicated to making software imaging solutions freely available. % 22% % 23% You may not use this file except in compliance with the License. You may % 24% obtain a copy of the License at % 25% % 26% http://www.imagemagick.org/script/license.php % 27% % 28% Unless required by applicable law or agreed to in writing, software % 29% distributed under the License is distributed on an "AS IS" BASIS, % 30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31% See the License for the specific language governing permissions and % 32% limitations under the License. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 36% 37*/ 38 39/* 40 Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/artifact.h" 44#include "MagickCore/blob.h" 45#include "MagickCore/cache.h" 46#include "MagickCore/cache-private.h" 47#include "MagickCore/client.h" 48#include "MagickCore/color.h" 49#include "MagickCore/colorspace.h" 50#include "MagickCore/composite.h" 51#include "MagickCore/constitute.h" 52#include "MagickCore/decorate.h" 53#include "MagickCore/delegate.h" 54#include "MagickCore/display.h" 55#include "MagickCore/display-private.h" 56#include "MagickCore/distort.h" 57#include "MagickCore/draw.h" 58#include "MagickCore/effect.h" 59#include "MagickCore/enhance.h" 60#include "MagickCore/exception.h" 61#include "MagickCore/exception-private.h" 62#include "MagickCore/fx.h" 63#include "MagickCore/geometry.h" 64#include "MagickCore/image.h" 65#include "MagickCore/image-private.h" 66#include "MagickCore/list.h" 67#include "MagickCore/log.h" 68#include "MagickCore/magick.h" 69#include "MagickCore/memory_.h" 70#include "MagickCore/monitor.h" 71#include "MagickCore/monitor-private.h" 72#include "MagickCore/montage.h" 73#include "MagickCore/option.h" 74#include "MagickCore/paint.h" 75#include "MagickCore/pixel.h" 76#include "MagickCore/pixel-accessor.h" 77#include "MagickCore/PreRvIcccm.h" 78#include "MagickCore/property.h" 79#include "MagickCore/quantum.h" 80#include "MagickCore/quantum-private.h" 81#include "MagickCore/resize.h" 82#include "MagickCore/resource_.h" 83#include "MagickCore/shear.h" 84#include "MagickCore/segment.h" 85#include "MagickCore/statistic.h" 86#include "MagickCore/string_.h" 87#include "MagickCore/string-private.h" 88#include "MagickCore/transform.h" 89#include "MagickCore/threshold.h" 90#include "MagickCore/utility.h" 91#include "MagickCore/utility-private.h" 92#include "MagickCore/version.h" 93#include "MagickCore/widget.h" 94#include "MagickCore/widget-private.h" 95#include "MagickCore/xwindow.h" 96#include "MagickCore/xwindow-private.h" 97 98#if defined(MAGICKCORE_X11_DELEGATE) 99/* 100 Define declarations. 101*/ 102#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L) 103 104/* 105 Constant declarations. 106*/ 107static const unsigned char 108 HighlightBitmap[8] = 109 { 110 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 111 }, 112 OpaqueBitmap[8] = 113 { 114 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 115 }, 116 ShadowBitmap[8] = 117 { 118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 119 }; 120 121static const char 122 *PageSizes[] = 123 { 124 "Letter", 125 "Tabloid", 126 "Ledger", 127 "Legal", 128 "Statement", 129 "Executive", 130 "A3", 131 "A4", 132 "A5", 133 "B4", 134 "B5", 135 "Folio", 136 "Quarto", 137 "10x14", 138 (char *) NULL 139 }; 140 141/* 142 Help widget declarations. 143*/ 144static const char 145 *ImageAnnotateHelp[] = 146 { 147 "In annotate mode, the Command widget has these options:", 148 "", 149 " Font Name", 150 " fixed", 151 " variable", 152 " 5x8", 153 " 6x10", 154 " 7x13bold", 155 " 8x13bold", 156 " 9x15bold", 157 " 10x20", 158 " 12x24", 159 " Browser...", 160 " Font Color", 161 " black", 162 " blue", 163 " cyan", 164 " green", 165 " gray", 166 " red", 167 " magenta", 168 " yellow", 169 " white", 170 " transparent", 171 " Browser...", 172 " Font Color", 173 " black", 174 " blue", 175 " cyan", 176 " green", 177 " gray", 178 " red", 179 " magenta", 180 " yellow", 181 " white", 182 " transparent", 183 " Browser...", 184 " Rotate Text", 185 " -90", 186 " -45", 187 " -30", 188 " 0", 189 " 30", 190 " 45", 191 " 90", 192 " 180", 193 " Dialog...", 194 " Help", 195 " Dismiss", 196 "", 197 "Choose a font name from the Font Name sub-menu. Additional", 198 "font names can be specified with the font browser. You can", 199 "change the menu names by setting the X resources font1", 200 "through font9.", 201 "", 202 "Choose a font color from the Font Color sub-menu.", 203 "Additional font colors can be specified with the color", 204 "browser. You can change the menu colors by setting the X", 205 "resources pen1 through pen9.", 206 "", 207 "If you select the color browser and press Grab, you can", 208 "choose the font color by moving the pointer to the desired", 209 "color on the screen and press any button.", 210 "", 211 "If you choose to rotate the text, choose Rotate Text from the", 212 "menu and select an angle. Typically you will only want to", 213 "rotate one line of text at a time. Depending on the angle you", 214 "choose, subsequent lines may end up overwriting each other.", 215 "", 216 "Choosing a font and its color is optional. The default font", 217 "is fixed and the default color is black. However, you must", 218 "choose a location to begin entering text and press button 1.", 219 "An underscore character will appear at the location of the", 220 "pointer. The cursor changes to a pencil to indicate you are", 221 "in text mode. To exit immediately, press Dismiss.", 222 "", 223 "In text mode, any key presses will display the character at", 224 "the location of the underscore and advance the underscore", 225 "cursor. Enter your text and once completed press Apply to", 226 "finish your image annotation. To correct errors press BACK", 227 "SPACE. To delete an entire line of text, press DELETE. Any", 228 "text that exceeds the boundaries of the image window is", 229 "automagically continued onto the next line.", 230 "", 231 "The actual color you request for the font is saved in the", 232 "image. However, the color that appears in your image window", 233 "may be different. For example, on a monochrome screen the", 234 "text will appear black or white even if you choose the color", 235 "red as the font color. However, the image saved to a file", 236 "with -write is written with red lettering. To assure the", 237 "correct color text in the final image, any PseudoClass image", 238 "is promoted to DirectClass (see miff(5)). To force a", 239 "PseudoClass image to remain PseudoClass, use -colors.", 240 (char *) NULL, 241 }, 242 *ImageChopHelp[] = 243 { 244 "In chop mode, the Command widget has these options:", 245 "", 246 " Direction", 247 " horizontal", 248 " vertical", 249 " Help", 250 " Dismiss", 251 "", 252 "If the you choose the horizontal direction (this the", 253 "default), the area of the image between the two horizontal", 254 "endpoints of the chop line is removed. Otherwise, the area", 255 "of the image between the two vertical endpoints of the chop", 256 "line is removed.", 257 "", 258 "Select a location within the image window to begin your chop,", 259 "press and hold any button. Next, move the pointer to", 260 "another location in the image. As you move a line will", 261 "connect the initial location and the pointer. When you", 262 "release the button, the area within the image to chop is", 263 "determined by which direction you choose from the Command", 264 "widget.", 265 "", 266 "To cancel the image chopping, move the pointer back to the", 267 "starting point of the line and release the button.", 268 (char *) NULL, 269 }, 270 *ImageColorEditHelp[] = 271 { 272 "In color edit mode, the Command widget has these options:", 273 "", 274 " Method", 275 " point", 276 " replace", 277 " floodfill", 278 " filltoborder", 279 " reset", 280 " Pixel Color", 281 " black", 282 " blue", 283 " cyan", 284 " green", 285 " gray", 286 " red", 287 " magenta", 288 " yellow", 289 " white", 290 " Browser...", 291 " Border Color", 292 " black", 293 " blue", 294 " cyan", 295 " green", 296 " gray", 297 " red", 298 " magenta", 299 " yellow", 300 " white", 301 " Browser...", 302 " Fuzz", 303 " 0%", 304 " 2%", 305 " 5%", 306 " 10%", 307 " 15%", 308 " Dialog...", 309 " Undo", 310 " Help", 311 " Dismiss", 312 "", 313 "Choose a color editing method from the Method sub-menu", 314 "of the Command widget. The point method recolors any pixel", 315 "selected with the pointer until the button is released. The", 316 "replace method recolors any pixel that matches the color of", 317 "the pixel you select with a button press. Floodfill recolors", 318 "any pixel that matches the color of the pixel you select with", 319 "a button press and is a neighbor. Whereas filltoborder recolors", 320 "any neighbor pixel that is not the border color. Finally reset", 321 "changes the entire image to the designated color.", 322 "", 323 "Next, choose a pixel color from the Pixel Color sub-menu.", 324 "Additional pixel colors can be specified with the color", 325 "browser. You can change the menu colors by setting the X", 326 "resources pen1 through pen9.", 327 "", 328 "Now press button 1 to select a pixel within the image window", 329 "to change its color. Additional pixels may be recolored as", 330 "prescribed by the method you choose.", 331 "", 332 "If the Magnify widget is mapped, it can be helpful in positioning", 333 "your pointer within the image (refer to button 2).", 334 "", 335 "The actual color you request for the pixels is saved in the", 336 "image. However, the color that appears in your image window", 337 "may be different. For example, on a monochrome screen the", 338 "pixel will appear black or white even if you choose the", 339 "color red as the pixel color. However, the image saved to a", 340 "file with -write is written with red pixels. To assure the", 341 "correct color text in the final image, any PseudoClass image", 342 "is promoted to DirectClass (see miff(5)). To force a", 343 "PseudoClass image to remain PseudoClass, use -colors.", 344 (char *) NULL, 345 }, 346 *ImageCompositeHelp[] = 347 { 348 "First a widget window is displayed requesting you to enter an", 349 "image name. Press Composite, Grab or type a file name.", 350 "Press Cancel if you choose not to create a composite image.", 351 "When you choose Grab, move the pointer to the desired window", 352 "and press any button.", 353 "", 354 "If the Composite image does not have any matte information,", 355 "you are informed and the file browser is displayed again.", 356 "Enter the name of a mask image. The image is typically", 357 "grayscale and the same size as the composite image. If the", 358 "image is not grayscale, it is converted to grayscale and the", 359 "resulting intensities are used as matte information.", 360 "", 361 "A small window appears showing the location of the cursor in", 362 "the image window. You are now in composite mode. To exit", 363 "immediately, press Dismiss. In composite mode, the Command", 364 "widget has these options:", 365 "", 366 " Operators", 367 " Over", 368 " In", 369 " Out", 370 " Atop", 371 " Xor", 372 " Plus", 373 " Minus", 374 " Add", 375 " Subtract", 376 " Difference", 377 " Multiply", 378 " Bumpmap", 379 " Copy", 380 " CopyRed", 381 " CopyGreen", 382 " CopyBlue", 383 " CopyOpacity", 384 " Clear", 385 " Dissolve", 386 " Displace", 387 " Help", 388 " Dismiss", 389 "", 390 "Choose a composite operation from the Operators sub-menu of", 391 "the Command widget. How each operator behaves is described", 392 "below. Image window is the image currently displayed on", 393 "your X server and image is the image obtained with the File", 394 "Browser widget.", 395 "", 396 "Over The result is the union of the two image shapes,", 397 " with image obscuring image window in the region of", 398 " overlap.", 399 "", 400 "In The result is simply image cut by the shape of", 401 " image window. None of the image data of image", 402 " window is in the result.", 403 "", 404 "Out The resulting image is image with the shape of", 405 " image window cut out.", 406 "", 407 "Atop The result is the same shape as image image window,", 408 " with image obscuring image window where the image", 409 " shapes overlap. Note this differs from over", 410 " because the portion of image outside image window's", 411 " shape does not appear in the result.", 412 "", 413 "Xor The result is the image data from both image and", 414 " image window that is outside the overlap region.", 415 " The overlap region is blank.", 416 "", 417 "Plus The result is just the sum of the image data.", 418 " Output values are cropped to QuantumRange (no overflow).", 419 "", 420 "Minus The result of image - image window, with underflow", 421 " cropped to zero.", 422 "", 423 "Add The result of image + image window, with overflow", 424 " wrapping around (mod 256).", 425 "", 426 "Subtract The result of image - image window, with underflow", 427 " wrapping around (mod 256). The add and subtract", 428 " operators can be used to perform reversible", 429 " transformations.", 430 "", 431 "Difference", 432 " The result of abs(image - image window). This", 433 " useful for comparing two very similar images.", 434 "", 435 "Multiply", 436 " The result of image * image window. This", 437 " useful for the creation of drop-shadows.", 438 "", 439 "Bumpmap The result of surface normals from image * image", 440 " window.", 441 "", 442 "Copy The resulting image is image window replaced with", 443 " image. Here the matte information is ignored.", 444 "", 445 "CopyRed The red layer of the image window is replace with", 446 " the red layer of the image. The other layers are", 447 " untouched.", 448 "", 449 "CopyGreen", 450 " The green layer of the image window is replace with", 451 " the green layer of the image. The other layers are", 452 " untouched.", 453 "", 454 "CopyBlue The blue layer of the image window is replace with", 455 " the blue layer of the image. The other layers are", 456 " untouched.", 457 "", 458 "CopyOpacity", 459 " The matte layer of the image window is replace with", 460 " the matte layer of the image. The other layers are", 461 " untouched.", 462 "", 463 "The image compositor requires a matte, or alpha channel in", 464 "the image for some operations. This extra channel usually", 465 "defines a mask which represents a sort of a cookie-cutter", 466 "for the image. This the case when matte is opaque (full", 467 "coverage) for pixels inside the shape, zero outside, and", 468 "between 0 and QuantumRange on the boundary. If image does not", 469 "have a matte channel, it is initialized with 0 for any pixel", 470 "matching in color to pixel location (0,0), otherwise QuantumRange.", 471 "", 472 "If you choose Dissolve, the composite operator becomes Over. The", 473 "image matte channel percent transparency is initialized to factor.", 474 "The image window is initialized to (100-factor). Where factor is the", 475 "value you specify in the Dialog widget.", 476 "", 477 "Displace shifts the image pixels as defined by a displacement", 478 "map. With this option, image is used as a displacement map.", 479 "Black, within the displacement map, is a maximum positive", 480 "displacement. White is a maximum negative displacement and", 481 "middle gray is neutral. The displacement is scaled to determine", 482 "the pixel shift. By default, the displacement applies in both the", 483 "horizontal and vertical directions. However, if you specify a mask,", 484 "image is the horizontal X displacement and mask the vertical Y", 485 "displacement.", 486 "", 487 "Note that matte information for image window is not retained", 488 "for colormapped X server visuals (e.g. StaticColor,", 489 "StaticColor, GrayScale, PseudoColor). Correct compositing", 490 "behavior may require a TrueColor or DirectColor visual or a", 491 "Standard Colormap.", 492 "", 493 "Choosing a composite operator is optional. The default", 494 "operator is replace. However, you must choose a location to", 495 "composite your image and press button 1. Press and hold the", 496 "button before releasing and an outline of the image will", 497 "appear to help you identify your location.", 498 "", 499 "The actual colors of the composite image is saved. However,", 500 "the color that appears in image window may be different.", 501 "For example, on a monochrome screen image window will appear", 502 "black or white even though your composited image may have", 503 "many colors. If the image is saved to a file it is written", 504 "with the correct colors. To assure the correct colors are", 505 "saved in the final image, any PseudoClass image is promoted", 506 "to DirectClass (see miff(5)). To force a PseudoClass image", 507 "to remain PseudoClass, use -colors.", 508 (char *) NULL, 509 }, 510 *ImageCutHelp[] = 511 { 512 "In cut mode, the Command widget has these options:", 513 "", 514 " Help", 515 " Dismiss", 516 "", 517 "To define a cut region, press button 1 and drag. The", 518 "cut region is defined by a highlighted rectangle that", 519 "expands or contracts as it follows the pointer. Once you", 520 "are satisfied with the cut region, release the button.", 521 "You are now in rectify mode. In rectify mode, the Command", 522 "widget has these options:", 523 "", 524 " Cut", 525 " Help", 526 " Dismiss", 527 "", 528 "You can make adjustments by moving the pointer to one of the", 529 "cut rectangle corners, pressing a button, and dragging.", 530 "Finally, press Cut to commit your copy region. To", 531 "exit without cutting the image, press Dismiss.", 532 (char *) NULL, 533 }, 534 *ImageCopyHelp[] = 535 { 536 "In copy mode, the Command widget has these options:", 537 "", 538 " Help", 539 " Dismiss", 540 "", 541 "To define a copy region, press button 1 and drag. The", 542 "copy region is defined by a highlighted rectangle that", 543 "expands or contracts as it follows the pointer. Once you", 544 "are satisfied with the copy region, release the button.", 545 "You are now in rectify mode. In rectify mode, the Command", 546 "widget has these options:", 547 "", 548 " Copy", 549 " Help", 550 " Dismiss", 551 "", 552 "You can make adjustments by moving the pointer to one of the", 553 "copy rectangle corners, pressing a button, and dragging.", 554 "Finally, press Copy to commit your copy region. To", 555 "exit without copying the image, press Dismiss.", 556 (char *) NULL, 557 }, 558 *ImageCropHelp[] = 559 { 560 "In crop mode, the Command widget has these options:", 561 "", 562 " Help", 563 " Dismiss", 564 "", 565 "To define a cropping region, press button 1 and drag. The", 566 "cropping region is defined by a highlighted rectangle that", 567 "expands or contracts as it follows the pointer. Once you", 568 "are satisfied with the cropping region, release the button.", 569 "You are now in rectify mode. In rectify mode, the Command", 570 "widget has these options:", 571 "", 572 " Crop", 573 " Help", 574 " Dismiss", 575 "", 576 "You can make adjustments by moving the pointer to one of the", 577 "cropping rectangle corners, pressing a button, and dragging.", 578 "Finally, press Crop to commit your cropping region. To", 579 "exit without cropping the image, press Dismiss.", 580 (char *) NULL, 581 }, 582 *ImageDrawHelp[] = 583 { 584 "The cursor changes to a crosshair to indicate you are in", 585 "draw mode. To exit immediately, press Dismiss. In draw mode,", 586 "the Command widget has these options:", 587 "", 588 " Element", 589 " point", 590 " line", 591 " rectangle", 592 " fill rectangle", 593 " circle", 594 " fill circle", 595 " ellipse", 596 " fill ellipse", 597 " polygon", 598 " fill polygon", 599 " Color", 600 " black", 601 " blue", 602 " cyan", 603 " green", 604 " gray", 605 " red", 606 " magenta", 607 " yellow", 608 " white", 609 " transparent", 610 " Browser...", 611 " Stipple", 612 " Brick", 613 " Diagonal", 614 " Scales", 615 " Vertical", 616 " Wavy", 617 " Translucent", 618 " Opaque", 619 " Open...", 620 " Width", 621 " 1", 622 " 2", 623 " 4", 624 " 8", 625 " 16", 626 " Dialog...", 627 " Undo", 628 " Help", 629 " Dismiss", 630 "", 631 "Choose a drawing primitive from the Element sub-menu.", 632 "", 633 "Choose a color from the Color sub-menu. Additional", 634 "colors can be specified with the color browser.", 635 "", 636 "If you choose the color browser and press Grab, you can", 637 "select the color by moving the pointer to the desired", 638 "color on the screen and press any button. The transparent", 639 "color updates the image matte channel and is useful for", 640 "image compositing.", 641 "", 642 "Choose a stipple, if appropriate, from the Stipple sub-menu.", 643 "Additional stipples can be specified with the file browser.", 644 "Stipples obtained from the file browser must be on disk in the", 645 "X11 bitmap format.", 646 "", 647 "Choose a width, if appropriate, from the Width sub-menu. To", 648 "choose a specific width select the Dialog widget.", 649 "", 650 "Choose a point in the Image window and press button 1 and", 651 "hold. Next, move the pointer to another location in the", 652 "image. As you move, a line connects the initial location and", 653 "the pointer. When you release the button, the image is", 654 "updated with the primitive you just drew. For polygons, the", 655 "image is updated when you press and release the button without", 656 "moving the pointer.", 657 "", 658 "To cancel image drawing, move the pointer back to the", 659 "starting point of the line and release the button.", 660 (char *) NULL, 661 }, 662 *DisplayHelp[] = 663 { 664 "BUTTONS", 665 " The effects of each button press is described below. Three", 666 " buttons are required. If you have a two button mouse,", 667 " button 1 and 3 are returned. Press ALT and button 3 to", 668 " simulate button 2.", 669 "", 670 " 1 Press this button to map or unmap the Command widget.", 671 "", 672 " 2 Press and drag to define a region of the image to", 673 " magnify.", 674 "", 675 " 3 Press and drag to choose from a select set of commands.", 676 " This button behaves differently if the image being", 677 " displayed is a visual image directory. Here, choose a", 678 " particular tile of the directory and press this button and", 679 " drag to select a command from a pop-up menu. Choose from", 680 " these menu items:", 681 "", 682 " Open", 683 " Next", 684 " Former", 685 " Delete", 686 " Update", 687 "", 688 " If you choose Open, the image represented by the tile is", 689 " displayed. To return to the visual image directory, choose", 690 " Next from the Command widget. Next and Former moves to the", 691 " next or former image respectively. Choose Delete to delete", 692 " a particular image tile. Finally, choose Update to", 693 " synchronize all the image tiles with their respective", 694 " images.", 695 "", 696 "COMMAND WIDGET", 697 " The Command widget lists a number of sub-menus and commands.", 698 " They are", 699 "", 700 " File", 701 " Open...", 702 " Next", 703 " Former", 704 " Select...", 705 " Save...", 706 " Print...", 707 " Delete...", 708 " New...", 709 " Visual Directory...", 710 " Quit", 711 " Edit", 712 " Undo", 713 " Redo", 714 " Cut", 715 " Copy", 716 " Paste", 717 " View", 718 " Half Size", 719 " Original Size", 720 " Double Size", 721 " Resize...", 722 " Apply", 723 " Refresh", 724 " Restore", 725 " Transform", 726 " Crop", 727 " Chop", 728 " Flop", 729 " Flip", 730 " Rotate Right", 731 " Rotate Left", 732 " Rotate...", 733 " Shear...", 734 " Roll...", 735 " Trim Edges", 736 " Enhance", 737 " Brightness...", 738 " Saturation...", 739 " Hue...", 740 " Gamma...", 741 " Sharpen...", 742 " Dull", 743 " Contrast Stretch...", 744 " Sigmoidal Contrast...", 745 " Normalize", 746 " Equalize", 747 " Negate", 748 " Grayscale", 749 " Map...", 750 " Quantize...", 751 " Effects", 752 " Despeckle", 753 " Emboss", 754 " Reduce Noise", 755 " Add Noise", 756 " Sharpen...", 757 " Blur...", 758 " Threshold...", 759 " Edge Detect...", 760 " Spread...", 761 " Shade...", 762 " Painting...", 763 " Segment...", 764 " F/X", 765 " Solarize...", 766 " Sepia Tone...", 767 " Swirl...", 768 " Implode...", 769 " Vignette...", 770 " Wave...", 771 " Oil Painting...", 772 " Charcoal Drawing...", 773 " Image Edit", 774 " Annotate...", 775 " Draw...", 776 " Color...", 777 " Matte...", 778 " Composite...", 779 " Add Border...", 780 " Add Frame...", 781 " Comment...", 782 " Launch...", 783 " Region of Interest...", 784 " Miscellany", 785 " Image Info", 786 " Zoom Image", 787 " Show Preview...", 788 " Show Histogram", 789 " Show Matte", 790 " Background...", 791 " Slide Show", 792 " Preferences...", 793 " Help", 794 " Overview", 795 " Browse Documentation", 796 " About Display", 797 "", 798 " Menu items with a indented triangle have a sub-menu. They", 799 " are represented above as the indented items. To access a", 800 " sub-menu item, move the pointer to the appropriate menu and", 801 " press a button and drag. When you find the desired sub-menu", 802 " item, release the button and the command is executed. Move", 803 " the pointer away from the sub-menu if you decide not to", 804 " execute a particular command.", 805 "", 806 "KEYBOARD ACCELERATORS", 807 " Accelerators are one or two key presses that effect a", 808 " particular command. The keyboard accelerators that", 809 " display(1) understands is:", 810 "", 811 " Ctl+O Press to open an image from a file.", 812 "", 813 " space Press to display the next image.", 814 "", 815 " If the image is a multi-paged document such as a Postscript", 816 " document, you can skip ahead several pages by preceding", 817 " this command with a number. For example to display the", 818 " third page beyond the current page, press 3<space>.", 819 "", 820 " backspace Press to display the former image.", 821 "", 822 " If the image is a multi-paged document such as a Postscript", 823 " document, you can skip behind several pages by preceding", 824 " this command with a number. For example to display the", 825 " third page preceding the current page, press 3<backspace>.", 826 "", 827 " Ctl+S Press to write the image to a file.", 828 "", 829 " Ctl+P Press to print the image to a Postscript printer.", 830 "", 831 " Ctl+D Press to delete an image file.", 832 "", 833 " Ctl+N Press to create a blank canvas.", 834 "", 835 " Ctl+Q Press to discard all images and exit program.", 836 "", 837 " Ctl+Z Press to undo last image transformation.", 838 "", 839 " Ctl+R Press to redo last image transformation.", 840 "", 841 " Ctl+X Press to cut a region of the image.", 842 "", 843 " Ctl+C Press to copy a region of the image.", 844 "", 845 " Ctl+V Press to paste a region to the image.", 846 "", 847 " < Press to half the image size.", 848 "", 849 " - Press to return to the original image size.", 850 "", 851 " > Press to double the image size.", 852 "", 853 " % Press to resize the image to a width and height you", 854 " specify.", 855 "", 856 "Cmd-A Press to make any image transformations permanent." 857 "", 858 " By default, any image size transformations are applied", 859 " to the original image to create the image displayed on", 860 " the X server. However, the transformations are not", 861 " permanent (i.e. the original image does not change", 862 " size only the X image does). For example, if you", 863 " press > the X image will appear to double in size,", 864 " but the original image will in fact remain the same size.", 865 " To force the original image to double in size, press >", 866 " followed by Cmd-A.", 867 "", 868 " @ Press to refresh the image window.", 869 "", 870 " C Press to cut out a rectangular region of the image.", 871 "", 872 " [ Press to chop the image.", 873 "", 874 " H Press to flop image in the horizontal direction.", 875 "", 876 " V Press to flip image in the vertical direction.", 877 "", 878 " / Press to rotate the image 90 degrees clockwise.", 879 "", 880 " \\ Press to rotate the image 90 degrees counter-clockwise.", 881 "", 882 " * Press to rotate the image the number of degrees you", 883 " specify.", 884 "", 885 " S Press to shear the image the number of degrees you", 886 " specify.", 887 "", 888 " R Press to roll the image.", 889 "", 890 " T Press to trim the image edges.", 891 "", 892 " Shft-H Press to vary the image hue.", 893 "", 894 " Shft-S Press to vary the color saturation.", 895 "", 896 " Shft-L Press to vary the color brightness.", 897 "", 898 " Shft-G Press to gamma correct the image.", 899 "", 900 " Shft-C Press to sharpen the image contrast.", 901 "", 902 " Shft-Z Press to dull the image contrast.", 903 "", 904 " = Press to perform histogram equalization on the image.", 905 "", 906 " Shft-N Press to perform histogram normalization on the image.", 907 "", 908 " Shft-~ Press to negate the colors of the image.", 909 "", 910 " . Press to convert the image colors to gray.", 911 "", 912 " Shft-# Press to set the maximum number of unique colors in the", 913 " image.", 914 "", 915 " F2 Press to reduce the speckles in an image.", 916 "", 917 " F3 Press to eliminate peak noise from an image.", 918 "", 919 " F4 Press to add noise to an image.", 920 "", 921 " F5 Press to sharpen an image.", 922 "", 923 " F6 Press to delete an image file.", 924 "", 925 " F7 Press to threshold the image.", 926 "", 927 " F8 Press to detect edges within an image.", 928 "", 929 " F9 Press to emboss an image.", 930 "", 931 " F10 Press to displace pixels by a random amount.", 932 "", 933 " F11 Press to negate all pixels above the threshold level.", 934 "", 935 " F12 Press to shade the image using a distant light source.", 936 "", 937 " F13 Press to lighten or darken image edges to create a 3-D effect.", 938 "", 939 " F14 Press to segment the image by color.", 940 "", 941 " Meta-S Press to swirl image pixels about the center.", 942 "", 943 " Meta-I Press to implode image pixels about the center.", 944 "", 945 " Meta-W Press to alter an image along a sine wave.", 946 "", 947 " Meta-P Press to simulate an oil painting.", 948 "", 949 " Meta-C Press to simulate a charcoal drawing.", 950 "", 951 " Alt-A Press to annotate the image with text.", 952 "", 953 " Alt-D Press to draw on an image.", 954 "", 955 " Alt-P Press to edit an image pixel color.", 956 "", 957 " Alt-M Press to edit the image matte information.", 958 "", 959 " Alt-V Press to composite the image with another.", 960 "", 961 " Alt-B Press to add a border to the image.", 962 "", 963 " Alt-F Press to add an ornamental border to the image.", 964 "", 965 " Alt-Shft-!", 966 " Press to add an image comment.", 967 "", 968 " Ctl-A Press to apply image processing techniques to a region", 969 " of interest.", 970 "", 971 " Shft-? Press to display information about the image.", 972 "", 973 " Shft-+ Press to map the zoom image window.", 974 "", 975 " Shft-P Press to preview an image enhancement, effect, or f/x.", 976 "", 977 " F1 Press to display helpful information about display(1).", 978 "", 979 " Find Press to browse documentation about ImageMagick.", 980 "", 981 " 1-9 Press to change the level of magnification.", 982 "", 983 " Use the arrow keys to move the image one pixel up, down,", 984 " left, or right within the magnify window. Be sure to first", 985 " map the magnify window by pressing button 2.", 986 "", 987 " Press ALT and one of the arrow keys to trim off one pixel", 988 " from any side of the image.", 989 (char *) NULL, 990 }, 991 *ImageMatteEditHelp[] = 992 { 993 "Matte information within an image is useful for some", 994 "operations such as image compositing (See IMAGE", 995 "COMPOSITING). This extra channel usually defines a mask", 996 "which represents a sort of a cookie-cutter for the image.", 997 "This the case when matte is opaque (full coverage) for", 998 "pixels inside the shape, zero outside, and between 0 and", 999 "QuantumRange on the boundary.", 1000 "", 1001 "A small window appears showing the location of the cursor in", 1002 "the image window. You are now in matte edit mode. To exit", 1003 "immediately, press Dismiss. In matte edit mode, the Command", 1004 "widget has these options:", 1005 "", 1006 " Method", 1007 " point", 1008 " replace", 1009 " floodfill", 1010 " filltoborder", 1011 " reset", 1012 " Border Color", 1013 " black", 1014 " blue", 1015 " cyan", 1016 " green", 1017 " gray", 1018 " red", 1019 " magenta", 1020 " yellow", 1021 " white", 1022 " Browser...", 1023 " Fuzz", 1024 " 0%", 1025 " 2%", 1026 " 5%", 1027 " 10%", 1028 " 15%", 1029 " Dialog...", 1030 " Matte", 1031 " Opaque", 1032 " Transparent", 1033 " Dialog...", 1034 " Undo", 1035 " Help", 1036 " Dismiss", 1037 "", 1038 "Choose a matte editing method from the Method sub-menu of", 1039 "the Command widget. The point method changes the matte value", 1040 "of any pixel selected with the pointer until the button is", 1041 "is released. The replace method changes the matte value of", 1042 "any pixel that matches the color of the pixel you select with", 1043 "a button press. Floodfill changes the matte value of any pixel", 1044 "that matches the color of the pixel you select with a button", 1045 "press and is a neighbor. Whereas filltoborder changes the matte", 1046 "value any neighbor pixel that is not the border color. Finally", 1047 "reset changes the entire image to the designated matte value.", 1048 "", 1049 "Choose Matte Value and pick Opaque or Transarent. For other values", 1050 "select the Dialog entry. Here a dialog appears requesting a matte", 1051 "value. The value you select is assigned as the opacity value of the", 1052 "selected pixel or pixels.", 1053 "", 1054 "Now, press any button to select a pixel within the image", 1055 "window to change its matte value.", 1056 "", 1057 "If the Magnify widget is mapped, it can be helpful in positioning", 1058 "your pointer within the image (refer to button 2).", 1059 "", 1060 "Matte information is only valid in a DirectClass image.", 1061 "Therefore, any PseudoClass image is promoted to DirectClass", 1062 "(see miff(5)). Note that matte information for PseudoClass", 1063 "is not retained for colormapped X server visuals (e.g.", 1064 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you", 1065 "immediately save your image to a file (refer to Write).", 1066 "Correct matte editing behavior may require a TrueColor or", 1067 "DirectColor visual or a Standard Colormap.", 1068 (char *) NULL, 1069 }, 1070 *ImagePanHelp[] = 1071 { 1072 "When an image exceeds the width or height of the X server", 1073 "screen, display maps a small panning icon. The rectangle", 1074 "within the panning icon shows the area that is currently", 1075 "displayed in the image window. To pan about the image,", 1076 "press any button and drag the pointer within the panning", 1077 "icon. The pan rectangle moves with the pointer and the", 1078 "image window is updated to reflect the location of the", 1079 "rectangle within the panning icon. When you have selected", 1080 "the area of the image you wish to view, release the button.", 1081 "", 1082 "Use the arrow keys to pan the image one pixel up, down,", 1083 "left, or right within the image window.", 1084 "", 1085 "The panning icon is withdrawn if the image becomes smaller", 1086 "than the dimensions of the X server screen.", 1087 (char *) NULL, 1088 }, 1089 *ImagePasteHelp[] = 1090 { 1091 "A small window appears showing the location of the cursor in", 1092 "the image window. You are now in paste mode. To exit", 1093 "immediately, press Dismiss. In paste mode, the Command", 1094 "widget has these options:", 1095 "", 1096 " Operators", 1097 " over", 1098 " in", 1099 " out", 1100 " atop", 1101 " xor", 1102 " plus", 1103 " minus", 1104 " add", 1105 " subtract", 1106 " difference", 1107 " replace", 1108 " Help", 1109 " Dismiss", 1110 "", 1111 "Choose a composite operation from the Operators sub-menu of", 1112 "the Command widget. How each operator behaves is described", 1113 "below. Image window is the image currently displayed on", 1114 "your X server and image is the image obtained with the File", 1115 "Browser widget.", 1116 "", 1117 "Over The result is the union of the two image shapes,", 1118 " with image obscuring image window in the region of", 1119 " overlap.", 1120 "", 1121 "In The result is simply image cut by the shape of", 1122 " image window. None of the image data of image", 1123 " window is in the result.", 1124 "", 1125 "Out The resulting image is image with the shape of", 1126 " image window cut out.", 1127 "", 1128 "Atop The result is the same shape as image image window,", 1129 " with image obscuring image window where the image", 1130 " shapes overlap. Note this differs from over", 1131 " because the portion of image outside image window's", 1132 " shape does not appear in the result.", 1133 "", 1134 "Xor The result is the image data from both image and", 1135 " image window that is outside the overlap region.", 1136 " The overlap region is blank.", 1137 "", 1138 "Plus The result is just the sum of the image data.", 1139 " Output values are cropped to QuantumRange (no overflow).", 1140 " This operation is independent of the matte", 1141 " channels.", 1142 "", 1143 "Minus The result of image - image window, with underflow", 1144 " cropped to zero.", 1145 "", 1146 "Add The result of image + image window, with overflow", 1147 " wrapping around (mod 256).", 1148 "", 1149 "Subtract The result of image - image window, with underflow", 1150 " wrapping around (mod 256). The add and subtract", 1151 " operators can be used to perform reversible", 1152 " transformations.", 1153 "", 1154 "Difference", 1155 " The result of abs(image - image window). This", 1156 " useful for comparing two very similar images.", 1157 "", 1158 "Copy The resulting image is image window replaced with", 1159 " image. Here the matte information is ignored.", 1160 "", 1161 "CopyRed The red layer of the image window is replace with", 1162 " the red layer of the image. The other layers are", 1163 " untouched.", 1164 "", 1165 "CopyGreen", 1166 " The green layer of the image window is replace with", 1167 " the green layer of the image. The other layers are", 1168 " untouched.", 1169 "", 1170 "CopyBlue The blue layer of the image window is replace with", 1171 " the blue layer of the image. The other layers are", 1172 " untouched.", 1173 "", 1174 "CopyOpacity", 1175 " The matte layer of the image window is replace with", 1176 " the matte layer of the image. The other layers are", 1177 " untouched.", 1178 "", 1179 "The image compositor requires a matte, or alpha channel in", 1180 "the image for some operations. This extra channel usually", 1181 "defines a mask which represents a sort of a cookie-cutter", 1182 "for the image. This the case when matte is opaque (full", 1183 "coverage) for pixels inside the shape, zero outside, and", 1184 "between 0 and QuantumRange on the boundary. If image does not", 1185 "have a matte channel, it is initialized with 0 for any pixel", 1186 "matching in color to pixel location (0,0), otherwise QuantumRange.", 1187 "", 1188 "Note that matte information for image window is not retained", 1189 "for colormapped X server visuals (e.g. StaticColor,", 1190 "StaticColor, GrayScale, PseudoColor). Correct compositing", 1191 "behavior may require a TrueColor or DirectColor visual or a", 1192 "Standard Colormap.", 1193 "", 1194 "Choosing a composite operator is optional. The default", 1195 "operator is replace. However, you must choose a location to", 1196 "paste your image and press button 1. Press and hold the", 1197 "button before releasing and an outline of the image will", 1198 "appear to help you identify your location.", 1199 "", 1200 "The actual colors of the pasted image is saved. However,", 1201 "the color that appears in image window may be different.", 1202 "For example, on a monochrome screen image window will appear", 1203 "black or white even though your pasted image may have", 1204 "many colors. If the image is saved to a file it is written", 1205 "with the correct colors. To assure the correct colors are", 1206 "saved in the final image, any PseudoClass image is promoted", 1207 "to DirectClass (see miff(5)). To force a PseudoClass image", 1208 "to remain PseudoClass, use -colors.", 1209 (char *) NULL, 1210 }, 1211 *ImageROIHelp[] = 1212 { 1213 "In region of interest mode, the Command widget has these", 1214 "options:", 1215 "", 1216 " Help", 1217 " Dismiss", 1218 "", 1219 "To define a region of interest, press button 1 and drag.", 1220 "The region of interest is defined by a highlighted rectangle", 1221 "that expands or contracts as it follows the pointer. Once", 1222 "you are satisfied with the region of interest, release the", 1223 "button. You are now in apply mode. In apply mode the", 1224 "Command widget has these options:", 1225 "", 1226 " File", 1227 " Save...", 1228 " Print...", 1229 " Edit", 1230 " Undo", 1231 " Redo", 1232 " Transform", 1233 " Flop", 1234 " Flip", 1235 " Rotate Right", 1236 " Rotate Left", 1237 " Enhance", 1238 " Hue...", 1239 " Saturation...", 1240 " Brightness...", 1241 " Gamma...", 1242 " Spiff", 1243 " Dull", 1244 " Contrast Stretch", 1245 " Sigmoidal Contrast...", 1246 " Normalize", 1247 " Equalize", 1248 " Negate", 1249 " Grayscale", 1250 " Map...", 1251 " Quantize...", 1252 " Effects", 1253 " Despeckle", 1254 " Emboss", 1255 " Reduce Noise", 1256 " Sharpen...", 1257 " Blur...", 1258 " Threshold...", 1259 " Edge Detect...", 1260 " Spread...", 1261 " Shade...", 1262 " Raise...", 1263 " Segment...", 1264 " F/X", 1265 " Solarize...", 1266 " Sepia Tone...", 1267 " Swirl...", 1268 " Implode...", 1269 " Vignette...", 1270 " Wave...", 1271 " Oil Painting...", 1272 " Charcoal Drawing...", 1273 " Miscellany", 1274 " Image Info", 1275 " Zoom Image", 1276 " Show Preview...", 1277 " Show Histogram", 1278 " Show Matte", 1279 " Help", 1280 " Dismiss", 1281 "", 1282 "You can make adjustments to the region of interest by moving", 1283 "the pointer to one of the rectangle corners, pressing a", 1284 "button, and dragging. Finally, choose an image processing", 1285 "technique from the Command widget. You can choose more than", 1286 "one image processing technique to apply to an area.", 1287 "Alternatively, you can move the region of interest before", 1288 "applying another image processing technique. To exit, press", 1289 "Dismiss.", 1290 (char *) NULL, 1291 }, 1292 *ImageRotateHelp[] = 1293 { 1294 "In rotate mode, the Command widget has these options:", 1295 "", 1296 " Pixel Color", 1297 " black", 1298 " blue", 1299 " cyan", 1300 " green", 1301 " gray", 1302 " red", 1303 " magenta", 1304 " yellow", 1305 " white", 1306 " Browser...", 1307 " Direction", 1308 " horizontal", 1309 " vertical", 1310 " Help", 1311 " Dismiss", 1312 "", 1313 "Choose a background color from the Pixel Color sub-menu.", 1314 "Additional background colors can be specified with the color", 1315 "browser. You can change the menu colors by setting the X", 1316 "resources pen1 through pen9.", 1317 "", 1318 "If you choose the color browser and press Grab, you can", 1319 "select the background color by moving the pointer to the", 1320 "desired color on the screen and press any button.", 1321 "", 1322 "Choose a point in the image window and press this button and", 1323 "hold. Next, move the pointer to another location in the", 1324 "image. As you move a line connects the initial location and", 1325 "the pointer. When you release the button, the degree of", 1326 "image rotation is determined by the slope of the line you", 1327 "just drew. The slope is relative to the direction you", 1328 "choose from the Direction sub-menu of the Command widget.", 1329 "", 1330 "To cancel the image rotation, move the pointer back to the", 1331 "starting point of the line and release the button.", 1332 (char *) NULL, 1333 }; 1334 1335/* 1336 Enumeration declarations. 1337*/ 1338typedef enum 1339{ 1340 CopyMode, 1341 CropMode, 1342 CutMode 1343} ClipboardMode; 1344 1345typedef enum 1346{ 1347 OpenCommand, 1348 NextCommand, 1349 FormerCommand, 1350 SelectCommand, 1351 SaveCommand, 1352 PrintCommand, 1353 DeleteCommand, 1354 NewCommand, 1355 VisualDirectoryCommand, 1356 QuitCommand, 1357 UndoCommand, 1358 RedoCommand, 1359 CutCommand, 1360 CopyCommand, 1361 PasteCommand, 1362 HalfSizeCommand, 1363 OriginalSizeCommand, 1364 DoubleSizeCommand, 1365 ResizeCommand, 1366 ApplyCommand, 1367 RefreshCommand, 1368 RestoreCommand, 1369 CropCommand, 1370 ChopCommand, 1371 FlopCommand, 1372 FlipCommand, 1373 RotateRightCommand, 1374 RotateLeftCommand, 1375 RotateCommand, 1376 ShearCommand, 1377 RollCommand, 1378 TrimCommand, 1379 HueCommand, 1380 SaturationCommand, 1381 BrightnessCommand, 1382 GammaCommand, 1383 SpiffCommand, 1384 DullCommand, 1385 ContrastStretchCommand, 1386 SigmoidalContrastCommand, 1387 NormalizeCommand, 1388 EqualizeCommand, 1389 NegateCommand, 1390 GrayscaleCommand, 1391 MapCommand, 1392 QuantizeCommand, 1393 DespeckleCommand, 1394 EmbossCommand, 1395 ReduceNoiseCommand, 1396 AddNoiseCommand, 1397 SharpenCommand, 1398 BlurCommand, 1399 ThresholdCommand, 1400 EdgeDetectCommand, 1401 SpreadCommand, 1402 ShadeCommand, 1403 RaiseCommand, 1404 SegmentCommand, 1405 SolarizeCommand, 1406 SepiaToneCommand, 1407 SwirlCommand, 1408 ImplodeCommand, 1409 VignetteCommand, 1410 WaveCommand, 1411 OilPaintCommand, 1412 CharcoalDrawCommand, 1413 AnnotateCommand, 1414 DrawCommand, 1415 ColorCommand, 1416 MatteCommand, 1417 CompositeCommand, 1418 AddBorderCommand, 1419 AddFrameCommand, 1420 CommentCommand, 1421 LaunchCommand, 1422 RegionofInterestCommand, 1423 ROIHelpCommand, 1424 ROIDismissCommand, 1425 InfoCommand, 1426 ZoomCommand, 1427 ShowPreviewCommand, 1428 ShowHistogramCommand, 1429 ShowMatteCommand, 1430 BackgroundCommand, 1431 SlideShowCommand, 1432 PreferencesCommand, 1433 HelpCommand, 1434 BrowseDocumentationCommand, 1435 VersionCommand, 1436 SaveToUndoBufferCommand, 1437 FreeBuffersCommand, 1438 NullCommand 1439} CommandType; 1440 1441typedef enum 1442{ 1443 AnnotateNameCommand, 1444 AnnotateFontColorCommand, 1445 AnnotateBackgroundColorCommand, 1446 AnnotateRotateCommand, 1447 AnnotateHelpCommand, 1448 AnnotateDismissCommand, 1449 TextHelpCommand, 1450 TextApplyCommand, 1451 ChopDirectionCommand, 1452 ChopHelpCommand, 1453 ChopDismissCommand, 1454 HorizontalChopCommand, 1455 VerticalChopCommand, 1456 ColorEditMethodCommand, 1457 ColorEditColorCommand, 1458 ColorEditBorderCommand, 1459 ColorEditFuzzCommand, 1460 ColorEditUndoCommand, 1461 ColorEditHelpCommand, 1462 ColorEditDismissCommand, 1463 CompositeOperatorsCommand, 1464 CompositeDissolveCommand, 1465 CompositeDisplaceCommand, 1466 CompositeHelpCommand, 1467 CompositeDismissCommand, 1468 CropHelpCommand, 1469 CropDismissCommand, 1470 RectifyCopyCommand, 1471 RectifyHelpCommand, 1472 RectifyDismissCommand, 1473 DrawElementCommand, 1474 DrawColorCommand, 1475 DrawStippleCommand, 1476 DrawWidthCommand, 1477 DrawUndoCommand, 1478 DrawHelpCommand, 1479 DrawDismissCommand, 1480 MatteEditMethod, 1481 MatteEditBorderCommand, 1482 MatteEditFuzzCommand, 1483 MatteEditValueCommand, 1484 MatteEditUndoCommand, 1485 MatteEditHelpCommand, 1486 MatteEditDismissCommand, 1487 PasteOperatorsCommand, 1488 PasteHelpCommand, 1489 PasteDismissCommand, 1490 RotateColorCommand, 1491 RotateDirectionCommand, 1492 RotateCropCommand, 1493 RotateSharpenCommand, 1494 RotateHelpCommand, 1495 RotateDismissCommand, 1496 HorizontalRotateCommand, 1497 VerticalRotateCommand, 1498 TileLoadCommand, 1499 TileNextCommand, 1500 TileFormerCommand, 1501 TileDeleteCommand, 1502 TileUpdateCommand 1503} ModeType; 1504 1505/* 1506 Stipples. 1507*/ 1508#define BricksWidth 20 1509#define BricksHeight 20 1510#define DiagonalWidth 16 1511#define DiagonalHeight 16 1512#define HighlightWidth 8 1513#define HighlightHeight 8 1514#define OpaqueWidth 8 1515#define OpaqueHeight 8 1516#define ScalesWidth 16 1517#define ScalesHeight 16 1518#define ShadowWidth 8 1519#define ShadowHeight 8 1520#define VerticalWidth 16 1521#define VerticalHeight 16 1522#define WavyWidth 16 1523#define WavyHeight 16 1524 1525/* 1526 Constant declaration. 1527*/ 1528static const int 1529 RoiDelta = 8; 1530 1531static const unsigned char 1532 BricksBitmap[] = 1533 { 1534 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 1535 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 1536 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 1537 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 1538 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01 1539 }, 1540 DiagonalBitmap[] = 1541 { 1542 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 1543 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 1544 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22 1545 }, 1546 ScalesBitmap[] = 1547 { 1548 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80, 1549 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 1550 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e 1551 }, 1552 VerticalBitmap[] = 1553 { 1554 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1555 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1556 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 1557 }, 1558 WavyBitmap[] = 1559 { 1560 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff, 1561 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf, 1562 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f 1563 }; 1564 1565/* 1566 Function prototypes. 1567*/ 1568static CommandType 1569 XImageWindowCommand(Display *,XResourceInfo *,XWindows *, 1570 const MagickStatusType,KeySym,Image **,ExceptionInfo *); 1571 1572static Image 1573 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType, 1574 Image **,ExceptionInfo *), 1575 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType), 1576 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *, 1577 ExceptionInfo *), 1578 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *, 1579 ExceptionInfo *); 1580 1581static MagickBooleanType 1582 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *, 1583 ExceptionInfo *), 1584 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **, 1585 ExceptionInfo *), 1586 XChopImage(Display *,XResourceInfo *,XWindows *,Image **, 1587 ExceptionInfo *), 1588 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode, 1589 ExceptionInfo *), 1590 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1591 ExceptionInfo *), 1592 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *, 1593 ExceptionInfo *), 1594 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1595 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1596 ExceptionInfo *), 1597 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1598 ExceptionInfo *), 1599 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1600 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1601 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **, 1602 ExceptionInfo *), 1603 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *), 1604 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1605 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *); 1606 1607static void 1608 XDrawPanRectangle(Display *,XWindows *), 1609 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **, 1610 ExceptionInfo *), 1611 XMagnifyImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1612 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1613 XPanImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1614 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType, 1615 const KeySym,ExceptionInfo *), 1616 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *), 1617 XScreenEvent(Display *,XWindows *,XEvent *,ExceptionInfo *), 1618 XTranslateImage(Display *,XWindows *,Image *,const KeySym); 1619 1620/* 1621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1622% % 1623% % 1624% % 1625% D i s p l a y I m a g e s % 1626% % 1627% % 1628% % 1629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1630% 1631% DisplayImages() displays an image sequence to any X window screen. It 1632% returns a value other than 0 if successful. Check the exception member 1633% of image to determine the reason for any failure. 1634% 1635% The format of the DisplayImages method is: 1636% 1637% MagickBooleanType DisplayImages(const ImageInfo *image_info, 1638% Image *images,ExceptionInfo *exception) 1639% 1640% A description of each parameter follows: 1641% 1642% o image_info: the image info. 1643% 1644% o image: the image. 1645% 1646% o exception: return any errors or warnings in this structure. 1647% 1648*/ 1649MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 1650 Image *images,ExceptionInfo *exception) 1651{ 1652 char 1653 *argv[1]; 1654 1655 Display 1656 *display; 1657 1658 Image 1659 *image; 1660 1661 register ssize_t 1662 i; 1663 1664 size_t 1665 state; 1666 1667 XrmDatabase 1668 resource_database; 1669 1670 XResourceInfo 1671 resource_info; 1672 1673 assert(image_info != (const ImageInfo *) NULL); 1674 assert(image_info->signature == MagickSignature); 1675 assert(images != (Image *) NULL); 1676 assert(images->signature == MagickSignature); 1677 if (images->debug != MagickFalse) 1678 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 1679 display=XOpenDisplay(image_info->server_name); 1680 if (display == (Display *) NULL) 1681 { 1682 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1683 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1684 return(MagickFalse); 1685 } 1686 if (exception->severity != UndefinedException) 1687 CatchException(exception); 1688 (void) XSetErrorHandler(XError); 1689 resource_database=XGetResourceDatabase(display,GetClientName()); 1690 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info)); 1691 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info); 1692 if (image_info->page != (char *) NULL) 1693 resource_info.image_geometry=AcquireString(image_info->page); 1694 resource_info.immutable=MagickTrue; 1695 argv[0]=AcquireString(GetClientName()); 1696 state=DefaultState; 1697 for (i=0; (state & ExitState) == 0; i++) 1698 { 1699 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations)) 1700 break; 1701 image=GetImageFromList(images,i % GetImageListLength(images)); 1702 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception); 1703 } 1704 SetErrorHandler((ErrorHandler) NULL); 1705 SetWarningHandler((WarningHandler) NULL); 1706 argv[0]=DestroyString(argv[0]); 1707 (void) XCloseDisplay(display); 1708 XDestroyResourceInfo(&resource_info); 1709 if (exception->severity != UndefinedException) 1710 return(MagickFalse); 1711 return(MagickTrue); 1712} 1713 1714/* 1715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1716% % 1717% % 1718% % 1719% R e m o t e D i s p l a y C o m m a n d % 1720% % 1721% % 1722% % 1723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1724% 1725% RemoteDisplayCommand() encourages a remote display program to display the 1726% specified image filename. 1727% 1728% The format of the RemoteDisplayCommand method is: 1729% 1730% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1731% const char *window,const char *filename,ExceptionInfo *exception) 1732% 1733% A description of each parameter follows: 1734% 1735% o image_info: the image info. 1736% 1737% o window: Specifies the name or id of an X window. 1738% 1739% o filename: the name of the image filename to display. 1740% 1741% o exception: return any errors or warnings in this structure. 1742% 1743*/ 1744MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1745 const char *window,const char *filename,ExceptionInfo *exception) 1746{ 1747 Display 1748 *display; 1749 1750 MagickStatusType 1751 status; 1752 1753 assert(image_info != (const ImageInfo *) NULL); 1754 assert(image_info->signature == MagickSignature); 1755 assert(filename != (char *) NULL); 1756 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 1757 display=XOpenDisplay(image_info->server_name); 1758 if (display == (Display *) NULL) 1759 { 1760 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1761 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1762 return(MagickFalse); 1763 } 1764 (void) XSetErrorHandler(XError); 1765 status=XRemoteCommand(display,window,filename); 1766 (void) XCloseDisplay(display); 1767 return(status != 0 ? MagickTrue : MagickFalse); 1768} 1769 1770/* 1771%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1772% % 1773% % 1774% % 1775+ X A n n o t a t e E d i t I m a g e % 1776% % 1777% % 1778% % 1779%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1780% 1781% XAnnotateEditImage() annotates the image with text. 1782% 1783% The format of the XAnnotateEditImage method is: 1784% 1785% MagickBooleanType XAnnotateEditImage(Display *display, 1786% XResourceInfo *resource_info,XWindows *windows,Image *image, 1787% ExceptionInfo *exception) 1788% 1789% A description of each parameter follows: 1790% 1791% o display: Specifies a connection to an X server; returned from 1792% XOpenDisplay. 1793% 1794% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 1795% 1796% o windows: Specifies a pointer to a XWindows structure. 1797% 1798% o image: the image; returned from ReadImage. 1799% 1800*/ 1801 1802static inline ssize_t MagickMax(const ssize_t x,const ssize_t y) 1803{ 1804 if (x > y) 1805 return(x); 1806 return(y); 1807} 1808 1809static inline ssize_t MagickMin(const ssize_t x,const ssize_t y) 1810{ 1811 if (x < y) 1812 return(x); 1813 return(y); 1814} 1815 1816static MagickBooleanType XAnnotateEditImage(Display *display, 1817 XResourceInfo *resource_info,XWindows *windows,Image *image, 1818 ExceptionInfo *exception) 1819{ 1820 static const char 1821 *AnnotateMenu[] = 1822 { 1823 "Font Name", 1824 "Font Color", 1825 "Box Color", 1826 "Rotate Text", 1827 "Help", 1828 "Dismiss", 1829 (char *) NULL 1830 }, 1831 *TextMenu[] = 1832 { 1833 "Help", 1834 "Apply", 1835 (char *) NULL 1836 }; 1837 1838 static const ModeType 1839 AnnotateCommands[] = 1840 { 1841 AnnotateNameCommand, 1842 AnnotateFontColorCommand, 1843 AnnotateBackgroundColorCommand, 1844 AnnotateRotateCommand, 1845 AnnotateHelpCommand, 1846 AnnotateDismissCommand 1847 }, 1848 TextCommands[] = 1849 { 1850 TextHelpCommand, 1851 TextApplyCommand 1852 }; 1853 1854 static MagickBooleanType 1855 transparent_box = MagickTrue, 1856 transparent_pen = MagickFalse; 1857 1858 static MagickRealType 1859 degrees = 0.0; 1860 1861 static unsigned int 1862 box_id = MaxNumberPens-2, 1863 font_id = 0, 1864 pen_id = 0; 1865 1866 char 1867 command[MaxTextExtent], 1868 text[MaxTextExtent]; 1869 1870 const char 1871 *ColorMenu[MaxNumberPens+1]; 1872 1873 Cursor 1874 cursor; 1875 1876 GC 1877 annotate_context; 1878 1879 int 1880 id, 1881 pen_number, 1882 status, 1883 x, 1884 y; 1885 1886 KeySym 1887 key_symbol; 1888 1889 register char 1890 *p; 1891 1892 register ssize_t 1893 i; 1894 1895 unsigned int 1896 height, 1897 width; 1898 1899 size_t 1900 state; 1901 1902 XAnnotateInfo 1903 *annotate_info, 1904 *previous_info; 1905 1906 XColor 1907 color; 1908 1909 XFontStruct 1910 *font_info; 1911 1912 XEvent 1913 event, 1914 text_event; 1915 1916 /* 1917 Map Command widget. 1918 */ 1919 (void) CloneString(&windows->command.name,"Annotate"); 1920 windows->command.data=4; 1921 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL); 1922 (void) XMapRaised(display,windows->command.id); 1923 XClientMessage(display,windows->image.id,windows->im_protocols, 1924 windows->im_update_widget,CurrentTime); 1925 /* 1926 Track pointer until button 1 is pressed. 1927 */ 1928 XQueryPosition(display,windows->image.id,&x,&y); 1929 (void) XSelectInput(display,windows->image.id, 1930 windows->image.attributes.event_mask | PointerMotionMask); 1931 cursor=XCreateFontCursor(display,XC_left_side); 1932 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1933 state=DefaultState; 1934 do 1935 { 1936 if (windows->info.mapped != MagickFalse) 1937 { 1938 /* 1939 Display pointer position. 1940 */ 1941 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 1942 x+windows->image.x,y+windows->image.y); 1943 XInfoWidget(display,windows,text); 1944 } 1945 /* 1946 Wait for next event. 1947 */ 1948 XScreenEvent(display,windows,&event,exception); 1949 if (event.xany.window == windows->command.id) 1950 { 1951 /* 1952 Select a command from the Command widget. 1953 */ 1954 id=XCommandWidget(display,windows,AnnotateMenu,&event); 1955 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1956 if (id < 0) 1957 continue; 1958 switch (AnnotateCommands[id]) 1959 { 1960 case AnnotateNameCommand: 1961 { 1962 const char 1963 *FontMenu[MaxNumberFonts]; 1964 1965 int 1966 font_number; 1967 1968 /* 1969 Initialize menu selections. 1970 */ 1971 for (i=0; i < MaxNumberFonts; i++) 1972 FontMenu[i]=resource_info->font_name[i]; 1973 FontMenu[MaxNumberFonts-2]="Browser..."; 1974 FontMenu[MaxNumberFonts-1]=(const char *) NULL; 1975 /* 1976 Select a font name from the pop-up menu. 1977 */ 1978 font_number=XMenuWidget(display,windows,AnnotateMenu[id], 1979 (const char **) FontMenu,command); 1980 if (font_number < 0) 1981 break; 1982 if (font_number == (MaxNumberFonts-2)) 1983 { 1984 static char 1985 font_name[MaxTextExtent] = "fixed"; 1986 1987 /* 1988 Select a font name from a browser. 1989 */ 1990 resource_info->font_name[font_number]=font_name; 1991 XFontBrowserWidget(display,windows,"Select",font_name); 1992 if (*font_name == '\0') 1993 break; 1994 } 1995 /* 1996 Initialize font info. 1997 */ 1998 font_info=XLoadQueryFont(display,resource_info->font_name[ 1999 font_number]); 2000 if (font_info == (XFontStruct *) NULL) 2001 { 2002 XNoticeWidget(display,windows,"Unable to load font:", 2003 resource_info->font_name[font_number]); 2004 break; 2005 } 2006 font_id=(unsigned int) font_number; 2007 (void) XFreeFont(display,font_info); 2008 break; 2009 } 2010 case AnnotateFontColorCommand: 2011 { 2012 /* 2013 Initialize menu selections. 2014 */ 2015 for (i=0; i < (int) (MaxNumberPens-2); i++) 2016 ColorMenu[i]=resource_info->pen_colors[i]; 2017 ColorMenu[MaxNumberPens-2]="transparent"; 2018 ColorMenu[MaxNumberPens-1]="Browser..."; 2019 ColorMenu[MaxNumberPens]=(const char *) NULL; 2020 /* 2021 Select a pen color from the pop-up menu. 2022 */ 2023 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2024 (const char **) ColorMenu,command); 2025 if (pen_number < 0) 2026 break; 2027 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue : 2028 MagickFalse; 2029 if (transparent_pen != MagickFalse) 2030 break; 2031 if (pen_number == (MaxNumberPens-1)) 2032 { 2033 static char 2034 color_name[MaxTextExtent] = "gray"; 2035 2036 /* 2037 Select a pen color from a dialog. 2038 */ 2039 resource_info->pen_colors[pen_number]=color_name; 2040 XColorBrowserWidget(display,windows,"Select",color_name); 2041 if (*color_name == '\0') 2042 break; 2043 } 2044 /* 2045 Set pen color. 2046 */ 2047 (void) XParseColor(display,windows->map_info->colormap, 2048 resource_info->pen_colors[pen_number],&color); 2049 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2050 (unsigned int) MaxColors,&color); 2051 windows->pixel_info->pen_colors[pen_number]=color; 2052 pen_id=(unsigned int) pen_number; 2053 break; 2054 } 2055 case AnnotateBackgroundColorCommand: 2056 { 2057 /* 2058 Initialize menu selections. 2059 */ 2060 for (i=0; i < (int) (MaxNumberPens-2); i++) 2061 ColorMenu[i]=resource_info->pen_colors[i]; 2062 ColorMenu[MaxNumberPens-2]="transparent"; 2063 ColorMenu[MaxNumberPens-1]="Browser..."; 2064 ColorMenu[MaxNumberPens]=(const char *) NULL; 2065 /* 2066 Select a pen color from the pop-up menu. 2067 */ 2068 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2069 (const char **) ColorMenu,command); 2070 if (pen_number < 0) 2071 break; 2072 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue : 2073 MagickFalse; 2074 if (transparent_box != MagickFalse) 2075 break; 2076 if (pen_number == (MaxNumberPens-1)) 2077 { 2078 static char 2079 color_name[MaxTextExtent] = "gray"; 2080 2081 /* 2082 Select a pen color from a dialog. 2083 */ 2084 resource_info->pen_colors[pen_number]=color_name; 2085 XColorBrowserWidget(display,windows,"Select",color_name); 2086 if (*color_name == '\0') 2087 break; 2088 } 2089 /* 2090 Set pen color. 2091 */ 2092 (void) XParseColor(display,windows->map_info->colormap, 2093 resource_info->pen_colors[pen_number],&color); 2094 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2095 (unsigned int) MaxColors,&color); 2096 windows->pixel_info->pen_colors[pen_number]=color; 2097 box_id=(unsigned int) pen_number; 2098 break; 2099 } 2100 case AnnotateRotateCommand: 2101 { 2102 int 2103 entry; 2104 2105 static char 2106 angle[MaxTextExtent] = "30.0"; 2107 2108 static const char 2109 *RotateMenu[] = 2110 { 2111 "-90", 2112 "-45", 2113 "-30", 2114 "0", 2115 "30", 2116 "45", 2117 "90", 2118 "180", 2119 "Dialog...", 2120 (char *) NULL, 2121 }; 2122 2123 /* 2124 Select a command from the pop-up menu. 2125 */ 2126 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu, 2127 command); 2128 if (entry < 0) 2129 break; 2130 if (entry != 8) 2131 { 2132 degrees=StringToDouble(RotateMenu[entry],(char **) NULL); 2133 break; 2134 } 2135 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:", 2136 angle); 2137 if (*angle == '\0') 2138 break; 2139 degrees=StringToDouble(angle,(char **) NULL); 2140 break; 2141 } 2142 case AnnotateHelpCommand: 2143 { 2144 XTextViewWidget(display,resource_info,windows,MagickFalse, 2145 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2146 break; 2147 } 2148 case AnnotateDismissCommand: 2149 { 2150 /* 2151 Prematurely exit. 2152 */ 2153 state|=EscapeState; 2154 state|=ExitState; 2155 break; 2156 } 2157 default: 2158 break; 2159 } 2160 continue; 2161 } 2162 switch (event.type) 2163 { 2164 case ButtonPress: 2165 { 2166 if (event.xbutton.button != Button1) 2167 break; 2168 if (event.xbutton.window != windows->image.id) 2169 break; 2170 /* 2171 Change to text entering mode. 2172 */ 2173 x=event.xbutton.x; 2174 y=event.xbutton.y; 2175 state|=ExitState; 2176 break; 2177 } 2178 case ButtonRelease: 2179 break; 2180 case Expose: 2181 break; 2182 case KeyPress: 2183 { 2184 if (event.xkey.window != windows->image.id) 2185 break; 2186 /* 2187 Respond to a user key press. 2188 */ 2189 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2190 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2191 switch ((int) key_symbol) 2192 { 2193 case XK_Escape: 2194 case XK_F20: 2195 { 2196 /* 2197 Prematurely exit. 2198 */ 2199 state|=EscapeState; 2200 state|=ExitState; 2201 break; 2202 } 2203 case XK_F1: 2204 case XK_Help: 2205 { 2206 XTextViewWidget(display,resource_info,windows,MagickFalse, 2207 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2208 break; 2209 } 2210 default: 2211 { 2212 (void) XBell(display,0); 2213 break; 2214 } 2215 } 2216 break; 2217 } 2218 case MotionNotify: 2219 { 2220 /* 2221 Map and unmap Info widget as cursor crosses its boundaries. 2222 */ 2223 x=event.xmotion.x; 2224 y=event.xmotion.y; 2225 if (windows->info.mapped != MagickFalse) 2226 { 2227 if ((x < (int) (windows->info.x+windows->info.width)) && 2228 (y < (int) (windows->info.y+windows->info.height))) 2229 (void) XWithdrawWindow(display,windows->info.id, 2230 windows->info.screen); 2231 } 2232 else 2233 if ((x > (int) (windows->info.x+windows->info.width)) || 2234 (y > (int) (windows->info.y+windows->info.height))) 2235 (void) XMapWindow(display,windows->info.id); 2236 break; 2237 } 2238 default: 2239 break; 2240 } 2241 } while ((state & ExitState) == 0); 2242 (void) XSelectInput(display,windows->image.id, 2243 windows->image.attributes.event_mask); 2244 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 2245 if ((state & EscapeState) != 0) 2246 return(MagickTrue); 2247 /* 2248 Set font info and check boundary conditions. 2249 */ 2250 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]); 2251 if (font_info == (XFontStruct *) NULL) 2252 { 2253 XNoticeWidget(display,windows,"Unable to load font:", 2254 resource_info->font_name[font_id]); 2255 font_info=windows->font_info; 2256 } 2257 if ((x+font_info->max_bounds.width) >= (int) windows->image.width) 2258 x=(int) windows->image.width-font_info->max_bounds.width; 2259 if (y < (int) (font_info->ascent+font_info->descent)) 2260 y=(int) font_info->ascent+font_info->descent; 2261 if (((int) font_info->max_bounds.width > (int) windows->image.width) || 2262 ((font_info->ascent+font_info->descent) >= (int) windows->image.height)) 2263 return(MagickFalse); 2264 /* 2265 Initialize annotate structure. 2266 */ 2267 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info)); 2268 if (annotate_info == (XAnnotateInfo *) NULL) 2269 return(MagickFalse); 2270 XGetAnnotateInfo(annotate_info); 2271 annotate_info->x=x; 2272 annotate_info->y=y; 2273 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse)) 2274 annotate_info->stencil=OpaqueStencil; 2275 else 2276 if (transparent_box == MagickFalse) 2277 annotate_info->stencil=BackgroundStencil; 2278 else 2279 annotate_info->stencil=ForegroundStencil; 2280 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent; 2281 annotate_info->degrees=degrees; 2282 annotate_info->font_info=font_info; 2283 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2284 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL, 2285 sizeof(*annotate_info->text)); 2286 if (annotate_info->text == (char *) NULL) 2287 return(MagickFalse); 2288 /* 2289 Create cursor and set graphic context. 2290 */ 2291 cursor=XCreateFontCursor(display,XC_pencil); 2292 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2293 annotate_context=windows->image.annotate_context; 2294 (void) XSetFont(display,annotate_context,font_info->fid); 2295 (void) XSetBackground(display,annotate_context, 2296 windows->pixel_info->pen_colors[box_id].pixel); 2297 (void) XSetForeground(display,annotate_context, 2298 windows->pixel_info->pen_colors[pen_id].pixel); 2299 /* 2300 Begin annotating the image with text. 2301 */ 2302 (void) CloneString(&windows->command.name,"Text"); 2303 windows->command.data=0; 2304 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL); 2305 state=DefaultState; 2306 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2307 text_event.xexpose.width=(int) font_info->max_bounds.width; 2308 text_event.xexpose.height=font_info->max_bounds.ascent+ 2309 font_info->max_bounds.descent; 2310 p=annotate_info->text; 2311 do 2312 { 2313 /* 2314 Display text cursor. 2315 */ 2316 *p='\0'; 2317 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2318 /* 2319 Wait for next event. 2320 */ 2321 XScreenEvent(display,windows,&event,exception); 2322 if (event.xany.window == windows->command.id) 2323 { 2324 /* 2325 Select a command from the Command widget. 2326 */ 2327 (void) XSetBackground(display,annotate_context, 2328 windows->pixel_info->background_color.pixel); 2329 (void) XSetForeground(display,annotate_context, 2330 windows->pixel_info->foreground_color.pixel); 2331 id=XCommandWidget(display,windows,AnnotateMenu,&event); 2332 (void) XSetBackground(display,annotate_context, 2333 windows->pixel_info->pen_colors[box_id].pixel); 2334 (void) XSetForeground(display,annotate_context, 2335 windows->pixel_info->pen_colors[pen_id].pixel); 2336 if (id < 0) 2337 continue; 2338 switch (TextCommands[id]) 2339 { 2340 case TextHelpCommand: 2341 { 2342 XTextViewWidget(display,resource_info,windows,MagickFalse, 2343 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2344 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2345 break; 2346 } 2347 case TextApplyCommand: 2348 { 2349 /* 2350 Finished annotating. 2351 */ 2352 annotate_info->width=(unsigned int) XTextWidth(font_info, 2353 annotate_info->text,(int) strlen(annotate_info->text)); 2354 XRefreshWindow(display,&windows->image,&text_event); 2355 state|=ExitState; 2356 break; 2357 } 2358 default: 2359 break; 2360 } 2361 continue; 2362 } 2363 /* 2364 Erase text cursor. 2365 */ 2366 text_event.xexpose.x=x; 2367 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2368 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y, 2369 (unsigned int) text_event.xexpose.width,(unsigned int) 2370 text_event.xexpose.height,MagickFalse); 2371 XRefreshWindow(display,&windows->image,&text_event); 2372 switch (event.type) 2373 { 2374 case ButtonPress: 2375 { 2376 if (event.xbutton.window != windows->image.id) 2377 break; 2378 if (event.xbutton.button == Button2) 2379 { 2380 /* 2381 Request primary selection. 2382 */ 2383 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, 2384 windows->image.id,CurrentTime); 2385 break; 2386 } 2387 break; 2388 } 2389 case Expose: 2390 { 2391 if (event.xexpose.count == 0) 2392 { 2393 XAnnotateInfo 2394 *text_info; 2395 2396 /* 2397 Refresh Image window. 2398 */ 2399 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 2400 text_info=annotate_info; 2401 while (text_info != (XAnnotateInfo *) NULL) 2402 { 2403 if (annotate_info->stencil == ForegroundStencil) 2404 (void) XDrawString(display,windows->image.id,annotate_context, 2405 text_info->x,text_info->y,text_info->text, 2406 (int) strlen(text_info->text)); 2407 else 2408 (void) XDrawImageString(display,windows->image.id, 2409 annotate_context,text_info->x,text_info->y,text_info->text, 2410 (int) strlen(text_info->text)); 2411 text_info=text_info->previous; 2412 } 2413 (void) XDrawString(display,windows->image.id,annotate_context, 2414 x,y,"_",1); 2415 } 2416 break; 2417 } 2418 case KeyPress: 2419 { 2420 int 2421 length; 2422 2423 if (event.xkey.window != windows->image.id) 2424 break; 2425 /* 2426 Respond to a user key press. 2427 */ 2428 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 2429 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2430 *(command+length)='\0'; 2431 if (((event.xkey.state & ControlMask) != 0) || 2432 ((event.xkey.state & Mod1Mask) != 0)) 2433 state|=ModifierState; 2434 if ((state & ModifierState) != 0) 2435 switch ((int) key_symbol) 2436 { 2437 case XK_u: 2438 case XK_U: 2439 { 2440 key_symbol=DeleteCommand; 2441 break; 2442 } 2443 default: 2444 break; 2445 } 2446 switch ((int) key_symbol) 2447 { 2448 case XK_BackSpace: 2449 { 2450 /* 2451 Erase one character. 2452 */ 2453 if (p == annotate_info->text) 2454 { 2455 if (annotate_info->previous == (XAnnotateInfo *) NULL) 2456 break; 2457 else 2458 { 2459 /* 2460 Go to end of the previous line of text. 2461 */ 2462 annotate_info=annotate_info->previous; 2463 p=annotate_info->text; 2464 x=annotate_info->x+annotate_info->width; 2465 y=annotate_info->y; 2466 if (annotate_info->width != 0) 2467 p+=strlen(annotate_info->text); 2468 break; 2469 } 2470 } 2471 p--; 2472 x-=XTextWidth(font_info,p,1); 2473 text_event.xexpose.x=x; 2474 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2475 XRefreshWindow(display,&windows->image,&text_event); 2476 break; 2477 } 2478 case XK_bracketleft: 2479 { 2480 key_symbol=XK_Escape; 2481 break; 2482 } 2483 case DeleteCommand: 2484 { 2485 /* 2486 Erase the entire line of text. 2487 */ 2488 while (p != annotate_info->text) 2489 { 2490 p--; 2491 x-=XTextWidth(font_info,p,1); 2492 text_event.xexpose.x=x; 2493 XRefreshWindow(display,&windows->image,&text_event); 2494 } 2495 break; 2496 } 2497 case XK_Escape: 2498 case XK_F20: 2499 { 2500 /* 2501 Finished annotating. 2502 */ 2503 annotate_info->width=(unsigned int) XTextWidth(font_info, 2504 annotate_info->text,(int) strlen(annotate_info->text)); 2505 XRefreshWindow(display,&windows->image,&text_event); 2506 state|=ExitState; 2507 break; 2508 } 2509 default: 2510 { 2511 /* 2512 Draw a single character on the Image window. 2513 */ 2514 if ((state & ModifierState) != 0) 2515 break; 2516 if (*command == '\0') 2517 break; 2518 *p=(*command); 2519 if (annotate_info->stencil == ForegroundStencil) 2520 (void) XDrawString(display,windows->image.id,annotate_context, 2521 x,y,p,1); 2522 else 2523 (void) XDrawImageString(display,windows->image.id, 2524 annotate_context,x,y,p,1); 2525 x+=XTextWidth(font_info,p,1); 2526 p++; 2527 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2528 break; 2529 } 2530 case XK_Return: 2531 case XK_KP_Enter: 2532 { 2533 /* 2534 Advance to the next line of text. 2535 */ 2536 *p='\0'; 2537 annotate_info->width=(unsigned int) XTextWidth(font_info, 2538 annotate_info->text,(int) strlen(annotate_info->text)); 2539 if (annotate_info->next != (XAnnotateInfo *) NULL) 2540 { 2541 /* 2542 Line of text already exists. 2543 */ 2544 annotate_info=annotate_info->next; 2545 x=annotate_info->x; 2546 y=annotate_info->y; 2547 p=annotate_info->text; 2548 break; 2549 } 2550 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2551 sizeof(*annotate_info->next)); 2552 if (annotate_info->next == (XAnnotateInfo *) NULL) 2553 return(MagickFalse); 2554 *annotate_info->next=(*annotate_info); 2555 annotate_info->next->previous=annotate_info; 2556 annotate_info=annotate_info->next; 2557 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2558 windows->image.width/MagickMax((ssize_t) 2559 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2560 if (annotate_info->text == (char *) NULL) 2561 return(MagickFalse); 2562 annotate_info->y+=annotate_info->height; 2563 if (annotate_info->y > (int) windows->image.height) 2564 annotate_info->y=(int) annotate_info->height; 2565 annotate_info->next=(XAnnotateInfo *) NULL; 2566 x=annotate_info->x; 2567 y=annotate_info->y; 2568 p=annotate_info->text; 2569 break; 2570 } 2571 } 2572 break; 2573 } 2574 case KeyRelease: 2575 { 2576 /* 2577 Respond to a user key release. 2578 */ 2579 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2580 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2581 state&=(~ModifierState); 2582 break; 2583 } 2584 case SelectionNotify: 2585 { 2586 Atom 2587 type; 2588 2589 int 2590 format; 2591 2592 unsigned char 2593 *data; 2594 2595 unsigned long 2596 after, 2597 length; 2598 2599 /* 2600 Obtain response from primary selection. 2601 */ 2602 if (event.xselection.property == (Atom) None) 2603 break; 2604 status=XGetWindowProperty(display,event.xselection.requestor, 2605 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING, 2606 &type,&format,&length,&after,&data); 2607 if ((status != Success) || (type != XA_STRING) || (format == 32) || 2608 (length == 0)) 2609 break; 2610 /* 2611 Annotate Image window with primary selection. 2612 */ 2613 for (i=0; i < (ssize_t) length; i++) 2614 { 2615 if ((char) data[i] != '\n') 2616 { 2617 /* 2618 Draw a single character on the Image window. 2619 */ 2620 *p=(char) data[i]; 2621 (void) XDrawString(display,windows->image.id,annotate_context, 2622 x,y,p,1); 2623 x+=XTextWidth(font_info,p,1); 2624 p++; 2625 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2626 continue; 2627 } 2628 /* 2629 Advance to the next line of text. 2630 */ 2631 *p='\0'; 2632 annotate_info->width=(unsigned int) XTextWidth(font_info, 2633 annotate_info->text,(int) strlen(annotate_info->text)); 2634 if (annotate_info->next != (XAnnotateInfo *) NULL) 2635 { 2636 /* 2637 Line of text already exists. 2638 */ 2639 annotate_info=annotate_info->next; 2640 x=annotate_info->x; 2641 y=annotate_info->y; 2642 p=annotate_info->text; 2643 continue; 2644 } 2645 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2646 sizeof(*annotate_info->next)); 2647 if (annotate_info->next == (XAnnotateInfo *) NULL) 2648 return(MagickFalse); 2649 *annotate_info->next=(*annotate_info); 2650 annotate_info->next->previous=annotate_info; 2651 annotate_info=annotate_info->next; 2652 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2653 windows->image.width/MagickMax((ssize_t) 2654 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2655 if (annotate_info->text == (char *) NULL) 2656 return(MagickFalse); 2657 annotate_info->y+=annotate_info->height; 2658 if (annotate_info->y > (int) windows->image.height) 2659 annotate_info->y=(int) annotate_info->height; 2660 annotate_info->next=(XAnnotateInfo *) NULL; 2661 x=annotate_info->x; 2662 y=annotate_info->y; 2663 p=annotate_info->text; 2664 } 2665 (void) XFree((void *) data); 2666 break; 2667 } 2668 default: 2669 break; 2670 } 2671 } while ((state & ExitState) == 0); 2672 (void) XFreeCursor(display,cursor); 2673 /* 2674 Annotation is relative to image configuration. 2675 */ 2676 width=(unsigned int) image->columns; 2677 height=(unsigned int) image->rows; 2678 x=0; 2679 y=0; 2680 if (windows->image.crop_geometry != (char *) NULL) 2681 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 2682 /* 2683 Initialize annotated image. 2684 */ 2685 XSetCursorState(display,windows,MagickTrue); 2686 XCheckRefreshWindows(display,windows); 2687 while (annotate_info != (XAnnotateInfo *) NULL) 2688 { 2689 if (annotate_info->width == 0) 2690 { 2691 /* 2692 No text on this line-- go to the next line of text. 2693 */ 2694 previous_info=annotate_info->previous; 2695 annotate_info->text=(char *) 2696 RelinquishMagickMemory(annotate_info->text); 2697 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2698 annotate_info=previous_info; 2699 continue; 2700 } 2701 /* 2702 Determine pixel index for box and pen color. 2703 */ 2704 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id]; 2705 if (windows->pixel_info->colors != 0) 2706 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2707 if (windows->pixel_info->pixels[i] == 2708 windows->pixel_info->pen_colors[box_id].pixel) 2709 { 2710 windows->pixel_info->box_index=(unsigned short) i; 2711 break; 2712 } 2713 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 2714 if (windows->pixel_info->colors != 0) 2715 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2716 if (windows->pixel_info->pixels[i] == 2717 windows->pixel_info->pen_colors[pen_id].pixel) 2718 { 2719 windows->pixel_info->pen_index=(unsigned short) i; 2720 break; 2721 } 2722 /* 2723 Define the annotate geometry string. 2724 */ 2725 annotate_info->x=(int) 2726 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width; 2727 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+ 2728 windows->image.y)/windows->image.ximage->height; 2729 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent, 2730 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width, 2731 height*annotate_info->height/windows->image.ximage->height, 2732 annotate_info->x+x,annotate_info->y+y); 2733 /* 2734 Annotate image with text. 2735 */ 2736 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image, 2737 exception); 2738 if (status == 0) 2739 return(MagickFalse); 2740 /* 2741 Free up memory. 2742 */ 2743 previous_info=annotate_info->previous; 2744 annotate_info->text=DestroyString(annotate_info->text); 2745 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2746 annotate_info=previous_info; 2747 } 2748 (void) XSetForeground(display,annotate_context, 2749 windows->pixel_info->foreground_color.pixel); 2750 (void) XSetBackground(display,annotate_context, 2751 windows->pixel_info->background_color.pixel); 2752 (void) XSetFont(display,annotate_context,windows->font_info->fid); 2753 XSetCursorState(display,windows,MagickFalse); 2754 (void) XFreeFont(display,font_info); 2755 /* 2756 Update image configuration. 2757 */ 2758 XConfigureImageColormap(display,resource_info,windows,image,exception); 2759 (void) XConfigureImage(display,resource_info,windows,image,exception); 2760 return(MagickTrue); 2761} 2762 2763/* 2764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2765% % 2766% % 2767% % 2768+ X B a c k g r o u n d I m a g e % 2769% % 2770% % 2771% % 2772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2773% 2774% XBackgroundImage() displays the image in the background of a window. 2775% 2776% The format of the XBackgroundImage method is: 2777% 2778% MagickBooleanType XBackgroundImage(Display *display, 2779% XResourceInfo *resource_info,XWindows *windows,Image **image, 2780% ExceptionInfo *exception) 2781% 2782% A description of each parameter follows: 2783% 2784% o display: Specifies a connection to an X server; returned from 2785% XOpenDisplay. 2786% 2787% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2788% 2789% o windows: Specifies a pointer to a XWindows structure. 2790% 2791% o image: the image. 2792% 2793% o exception: return any errors or warnings in this structure. 2794% 2795*/ 2796static MagickBooleanType XBackgroundImage(Display *display, 2797 XResourceInfo *resource_info,XWindows *windows,Image **image, 2798 ExceptionInfo *exception) 2799{ 2800#define BackgroundImageTag "Background/Image" 2801 2802 int 2803 status; 2804 2805 static char 2806 window_id[MaxTextExtent] = "root"; 2807 2808 XResourceInfo 2809 background_resources; 2810 2811 /* 2812 Put image in background. 2813 */ 2814 status=XDialogWidget(display,windows,"Background", 2815 "Enter window id (id 0x00 selects window with pointer):",window_id); 2816 if (*window_id == '\0') 2817 return(MagickFalse); 2818 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 2819 exception); 2820 XInfoWidget(display,windows,BackgroundImageTag); 2821 XSetCursorState(display,windows,MagickTrue); 2822 XCheckRefreshWindows(display,windows); 2823 background_resources=(*resource_info); 2824 background_resources.window_id=window_id; 2825 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse; 2826 status=XDisplayBackgroundImage(display,&background_resources,*image, 2827 exception); 2828 if (status != MagickFalse) 2829 XClientMessage(display,windows->image.id,windows->im_protocols, 2830 windows->im_retain_colors,CurrentTime); 2831 XSetCursorState(display,windows,MagickFalse); 2832 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image, 2833 exception); 2834 return(MagickTrue); 2835} 2836 2837/* 2838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2839% % 2840% % 2841% % 2842+ X C h o p I m a g e % 2843% % 2844% % 2845% % 2846%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2847% 2848% XChopImage() chops the X image. 2849% 2850% The format of the XChopImage method is: 2851% 2852% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info, 2853% XWindows *windows,Image **image,ExceptionInfo *exception) 2854% 2855% A description of each parameter follows: 2856% 2857% o display: Specifies a connection to an X server; returned from 2858% XOpenDisplay. 2859% 2860% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2861% 2862% o windows: Specifies a pointer to a XWindows structure. 2863% 2864% o image: the image. 2865% 2866% o exception: return any errors or warnings in this structure. 2867% 2868*/ 2869static MagickBooleanType XChopImage(Display *display, 2870 XResourceInfo *resource_info,XWindows *windows,Image **image, 2871 ExceptionInfo *exception) 2872{ 2873 static const char 2874 *ChopMenu[] = 2875 { 2876 "Direction", 2877 "Help", 2878 "Dismiss", 2879 (char *) NULL 2880 }; 2881 2882 static ModeType 2883 direction = HorizontalChopCommand; 2884 2885 static const ModeType 2886 ChopCommands[] = 2887 { 2888 ChopDirectionCommand, 2889 ChopHelpCommand, 2890 ChopDismissCommand 2891 }, 2892 DirectionCommands[] = 2893 { 2894 HorizontalChopCommand, 2895 VerticalChopCommand 2896 }; 2897 2898 char 2899 text[MaxTextExtent]; 2900 2901 Image 2902 *chop_image; 2903 2904 int 2905 id, 2906 x, 2907 y; 2908 2909 MagickRealType 2910 scale_factor; 2911 2912 RectangleInfo 2913 chop_info; 2914 2915 unsigned int 2916 distance, 2917 height, 2918 width; 2919 2920 size_t 2921 state; 2922 2923 XEvent 2924 event; 2925 2926 XSegment 2927 segment_info; 2928 2929 /* 2930 Map Command widget. 2931 */ 2932 (void) CloneString(&windows->command.name,"Chop"); 2933 windows->command.data=1; 2934 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL); 2935 (void) XMapRaised(display,windows->command.id); 2936 XClientMessage(display,windows->image.id,windows->im_protocols, 2937 windows->im_update_widget,CurrentTime); 2938 /* 2939 Track pointer until button 1 is pressed. 2940 */ 2941 XQueryPosition(display,windows->image.id,&x,&y); 2942 (void) XSelectInput(display,windows->image.id, 2943 windows->image.attributes.event_mask | PointerMotionMask); 2944 state=DefaultState; 2945 do 2946 { 2947 if (windows->info.mapped != MagickFalse) 2948 { 2949 /* 2950 Display pointer position. 2951 */ 2952 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 2953 x+windows->image.x,y+windows->image.y); 2954 XInfoWidget(display,windows,text); 2955 } 2956 /* 2957 Wait for next event. 2958 */ 2959 XScreenEvent(display,windows,&event,exception); 2960 if (event.xany.window == windows->command.id) 2961 { 2962 /* 2963 Select a command from the Command widget. 2964 */ 2965 id=XCommandWidget(display,windows,ChopMenu,&event); 2966 if (id < 0) 2967 continue; 2968 switch (ChopCommands[id]) 2969 { 2970 case ChopDirectionCommand: 2971 { 2972 char 2973 command[MaxTextExtent]; 2974 2975 static const char 2976 *Directions[] = 2977 { 2978 "horizontal", 2979 "vertical", 2980 (char *) NULL, 2981 }; 2982 2983 /* 2984 Select a command from the pop-up menu. 2985 */ 2986 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 2987 if (id >= 0) 2988 direction=DirectionCommands[id]; 2989 break; 2990 } 2991 case ChopHelpCommand: 2992 { 2993 XTextViewWidget(display,resource_info,windows,MagickFalse, 2994 "Help Viewer - Image Chop",ImageChopHelp); 2995 break; 2996 } 2997 case ChopDismissCommand: 2998 { 2999 /* 3000 Prematurely exit. 3001 */ 3002 state|=EscapeState; 3003 state|=ExitState; 3004 break; 3005 } 3006 default: 3007 break; 3008 } 3009 continue; 3010 } 3011 switch (event.type) 3012 { 3013 case ButtonPress: 3014 { 3015 if (event.xbutton.button != Button1) 3016 break; 3017 if (event.xbutton.window != windows->image.id) 3018 break; 3019 /* 3020 User has committed to start point of chopping line. 3021 */ 3022 segment_info.x1=(short int) event.xbutton.x; 3023 segment_info.x2=(short int) event.xbutton.x; 3024 segment_info.y1=(short int) event.xbutton.y; 3025 segment_info.y2=(short int) event.xbutton.y; 3026 state|=ExitState; 3027 break; 3028 } 3029 case ButtonRelease: 3030 break; 3031 case Expose: 3032 break; 3033 case KeyPress: 3034 { 3035 char 3036 command[MaxTextExtent]; 3037 3038 KeySym 3039 key_symbol; 3040 3041 if (event.xkey.window != windows->image.id) 3042 break; 3043 /* 3044 Respond to a user key press. 3045 */ 3046 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3047 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3048 switch ((int) key_symbol) 3049 { 3050 case XK_Escape: 3051 case XK_F20: 3052 { 3053 /* 3054 Prematurely exit. 3055 */ 3056 state|=EscapeState; 3057 state|=ExitState; 3058 break; 3059 } 3060 case XK_F1: 3061 case XK_Help: 3062 { 3063 (void) XSetFunction(display,windows->image.highlight_context, 3064 GXcopy); 3065 XTextViewWidget(display,resource_info,windows,MagickFalse, 3066 "Help Viewer - Image Chop",ImageChopHelp); 3067 (void) XSetFunction(display,windows->image.highlight_context, 3068 GXinvert); 3069 break; 3070 } 3071 default: 3072 { 3073 (void) XBell(display,0); 3074 break; 3075 } 3076 } 3077 break; 3078 } 3079 case MotionNotify: 3080 { 3081 /* 3082 Map and unmap Info widget as text cursor crosses its boundaries. 3083 */ 3084 x=event.xmotion.x; 3085 y=event.xmotion.y; 3086 if (windows->info.mapped != MagickFalse) 3087 { 3088 if ((x < (int) (windows->info.x+windows->info.width)) && 3089 (y < (int) (windows->info.y+windows->info.height))) 3090 (void) XWithdrawWindow(display,windows->info.id, 3091 windows->info.screen); 3092 } 3093 else 3094 if ((x > (int) (windows->info.x+windows->info.width)) || 3095 (y > (int) (windows->info.y+windows->info.height))) 3096 (void) XMapWindow(display,windows->info.id); 3097 } 3098 } 3099 } while ((state & ExitState) == 0); 3100 (void) XSelectInput(display,windows->image.id, 3101 windows->image.attributes.event_mask); 3102 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3103 if ((state & EscapeState) != 0) 3104 return(MagickTrue); 3105 /* 3106 Draw line as pointer moves until the mouse button is released. 3107 */ 3108 chop_info.width=0; 3109 chop_info.height=0; 3110 chop_info.x=0; 3111 chop_info.y=0; 3112 distance=0; 3113 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3114 state=DefaultState; 3115 do 3116 { 3117 if (distance > 9) 3118 { 3119 /* 3120 Display info and draw chopping line. 3121 */ 3122 if (windows->info.mapped == MagickFalse) 3123 (void) XMapWindow(display,windows->info.id); 3124 (void) FormatLocaleString(text,MaxTextExtent, 3125 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 3126 chop_info.height,(double) chop_info.x,(double) chop_info.y); 3127 XInfoWidget(display,windows,text); 3128 XHighlightLine(display,windows->image.id, 3129 windows->image.highlight_context,&segment_info); 3130 } 3131 else 3132 if (windows->info.mapped != MagickFalse) 3133 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3134 /* 3135 Wait for next event. 3136 */ 3137 XScreenEvent(display,windows,&event,exception); 3138 if (distance > 9) 3139 XHighlightLine(display,windows->image.id, 3140 windows->image.highlight_context,&segment_info); 3141 switch (event.type) 3142 { 3143 case ButtonPress: 3144 { 3145 segment_info.x2=(short int) event.xmotion.x; 3146 segment_info.y2=(short int) event.xmotion.y; 3147 break; 3148 } 3149 case ButtonRelease: 3150 { 3151 /* 3152 User has committed to chopping line. 3153 */ 3154 segment_info.x2=(short int) event.xbutton.x; 3155 segment_info.y2=(short int) event.xbutton.y; 3156 state|=ExitState; 3157 break; 3158 } 3159 case Expose: 3160 break; 3161 case MotionNotify: 3162 { 3163 segment_info.x2=(short int) event.xmotion.x; 3164 segment_info.y2=(short int) event.xmotion.y; 3165 } 3166 default: 3167 break; 3168 } 3169 /* 3170 Check boundary conditions. 3171 */ 3172 if (segment_info.x2 < 0) 3173 segment_info.x2=0; 3174 else 3175 if (segment_info.x2 > windows->image.ximage->width) 3176 segment_info.x2=windows->image.ximage->width; 3177 if (segment_info.y2 < 0) 3178 segment_info.y2=0; 3179 else 3180 if (segment_info.y2 > windows->image.ximage->height) 3181 segment_info.y2=windows->image.ximage->height; 3182 distance=(unsigned int) 3183 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 3184 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 3185 /* 3186 Compute chopping geometry. 3187 */ 3188 if (direction == HorizontalChopCommand) 3189 { 3190 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 3191 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 3192 chop_info.height=0; 3193 chop_info.y=0; 3194 if (segment_info.x1 > (int) segment_info.x2) 3195 { 3196 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 3197 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 3198 } 3199 } 3200 else 3201 { 3202 chop_info.width=0; 3203 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 3204 chop_info.x=0; 3205 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 3206 if (segment_info.y1 > segment_info.y2) 3207 { 3208 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 3209 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 3210 } 3211 } 3212 } while ((state & ExitState) == 0); 3213 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 3214 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3215 if (distance <= 9) 3216 return(MagickTrue); 3217 /* 3218 Image chopping is relative to image configuration. 3219 */ 3220 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 3221 exception); 3222 XSetCursorState(display,windows,MagickTrue); 3223 XCheckRefreshWindows(display,windows); 3224 windows->image.window_changes.width=windows->image.ximage->width- 3225 (unsigned int) chop_info.width; 3226 windows->image.window_changes.height=windows->image.ximage->height- 3227 (unsigned int) chop_info.height; 3228 width=(unsigned int) (*image)->columns; 3229 height=(unsigned int) (*image)->rows; 3230 x=0; 3231 y=0; 3232 if (windows->image.crop_geometry != (char *) NULL) 3233 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 3234 scale_factor=(MagickRealType) width/windows->image.ximage->width; 3235 chop_info.x+=x; 3236 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 3237 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 3238 scale_factor=(MagickRealType) height/windows->image.ximage->height; 3239 chop_info.y+=y; 3240 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 3241 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 3242 /* 3243 Chop image. 3244 */ 3245 chop_image=ChopImage(*image,&chop_info,exception); 3246 XSetCursorState(display,windows,MagickFalse); 3247 if (chop_image == (Image *) NULL) 3248 return(MagickFalse); 3249 *image=DestroyImage(*image); 3250 *image=chop_image; 3251 /* 3252 Update image configuration. 3253 */ 3254 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3255 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3256 return(MagickTrue); 3257} 3258 3259/* 3260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3261% % 3262% % 3263% % 3264+ X C o l o r E d i t I m a g e % 3265% % 3266% % 3267% % 3268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3269% 3270% XColorEditImage() allows the user to interactively change the color of one 3271% pixel for a DirectColor image or one colormap entry for a PseudoClass image. 3272% 3273% The format of the XColorEditImage method is: 3274% 3275% MagickBooleanType XColorEditImage(Display *display, 3276% XResourceInfo *resource_info,XWindows *windows,Image **image, 3277% ExceptionInfo *exception) 3278% 3279% A description of each parameter follows: 3280% 3281% o display: Specifies a connection to an X server; returned from 3282% XOpenDisplay. 3283% 3284% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3285% 3286% o windows: Specifies a pointer to a XWindows structure. 3287% 3288% o image: the image; returned from ReadImage. 3289% 3290% o exception: return any errors or warnings in this structure. 3291% 3292*/ 3293static MagickBooleanType XColorEditImage(Display *display, 3294 XResourceInfo *resource_info,XWindows *windows,Image **image, 3295 ExceptionInfo *exception) 3296{ 3297 static const char 3298 *ColorEditMenu[] = 3299 { 3300 "Method", 3301 "Pixel Color", 3302 "Border Color", 3303 "Fuzz", 3304 "Undo", 3305 "Help", 3306 "Dismiss", 3307 (char *) NULL 3308 }; 3309 3310 static const ModeType 3311 ColorEditCommands[] = 3312 { 3313 ColorEditMethodCommand, 3314 ColorEditColorCommand, 3315 ColorEditBorderCommand, 3316 ColorEditFuzzCommand, 3317 ColorEditUndoCommand, 3318 ColorEditHelpCommand, 3319 ColorEditDismissCommand 3320 }; 3321 3322 static PaintMethod 3323 method = PointMethod; 3324 3325 static unsigned int 3326 pen_id = 0; 3327 3328 static XColor 3329 border_color = { 0, 0, 0, 0, 0, 0 }; 3330 3331 char 3332 command[MaxTextExtent], 3333 text[MaxTextExtent]; 3334 3335 Cursor 3336 cursor; 3337 3338 int 3339 entry, 3340 id, 3341 x, 3342 x_offset, 3343 y, 3344 y_offset; 3345 3346 register Quantum 3347 *q; 3348 3349 register ssize_t 3350 i; 3351 3352 unsigned int 3353 height, 3354 width; 3355 3356 size_t 3357 state; 3358 3359 XColor 3360 color; 3361 3362 XEvent 3363 event; 3364 3365 /* 3366 Map Command widget. 3367 */ 3368 (void) CloneString(&windows->command.name,"Color Edit"); 3369 windows->command.data=4; 3370 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 3371 (void) XMapRaised(display,windows->command.id); 3372 XClientMessage(display,windows->image.id,windows->im_protocols, 3373 windows->im_update_widget,CurrentTime); 3374 /* 3375 Make cursor. 3376 */ 3377 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 3378 resource_info->background_color,resource_info->foreground_color); 3379 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3380 /* 3381 Track pointer until button 1 is pressed. 3382 */ 3383 XQueryPosition(display,windows->image.id,&x,&y); 3384 (void) XSelectInput(display,windows->image.id, 3385 windows->image.attributes.event_mask | PointerMotionMask); 3386 state=DefaultState; 3387 do 3388 { 3389 if (windows->info.mapped != MagickFalse) 3390 { 3391 /* 3392 Display pointer position. 3393 */ 3394 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 3395 x+windows->image.x,y+windows->image.y); 3396 XInfoWidget(display,windows,text); 3397 } 3398 /* 3399 Wait for next event. 3400 */ 3401 XScreenEvent(display,windows,&event,exception); 3402 if (event.xany.window == windows->command.id) 3403 { 3404 /* 3405 Select a command from the Command widget. 3406 */ 3407 id=XCommandWidget(display,windows,ColorEditMenu,&event); 3408 if (id < 0) 3409 { 3410 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3411 continue; 3412 } 3413 switch (ColorEditCommands[id]) 3414 { 3415 case ColorEditMethodCommand: 3416 { 3417 char 3418 **methods; 3419 3420 /* 3421 Select a method from the pop-up menu. 3422 */ 3423 methods=(char **) GetCommandOptions(MagickMethodOptions); 3424 if (methods == (char **) NULL) 3425 break; 3426 entry=XMenuWidget(display,windows,ColorEditMenu[id], 3427 (const char **) methods,command); 3428 if (entry >= 0) 3429 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 3430 MagickFalse,methods[entry]); 3431 methods=DestroyStringList(methods); 3432 break; 3433 } 3434 case ColorEditColorCommand: 3435 { 3436 const char 3437 *ColorMenu[MaxNumberPens]; 3438 3439 int 3440 pen_number; 3441 3442 /* 3443 Initialize menu selections. 3444 */ 3445 for (i=0; i < (int) (MaxNumberPens-2); i++) 3446 ColorMenu[i]=resource_info->pen_colors[i]; 3447 ColorMenu[MaxNumberPens-2]="Browser..."; 3448 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3449 /* 3450 Select a pen color from the pop-up menu. 3451 */ 3452 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3453 (const char **) ColorMenu,command); 3454 if (pen_number < 0) 3455 break; 3456 if (pen_number == (MaxNumberPens-2)) 3457 { 3458 static char 3459 color_name[MaxTextExtent] = "gray"; 3460 3461 /* 3462 Select a pen color from a dialog. 3463 */ 3464 resource_info->pen_colors[pen_number]=color_name; 3465 XColorBrowserWidget(display,windows,"Select",color_name); 3466 if (*color_name == '\0') 3467 break; 3468 } 3469 /* 3470 Set pen color. 3471 */ 3472 (void) XParseColor(display,windows->map_info->colormap, 3473 resource_info->pen_colors[pen_number],&color); 3474 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 3475 (unsigned int) MaxColors,&color); 3476 windows->pixel_info->pen_colors[pen_number]=color; 3477 pen_id=(unsigned int) pen_number; 3478 break; 3479 } 3480 case ColorEditBorderCommand: 3481 { 3482 const char 3483 *ColorMenu[MaxNumberPens]; 3484 3485 int 3486 pen_number; 3487 3488 /* 3489 Initialize menu selections. 3490 */ 3491 for (i=0; i < (int) (MaxNumberPens-2); i++) 3492 ColorMenu[i]=resource_info->pen_colors[i]; 3493 ColorMenu[MaxNumberPens-2]="Browser..."; 3494 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3495 /* 3496 Select a pen color from the pop-up menu. 3497 */ 3498 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3499 (const char **) ColorMenu,command); 3500 if (pen_number < 0) 3501 break; 3502 if (pen_number == (MaxNumberPens-2)) 3503 { 3504 static char 3505 color_name[MaxTextExtent] = "gray"; 3506 3507 /* 3508 Select a pen color from a dialog. 3509 */ 3510 resource_info->pen_colors[pen_number]=color_name; 3511 XColorBrowserWidget(display,windows,"Select",color_name); 3512 if (*color_name == '\0') 3513 break; 3514 } 3515 /* 3516 Set border color. 3517 */ 3518 (void) XParseColor(display,windows->map_info->colormap, 3519 resource_info->pen_colors[pen_number],&border_color); 3520 break; 3521 } 3522 case ColorEditFuzzCommand: 3523 { 3524 static char 3525 fuzz[MaxTextExtent]; 3526 3527 static const char 3528 *FuzzMenu[] = 3529 { 3530 "0%", 3531 "2%", 3532 "5%", 3533 "10%", 3534 "15%", 3535 "Dialog...", 3536 (char *) NULL, 3537 }; 3538 3539 /* 3540 Select a command from the pop-up menu. 3541 */ 3542 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 3543 command); 3544 if (entry < 0) 3545 break; 3546 if (entry != 5) 3547 { 3548 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 3549 QuantumRange+1.0); 3550 break; 3551 } 3552 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 3553 (void) XDialogWidget(display,windows,"Ok", 3554 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 3555 if (*fuzz == '\0') 3556 break; 3557 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 3558 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 3559 1.0); 3560 break; 3561 } 3562 case ColorEditUndoCommand: 3563 { 3564 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 3565 image,exception); 3566 break; 3567 } 3568 case ColorEditHelpCommand: 3569 default: 3570 { 3571 XTextViewWidget(display,resource_info,windows,MagickFalse, 3572 "Help Viewer - Image Annotation",ImageColorEditHelp); 3573 break; 3574 } 3575 case ColorEditDismissCommand: 3576 { 3577 /* 3578 Prematurely exit. 3579 */ 3580 state|=EscapeState; 3581 state|=ExitState; 3582 break; 3583 } 3584 } 3585 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3586 continue; 3587 } 3588 switch (event.type) 3589 { 3590 case ButtonPress: 3591 { 3592 if (event.xbutton.button != Button1) 3593 break; 3594 if ((event.xbutton.window != windows->image.id) && 3595 (event.xbutton.window != windows->magnify.id)) 3596 break; 3597 /* 3598 exit loop. 3599 */ 3600 x=event.xbutton.x; 3601 y=event.xbutton.y; 3602 (void) XMagickCommand(display,resource_info,windows, 3603 SaveToUndoBufferCommand,image,exception); 3604 state|=UpdateConfigurationState; 3605 break; 3606 } 3607 case ButtonRelease: 3608 { 3609 if (event.xbutton.button != Button1) 3610 break; 3611 if ((event.xbutton.window != windows->image.id) && 3612 (event.xbutton.window != windows->magnify.id)) 3613 break; 3614 /* 3615 Update colormap information. 3616 */ 3617 x=event.xbutton.x; 3618 y=event.xbutton.y; 3619 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3620 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3621 XInfoWidget(display,windows,text); 3622 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3623 state&=(~UpdateConfigurationState); 3624 break; 3625 } 3626 case Expose: 3627 break; 3628 case KeyPress: 3629 { 3630 KeySym 3631 key_symbol; 3632 3633 if (event.xkey.window == windows->magnify.id) 3634 { 3635 Window 3636 window; 3637 3638 window=windows->magnify.id; 3639 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 3640 } 3641 if (event.xkey.window != windows->image.id) 3642 break; 3643 /* 3644 Respond to a user key press. 3645 */ 3646 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3647 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3648 switch ((int) key_symbol) 3649 { 3650 case XK_Escape: 3651 case XK_F20: 3652 { 3653 /* 3654 Prematurely exit. 3655 */ 3656 state|=ExitState; 3657 break; 3658 } 3659 case XK_F1: 3660 case XK_Help: 3661 { 3662 XTextViewWidget(display,resource_info,windows,MagickFalse, 3663 "Help Viewer - Image Annotation",ImageColorEditHelp); 3664 break; 3665 } 3666 default: 3667 { 3668 (void) XBell(display,0); 3669 break; 3670 } 3671 } 3672 break; 3673 } 3674 case MotionNotify: 3675 { 3676 /* 3677 Map and unmap Info widget as cursor crosses its boundaries. 3678 */ 3679 x=event.xmotion.x; 3680 y=event.xmotion.y; 3681 if (windows->info.mapped != MagickFalse) 3682 { 3683 if ((x < (int) (windows->info.x+windows->info.width)) && 3684 (y < (int) (windows->info.y+windows->info.height))) 3685 (void) XWithdrawWindow(display,windows->info.id, 3686 windows->info.screen); 3687 } 3688 else 3689 if ((x > (int) (windows->info.x+windows->info.width)) || 3690 (y > (int) (windows->info.y+windows->info.height))) 3691 (void) XMapWindow(display,windows->info.id); 3692 break; 3693 } 3694 default: 3695 break; 3696 } 3697 if (event.xany.window == windows->magnify.id) 3698 { 3699 x=windows->magnify.x-windows->image.x; 3700 y=windows->magnify.y-windows->image.y; 3701 } 3702 x_offset=x; 3703 y_offset=y; 3704 if ((state & UpdateConfigurationState) != 0) 3705 { 3706 CacheView 3707 *image_view; 3708 3709 int 3710 x, 3711 y; 3712 3713 /* 3714 Pixel edit is relative to image configuration. 3715 */ 3716 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 3717 MagickTrue); 3718 color=windows->pixel_info->pen_colors[pen_id]; 3719 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 3720 width=(unsigned int) (*image)->columns; 3721 height=(unsigned int) (*image)->rows; 3722 x=0; 3723 y=0; 3724 if (windows->image.crop_geometry != (char *) NULL) 3725 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 3726 &width,&height); 3727 x_offset=(int) 3728 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 3729 y_offset=(int) 3730 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 3731 if ((x_offset < 0) || (y_offset < 0)) 3732 continue; 3733 if ((x_offset >= (int) (*image)->columns) || 3734 (y_offset >= (int) (*image)->rows)) 3735 continue; 3736 image_view=AcquireCacheView(*image); 3737 switch (method) 3738 { 3739 case PointMethod: 3740 default: 3741 { 3742 /* 3743 Update color information using point algorithm. 3744 */ 3745 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3746 return(MagickFalse); 3747 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 3748 (ssize_t) y_offset,1,1,exception); 3749 if (q == (Quantum *) NULL) 3750 break; 3751 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3752 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3753 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3754 (void) SyncCacheViewAuthenticPixels(image_view,exception); 3755 break; 3756 } 3757 case ReplaceMethod: 3758 { 3759 PixelInfo 3760 pixel, 3761 target; 3762 3763 Quantum 3764 virtual_pixel[CompositePixelChannel]; 3765 3766 /* 3767 Update color information using replace algorithm. 3768 */ 3769 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 3770 (ssize_t) y_offset,virtual_pixel,exception); 3771 target.red=virtual_pixel[RedPixelChannel]; 3772 target.green=virtual_pixel[GreenPixelChannel]; 3773 target.blue=virtual_pixel[BluePixelChannel]; 3774 target.alpha=virtual_pixel[AlphaPixelChannel]; 3775 if ((*image)->storage_class == DirectClass) 3776 { 3777 for (y=0; y < (int) (*image)->rows; y++) 3778 { 3779 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3780 (*image)->columns,1,exception); 3781 if (q == (Quantum *) NULL) 3782 break; 3783 for (x=0; x < (int) (*image)->columns; x++) 3784 { 3785 GetPixelInfoPixel(*image,q,&pixel); 3786 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 3787 { 3788 SetPixelRed(*image,ScaleShortToQuantum( 3789 color.red),q); 3790 SetPixelGreen(*image,ScaleShortToQuantum( 3791 color.green),q); 3792 SetPixelBlue(*image,ScaleShortToQuantum( 3793 color.blue),q); 3794 } 3795 q+=GetPixelChannels(*image); 3796 } 3797 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3798 break; 3799 } 3800 } 3801 else 3802 { 3803 for (i=0; i < (ssize_t) (*image)->colors; i++) 3804 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target)) 3805 { 3806 (*image)->colormap[i].red=ScaleShortToQuantum( 3807 color.red); 3808 (*image)->colormap[i].green=ScaleShortToQuantum( 3809 color.green); 3810 (*image)->colormap[i].blue=ScaleShortToQuantum( 3811 color.blue); 3812 } 3813 (void) SyncImage(*image,exception); 3814 } 3815 break; 3816 } 3817 case FloodfillMethod: 3818 case FillToBorderMethod: 3819 { 3820 DrawInfo 3821 *draw_info; 3822 3823 PixelInfo 3824 target; 3825 3826 /* 3827 Update color information using floodfill algorithm. 3828 */ 3829 (void) GetOneVirtualPixelInfo(*image, 3830 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 3831 y_offset,&target,exception); 3832 if (method == FillToBorderMethod) 3833 { 3834 target.red=(MagickRealType) 3835 ScaleShortToQuantum(border_color.red); 3836 target.green=(MagickRealType) 3837 ScaleShortToQuantum(border_color.green); 3838 target.blue=(MagickRealType) 3839 ScaleShortToQuantum(border_color.blue); 3840 } 3841 draw_info=CloneDrawInfo(resource_info->image_info, 3842 (DrawInfo *) NULL); 3843 (void) QueryColorCompliance(resource_info->pen_colors[pen_id], 3844 AllCompliance,&draw_info->fill,exception); 3845 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 3846 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 3847 MagickFalse : MagickTrue,exception); 3848 draw_info=DestroyDrawInfo(draw_info); 3849 break; 3850 } 3851 case ResetMethod: 3852 { 3853 /* 3854 Update color information using reset algorithm. 3855 */ 3856 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 3857 return(MagickFalse); 3858 for (y=0; y < (int) (*image)->rows; y++) 3859 { 3860 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3861 (*image)->columns,1,exception); 3862 if (q == (Quantum *) NULL) 3863 break; 3864 for (x=0; x < (int) (*image)->columns; x++) 3865 { 3866 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3867 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3868 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3869 q+=GetPixelChannels(*image); 3870 } 3871 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 3872 break; 3873 } 3874 break; 3875 } 3876 } 3877 image_view=DestroyCacheView(image_view); 3878 state&=(~UpdateConfigurationState); 3879 } 3880 } while ((state & ExitState) == 0); 3881 (void) XSelectInput(display,windows->image.id, 3882 windows->image.attributes.event_mask); 3883 XSetCursorState(display,windows,MagickFalse); 3884 (void) XFreeCursor(display,cursor); 3885 return(MagickTrue); 3886} 3887 3888/* 3889%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3890% % 3891% % 3892% % 3893+ X C o m p o s i t e I m a g e % 3894% % 3895% % 3896% % 3897%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3898% 3899% XCompositeImage() requests an image name from the user, reads the image and 3900% composites it with the X window image at a location the user chooses with 3901% the pointer. 3902% 3903% The format of the XCompositeImage method is: 3904% 3905% MagickBooleanType XCompositeImage(Display *display, 3906% XResourceInfo *resource_info,XWindows *windows,Image *image, 3907% ExceptionInfo *exception) 3908% 3909% A description of each parameter follows: 3910% 3911% o display: Specifies a connection to an X server; returned from 3912% XOpenDisplay. 3913% 3914% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3915% 3916% o windows: Specifies a pointer to a XWindows structure. 3917% 3918% o image: the image; returned from ReadImage. 3919% 3920% o exception: return any errors or warnings in this structure. 3921% 3922*/ 3923static MagickBooleanType XCompositeImage(Display *display, 3924 XResourceInfo *resource_info,XWindows *windows,Image *image, 3925 ExceptionInfo *exception) 3926{ 3927 static char 3928 displacement_geometry[MaxTextExtent] = "30x30", 3929 filename[MaxTextExtent] = "\0"; 3930 3931 static const char 3932 *CompositeMenu[] = 3933 { 3934 "Operators", 3935 "Dissolve", 3936 "Displace", 3937 "Help", 3938 "Dismiss", 3939 (char *) NULL 3940 }; 3941 3942 static CompositeOperator 3943 compose = CopyCompositeOp; 3944 3945 static const ModeType 3946 CompositeCommands[] = 3947 { 3948 CompositeOperatorsCommand, 3949 CompositeDissolveCommand, 3950 CompositeDisplaceCommand, 3951 CompositeHelpCommand, 3952 CompositeDismissCommand 3953 }; 3954 3955 char 3956 text[MaxTextExtent]; 3957 3958 Cursor 3959 cursor; 3960 3961 Image 3962 *composite_image; 3963 3964 int 3965 entry, 3966 id, 3967 x, 3968 y; 3969 3970 MagickRealType 3971 blend, 3972 scale_factor; 3973 3974 RectangleInfo 3975 highlight_info, 3976 composite_info; 3977 3978 unsigned int 3979 height, 3980 width; 3981 3982 size_t 3983 state; 3984 3985 XEvent 3986 event; 3987 3988 /* 3989 Request image file name from user. 3990 */ 3991 XFileBrowserWidget(display,windows,"Composite",filename); 3992 if (*filename == '\0') 3993 return(MagickTrue); 3994 /* 3995 Read image. 3996 */ 3997 XSetCursorState(display,windows,MagickTrue); 3998 XCheckRefreshWindows(display,windows); 3999 (void) CopyMagickString(resource_info->image_info->filename,filename, 4000 MaxTextExtent); 4001 composite_image=ReadImage(resource_info->image_info,exception); 4002 CatchException(exception); 4003 XSetCursorState(display,windows,MagickFalse); 4004 if (composite_image == (Image *) NULL) 4005 return(MagickFalse); 4006 /* 4007 Map Command widget. 4008 */ 4009 (void) CloneString(&windows->command.name,"Composite"); 4010 windows->command.data=1; 4011 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 4012 (void) XMapRaised(display,windows->command.id); 4013 XClientMessage(display,windows->image.id,windows->im_protocols, 4014 windows->im_update_widget,CurrentTime); 4015 /* 4016 Track pointer until button 1 is pressed. 4017 */ 4018 XQueryPosition(display,windows->image.id,&x,&y); 4019 (void) XSelectInput(display,windows->image.id, 4020 windows->image.attributes.event_mask | PointerMotionMask); 4021 composite_info.x=(ssize_t) windows->image.x+x; 4022 composite_info.y=(ssize_t) windows->image.y+y; 4023 composite_info.width=0; 4024 composite_info.height=0; 4025 cursor=XCreateFontCursor(display,XC_ul_angle); 4026 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4027 blend=0.0; 4028 state=DefaultState; 4029 do 4030 { 4031 if (windows->info.mapped != MagickFalse) 4032 { 4033 /* 4034 Display pointer position. 4035 */ 4036 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4037 (long) composite_info.x,(long) composite_info.y); 4038 XInfoWidget(display,windows,text); 4039 } 4040 highlight_info=composite_info; 4041 highlight_info.x=composite_info.x-windows->image.x; 4042 highlight_info.y=composite_info.y-windows->image.y; 4043 XHighlightRectangle(display,windows->image.id, 4044 windows->image.highlight_context,&highlight_info); 4045 /* 4046 Wait for next event. 4047 */ 4048 XScreenEvent(display,windows,&event,exception); 4049 XHighlightRectangle(display,windows->image.id, 4050 windows->image.highlight_context,&highlight_info); 4051 if (event.xany.window == windows->command.id) 4052 { 4053 /* 4054 Select a command from the Command widget. 4055 */ 4056 id=XCommandWidget(display,windows,CompositeMenu,&event); 4057 if (id < 0) 4058 continue; 4059 switch (CompositeCommands[id]) 4060 { 4061 case CompositeOperatorsCommand: 4062 { 4063 char 4064 command[MaxTextExtent], 4065 **operators; 4066 4067 /* 4068 Select a command from the pop-up menu. 4069 */ 4070 operators=GetCommandOptions(MagickComposeOptions); 4071 if (operators == (char **) NULL) 4072 break; 4073 entry=XMenuWidget(display,windows,CompositeMenu[id], 4074 (const char **) operators,command); 4075 if (entry >= 0) 4076 compose=(CompositeOperator) ParseCommandOption( 4077 MagickComposeOptions,MagickFalse,operators[entry]); 4078 operators=DestroyStringList(operators); 4079 break; 4080 } 4081 case CompositeDissolveCommand: 4082 { 4083 static char 4084 factor[MaxTextExtent] = "20.0"; 4085 4086 /* 4087 Dissolve the two images a given percent. 4088 */ 4089 (void) XSetFunction(display,windows->image.highlight_context, 4090 GXcopy); 4091 (void) XDialogWidget(display,windows,"Dissolve", 4092 "Enter the blend factor (0.0 - 99.9%):",factor); 4093 (void) XSetFunction(display,windows->image.highlight_context, 4094 GXinvert); 4095 if (*factor == '\0') 4096 break; 4097 blend=StringToDouble(factor,(char **) NULL); 4098 compose=DissolveCompositeOp; 4099 break; 4100 } 4101 case CompositeDisplaceCommand: 4102 { 4103 /* 4104 Get horizontal and vertical scale displacement geometry. 4105 */ 4106 (void) XSetFunction(display,windows->image.highlight_context, 4107 GXcopy); 4108 (void) XDialogWidget(display,windows,"Displace", 4109 "Enter the horizontal and vertical scale:",displacement_geometry); 4110 (void) XSetFunction(display,windows->image.highlight_context, 4111 GXinvert); 4112 if (*displacement_geometry == '\0') 4113 break; 4114 compose=DisplaceCompositeOp; 4115 break; 4116 } 4117 case CompositeHelpCommand: 4118 { 4119 (void) XSetFunction(display,windows->image.highlight_context, 4120 GXcopy); 4121 XTextViewWidget(display,resource_info,windows,MagickFalse, 4122 "Help Viewer - Image Composite",ImageCompositeHelp); 4123 (void) XSetFunction(display,windows->image.highlight_context, 4124 GXinvert); 4125 break; 4126 } 4127 case CompositeDismissCommand: 4128 { 4129 /* 4130 Prematurely exit. 4131 */ 4132 state|=EscapeState; 4133 state|=ExitState; 4134 break; 4135 } 4136 default: 4137 break; 4138 } 4139 continue; 4140 } 4141 switch (event.type) 4142 { 4143 case ButtonPress: 4144 { 4145 if (image->debug != MagickFalse) 4146 (void) LogMagickEvent(X11Event,GetMagickModule(), 4147 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 4148 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4149 if (event.xbutton.button != Button1) 4150 break; 4151 if (event.xbutton.window != windows->image.id) 4152 break; 4153 /* 4154 Change cursor. 4155 */ 4156 composite_info.width=composite_image->columns; 4157 composite_info.height=composite_image->rows; 4158 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4159 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4160 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4161 break; 4162 } 4163 case ButtonRelease: 4164 { 4165 if (image->debug != MagickFalse) 4166 (void) LogMagickEvent(X11Event,GetMagickModule(), 4167 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 4168 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4169 if (event.xbutton.button != Button1) 4170 break; 4171 if (event.xbutton.window != windows->image.id) 4172 break; 4173 if ((composite_info.width != 0) && (composite_info.height != 0)) 4174 { 4175 /* 4176 User has selected the location of the composite image. 4177 */ 4178 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4179 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4180 state|=ExitState; 4181 } 4182 break; 4183 } 4184 case Expose: 4185 break; 4186 case KeyPress: 4187 { 4188 char 4189 command[MaxTextExtent]; 4190 4191 KeySym 4192 key_symbol; 4193 4194 int 4195 length; 4196 4197 if (event.xkey.window != windows->image.id) 4198 break; 4199 /* 4200 Respond to a user key press. 4201 */ 4202 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 4203 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4204 *(command+length)='\0'; 4205 if (image->debug != MagickFalse) 4206 (void) LogMagickEvent(X11Event,GetMagickModule(), 4207 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 4208 switch ((int) key_symbol) 4209 { 4210 case XK_Escape: 4211 case XK_F20: 4212 { 4213 /* 4214 Prematurely exit. 4215 */ 4216 composite_image=DestroyImage(composite_image); 4217 state|=EscapeState; 4218 state|=ExitState; 4219 break; 4220 } 4221 case XK_F1: 4222 case XK_Help: 4223 { 4224 (void) XSetFunction(display,windows->image.highlight_context, 4225 GXcopy); 4226 XTextViewWidget(display,resource_info,windows,MagickFalse, 4227 "Help Viewer - Image Composite",ImageCompositeHelp); 4228 (void) XSetFunction(display,windows->image.highlight_context, 4229 GXinvert); 4230 break; 4231 } 4232 default: 4233 { 4234 (void) XBell(display,0); 4235 break; 4236 } 4237 } 4238 break; 4239 } 4240 case MotionNotify: 4241 { 4242 /* 4243 Map and unmap Info widget as text cursor crosses its boundaries. 4244 */ 4245 x=event.xmotion.x; 4246 y=event.xmotion.y; 4247 if (windows->info.mapped != MagickFalse) 4248 { 4249 if ((x < (int) (windows->info.x+windows->info.width)) && 4250 (y < (int) (windows->info.y+windows->info.height))) 4251 (void) XWithdrawWindow(display,windows->info.id, 4252 windows->info.screen); 4253 } 4254 else 4255 if ((x > (int) (windows->info.x+windows->info.width)) || 4256 (y > (int) (windows->info.y+windows->info.height))) 4257 (void) XMapWindow(display,windows->info.id); 4258 composite_info.x=(ssize_t) windows->image.x+x; 4259 composite_info.y=(ssize_t) windows->image.y+y; 4260 break; 4261 } 4262 default: 4263 { 4264 if (image->debug != MagickFalse) 4265 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 4266 event.type); 4267 break; 4268 } 4269 } 4270 } while ((state & ExitState) == 0); 4271 (void) XSelectInput(display,windows->image.id, 4272 windows->image.attributes.event_mask); 4273 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4274 XSetCursorState(display,windows,MagickFalse); 4275 (void) XFreeCursor(display,cursor); 4276 if ((state & EscapeState) != 0) 4277 return(MagickTrue); 4278 /* 4279 Image compositing is relative to image configuration. 4280 */ 4281 XSetCursorState(display,windows,MagickTrue); 4282 XCheckRefreshWindows(display,windows); 4283 width=(unsigned int) image->columns; 4284 height=(unsigned int) image->rows; 4285 x=0; 4286 y=0; 4287 if (windows->image.crop_geometry != (char *) NULL) 4288 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 4289 scale_factor=(MagickRealType) width/windows->image.ximage->width; 4290 composite_info.x+=x; 4291 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 4292 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 4293 scale_factor=(MagickRealType) height/windows->image.ximage->height; 4294 composite_info.y+=y; 4295 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 4296 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 4297 if ((composite_info.width != composite_image->columns) || 4298 (composite_info.height != composite_image->rows)) 4299 { 4300 Image 4301 *resize_image; 4302 4303 /* 4304 Scale composite image. 4305 */ 4306 resize_image=ResizeImage(composite_image,composite_info.width, 4307 composite_info.height,composite_image->filter,composite_image->blur, 4308 exception); 4309 composite_image=DestroyImage(composite_image); 4310 if (resize_image == (Image *) NULL) 4311 { 4312 XSetCursorState(display,windows,MagickFalse); 4313 return(MagickFalse); 4314 } 4315 composite_image=resize_image; 4316 } 4317 if (compose == DisplaceCompositeOp) 4318 (void) SetImageArtifact(composite_image,"compose:args", 4319 displacement_geometry); 4320 if (blend != 0.0) 4321 { 4322 CacheView 4323 *image_view; 4324 4325 int 4326 y; 4327 4328 Quantum 4329 opacity; 4330 4331 register int 4332 x; 4333 4334 register Quantum 4335 *q; 4336 4337 /* 4338 Create mattes for blending. 4339 */ 4340 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception); 4341 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)- 4342 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100); 4343 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 4344 return(MagickFalse); 4345 image->matte=MagickTrue; 4346 image_view=AcquireCacheView(image); 4347 for (y=0; y < (int) image->rows; y++) 4348 { 4349 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 4350 exception); 4351 if (q == (Quantum *) NULL) 4352 break; 4353 for (x=0; x < (int) image->columns; x++) 4354 { 4355 SetPixelAlpha(image,opacity,q); 4356 q+=GetPixelChannels(image); 4357 } 4358 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 4359 break; 4360 } 4361 image_view=DestroyCacheView(image_view); 4362 } 4363 /* 4364 Composite image with X Image window. 4365 */ 4366 (void) CompositeImage(image,compose,composite_image,composite_info.x, 4367 composite_info.y,exception); 4368 composite_image=DestroyImage(composite_image); 4369 XSetCursorState(display,windows,MagickFalse); 4370 /* 4371 Update image configuration. 4372 */ 4373 XConfigureImageColormap(display,resource_info,windows,image,exception); 4374 (void) XConfigureImage(display,resource_info,windows,image,exception); 4375 return(MagickTrue); 4376} 4377 4378/* 4379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4380% % 4381% % 4382% % 4383+ X C o n f i g u r e I m a g e % 4384% % 4385% % 4386% % 4387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4388% 4389% XConfigureImage() creates a new X image. It also notifies the window 4390% manager of the new image size and configures the transient widows. 4391% 4392% The format of the XConfigureImage method is: 4393% 4394% MagickBooleanType XConfigureImage(Display *display, 4395% XResourceInfo *resource_info,XWindows *windows,Image *image, 4396% ExceptionInfo *exception) 4397% 4398% A description of each parameter follows: 4399% 4400% o display: Specifies a connection to an X server; returned from 4401% XOpenDisplay. 4402% 4403% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4404% 4405% o windows: Specifies a pointer to a XWindows structure. 4406% 4407% o image: the image. 4408% 4409% o exception: return any errors or warnings in this structure. 4410% 4411% o exception: return any errors or warnings in this structure. 4412% 4413*/ 4414static MagickBooleanType XConfigureImage(Display *display, 4415 XResourceInfo *resource_info,XWindows *windows,Image *image, 4416 ExceptionInfo *exception) 4417{ 4418 char 4419 geometry[MaxTextExtent]; 4420 4421 MagickStatusType 4422 status; 4423 4424 size_t 4425 mask, 4426 height, 4427 width; 4428 4429 ssize_t 4430 x, 4431 y; 4432 4433 XSizeHints 4434 *size_hints; 4435 4436 XWindowChanges 4437 window_changes; 4438 4439 /* 4440 Dismiss if window dimensions are zero. 4441 */ 4442 width=(unsigned int) windows->image.window_changes.width; 4443 height=(unsigned int) windows->image.window_changes.height; 4444 if (image->debug != MagickFalse) 4445 (void) LogMagickEvent(X11Event,GetMagickModule(), 4446 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 4447 windows->image.ximage->height,(double) width,(double) height); 4448 if ((width*height) == 0) 4449 return(MagickTrue); 4450 x=0; 4451 y=0; 4452 /* 4453 Resize image to fit Image window dimensions. 4454 */ 4455 XSetCursorState(display,windows,MagickTrue); 4456 (void) XFlush(display); 4457 if (((int) width != windows->image.ximage->width) || 4458 ((int) height != windows->image.ximage->height)) 4459 image->taint=MagickTrue; 4460 windows->magnify.x=(int) 4461 width*windows->magnify.x/windows->image.ximage->width; 4462 windows->magnify.y=(int) 4463 height*windows->magnify.y/windows->image.ximage->height; 4464 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 4465 windows->image.y=(int) 4466 (height*windows->image.y/windows->image.ximage->height); 4467 status=XMakeImage(display,resource_info,&windows->image,image, 4468 (unsigned int) width,(unsigned int) height,exception); 4469 if (status == MagickFalse) 4470 XNoticeWidget(display,windows,"Unable to configure X image:", 4471 windows->image.name); 4472 /* 4473 Notify window manager of the new configuration. 4474 */ 4475 if (resource_info->image_geometry != (char *) NULL) 4476 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!", 4477 resource_info->image_geometry); 4478 else 4479 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 4480 XDisplayWidth(display,windows->image.screen), 4481 XDisplayHeight(display,windows->image.screen)); 4482 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 4483 window_changes.width=(int) width; 4484 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 4485 window_changes.width=XDisplayWidth(display,windows->image.screen); 4486 window_changes.height=(int) height; 4487 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 4488 window_changes.height=XDisplayHeight(display,windows->image.screen); 4489 mask=(size_t) (CWWidth | CWHeight); 4490 if (resource_info->backdrop) 4491 { 4492 mask|=CWX | CWY; 4493 window_changes.x=(int) 4494 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 4495 window_changes.y=(int) 4496 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 4497 } 4498 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 4499 (unsigned int) mask,&window_changes); 4500 (void) XClearWindow(display,windows->image.id); 4501 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 4502 /* 4503 Update Magnify window configuration. 4504 */ 4505 if (windows->magnify.mapped != MagickFalse) 4506 XMakeMagnifyImage(display,windows,exception); 4507 windows->pan.crop_geometry=windows->image.crop_geometry; 4508 XBestIconSize(display,&windows->pan,image); 4509 while (((windows->pan.width << 1) < MaxIconSize) && 4510 ((windows->pan.height << 1) < MaxIconSize)) 4511 { 4512 windows->pan.width<<=1; 4513 windows->pan.height<<=1; 4514 } 4515 if (windows->pan.geometry != (char *) NULL) 4516 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 4517 &windows->pan.width,&windows->pan.height); 4518 window_changes.width=(int) windows->pan.width; 4519 window_changes.height=(int) windows->pan.height; 4520 size_hints=XAllocSizeHints(); 4521 if (size_hints != (XSizeHints *) NULL) 4522 { 4523 /* 4524 Set new size hints. 4525 */ 4526 size_hints->flags=PSize | PMinSize | PMaxSize; 4527 size_hints->width=window_changes.width; 4528 size_hints->height=window_changes.height; 4529 size_hints->min_width=size_hints->width; 4530 size_hints->min_height=size_hints->height; 4531 size_hints->max_width=size_hints->width; 4532 size_hints->max_height=size_hints->height; 4533 (void) XSetNormalHints(display,windows->pan.id,size_hints); 4534 (void) XFree((void *) size_hints); 4535 } 4536 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 4537 (unsigned int) (CWWidth | CWHeight),&window_changes); 4538 /* 4539 Update icon window configuration. 4540 */ 4541 windows->icon.crop_geometry=windows->image.crop_geometry; 4542 XBestIconSize(display,&windows->icon,image); 4543 window_changes.width=(int) windows->icon.width; 4544 window_changes.height=(int) windows->icon.height; 4545 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 4546 (unsigned int) (CWWidth | CWHeight),&window_changes); 4547 XSetCursorState(display,windows,MagickFalse); 4548 return(status != 0 ? MagickTrue : MagickFalse); 4549} 4550 4551/* 4552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4553% % 4554% % 4555% % 4556+ X C r o p I m a g e % 4557% % 4558% % 4559% % 4560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4561% 4562% XCropImage() allows the user to select a region of the image and crop, copy, 4563% or cut it. For copy or cut, the image can subsequently be composited onto 4564% the image with XPasteImage. 4565% 4566% The format of the XCropImage method is: 4567% 4568% MagickBooleanType XCropImage(Display *display, 4569% XResourceInfo *resource_info,XWindows *windows,Image *image, 4570% const ClipboardMode mode,ExceptionInfo *exception) 4571% 4572% A description of each parameter follows: 4573% 4574% o display: Specifies a connection to an X server; returned from 4575% XOpenDisplay. 4576% 4577% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4578% 4579% o windows: Specifies a pointer to a XWindows structure. 4580% 4581% o image: the image; returned from ReadImage. 4582% 4583% o mode: This unsigned value specified whether the image should be 4584% cropped, copied, or cut. 4585% 4586% o exception: return any errors or warnings in this structure. 4587% 4588*/ 4589static MagickBooleanType XCropImage(Display *display, 4590 XResourceInfo *resource_info,XWindows *windows,Image *image, 4591 const ClipboardMode mode,ExceptionInfo *exception) 4592{ 4593 static const char 4594 *CropModeMenu[] = 4595 { 4596 "Help", 4597 "Dismiss", 4598 (char *) NULL 4599 }, 4600 *RectifyModeMenu[] = 4601 { 4602 "Crop", 4603 "Help", 4604 "Dismiss", 4605 (char *) NULL 4606 }; 4607 4608 static const ModeType 4609 CropCommands[] = 4610 { 4611 CropHelpCommand, 4612 CropDismissCommand 4613 }, 4614 RectifyCommands[] = 4615 { 4616 RectifyCopyCommand, 4617 RectifyHelpCommand, 4618 RectifyDismissCommand 4619 }; 4620 4621 CacheView 4622 *image_view; 4623 4624 char 4625 command[MaxTextExtent], 4626 text[MaxTextExtent]; 4627 4628 Cursor 4629 cursor; 4630 4631 int 4632 id, 4633 x, 4634 y; 4635 4636 KeySym 4637 key_symbol; 4638 4639 Image 4640 *crop_image; 4641 4642 MagickRealType 4643 scale_factor; 4644 4645 RectangleInfo 4646 crop_info, 4647 highlight_info; 4648 4649 register Quantum 4650 *q; 4651 4652 unsigned int 4653 height, 4654 width; 4655 4656 size_t 4657 state; 4658 4659 XEvent 4660 event; 4661 4662 /* 4663 Map Command widget. 4664 */ 4665 switch (mode) 4666 { 4667 case CopyMode: 4668 { 4669 (void) CloneString(&windows->command.name,"Copy"); 4670 break; 4671 } 4672 case CropMode: 4673 { 4674 (void) CloneString(&windows->command.name,"Crop"); 4675 break; 4676 } 4677 case CutMode: 4678 { 4679 (void) CloneString(&windows->command.name,"Cut"); 4680 break; 4681 } 4682 } 4683 RectifyModeMenu[0]=windows->command.name; 4684 windows->command.data=0; 4685 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 4686 (void) XMapRaised(display,windows->command.id); 4687 XClientMessage(display,windows->image.id,windows->im_protocols, 4688 windows->im_update_widget,CurrentTime); 4689 /* 4690 Track pointer until button 1 is pressed. 4691 */ 4692 XQueryPosition(display,windows->image.id,&x,&y); 4693 (void) XSelectInput(display,windows->image.id, 4694 windows->image.attributes.event_mask | PointerMotionMask); 4695 crop_info.x=(ssize_t) windows->image.x+x; 4696 crop_info.y=(ssize_t) windows->image.y+y; 4697 crop_info.width=0; 4698 crop_info.height=0; 4699 cursor=XCreateFontCursor(display,XC_fleur); 4700 state=DefaultState; 4701 do 4702 { 4703 if (windows->info.mapped != MagickFalse) 4704 { 4705 /* 4706 Display pointer position. 4707 */ 4708 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4709 (long) crop_info.x,(long) crop_info.y); 4710 XInfoWidget(display,windows,text); 4711 } 4712 /* 4713 Wait for next event. 4714 */ 4715 XScreenEvent(display,windows,&event,exception); 4716 if (event.xany.window == windows->command.id) 4717 { 4718 /* 4719 Select a command from the Command widget. 4720 */ 4721 id=XCommandWidget(display,windows,CropModeMenu,&event); 4722 if (id < 0) 4723 continue; 4724 switch (CropCommands[id]) 4725 { 4726 case CropHelpCommand: 4727 { 4728 switch (mode) 4729 { 4730 case CopyMode: 4731 { 4732 XTextViewWidget(display,resource_info,windows,MagickFalse, 4733 "Help Viewer - Image Copy",ImageCopyHelp); 4734 break; 4735 } 4736 case CropMode: 4737 { 4738 XTextViewWidget(display,resource_info,windows,MagickFalse, 4739 "Help Viewer - Image Crop",ImageCropHelp); 4740 break; 4741 } 4742 case CutMode: 4743 { 4744 XTextViewWidget(display,resource_info,windows,MagickFalse, 4745 "Help Viewer - Image Cut",ImageCutHelp); 4746 break; 4747 } 4748 } 4749 break; 4750 } 4751 case CropDismissCommand: 4752 { 4753 /* 4754 Prematurely exit. 4755 */ 4756 state|=EscapeState; 4757 state|=ExitState; 4758 break; 4759 } 4760 default: 4761 break; 4762 } 4763 continue; 4764 } 4765 switch (event.type) 4766 { 4767 case ButtonPress: 4768 { 4769 if (event.xbutton.button != Button1) 4770 break; 4771 if (event.xbutton.window != windows->image.id) 4772 break; 4773 /* 4774 Note first corner of cropping rectangle-- exit loop. 4775 */ 4776 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4777 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4778 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4779 state|=ExitState; 4780 break; 4781 } 4782 case ButtonRelease: 4783 break; 4784 case Expose: 4785 break; 4786 case KeyPress: 4787 { 4788 if (event.xkey.window != windows->image.id) 4789 break; 4790 /* 4791 Respond to a user key press. 4792 */ 4793 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 4794 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4795 switch ((int) key_symbol) 4796 { 4797 case XK_Escape: 4798 case XK_F20: 4799 { 4800 /* 4801 Prematurely exit. 4802 */ 4803 state|=EscapeState; 4804 state|=ExitState; 4805 break; 4806 } 4807 case XK_F1: 4808 case XK_Help: 4809 { 4810 switch (mode) 4811 { 4812 case CopyMode: 4813 { 4814 XTextViewWidget(display,resource_info,windows,MagickFalse, 4815 "Help Viewer - Image Copy",ImageCopyHelp); 4816 break; 4817 } 4818 case CropMode: 4819 { 4820 XTextViewWidget(display,resource_info,windows,MagickFalse, 4821 "Help Viewer - Image Crop",ImageCropHelp); 4822 break; 4823 } 4824 case CutMode: 4825 { 4826 XTextViewWidget(display,resource_info,windows,MagickFalse, 4827 "Help Viewer - Image Cut",ImageCutHelp); 4828 break; 4829 } 4830 } 4831 break; 4832 } 4833 default: 4834 { 4835 (void) XBell(display,0); 4836 break; 4837 } 4838 } 4839 break; 4840 } 4841 case MotionNotify: 4842 { 4843 if (event.xmotion.window != windows->image.id) 4844 break; 4845 /* 4846 Map and unmap Info widget as text cursor crosses its boundaries. 4847 */ 4848 x=event.xmotion.x; 4849 y=event.xmotion.y; 4850 if (windows->info.mapped != MagickFalse) 4851 { 4852 if ((x < (int) (windows->info.x+windows->info.width)) && 4853 (y < (int) (windows->info.y+windows->info.height))) 4854 (void) XWithdrawWindow(display,windows->info.id, 4855 windows->info.screen); 4856 } 4857 else 4858 if ((x > (int) (windows->info.x+windows->info.width)) || 4859 (y > (int) (windows->info.y+windows->info.height))) 4860 (void) XMapWindow(display,windows->info.id); 4861 crop_info.x=(ssize_t) windows->image.x+x; 4862 crop_info.y=(ssize_t) windows->image.y+y; 4863 break; 4864 } 4865 default: 4866 break; 4867 } 4868 } while ((state & ExitState) == 0); 4869 (void) XSelectInput(display,windows->image.id, 4870 windows->image.attributes.event_mask); 4871 if ((state & EscapeState) != 0) 4872 { 4873 /* 4874 User want to exit without cropping. 4875 */ 4876 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4877 (void) XFreeCursor(display,cursor); 4878 return(MagickTrue); 4879 } 4880 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4881 do 4882 { 4883 /* 4884 Size rectangle as pointer moves until the mouse button is released. 4885 */ 4886 x=(int) crop_info.x; 4887 y=(int) crop_info.y; 4888 crop_info.width=0; 4889 crop_info.height=0; 4890 state=DefaultState; 4891 do 4892 { 4893 highlight_info=crop_info; 4894 highlight_info.x=crop_info.x-windows->image.x; 4895 highlight_info.y=crop_info.y-windows->image.y; 4896 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4897 { 4898 /* 4899 Display info and draw cropping rectangle. 4900 */ 4901 if (windows->info.mapped == MagickFalse) 4902 (void) XMapWindow(display,windows->info.id); 4903 (void) FormatLocaleString(text,MaxTextExtent, 4904 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4905 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4906 XInfoWidget(display,windows,text); 4907 XHighlightRectangle(display,windows->image.id, 4908 windows->image.highlight_context,&highlight_info); 4909 } 4910 else 4911 if (windows->info.mapped != MagickFalse) 4912 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4913 /* 4914 Wait for next event. 4915 */ 4916 XScreenEvent(display,windows,&event,exception); 4917 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4918 XHighlightRectangle(display,windows->image.id, 4919 windows->image.highlight_context,&highlight_info); 4920 switch (event.type) 4921 { 4922 case ButtonPress: 4923 { 4924 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4925 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4926 break; 4927 } 4928 case ButtonRelease: 4929 { 4930 /* 4931 User has committed to cropping rectangle. 4932 */ 4933 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4934 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4935 XSetCursorState(display,windows,MagickFalse); 4936 state|=ExitState; 4937 windows->command.data=0; 4938 (void) XCommandWidget(display,windows,RectifyModeMenu, 4939 (XEvent *) NULL); 4940 break; 4941 } 4942 case Expose: 4943 break; 4944 case MotionNotify: 4945 { 4946 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 4947 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 4948 } 4949 default: 4950 break; 4951 } 4952 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 4953 ((state & ExitState) != 0)) 4954 { 4955 /* 4956 Check boundary conditions. 4957 */ 4958 if (crop_info.x < 0) 4959 crop_info.x=0; 4960 else 4961 if (crop_info.x > (ssize_t) windows->image.ximage->width) 4962 crop_info.x=(ssize_t) windows->image.ximage->width; 4963 if ((int) crop_info.x < x) 4964 crop_info.width=(unsigned int) (x-crop_info.x); 4965 else 4966 { 4967 crop_info.width=(unsigned int) (crop_info.x-x); 4968 crop_info.x=(ssize_t) x; 4969 } 4970 if (crop_info.y < 0) 4971 crop_info.y=0; 4972 else 4973 if (crop_info.y > (ssize_t) windows->image.ximage->height) 4974 crop_info.y=(ssize_t) windows->image.ximage->height; 4975 if ((int) crop_info.y < y) 4976 crop_info.height=(unsigned int) (y-crop_info.y); 4977 else 4978 { 4979 crop_info.height=(unsigned int) (crop_info.y-y); 4980 crop_info.y=(ssize_t) y; 4981 } 4982 } 4983 } while ((state & ExitState) == 0); 4984 /* 4985 Wait for user to grab a corner of the rectangle or press return. 4986 */ 4987 state=DefaultState; 4988 (void) XMapWindow(display,windows->info.id); 4989 do 4990 { 4991 if (windows->info.mapped != MagickFalse) 4992 { 4993 /* 4994 Display pointer position. 4995 */ 4996 (void) FormatLocaleString(text,MaxTextExtent, 4997 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4998 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4999 XInfoWidget(display,windows,text); 5000 } 5001 highlight_info=crop_info; 5002 highlight_info.x=crop_info.x-windows->image.x; 5003 highlight_info.y=crop_info.y-windows->image.y; 5004 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 5005 { 5006 state|=EscapeState; 5007 state|=ExitState; 5008 break; 5009 } 5010 XHighlightRectangle(display,windows->image.id, 5011 windows->image.highlight_context,&highlight_info); 5012 XScreenEvent(display,windows,&event,exception); 5013 if (event.xany.window == windows->command.id) 5014 { 5015 /* 5016 Select a command from the Command widget. 5017 */ 5018 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5019 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 5020 (void) XSetFunction(display,windows->image.highlight_context, 5021 GXinvert); 5022 XHighlightRectangle(display,windows->image.id, 5023 windows->image.highlight_context,&highlight_info); 5024 if (id >= 0) 5025 switch (RectifyCommands[id]) 5026 { 5027 case RectifyCopyCommand: 5028 { 5029 state|=ExitState; 5030 break; 5031 } 5032 case RectifyHelpCommand: 5033 { 5034 (void) XSetFunction(display,windows->image.highlight_context, 5035 GXcopy); 5036 switch (mode) 5037 { 5038 case CopyMode: 5039 { 5040 XTextViewWidget(display,resource_info,windows,MagickFalse, 5041 "Help Viewer - Image Copy",ImageCopyHelp); 5042 break; 5043 } 5044 case CropMode: 5045 { 5046 XTextViewWidget(display,resource_info,windows,MagickFalse, 5047 "Help Viewer - Image Crop",ImageCropHelp); 5048 break; 5049 } 5050 case CutMode: 5051 { 5052 XTextViewWidget(display,resource_info,windows,MagickFalse, 5053 "Help Viewer - Image Cut",ImageCutHelp); 5054 break; 5055 } 5056 } 5057 (void) XSetFunction(display,windows->image.highlight_context, 5058 GXinvert); 5059 break; 5060 } 5061 case RectifyDismissCommand: 5062 { 5063 /* 5064 Prematurely exit. 5065 */ 5066 state|=EscapeState; 5067 state|=ExitState; 5068 break; 5069 } 5070 default: 5071 break; 5072 } 5073 continue; 5074 } 5075 XHighlightRectangle(display,windows->image.id, 5076 windows->image.highlight_context,&highlight_info); 5077 switch (event.type) 5078 { 5079 case ButtonPress: 5080 { 5081 if (event.xbutton.button != Button1) 5082 break; 5083 if (event.xbutton.window != windows->image.id) 5084 break; 5085 x=windows->image.x+event.xbutton.x; 5086 y=windows->image.y+event.xbutton.y; 5087 if ((x < (int) (crop_info.x+RoiDelta)) && 5088 (x > (int) (crop_info.x-RoiDelta)) && 5089 (y < (int) (crop_info.y+RoiDelta)) && 5090 (y > (int) (crop_info.y-RoiDelta))) 5091 { 5092 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5093 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5094 state|=UpdateConfigurationState; 5095 break; 5096 } 5097 if ((x < (int) (crop_info.x+RoiDelta)) && 5098 (x > (int) (crop_info.x-RoiDelta)) && 5099 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5100 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5101 { 5102 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5103 state|=UpdateConfigurationState; 5104 break; 5105 } 5106 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5107 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5108 (y < (int) (crop_info.y+RoiDelta)) && 5109 (y > (int) (crop_info.y-RoiDelta))) 5110 { 5111 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5112 state|=UpdateConfigurationState; 5113 break; 5114 } 5115 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5116 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5117 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5118 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5119 { 5120 state|=UpdateConfigurationState; 5121 break; 5122 } 5123 } 5124 case ButtonRelease: 5125 { 5126 if (event.xbutton.window == windows->pan.id) 5127 if ((highlight_info.x != crop_info.x-windows->image.x) || 5128 (highlight_info.y != crop_info.y-windows->image.y)) 5129 XHighlightRectangle(display,windows->image.id, 5130 windows->image.highlight_context,&highlight_info); 5131 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5132 event.xbutton.time); 5133 break; 5134 } 5135 case Expose: 5136 { 5137 if (event.xexpose.window == windows->image.id) 5138 if (event.xexpose.count == 0) 5139 { 5140 event.xexpose.x=(int) highlight_info.x; 5141 event.xexpose.y=(int) highlight_info.y; 5142 event.xexpose.width=(int) highlight_info.width; 5143 event.xexpose.height=(int) highlight_info.height; 5144 XRefreshWindow(display,&windows->image,&event); 5145 } 5146 if (event.xexpose.window == windows->info.id) 5147 if (event.xexpose.count == 0) 5148 XInfoWidget(display,windows,text); 5149 break; 5150 } 5151 case KeyPress: 5152 { 5153 if (event.xkey.window != windows->image.id) 5154 break; 5155 /* 5156 Respond to a user key press. 5157 */ 5158 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5159 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5160 switch ((int) key_symbol) 5161 { 5162 case XK_Escape: 5163 case XK_F20: 5164 state|=EscapeState; 5165 case XK_Return: 5166 { 5167 state|=ExitState; 5168 break; 5169 } 5170 case XK_Home: 5171 case XK_KP_Home: 5172 { 5173 crop_info.x=(ssize_t) (windows->image.width/2L- 5174 crop_info.width/2L); 5175 crop_info.y=(ssize_t) (windows->image.height/2L- 5176 crop_info.height/2L); 5177 break; 5178 } 5179 case XK_Left: 5180 case XK_KP_Left: 5181 { 5182 crop_info.x--; 5183 break; 5184 } 5185 case XK_Up: 5186 case XK_KP_Up: 5187 case XK_Next: 5188 { 5189 crop_info.y--; 5190 break; 5191 } 5192 case XK_Right: 5193 case XK_KP_Right: 5194 { 5195 crop_info.x++; 5196 break; 5197 } 5198 case XK_Prior: 5199 case XK_Down: 5200 case XK_KP_Down: 5201 { 5202 crop_info.y++; 5203 break; 5204 } 5205 case XK_F1: 5206 case XK_Help: 5207 { 5208 (void) XSetFunction(display,windows->image.highlight_context, 5209 GXcopy); 5210 switch (mode) 5211 { 5212 case CopyMode: 5213 { 5214 XTextViewWidget(display,resource_info,windows,MagickFalse, 5215 "Help Viewer - Image Copy",ImageCopyHelp); 5216 break; 5217 } 5218 case CropMode: 5219 { 5220 XTextViewWidget(display,resource_info,windows,MagickFalse, 5221 "Help Viewer - Image Cropg",ImageCropHelp); 5222 break; 5223 } 5224 case CutMode: 5225 { 5226 XTextViewWidget(display,resource_info,windows,MagickFalse, 5227 "Help Viewer - Image Cutg",ImageCutHelp); 5228 break; 5229 } 5230 } 5231 (void) XSetFunction(display,windows->image.highlight_context, 5232 GXinvert); 5233 break; 5234 } 5235 default: 5236 { 5237 (void) XBell(display,0); 5238 break; 5239 } 5240 } 5241 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5242 event.xkey.time); 5243 break; 5244 } 5245 case KeyRelease: 5246 break; 5247 case MotionNotify: 5248 { 5249 if (event.xmotion.window != windows->image.id) 5250 break; 5251 /* 5252 Map and unmap Info widget as text cursor crosses its boundaries. 5253 */ 5254 x=event.xmotion.x; 5255 y=event.xmotion.y; 5256 if (windows->info.mapped != MagickFalse) 5257 { 5258 if ((x < (int) (windows->info.x+windows->info.width)) && 5259 (y < (int) (windows->info.y+windows->info.height))) 5260 (void) XWithdrawWindow(display,windows->info.id, 5261 windows->info.screen); 5262 } 5263 else 5264 if ((x > (int) (windows->info.x+windows->info.width)) || 5265 (y > (int) (windows->info.y+windows->info.height))) 5266 (void) XMapWindow(display,windows->info.id); 5267 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 5268 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 5269 break; 5270 } 5271 case SelectionRequest: 5272 { 5273 XSelectionEvent 5274 notify; 5275 5276 XSelectionRequestEvent 5277 *request; 5278 5279 /* 5280 Set primary selection. 5281 */ 5282 (void) FormatLocaleString(text,MaxTextExtent, 5283 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 5284 crop_info.height,(double) crop_info.x,(double) crop_info.y); 5285 request=(&(event.xselectionrequest)); 5286 (void) XChangeProperty(request->display,request->requestor, 5287 request->property,request->target,8,PropModeReplace, 5288 (unsigned char *) text,(int) strlen(text)); 5289 notify.type=SelectionNotify; 5290 notify.display=request->display; 5291 notify.requestor=request->requestor; 5292 notify.selection=request->selection; 5293 notify.target=request->target; 5294 notify.time=request->time; 5295 if (request->property == None) 5296 notify.property=request->target; 5297 else 5298 notify.property=request->property; 5299 (void) XSendEvent(request->display,request->requestor,False,0, 5300 (XEvent *) ¬ify); 5301 } 5302 default: 5303 break; 5304 } 5305 if ((state & UpdateConfigurationState) != 0) 5306 { 5307 (void) XPutBackEvent(display,&event); 5308 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5309 break; 5310 } 5311 } while ((state & ExitState) == 0); 5312 } while ((state & ExitState) == 0); 5313 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5314 XSetCursorState(display,windows,MagickFalse); 5315 if ((state & EscapeState) != 0) 5316 return(MagickTrue); 5317 if (mode == CropMode) 5318 if (((int) crop_info.width != windows->image.ximage->width) || 5319 ((int) crop_info.height != windows->image.ximage->height)) 5320 { 5321 /* 5322 Reconfigure Image window as defined by cropping rectangle. 5323 */ 5324 XSetCropGeometry(display,windows,&crop_info,image); 5325 windows->image.window_changes.width=(int) crop_info.width; 5326 windows->image.window_changes.height=(int) crop_info.height; 5327 (void) XConfigureImage(display,resource_info,windows,image,exception); 5328 return(MagickTrue); 5329 } 5330 /* 5331 Copy image before applying image transforms. 5332 */ 5333 XSetCursorState(display,windows,MagickTrue); 5334 XCheckRefreshWindows(display,windows); 5335 width=(unsigned int) image->columns; 5336 height=(unsigned int) image->rows; 5337 x=0; 5338 y=0; 5339 if (windows->image.crop_geometry != (char *) NULL) 5340 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 5341 scale_factor=(MagickRealType) width/windows->image.ximage->width; 5342 crop_info.x+=x; 5343 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 5344 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 5345 scale_factor=(MagickRealType) height/windows->image.ximage->height; 5346 crop_info.y+=y; 5347 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 5348 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5); 5349 crop_image=CropImage(image,&crop_info,exception); 5350 XSetCursorState(display,windows,MagickFalse); 5351 if (crop_image == (Image *) NULL) 5352 return(MagickFalse); 5353 if (resource_info->copy_image != (Image *) NULL) 5354 resource_info->copy_image=DestroyImage(resource_info->copy_image); 5355 resource_info->copy_image=crop_image; 5356 if (mode == CopyMode) 5357 { 5358 (void) XConfigureImage(display,resource_info,windows,image,exception); 5359 return(MagickTrue); 5360 } 5361 /* 5362 Cut image. 5363 */ 5364 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 5365 return(MagickFalse); 5366 image->matte=MagickTrue; 5367 image_view=AcquireCacheView(image); 5368 for (y=0; y < (int) crop_info.height; y++) 5369 { 5370 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y, 5371 crop_info.width,1,exception); 5372 if (q == (Quantum *) NULL) 5373 break; 5374 for (x=0; x < (int) crop_info.width; x++) 5375 { 5376 SetPixelAlpha(image,TransparentAlpha,q); 5377 q+=GetPixelChannels(image); 5378 } 5379 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 5380 break; 5381 } 5382 image_view=DestroyCacheView(image_view); 5383 /* 5384 Update image configuration. 5385 */ 5386 XConfigureImageColormap(display,resource_info,windows,image,exception); 5387 (void) XConfigureImage(display,resource_info,windows,image,exception); 5388 return(MagickTrue); 5389} 5390 5391/* 5392%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5393% % 5394% % 5395% % 5396+ X D r a w I m a g e % 5397% % 5398% % 5399% % 5400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5401% 5402% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on 5403% the image. 5404% 5405% The format of the XDrawEditImage method is: 5406% 5407% MagickBooleanType XDrawEditImage(Display *display, 5408% XResourceInfo *resource_info,XWindows *windows,Image **image, 5409% ExceptionInfo *exception) 5410% 5411% A description of each parameter follows: 5412% 5413% o display: Specifies a connection to an X server; returned from 5414% XOpenDisplay. 5415% 5416% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 5417% 5418% o windows: Specifies a pointer to a XWindows structure. 5419% 5420% o image: the image. 5421% 5422% o exception: return any errors or warnings in this structure. 5423% 5424*/ 5425static MagickBooleanType XDrawEditImage(Display *display, 5426 XResourceInfo *resource_info,XWindows *windows,Image **image, 5427 ExceptionInfo *exception) 5428{ 5429 static const char 5430 *DrawMenu[] = 5431 { 5432 "Element", 5433 "Color", 5434 "Stipple", 5435 "Width", 5436 "Undo", 5437 "Help", 5438 "Dismiss", 5439 (char *) NULL 5440 }; 5441 5442 static ElementType 5443 element = PointElement; 5444 5445 static const ModeType 5446 DrawCommands[] = 5447 { 5448 DrawElementCommand, 5449 DrawColorCommand, 5450 DrawStippleCommand, 5451 DrawWidthCommand, 5452 DrawUndoCommand, 5453 DrawHelpCommand, 5454 DrawDismissCommand 5455 }; 5456 5457 static Pixmap 5458 stipple = (Pixmap) NULL; 5459 5460 static unsigned int 5461 pen_id = 0, 5462 line_width = 1; 5463 5464 char 5465 command[MaxTextExtent], 5466 text[MaxTextExtent]; 5467 5468 Cursor 5469 cursor; 5470 5471 int 5472 entry, 5473 id, 5474 number_coordinates, 5475 x, 5476 y; 5477 5478 MagickRealType 5479 degrees; 5480 5481 MagickStatusType 5482 status; 5483 5484 RectangleInfo 5485 rectangle_info; 5486 5487 register int 5488 i; 5489 5490 unsigned int 5491 distance, 5492 height, 5493 max_coordinates, 5494 width; 5495 5496 size_t 5497 state; 5498 5499 Window 5500 root_window; 5501 5502 XDrawInfo 5503 draw_info; 5504 5505 XEvent 5506 event; 5507 5508 XPoint 5509 *coordinate_info; 5510 5511 XSegment 5512 line_info; 5513 5514 /* 5515 Allocate polygon info. 5516 */ 5517 max_coordinates=2048; 5518 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates, 5519 sizeof(*coordinate_info)); 5520 if (coordinate_info == (XPoint *) NULL) 5521 { 5522 (void) ThrowMagickException(exception,GetMagickModule(), 5523 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 5524 return(MagickFalse); 5525 } 5526 /* 5527 Map Command widget. 5528 */ 5529 (void) CloneString(&windows->command.name,"Draw"); 5530 windows->command.data=4; 5531 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL); 5532 (void) XMapRaised(display,windows->command.id); 5533 XClientMessage(display,windows->image.id,windows->im_protocols, 5534 windows->im_update_widget,CurrentTime); 5535 /* 5536 Wait for first button press. 5537 */ 5538 root_window=XRootWindow(display,XDefaultScreen(display)); 5539 draw_info.stencil=OpaqueStencil; 5540 status=MagickTrue; 5541 cursor=XCreateFontCursor(display,XC_tcross); 5542 for ( ; ; ) 5543 { 5544 XQueryPosition(display,windows->image.id,&x,&y); 5545 (void) XSelectInput(display,windows->image.id, 5546 windows->image.attributes.event_mask | PointerMotionMask); 5547 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5548 state=DefaultState; 5549 do 5550 { 5551 if (windows->info.mapped != MagickFalse) 5552 { 5553 /* 5554 Display pointer position. 5555 */ 5556 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 5557 x+windows->image.x,y+windows->image.y); 5558 XInfoWidget(display,windows,text); 5559 } 5560 /* 5561 Wait for next event. 5562 */ 5563 XScreenEvent(display,windows,&event,exception); 5564 if (event.xany.window == windows->command.id) 5565 { 5566 /* 5567 Select a command from the Command widget. 5568 */ 5569 id=XCommandWidget(display,windows,DrawMenu,&event); 5570 if (id < 0) 5571 continue; 5572 switch (DrawCommands[id]) 5573 { 5574 case DrawElementCommand: 5575 { 5576 static const char 5577 *Elements[] = 5578 { 5579 "point", 5580 "line", 5581 "rectangle", 5582 "fill rectangle", 5583 "circle", 5584 "fill circle", 5585 "ellipse", 5586 "fill ellipse", 5587 "polygon", 5588 "fill polygon", 5589 (char *) NULL, 5590 }; 5591 5592 /* 5593 Select a command from the pop-up menu. 5594 */ 5595 element=(ElementType) (XMenuWidget(display,windows, 5596 DrawMenu[id],Elements,command)+1); 5597 break; 5598 } 5599 case DrawColorCommand: 5600 { 5601 const char 5602 *ColorMenu[MaxNumberPens+1]; 5603 5604 int 5605 pen_number; 5606 5607 MagickBooleanType 5608 transparent; 5609 5610 XColor 5611 color; 5612 5613 /* 5614 Initialize menu selections. 5615 */ 5616 for (i=0; i < (int) (MaxNumberPens-2); i++) 5617 ColorMenu[i]=resource_info->pen_colors[i]; 5618 ColorMenu[MaxNumberPens-2]="transparent"; 5619 ColorMenu[MaxNumberPens-1]="Browser..."; 5620 ColorMenu[MaxNumberPens]=(char *) NULL; 5621 /* 5622 Select a pen color from the pop-up menu. 5623 */ 5624 pen_number=XMenuWidget(display,windows,DrawMenu[id], 5625 (const char **) ColorMenu,command); 5626 if (pen_number < 0) 5627 break; 5628 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue : 5629 MagickFalse; 5630 if (transparent != MagickFalse) 5631 { 5632 draw_info.stencil=TransparentStencil; 5633 break; 5634 } 5635 if (pen_number == (MaxNumberPens-1)) 5636 { 5637 static char 5638 color_name[MaxTextExtent] = "gray"; 5639 5640 /* 5641 Select a pen color from a dialog. 5642 */ 5643 resource_info->pen_colors[pen_number]=color_name; 5644 XColorBrowserWidget(display,windows,"Select",color_name); 5645 if (*color_name == '\0') 5646 break; 5647 } 5648 /* 5649 Set pen color. 5650 */ 5651 (void) XParseColor(display,windows->map_info->colormap, 5652 resource_info->pen_colors[pen_number],&color); 5653 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 5654 (unsigned int) MaxColors,&color); 5655 windows->pixel_info->pen_colors[pen_number]=color; 5656 pen_id=(unsigned int) pen_number; 5657 draw_info.stencil=OpaqueStencil; 5658 break; 5659 } 5660 case DrawStippleCommand: 5661 { 5662 Image 5663 *stipple_image; 5664 5665 ImageInfo 5666 *image_info; 5667 5668 int 5669 status; 5670 5671 static char 5672 filename[MaxTextExtent] = "\0"; 5673 5674 static const char 5675 *StipplesMenu[] = 5676 { 5677 "Brick", 5678 "Diagonal", 5679 "Scales", 5680 "Vertical", 5681 "Wavy", 5682 "Translucent", 5683 "Opaque", 5684 (char *) NULL, 5685 (char *) NULL, 5686 }; 5687 5688 /* 5689 Select a command from the pop-up menu. 5690 */ 5691 StipplesMenu[7]="Open..."; 5692 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu, 5693 command); 5694 if (entry < 0) 5695 break; 5696 if (stipple != (Pixmap) NULL) 5697 (void) XFreePixmap(display,stipple); 5698 stipple=(Pixmap) NULL; 5699 if (entry != 7) 5700 { 5701 switch (entry) 5702 { 5703 case 0: 5704 { 5705 stipple=XCreateBitmapFromData(display,root_window, 5706 (char *) BricksBitmap,BricksWidth,BricksHeight); 5707 break; 5708 } 5709 case 1: 5710 { 5711 stipple=XCreateBitmapFromData(display,root_window, 5712 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight); 5713 break; 5714 } 5715 case 2: 5716 { 5717 stipple=XCreateBitmapFromData(display,root_window, 5718 (char *) ScalesBitmap,ScalesWidth,ScalesHeight); 5719 break; 5720 } 5721 case 3: 5722 { 5723 stipple=XCreateBitmapFromData(display,root_window, 5724 (char *) VerticalBitmap,VerticalWidth,VerticalHeight); 5725 break; 5726 } 5727 case 4: 5728 { 5729 stipple=XCreateBitmapFromData(display,root_window, 5730 (char *) WavyBitmap,WavyWidth,WavyHeight); 5731 break; 5732 } 5733 case 5: 5734 { 5735 stipple=XCreateBitmapFromData(display,root_window, 5736 (char *) HighlightBitmap,HighlightWidth, 5737 HighlightHeight); 5738 break; 5739 } 5740 case 6: 5741 default: 5742 { 5743 stipple=XCreateBitmapFromData(display,root_window, 5744 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight); 5745 break; 5746 } 5747 } 5748 break; 5749 } 5750 XFileBrowserWidget(display,windows,"Stipple",filename); 5751 if (*filename == '\0') 5752 break; 5753 /* 5754 Read image. 5755 */ 5756 XSetCursorState(display,windows,MagickTrue); 5757 XCheckRefreshWindows(display,windows); 5758 image_info=AcquireImageInfo(); 5759 (void) CopyMagickString(image_info->filename,filename, 5760 MaxTextExtent); 5761 stipple_image=ReadImage(image_info,exception); 5762 CatchException(exception); 5763 XSetCursorState(display,windows,MagickFalse); 5764 if (stipple_image == (Image *) NULL) 5765 break; 5766 (void) AcquireUniqueFileResource(filename); 5767 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent, 5768 "xbm:%s",filename); 5769 (void) WriteImage(image_info,stipple_image,exception); 5770 stipple_image=DestroyImage(stipple_image); 5771 image_info=DestroyImageInfo(image_info); 5772 status=XReadBitmapFile(display,root_window,filename,&width, 5773 &height,&stipple,&x,&y); 5774 (void) RelinquishUniqueFileResource(filename); 5775 if ((status != BitmapSuccess) != 0) 5776 XNoticeWidget(display,windows,"Unable to read X bitmap image:", 5777 filename); 5778 break; 5779 } 5780 case DrawWidthCommand: 5781 { 5782 static char 5783 width[MaxTextExtent] = "0"; 5784 5785 static const char 5786 *WidthsMenu[] = 5787 { 5788 "1", 5789 "2", 5790 "4", 5791 "8", 5792 "16", 5793 "Dialog...", 5794 (char *) NULL, 5795 }; 5796 5797 /* 5798 Select a command from the pop-up menu. 5799 */ 5800 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu, 5801 command); 5802 if (entry < 0) 5803 break; 5804 if (entry != 5) 5805 { 5806 line_width=(unsigned int) StringToUnsignedLong( 5807 WidthsMenu[entry]); 5808 break; 5809 } 5810 (void) XDialogWidget(display,windows,"Ok","Enter line width:", 5811 width); 5812 if (*width == '\0') 5813 break; 5814 line_width=(unsigned int) StringToUnsignedLong(width); 5815 break; 5816 } 5817 case DrawUndoCommand: 5818 { 5819 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 5820 image,exception); 5821 break; 5822 } 5823 case DrawHelpCommand: 5824 { 5825 XTextViewWidget(display,resource_info,windows,MagickFalse, 5826 "Help Viewer - Image Rotation",ImageDrawHelp); 5827 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5828 break; 5829 } 5830 case DrawDismissCommand: 5831 { 5832 /* 5833 Prematurely exit. 5834 */ 5835 state|=EscapeState; 5836 state|=ExitState; 5837 break; 5838 } 5839 default: 5840 break; 5841 } 5842 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5843 continue; 5844 } 5845 switch (event.type) 5846 { 5847 case ButtonPress: 5848 { 5849 if (event.xbutton.button != Button1) 5850 break; 5851 if (event.xbutton.window != windows->image.id) 5852 break; 5853 /* 5854 exit loop. 5855 */ 5856 x=event.xbutton.x; 5857 y=event.xbutton.y; 5858 state|=ExitState; 5859 break; 5860 } 5861 case ButtonRelease: 5862 break; 5863 case Expose: 5864 break; 5865 case KeyPress: 5866 { 5867 KeySym 5868 key_symbol; 5869 5870 if (event.xkey.window != windows->image.id) 5871 break; 5872 /* 5873 Respond to a user key press. 5874 */ 5875 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5876 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5877 switch ((int) key_symbol) 5878 { 5879 case XK_Escape: 5880 case XK_F20: 5881 { 5882 /* 5883 Prematurely exit. 5884 */ 5885 state|=EscapeState; 5886 state|=ExitState; 5887 break; 5888 } 5889 case XK_F1: 5890 case XK_Help: 5891 { 5892 XTextViewWidget(display,resource_info,windows,MagickFalse, 5893 "Help Viewer - Image Rotation",ImageDrawHelp); 5894 break; 5895 } 5896 default: 5897 { 5898 (void) XBell(display,0); 5899 break; 5900 } 5901 } 5902 break; 5903 } 5904 case MotionNotify: 5905 { 5906 /* 5907 Map and unmap Info widget as text cursor crosses its boundaries. 5908 */ 5909 x=event.xmotion.x; 5910 y=event.xmotion.y; 5911 if (windows->info.mapped != MagickFalse) 5912 { 5913 if ((x < (int) (windows->info.x+windows->info.width)) && 5914 (y < (int) (windows->info.y+windows->info.height))) 5915 (void) XWithdrawWindow(display,windows->info.id, 5916 windows->info.screen); 5917 } 5918 else 5919 if ((x > (int) (windows->info.x+windows->info.width)) || 5920 (y > (int) (windows->info.y+windows->info.height))) 5921 (void) XMapWindow(display,windows->info.id); 5922 break; 5923 } 5924 } 5925 } while ((state & ExitState) == 0); 5926 (void) XSelectInput(display,windows->image.id, 5927 windows->image.attributes.event_mask); 5928 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 5929 if ((state & EscapeState) != 0) 5930 break; 5931 /* 5932 Draw element as pointer moves until the button is released. 5933 */ 5934 distance=0; 5935 degrees=0.0; 5936 line_info.x1=x; 5937 line_info.y1=y; 5938 line_info.x2=x; 5939 line_info.y2=y; 5940 rectangle_info.x=(ssize_t) x; 5941 rectangle_info.y=(ssize_t) y; 5942 rectangle_info.width=0; 5943 rectangle_info.height=0; 5944 number_coordinates=1; 5945 coordinate_info->x=x; 5946 coordinate_info->y=y; 5947 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 5948 state=DefaultState; 5949 do 5950 { 5951 switch (element) 5952 { 5953 case PointElement: 5954 default: 5955 { 5956 if (number_coordinates > 1) 5957 { 5958 (void) XDrawLines(display,windows->image.id, 5959 windows->image.highlight_context,coordinate_info, 5960 number_coordinates,CoordModeOrigin); 5961 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d", 5962 coordinate_info[number_coordinates-1].x, 5963 coordinate_info[number_coordinates-1].y); 5964 XInfoWidget(display,windows,text); 5965 } 5966 break; 5967 } 5968 case LineElement: 5969 { 5970 if (distance > 9) 5971 { 5972 /* 5973 Display angle of the line. 5974 */ 5975 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 5976 line_info.y1),(double) (line_info.x2-line_info.x1))); 5977 (void) FormatLocaleString(text,MaxTextExtent," %g", 5978 (double) degrees); 5979 XInfoWidget(display,windows,text); 5980 XHighlightLine(display,windows->image.id, 5981 windows->image.highlight_context,&line_info); 5982 } 5983 else 5984 if (windows->info.mapped != MagickFalse) 5985 (void) XWithdrawWindow(display,windows->info.id, 5986 windows->info.screen); 5987 break; 5988 } 5989 case RectangleElement: 5990 case FillRectangleElement: 5991 { 5992 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5993 { 5994 /* 5995 Display info and draw drawing rectangle. 5996 */ 5997 (void) FormatLocaleString(text,MaxTextExtent, 5998 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5999 (double) rectangle_info.height,(double) rectangle_info.x, 6000 (double) rectangle_info.y); 6001 XInfoWidget(display,windows,text); 6002 XHighlightRectangle(display,windows->image.id, 6003 windows->image.highlight_context,&rectangle_info); 6004 } 6005 else 6006 if (windows->info.mapped != MagickFalse) 6007 (void) XWithdrawWindow(display,windows->info.id, 6008 windows->info.screen); 6009 break; 6010 } 6011 case CircleElement: 6012 case FillCircleElement: 6013 case EllipseElement: 6014 case FillEllipseElement: 6015 { 6016 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6017 { 6018 /* 6019 Display info and draw drawing rectangle. 6020 */ 6021 (void) FormatLocaleString(text,MaxTextExtent, 6022 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 6023 (double) rectangle_info.height,(double) rectangle_info.x, 6024 (double) rectangle_info.y); 6025 XInfoWidget(display,windows,text); 6026 XHighlightEllipse(display,windows->image.id, 6027 windows->image.highlight_context,&rectangle_info); 6028 } 6029 else 6030 if (windows->info.mapped != MagickFalse) 6031 (void) XWithdrawWindow(display,windows->info.id, 6032 windows->info.screen); 6033 break; 6034 } 6035 case PolygonElement: 6036 case FillPolygonElement: 6037 { 6038 if (number_coordinates > 1) 6039 (void) XDrawLines(display,windows->image.id, 6040 windows->image.highlight_context,coordinate_info, 6041 number_coordinates,CoordModeOrigin); 6042 if (distance > 9) 6043 { 6044 /* 6045 Display angle of the line. 6046 */ 6047 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 6048 line_info.y1),(double) (line_info.x2-line_info.x1))); 6049 (void) FormatLocaleString(text,MaxTextExtent," %g", 6050 (double) degrees); 6051 XInfoWidget(display,windows,text); 6052 XHighlightLine(display,windows->image.id, 6053 windows->image.highlight_context,&line_info); 6054 } 6055 else 6056 if (windows->info.mapped != MagickFalse) 6057 (void) XWithdrawWindow(display,windows->info.id, 6058 windows->info.screen); 6059 break; 6060 } 6061 } 6062 /* 6063 Wait for next event. 6064 */ 6065 XScreenEvent(display,windows,&event,exception); 6066 switch (element) 6067 { 6068 case PointElement: 6069 default: 6070 { 6071 if (number_coordinates > 1) 6072 (void) XDrawLines(display,windows->image.id, 6073 windows->image.highlight_context,coordinate_info, 6074 number_coordinates,CoordModeOrigin); 6075 break; 6076 } 6077 case LineElement: 6078 { 6079 if (distance > 9) 6080 XHighlightLine(display,windows->image.id, 6081 windows->image.highlight_context,&line_info); 6082 break; 6083 } 6084 case RectangleElement: 6085 case FillRectangleElement: 6086 { 6087 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6088 XHighlightRectangle(display,windows->image.id, 6089 windows->image.highlight_context,&rectangle_info); 6090 break; 6091 } 6092 case CircleElement: 6093 case FillCircleElement: 6094 case EllipseElement: 6095 case FillEllipseElement: 6096 { 6097 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6098 XHighlightEllipse(display,windows->image.id, 6099 windows->image.highlight_context,&rectangle_info); 6100 break; 6101 } 6102 case PolygonElement: 6103 case FillPolygonElement: 6104 { 6105 if (number_coordinates > 1) 6106 (void) XDrawLines(display,windows->image.id, 6107 windows->image.highlight_context,coordinate_info, 6108 number_coordinates,CoordModeOrigin); 6109 if (distance > 9) 6110 XHighlightLine(display,windows->image.id, 6111 windows->image.highlight_context,&line_info); 6112 break; 6113 } 6114 } 6115 switch (event.type) 6116 { 6117 case ButtonPress: 6118 break; 6119 case ButtonRelease: 6120 { 6121 /* 6122 User has committed to element. 6123 */ 6124 line_info.x2=event.xbutton.x; 6125 line_info.y2=event.xbutton.y; 6126 rectangle_info.x=(ssize_t) event.xbutton.x; 6127 rectangle_info.y=(ssize_t) event.xbutton.y; 6128 coordinate_info[number_coordinates].x=event.xbutton.x; 6129 coordinate_info[number_coordinates].y=event.xbutton.y; 6130 if (((element != PolygonElement) && 6131 (element != FillPolygonElement)) || (distance <= 9)) 6132 { 6133 state|=ExitState; 6134 break; 6135 } 6136 number_coordinates++; 6137 if (number_coordinates < (int) max_coordinates) 6138 { 6139 line_info.x1=event.xbutton.x; 6140 line_info.y1=event.xbutton.y; 6141 break; 6142 } 6143 max_coordinates<<=1; 6144 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6145 max_coordinates,sizeof(*coordinate_info)); 6146 if (coordinate_info == (XPoint *) NULL) 6147 (void) ThrowMagickException(exception,GetMagickModule(), 6148 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6149 break; 6150 } 6151 case Expose: 6152 break; 6153 case MotionNotify: 6154 { 6155 if (event.xmotion.window != windows->image.id) 6156 break; 6157 if (element != PointElement) 6158 { 6159 line_info.x2=event.xmotion.x; 6160 line_info.y2=event.xmotion.y; 6161 rectangle_info.x=(ssize_t) event.xmotion.x; 6162 rectangle_info.y=(ssize_t) event.xmotion.y; 6163 break; 6164 } 6165 coordinate_info[number_coordinates].x=event.xbutton.x; 6166 coordinate_info[number_coordinates].y=event.xbutton.y; 6167 number_coordinates++; 6168 if (number_coordinates < (int) max_coordinates) 6169 break; 6170 max_coordinates<<=1; 6171 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6172 max_coordinates,sizeof(*coordinate_info)); 6173 if (coordinate_info == (XPoint *) NULL) 6174 (void) ThrowMagickException(exception,GetMagickModule(), 6175 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6176 break; 6177 } 6178 default: 6179 break; 6180 } 6181 /* 6182 Check boundary conditions. 6183 */ 6184 if (line_info.x2 < 0) 6185 line_info.x2=0; 6186 else 6187 if (line_info.x2 > (int) windows->image.width) 6188 line_info.x2=(short) windows->image.width; 6189 if (line_info.y2 < 0) 6190 line_info.y2=0; 6191 else 6192 if (line_info.y2 > (int) windows->image.height) 6193 line_info.y2=(short) windows->image.height; 6194 distance=(unsigned int) 6195 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+ 6196 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1))); 6197 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) || 6198 ((state & ExitState) != 0)) 6199 { 6200 if (rectangle_info.x < 0) 6201 rectangle_info.x=0; 6202 else 6203 if (rectangle_info.x > (ssize_t) windows->image.width) 6204 rectangle_info.x=(ssize_t) windows->image.width; 6205 if ((int) rectangle_info.x < x) 6206 rectangle_info.width=(unsigned int) (x-rectangle_info.x); 6207 else 6208 { 6209 rectangle_info.width=(unsigned int) (rectangle_info.x-x); 6210 rectangle_info.x=(ssize_t) x; 6211 } 6212 if (rectangle_info.y < 0) 6213 rectangle_info.y=0; 6214 else 6215 if (rectangle_info.y > (ssize_t) windows->image.height) 6216 rectangle_info.y=(ssize_t) windows->image.height; 6217 if ((int) rectangle_info.y < y) 6218 rectangle_info.height=(unsigned int) (y-rectangle_info.y); 6219 else 6220 { 6221 rectangle_info.height=(unsigned int) (rectangle_info.y-y); 6222 rectangle_info.y=(ssize_t) y; 6223 } 6224 } 6225 } while ((state & ExitState) == 0); 6226 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 6227 if ((element == PointElement) || (element == PolygonElement) || 6228 (element == FillPolygonElement)) 6229 { 6230 /* 6231 Determine polygon bounding box. 6232 */ 6233 rectangle_info.x=(ssize_t) coordinate_info->x; 6234 rectangle_info.y=(ssize_t) coordinate_info->y; 6235 x=coordinate_info->x; 6236 y=coordinate_info->y; 6237 for (i=1; i < number_coordinates; i++) 6238 { 6239 if (coordinate_info[i].x > x) 6240 x=coordinate_info[i].x; 6241 if (coordinate_info[i].y > y) 6242 y=coordinate_info[i].y; 6243 if ((ssize_t) coordinate_info[i].x < rectangle_info.x) 6244 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0); 6245 if ((ssize_t) coordinate_info[i].y < rectangle_info.y) 6246 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0); 6247 } 6248 rectangle_info.width=(size_t) (x-rectangle_info.x); 6249 rectangle_info.height=(size_t) (y-rectangle_info.y); 6250 for (i=0; i < number_coordinates; i++) 6251 { 6252 coordinate_info[i].x-=rectangle_info.x; 6253 coordinate_info[i].y-=rectangle_info.y; 6254 } 6255 } 6256 else 6257 if (distance <= 9) 6258 continue; 6259 else 6260 if ((element == RectangleElement) || 6261 (element == CircleElement) || (element == EllipseElement)) 6262 { 6263 rectangle_info.width--; 6264 rectangle_info.height--; 6265 } 6266 /* 6267 Drawing is relative to image configuration. 6268 */ 6269 draw_info.x=(int) rectangle_info.x; 6270 draw_info.y=(int) rectangle_info.y; 6271 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand, 6272 image,exception); 6273 width=(unsigned int) (*image)->columns; 6274 height=(unsigned int) (*image)->rows; 6275 x=0; 6276 y=0; 6277 if (windows->image.crop_geometry != (char *) NULL) 6278 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 6279 draw_info.x+=windows->image.x-(line_width/2); 6280 if (draw_info.x < 0) 6281 draw_info.x=0; 6282 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width); 6283 draw_info.y+=windows->image.y-(line_width/2); 6284 if (draw_info.y < 0) 6285 draw_info.y=0; 6286 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height; 6287 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1); 6288 if (draw_info.width > (unsigned int) (*image)->columns) 6289 draw_info.width=(unsigned int) (*image)->columns; 6290 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1); 6291 if (draw_info.height > (unsigned int) (*image)->rows) 6292 draw_info.height=(unsigned int) (*image)->rows; 6293 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d", 6294 width*draw_info.width/windows->image.ximage->width, 6295 height*draw_info.height/windows->image.ximage->height, 6296 draw_info.x+x,draw_info.y+y); 6297 /* 6298 Initialize drawing attributes. 6299 */ 6300 draw_info.degrees=0.0; 6301 draw_info.element=element; 6302 draw_info.stipple=stipple; 6303 draw_info.line_width=line_width; 6304 draw_info.line_info=line_info; 6305 if (line_info.x1 > (int) (line_width/2)) 6306 draw_info.line_info.x1=(short) line_width/2; 6307 if (line_info.y1 > (int) (line_width/2)) 6308 draw_info.line_info.y1=(short) line_width/2; 6309 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2)); 6310 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2)); 6311 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0)) 6312 { 6313 draw_info.line_info.x2=(-draw_info.line_info.x2); 6314 draw_info.line_info.y2=(-draw_info.line_info.y2); 6315 } 6316 if (draw_info.line_info.x2 < 0) 6317 { 6318 draw_info.line_info.x2=(-draw_info.line_info.x2); 6319 Swap(draw_info.line_info.x1,draw_info.line_info.x2); 6320 } 6321 if (draw_info.line_info.y2 < 0) 6322 { 6323 draw_info.line_info.y2=(-draw_info.line_info.y2); 6324 Swap(draw_info.line_info.y1,draw_info.line_info.y2); 6325 } 6326 draw_info.rectangle_info=rectangle_info; 6327 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2)) 6328 draw_info.rectangle_info.x=(ssize_t) line_width/2; 6329 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2)) 6330 draw_info.rectangle_info.y=(ssize_t) line_width/2; 6331 draw_info.number_coordinates=(unsigned int) number_coordinates; 6332 draw_info.coordinate_info=coordinate_info; 6333 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 6334 /* 6335 Draw element on image. 6336 */ 6337 XSetCursorState(display,windows,MagickTrue); 6338 XCheckRefreshWindows(display,windows); 6339 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception); 6340 XSetCursorState(display,windows,MagickFalse); 6341 /* 6342 Update image colormap and return to image drawing. 6343 */ 6344 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6345 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6346 } 6347 XSetCursorState(display,windows,MagickFalse); 6348 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info); 6349 return(status != 0 ? MagickTrue : MagickFalse); 6350} 6351 6352/* 6353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6354% % 6355% % 6356% % 6357+ X D r a w P a n R e c t a n g l e % 6358% % 6359% % 6360% % 6361%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6362% 6363% XDrawPanRectangle() draws a rectangle in the pan window. The pan window 6364% displays a zoom image and the rectangle shows which portion of the image is 6365% displayed in the Image window. 6366% 6367% The format of the XDrawPanRectangle method is: 6368% 6369% XDrawPanRectangle(Display *display,XWindows *windows) 6370% 6371% A description of each parameter follows: 6372% 6373% o display: Specifies a connection to an X server; returned from 6374% XOpenDisplay. 6375% 6376% o windows: Specifies a pointer to a XWindows structure. 6377% 6378*/ 6379static void XDrawPanRectangle(Display *display,XWindows *windows) 6380{ 6381 MagickRealType 6382 scale_factor; 6383 6384 RectangleInfo 6385 highlight_info; 6386 6387 /* 6388 Determine dimensions of the panning rectangle. 6389 */ 6390 scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width; 6391 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5); 6392 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5); 6393 scale_factor=(MagickRealType) 6394 windows->pan.height/windows->image.ximage->height; 6395 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5); 6396 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5); 6397 /* 6398 Display the panning rectangle. 6399 */ 6400 (void) XClearWindow(display,windows->pan.id); 6401 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context, 6402 &highlight_info); 6403} 6404 6405/* 6406%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6407% % 6408% % 6409% % 6410+ X I m a g e C a c h e % 6411% % 6412% % 6413% % 6414%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6415% 6416% XImageCache() handles the creation, manipulation, and destruction of the 6417% image cache (undo and redo buffers). 6418% 6419% The format of the XImageCache method is: 6420% 6421% void XImageCache(Display *display,XResourceInfo *resource_info, 6422% XWindows *windows,const CommandType command,Image **image, 6423% ExceptionInfo *exception) 6424% 6425% A description of each parameter follows: 6426% 6427% o display: Specifies a connection to an X server; returned from 6428% XOpenDisplay. 6429% 6430% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6431% 6432% o windows: Specifies a pointer to a XWindows structure. 6433% 6434% o command: Specifies a command to perform. 6435% 6436% o image: the image; XImageCache may transform the image and return a new 6437% image pointer. 6438% 6439% o exception: return any errors or warnings in this structure. 6440% 6441*/ 6442static void XImageCache(Display *display,XResourceInfo *resource_info, 6443 XWindows *windows,const CommandType command,Image **image, 6444 ExceptionInfo *exception) 6445{ 6446 Image 6447 *cache_image; 6448 6449 static Image 6450 *redo_image = (Image *) NULL, 6451 *undo_image = (Image *) NULL; 6452 6453 switch (command) 6454 { 6455 case FreeBuffersCommand: 6456 { 6457 /* 6458 Free memory from the undo and redo cache. 6459 */ 6460 while (undo_image != (Image *) NULL) 6461 { 6462 cache_image=undo_image; 6463 undo_image=GetPreviousImageInList(undo_image); 6464 cache_image->list=DestroyImage(cache_image->list); 6465 cache_image=DestroyImage(cache_image); 6466 } 6467 undo_image=NewImageList(); 6468 if (redo_image != (Image *) NULL) 6469 redo_image=DestroyImage(redo_image); 6470 redo_image=NewImageList(); 6471 return; 6472 } 6473 case UndoCommand: 6474 { 6475 char 6476 image_geometry[MaxTextExtent]; 6477 6478 /* 6479 Undo the last image transformation. 6480 */ 6481 if (undo_image == (Image *) NULL) 6482 { 6483 (void) XBell(display,0); 6484 return; 6485 } 6486 cache_image=undo_image; 6487 undo_image=GetPreviousImageInList(undo_image); 6488 windows->image.window_changes.width=(int) cache_image->columns; 6489 windows->image.window_changes.height=(int) cache_image->rows; 6490 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 6491 windows->image.ximage->width,windows->image.ximage->height); 6492 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 6493 exception); 6494 if (windows->image.crop_geometry != (char *) NULL) 6495 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 6496 windows->image.crop_geometry); 6497 windows->image.crop_geometry=cache_image->geometry; 6498 if (redo_image != (Image *) NULL) 6499 redo_image=DestroyImage(redo_image); 6500 redo_image=(*image); 6501 *image=cache_image->list; 6502 cache_image=DestroyImage(cache_image); 6503 if (windows->image.orphan != MagickFalse) 6504 return; 6505 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6506 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6507 return; 6508 } 6509 case CutCommand: 6510 case PasteCommand: 6511 case ApplyCommand: 6512 case HalfSizeCommand: 6513 case OriginalSizeCommand: 6514 case DoubleSizeCommand: 6515 case ResizeCommand: 6516 case TrimCommand: 6517 case CropCommand: 6518 case ChopCommand: 6519 case FlipCommand: 6520 case FlopCommand: 6521 case RotateRightCommand: 6522 case RotateLeftCommand: 6523 case RotateCommand: 6524 case ShearCommand: 6525 case RollCommand: 6526 case NegateCommand: 6527 case ContrastStretchCommand: 6528 case SigmoidalContrastCommand: 6529 case NormalizeCommand: 6530 case EqualizeCommand: 6531 case HueCommand: 6532 case SaturationCommand: 6533 case BrightnessCommand: 6534 case GammaCommand: 6535 case SpiffCommand: 6536 case DullCommand: 6537 case GrayscaleCommand: 6538 case MapCommand: 6539 case QuantizeCommand: 6540 case DespeckleCommand: 6541 case EmbossCommand: 6542 case ReduceNoiseCommand: 6543 case AddNoiseCommand: 6544 case SharpenCommand: 6545 case BlurCommand: 6546 case ThresholdCommand: 6547 case EdgeDetectCommand: 6548 case SpreadCommand: 6549 case ShadeCommand: 6550 case RaiseCommand: 6551 case SegmentCommand: 6552 case SolarizeCommand: 6553 case SepiaToneCommand: 6554 case SwirlCommand: 6555 case ImplodeCommand: 6556 case VignetteCommand: 6557 case WaveCommand: 6558 case OilPaintCommand: 6559 case CharcoalDrawCommand: 6560 case AnnotateCommand: 6561 case AddBorderCommand: 6562 case AddFrameCommand: 6563 case CompositeCommand: 6564 case CommentCommand: 6565 case LaunchCommand: 6566 case RegionofInterestCommand: 6567 case SaveToUndoBufferCommand: 6568 case RedoCommand: 6569 { 6570 Image 6571 *previous_image; 6572 6573 ssize_t 6574 bytes; 6575 6576 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo)); 6577 if (undo_image != (Image *) NULL) 6578 { 6579 /* 6580 Ensure the undo cache has enough memory available. 6581 */ 6582 previous_image=undo_image; 6583 while (previous_image != (Image *) NULL) 6584 { 6585 bytes+=previous_image->list->columns*previous_image->list->rows* 6586 sizeof(PixelInfo); 6587 if (bytes <= (ssize_t) (resource_info->undo_cache << 20)) 6588 { 6589 previous_image=GetPreviousImageInList(previous_image); 6590 continue; 6591 } 6592 bytes-=previous_image->list->columns*previous_image->list->rows* 6593 sizeof(PixelInfo); 6594 if (previous_image == undo_image) 6595 undo_image=NewImageList(); 6596 else 6597 previous_image->next->previous=NewImageList(); 6598 break; 6599 } 6600 while (previous_image != (Image *) NULL) 6601 { 6602 /* 6603 Delete any excess memory from undo cache. 6604 */ 6605 cache_image=previous_image; 6606 previous_image=GetPreviousImageInList(previous_image); 6607 cache_image->list=DestroyImage(cache_image->list); 6608 cache_image=DestroyImage(cache_image); 6609 } 6610 } 6611 if (bytes > (ssize_t) (resource_info->undo_cache << 20)) 6612 break; 6613 /* 6614 Save image before transformations are applied. 6615 */ 6616 cache_image=AcquireImage((ImageInfo *) NULL,exception); 6617 if (cache_image == (Image *) NULL) 6618 break; 6619 XSetCursorState(display,windows,MagickTrue); 6620 XCheckRefreshWindows(display,windows); 6621 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception); 6622 XSetCursorState(display,windows,MagickFalse); 6623 if (cache_image->list == (Image *) NULL) 6624 { 6625 cache_image=DestroyImage(cache_image); 6626 break; 6627 } 6628 cache_image->columns=(size_t) windows->image.ximage->width; 6629 cache_image->rows=(size_t) windows->image.ximage->height; 6630 cache_image->geometry=windows->image.crop_geometry; 6631 if (windows->image.crop_geometry != (char *) NULL) 6632 { 6633 cache_image->geometry=AcquireString((char *) NULL); 6634 (void) CopyMagickString(cache_image->geometry, 6635 windows->image.crop_geometry,MaxTextExtent); 6636 } 6637 if (undo_image == (Image *) NULL) 6638 { 6639 undo_image=cache_image; 6640 break; 6641 } 6642 undo_image->next=cache_image; 6643 undo_image->next->previous=undo_image; 6644 undo_image=undo_image->next; 6645 break; 6646 } 6647 default: 6648 break; 6649 } 6650 if (command == RedoCommand) 6651 { 6652 /* 6653 Redo the last image transformation. 6654 */ 6655 if (redo_image == (Image *) NULL) 6656 { 6657 (void) XBell(display,0); 6658 return; 6659 } 6660 windows->image.window_changes.width=(int) redo_image->columns; 6661 windows->image.window_changes.height=(int) redo_image->rows; 6662 if (windows->image.crop_geometry != (char *) NULL) 6663 windows->image.crop_geometry=(char *) 6664 RelinquishMagickMemory(windows->image.crop_geometry); 6665 windows->image.crop_geometry=redo_image->geometry; 6666 *image=DestroyImage(*image); 6667 *image=redo_image; 6668 redo_image=NewImageList(); 6669 if (windows->image.orphan != MagickFalse) 6670 return; 6671 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6672 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6673 return; 6674 } 6675 if (command != InfoCommand) 6676 return; 6677 /* 6678 Display image info. 6679 */ 6680 XSetCursorState(display,windows,MagickTrue); 6681 XCheckRefreshWindows(display,windows); 6682 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception); 6683 XSetCursorState(display,windows,MagickFalse); 6684} 6685 6686/* 6687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6688% % 6689% % 6690% % 6691+ X I m a g e W i n d o w C o m m a n d % 6692% % 6693% % 6694% % 6695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6696% 6697% XImageWindowCommand() makes a transform to the image or Image window as 6698% specified by a user menu button or keyboard command. 6699% 6700% The format of the XImageWindowCommand method is: 6701% 6702% CommandType XImageWindowCommand(Display *display, 6703% XResourceInfo *resource_info,XWindows *windows, 6704% const MagickStatusType state,KeySym key_symbol,Image **image, 6705% ExceptionInfo *exception) 6706% 6707% A description of each parameter follows: 6708% 6709% o nexus: Method XImageWindowCommand returns an image when the 6710% user chooses 'Open Image' from the command menu. Otherwise a null 6711% image is returned. 6712% 6713% o display: Specifies a connection to an X server; returned from 6714% XOpenDisplay. 6715% 6716% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6717% 6718% o windows: Specifies a pointer to a XWindows structure. 6719% 6720% o state: key mask. 6721% 6722% o key_symbol: Specifies a command to perform. 6723% 6724% o image: the image; XImageWIndowCommand may transform the image and 6725% return a new image pointer. 6726% 6727% o exception: return any errors or warnings in this structure. 6728% 6729*/ 6730static CommandType XImageWindowCommand(Display *display, 6731 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state, 6732 KeySym key_symbol,Image **image,ExceptionInfo *exception) 6733{ 6734 static char 6735 delta[MaxTextExtent] = ""; 6736 6737 static const char 6738 Digits[] = "01234567890"; 6739 6740 static KeySym 6741 last_symbol = XK_0; 6742 6743 if ((key_symbol >= XK_0) && (key_symbol <= XK_9)) 6744 { 6745 if (((last_symbol < XK_0) || (last_symbol > XK_9))) 6746 { 6747 *delta='\0'; 6748 resource_info->quantum=1; 6749 } 6750 last_symbol=key_symbol; 6751 delta[strlen(delta)+1]='\0'; 6752 delta[strlen(delta)]=Digits[key_symbol-XK_0]; 6753 resource_info->quantum=StringToLong(delta); 6754 return(NullCommand); 6755 } 6756 last_symbol=key_symbol; 6757 if (resource_info->immutable) 6758 { 6759 /* 6760 Virtual image window has a restricted command set. 6761 */ 6762 switch (key_symbol) 6763 { 6764 case XK_question: 6765 return(InfoCommand); 6766 case XK_p: 6767 case XK_Print: 6768 return(PrintCommand); 6769 case XK_space: 6770 return(NextCommand); 6771 case XK_q: 6772 case XK_Escape: 6773 return(QuitCommand); 6774 default: 6775 break; 6776 } 6777 return(NullCommand); 6778 } 6779 switch ((int) key_symbol) 6780 { 6781 case XK_o: 6782 { 6783 if ((state & ControlMask) == 0) 6784 break; 6785 return(OpenCommand); 6786 } 6787 case XK_space: 6788 return(NextCommand); 6789 case XK_BackSpace: 6790 return(FormerCommand); 6791 case XK_s: 6792 { 6793 if ((state & Mod1Mask) != 0) 6794 return(SwirlCommand); 6795 if ((state & ControlMask) == 0) 6796 return(ShearCommand); 6797 return(SaveCommand); 6798 } 6799 case XK_p: 6800 case XK_Print: 6801 { 6802 if ((state & Mod1Mask) != 0) 6803 return(OilPaintCommand); 6804 if ((state & Mod4Mask) != 0) 6805 return(ColorCommand); 6806 if ((state & ControlMask) == 0) 6807 return(NullCommand); 6808 return(PrintCommand); 6809 } 6810 case XK_d: 6811 { 6812 if ((state & Mod4Mask) != 0) 6813 return(DrawCommand); 6814 if ((state & ControlMask) == 0) 6815 return(NullCommand); 6816 return(DeleteCommand); 6817 } 6818 case XK_Select: 6819 { 6820 if ((state & ControlMask) == 0) 6821 return(NullCommand); 6822 return(SelectCommand); 6823 } 6824 case XK_n: 6825 { 6826 if ((state & ControlMask) == 0) 6827 return(NullCommand); 6828 return(NewCommand); 6829 } 6830 case XK_q: 6831 case XK_Escape: 6832 return(QuitCommand); 6833 case XK_z: 6834 case XK_Undo: 6835 { 6836 if ((state & ControlMask) == 0) 6837 return(NullCommand); 6838 return(UndoCommand); 6839 } 6840 case XK_r: 6841 case XK_Redo: 6842 { 6843 if ((state & ControlMask) == 0) 6844 return(RollCommand); 6845 return(RedoCommand); 6846 } 6847 case XK_x: 6848 { 6849 if ((state & ControlMask) == 0) 6850 return(NullCommand); 6851 return(CutCommand); 6852 } 6853 case XK_c: 6854 { 6855 if ((state & Mod1Mask) != 0) 6856 return(CharcoalDrawCommand); 6857 if ((state & ControlMask) == 0) 6858 return(CropCommand); 6859 return(CopyCommand); 6860 } 6861 case XK_v: 6862 case XK_Insert: 6863 { 6864 if ((state & Mod4Mask) != 0) 6865 return(CompositeCommand); 6866 if ((state & ControlMask) == 0) 6867 return(FlipCommand); 6868 return(PasteCommand); 6869 } 6870 case XK_less: 6871 return(HalfSizeCommand); 6872 case XK_minus: 6873 return(OriginalSizeCommand); 6874 case XK_greater: 6875 return(DoubleSizeCommand); 6876 case XK_percent: 6877 return(ResizeCommand); 6878 case XK_at: 6879 return(RefreshCommand); 6880 case XK_bracketleft: 6881 return(ChopCommand); 6882 case XK_h: 6883 return(FlopCommand); 6884 case XK_slash: 6885 return(RotateRightCommand); 6886 case XK_backslash: 6887 return(RotateLeftCommand); 6888 case XK_asterisk: 6889 return(RotateCommand); 6890 case XK_t: 6891 return(TrimCommand); 6892 case XK_H: 6893 return(HueCommand); 6894 case XK_S: 6895 return(SaturationCommand); 6896 case XK_L: 6897 return(BrightnessCommand); 6898 case XK_G: 6899 return(GammaCommand); 6900 case XK_C: 6901 return(SpiffCommand); 6902 case XK_Z: 6903 return(DullCommand); 6904 case XK_N: 6905 return(NormalizeCommand); 6906 case XK_equal: 6907 return(EqualizeCommand); 6908 case XK_asciitilde: 6909 return(NegateCommand); 6910 case XK_period: 6911 return(GrayscaleCommand); 6912 case XK_numbersign: 6913 return(QuantizeCommand); 6914 case XK_F2: 6915 return(DespeckleCommand); 6916 case XK_F3: 6917 return(EmbossCommand); 6918 case XK_F4: 6919 return(ReduceNoiseCommand); 6920 case XK_F5: 6921 return(AddNoiseCommand); 6922 case XK_F6: 6923 return(SharpenCommand); 6924 case XK_F7: 6925 return(BlurCommand); 6926 case XK_F8: 6927 return(ThresholdCommand); 6928 case XK_F9: 6929 return(EdgeDetectCommand); 6930 case XK_F10: 6931 return(SpreadCommand); 6932 case XK_F11: 6933 return(ShadeCommand); 6934 case XK_F12: 6935 return(RaiseCommand); 6936 case XK_F13: 6937 return(SegmentCommand); 6938 case XK_i: 6939 { 6940 if ((state & Mod1Mask) == 0) 6941 return(NullCommand); 6942 return(ImplodeCommand); 6943 } 6944 case XK_w: 6945 { 6946 if ((state & Mod1Mask) == 0) 6947 return(NullCommand); 6948 return(WaveCommand); 6949 } 6950 case XK_m: 6951 { 6952 if ((state & Mod4Mask) == 0) 6953 return(NullCommand); 6954 return(MatteCommand); 6955 } 6956 case XK_b: 6957 { 6958 if ((state & Mod4Mask) == 0) 6959 return(NullCommand); 6960 return(AddBorderCommand); 6961 } 6962 case XK_f: 6963 { 6964 if ((state & Mod4Mask) == 0) 6965 return(NullCommand); 6966 return(AddFrameCommand); 6967 } 6968 case XK_exclam: 6969 { 6970 if ((state & Mod4Mask) == 0) 6971 return(NullCommand); 6972 return(CommentCommand); 6973 } 6974 case XK_a: 6975 { 6976 if ((state & Mod1Mask) != 0) 6977 return(ApplyCommand); 6978 if ((state & Mod4Mask) != 0) 6979 return(AnnotateCommand); 6980 if ((state & ControlMask) == 0) 6981 return(NullCommand); 6982 return(RegionofInterestCommand); 6983 } 6984 case XK_question: 6985 return(InfoCommand); 6986 case XK_plus: 6987 return(ZoomCommand); 6988 case XK_P: 6989 { 6990 if ((state & ShiftMask) == 0) 6991 return(NullCommand); 6992 return(ShowPreviewCommand); 6993 } 6994 case XK_Execute: 6995 return(LaunchCommand); 6996 case XK_F1: 6997 return(HelpCommand); 6998 case XK_Find: 6999 return(BrowseDocumentationCommand); 7000 case XK_Menu: 7001 { 7002 (void) XMapRaised(display,windows->command.id); 7003 return(NullCommand); 7004 } 7005 case XK_Next: 7006 case XK_Prior: 7007 case XK_Home: 7008 case XK_KP_Home: 7009 { 7010 XTranslateImage(display,windows,*image,key_symbol); 7011 return(NullCommand); 7012 } 7013 case XK_Up: 7014 case XK_KP_Up: 7015 case XK_Down: 7016 case XK_KP_Down: 7017 case XK_Left: 7018 case XK_KP_Left: 7019 case XK_Right: 7020 case XK_KP_Right: 7021 { 7022 if ((state & Mod1Mask) != 0) 7023 { 7024 RectangleInfo 7025 crop_info; 7026 7027 /* 7028 Trim one pixel from edge of image. 7029 */ 7030 crop_info.x=0; 7031 crop_info.y=0; 7032 crop_info.width=(size_t) windows->image.ximage->width; 7033 crop_info.height=(size_t) windows->image.ximage->height; 7034 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up)) 7035 { 7036 if (resource_info->quantum >= (int) crop_info.height) 7037 resource_info->quantum=(int) crop_info.height-1; 7038 crop_info.height-=resource_info->quantum; 7039 } 7040 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down)) 7041 { 7042 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y)) 7043 resource_info->quantum=(int) (crop_info.height-crop_info.y-1); 7044 crop_info.y+=resource_info->quantum; 7045 crop_info.height-=resource_info->quantum; 7046 } 7047 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left)) 7048 { 7049 if (resource_info->quantum >= (int) crop_info.width) 7050 resource_info->quantum=(int) crop_info.width-1; 7051 crop_info.width-=resource_info->quantum; 7052 } 7053 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right)) 7054 { 7055 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x)) 7056 resource_info->quantum=(int) (crop_info.width-crop_info.x-1); 7057 crop_info.x+=resource_info->quantum; 7058 crop_info.width-=resource_info->quantum; 7059 } 7060 if ((int) (windows->image.x+windows->image.width) > 7061 (int) crop_info.width) 7062 windows->image.x=(int) (crop_info.width-windows->image.width); 7063 if ((int) (windows->image.y+windows->image.height) > 7064 (int) crop_info.height) 7065 windows->image.y=(int) (crop_info.height-windows->image.height); 7066 XSetCropGeometry(display,windows,&crop_info,*image); 7067 windows->image.window_changes.width=(int) crop_info.width; 7068 windows->image.window_changes.height=(int) crop_info.height; 7069 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None); 7070 (void) XConfigureImage(display,resource_info,windows,*image, 7071 exception); 7072 return(NullCommand); 7073 } 7074 XTranslateImage(display,windows,*image,key_symbol); 7075 return(NullCommand); 7076 } 7077 default: 7078 return(NullCommand); 7079 } 7080 return(NullCommand); 7081} 7082 7083/* 7084%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7085% % 7086% % 7087% % 7088+ X M a g i c k C o m m a n d % 7089% % 7090% % 7091% % 7092%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7093% 7094% XMagickCommand() makes a transform to the image or Image window as 7095% specified by a user menu button or keyboard command. 7096% 7097% The format of the XMagickCommand method is: 7098% 7099% Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7100% XWindows *windows,const CommandType command,Image **image, 7101% ExceptionInfo *exception) 7102% 7103% A description of each parameter follows: 7104% 7105% o display: Specifies a connection to an X server; returned from 7106% XOpenDisplay. 7107% 7108% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 7109% 7110% o windows: Specifies a pointer to a XWindows structure. 7111% 7112% o command: Specifies a command to perform. 7113% 7114% o image: the image; XMagickCommand may transform the image and return a 7115% new image pointer. 7116% 7117% o exception: return any errors or warnings in this structure. 7118% 7119*/ 7120static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7121 XWindows *windows,const CommandType command,Image **image, 7122 ExceptionInfo *exception) 7123{ 7124 char 7125 filename[MaxTextExtent], 7126 geometry[MaxTextExtent], 7127 modulate_factors[MaxTextExtent]; 7128 7129 GeometryInfo 7130 geometry_info; 7131 7132 Image 7133 *nexus; 7134 7135 ImageInfo 7136 *image_info; 7137 7138 int 7139 x, 7140 y; 7141 7142 MagickStatusType 7143 flags, 7144 status; 7145 7146 QuantizeInfo 7147 quantize_info; 7148 7149 RectangleInfo 7150 page_geometry; 7151 7152 register int 7153 i; 7154 7155 static char 7156 color[MaxTextExtent] = "gray"; 7157 7158 unsigned int 7159 height, 7160 width; 7161 7162 /* 7163 Process user command. 7164 */ 7165 XCheckRefreshWindows(display,windows); 7166 XImageCache(display,resource_info,windows,command,image,exception); 7167 nexus=NewImageList(); 7168 windows->image.window_changes.width=windows->image.ximage->width; 7169 windows->image.window_changes.height=windows->image.ximage->height; 7170 image_info=CloneImageInfo(resource_info->image_info); 7171 SetGeometryInfo(&geometry_info); 7172 GetQuantizeInfo(&quantize_info); 7173 switch (command) 7174 { 7175 case OpenCommand: 7176 { 7177 /* 7178 Load image. 7179 */ 7180 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 7181 break; 7182 } 7183 case NextCommand: 7184 { 7185 /* 7186 Display next image. 7187 */ 7188 for (i=0; i < resource_info->quantum; i++) 7189 XClientMessage(display,windows->image.id,windows->im_protocols, 7190 windows->im_next_image,CurrentTime); 7191 break; 7192 } 7193 case FormerCommand: 7194 { 7195 /* 7196 Display former image. 7197 */ 7198 for (i=0; i < resource_info->quantum; i++) 7199 XClientMessage(display,windows->image.id,windows->im_protocols, 7200 windows->im_former_image,CurrentTime); 7201 break; 7202 } 7203 case SelectCommand: 7204 { 7205 int 7206 status; 7207 7208 /* 7209 Select image. 7210 */ 7211 status=chdir(resource_info->home_directory); 7212 if (status == -1) 7213 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 7214 "UnableToOpenFile","%s",resource_info->home_directory); 7215 nexus=XOpenImage(display,resource_info,windows,MagickTrue); 7216 break; 7217 } 7218 case SaveCommand: 7219 { 7220 /* 7221 Save image. 7222 */ 7223 status=XSaveImage(display,resource_info,windows,*image,exception); 7224 if (status == MagickFalse) 7225 { 7226 char 7227 message[MaxTextExtent]; 7228 7229 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7230 exception->reason != (char *) NULL ? exception->reason : "", 7231 exception->description != (char *) NULL ? exception->description : 7232 ""); 7233 XNoticeWidget(display,windows,"Unable to save file:",message); 7234 break; 7235 } 7236 break; 7237 } 7238 case PrintCommand: 7239 { 7240 /* 7241 Print image. 7242 */ 7243 status=XPrintImage(display,resource_info,windows,*image,exception); 7244 if (status == MagickFalse) 7245 { 7246 char 7247 message[MaxTextExtent]; 7248 7249 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7250 exception->reason != (char *) NULL ? exception->reason : "", 7251 exception->description != (char *) NULL ? exception->description : 7252 ""); 7253 XNoticeWidget(display,windows,"Unable to print file:",message); 7254 break; 7255 } 7256 break; 7257 } 7258 case DeleteCommand: 7259 { 7260 static char 7261 filename[MaxTextExtent] = "\0"; 7262 7263 /* 7264 Delete image file. 7265 */ 7266 XFileBrowserWidget(display,windows,"Delete",filename); 7267 if (*filename == '\0') 7268 break; 7269 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse; 7270 if (status != MagickFalse) 7271 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7272 break; 7273 } 7274 case NewCommand: 7275 { 7276 int 7277 status; 7278 7279 static char 7280 color[MaxTextExtent] = "gray", 7281 geometry[MaxTextExtent] = "640x480"; 7282 7283 static const char 7284 *format = "gradient"; 7285 7286 /* 7287 Query user for canvas geometry. 7288 */ 7289 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7290 geometry); 7291 if (*geometry == '\0') 7292 break; 7293 if (status == 0) 7294 format="xc"; 7295 XColorBrowserWidget(display,windows,"Select",color); 7296 if (*color == '\0') 7297 break; 7298 /* 7299 Create canvas. 7300 */ 7301 (void) FormatLocaleString(image_info->filename,MaxTextExtent, 7302 "%s:%s",format,color); 7303 (void) CloneString(&image_info->size,geometry); 7304 nexus=ReadImage(image_info,exception); 7305 CatchException(exception); 7306 XClientMessage(display,windows->image.id,windows->im_protocols, 7307 windows->im_next_image,CurrentTime); 7308 break; 7309 } 7310 case VisualDirectoryCommand: 7311 { 7312 /* 7313 Visual Image directory. 7314 */ 7315 nexus=XVisualDirectoryImage(display,resource_info,windows,exception); 7316 break; 7317 } 7318 case QuitCommand: 7319 { 7320 /* 7321 exit program. 7322 */ 7323 if (resource_info->confirm_exit == MagickFalse) 7324 XClientMessage(display,windows->image.id,windows->im_protocols, 7325 windows->im_exit,CurrentTime); 7326 else 7327 { 7328 int 7329 status; 7330 7331 /* 7332 Confirm program exit. 7333 */ 7334 status=XConfirmWidget(display,windows,"Do you really want to exit", 7335 resource_info->client_name); 7336 if (status > 0) 7337 XClientMessage(display,windows->image.id,windows->im_protocols, 7338 windows->im_exit,CurrentTime); 7339 } 7340 break; 7341 } 7342 case CutCommand: 7343 { 7344 /* 7345 Cut image. 7346 */ 7347 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception); 7348 break; 7349 } 7350 case CopyCommand: 7351 { 7352 /* 7353 Copy image. 7354 */ 7355 (void) XCropImage(display,resource_info,windows,*image,CopyMode, 7356 exception); 7357 break; 7358 } 7359 case PasteCommand: 7360 { 7361 /* 7362 Paste image. 7363 */ 7364 status=XPasteImage(display,resource_info,windows,*image,exception); 7365 if (status == MagickFalse) 7366 { 7367 XNoticeWidget(display,windows,"Unable to paste X image", 7368 (*image)->filename); 7369 break; 7370 } 7371 break; 7372 } 7373 case HalfSizeCommand: 7374 { 7375 /* 7376 Half image size. 7377 */ 7378 windows->image.window_changes.width=windows->image.ximage->width/2; 7379 windows->image.window_changes.height=windows->image.ximage->height/2; 7380 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7381 break; 7382 } 7383 case OriginalSizeCommand: 7384 { 7385 /* 7386 Original image size. 7387 */ 7388 windows->image.window_changes.width=(int) (*image)->columns; 7389 windows->image.window_changes.height=(int) (*image)->rows; 7390 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7391 break; 7392 } 7393 case DoubleSizeCommand: 7394 { 7395 /* 7396 Double the image size. 7397 */ 7398 windows->image.window_changes.width=windows->image.ximage->width << 1; 7399 windows->image.window_changes.height=windows->image.ximage->height << 1; 7400 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7401 break; 7402 } 7403 case ResizeCommand: 7404 { 7405 int 7406 status; 7407 7408 size_t 7409 height, 7410 width; 7411 7412 ssize_t 7413 x, 7414 y; 7415 7416 /* 7417 Resize image. 7418 */ 7419 width=(size_t) windows->image.ximage->width; 7420 height=(size_t) windows->image.ximage->height; 7421 x=0; 7422 y=0; 7423 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0", 7424 (double) width,(double) height); 7425 status=XDialogWidget(display,windows,"Resize", 7426 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7427 if (*geometry == '\0') 7428 break; 7429 if (status == 0) 7430 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent); 7431 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7432 windows->image.window_changes.width=(int) width; 7433 windows->image.window_changes.height=(int) height; 7434 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7435 break; 7436 } 7437 case ApplyCommand: 7438 { 7439 char 7440 image_geometry[MaxTextExtent]; 7441 7442 if ((windows->image.crop_geometry == (char *) NULL) && 7443 ((int) (*image)->columns == windows->image.ximage->width) && 7444 ((int) (*image)->rows == windows->image.ximage->height)) 7445 break; 7446 /* 7447 Apply size transforms to image. 7448 */ 7449 XSetCursorState(display,windows,MagickTrue); 7450 XCheckRefreshWindows(display,windows); 7451 /* 7452 Crop and/or scale displayed image. 7453 */ 7454 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 7455 windows->image.ximage->width,windows->image.ximage->height); 7456 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 7457 exception); 7458 if (windows->image.crop_geometry != (char *) NULL) 7459 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 7460 windows->image.crop_geometry); 7461 windows->image.x=0; 7462 windows->image.y=0; 7463 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7464 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7465 break; 7466 } 7467 case RefreshCommand: 7468 { 7469 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7470 break; 7471 } 7472 case RestoreCommand: 7473 { 7474 /* 7475 Restore Image window to its original size. 7476 */ 7477 if ((windows->image.width == (unsigned int) (*image)->columns) && 7478 (windows->image.height == (unsigned int) (*image)->rows) && 7479 (windows->image.crop_geometry == (char *) NULL)) 7480 { 7481 (void) XBell(display,0); 7482 break; 7483 } 7484 windows->image.window_changes.width=(int) (*image)->columns; 7485 windows->image.window_changes.height=(int) (*image)->rows; 7486 if (windows->image.crop_geometry != (char *) NULL) 7487 { 7488 windows->image.crop_geometry=(char *) 7489 RelinquishMagickMemory(windows->image.crop_geometry); 7490 windows->image.crop_geometry=(char *) NULL; 7491 windows->image.x=0; 7492 windows->image.y=0; 7493 } 7494 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7495 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7496 break; 7497 } 7498 case CropCommand: 7499 { 7500 /* 7501 Crop image. 7502 */ 7503 (void) XCropImage(display,resource_info,windows,*image,CropMode, 7504 exception); 7505 break; 7506 } 7507 case ChopCommand: 7508 { 7509 /* 7510 Chop image. 7511 */ 7512 status=XChopImage(display,resource_info,windows,image,exception); 7513 if (status == MagickFalse) 7514 { 7515 XNoticeWidget(display,windows,"Unable to cut X image", 7516 (*image)->filename); 7517 break; 7518 } 7519 break; 7520 } 7521 case FlopCommand: 7522 { 7523 Image 7524 *flop_image; 7525 7526 /* 7527 Flop image scanlines. 7528 */ 7529 XSetCursorState(display,windows,MagickTrue); 7530 XCheckRefreshWindows(display,windows); 7531 flop_image=FlopImage(*image,exception); 7532 if (flop_image != (Image *) NULL) 7533 { 7534 *image=DestroyImage(*image); 7535 *image=flop_image; 7536 } 7537 CatchException(exception); 7538 XSetCursorState(display,windows,MagickFalse); 7539 if (windows->image.crop_geometry != (char *) NULL) 7540 { 7541 /* 7542 Flop crop geometry. 7543 */ 7544 width=(unsigned int) (*image)->columns; 7545 height=(unsigned int) (*image)->rows; 7546 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7547 &width,&height); 7548 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7549 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7550 } 7551 if (windows->image.orphan != MagickFalse) 7552 break; 7553 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7554 break; 7555 } 7556 case FlipCommand: 7557 { 7558 Image 7559 *flip_image; 7560 7561 /* 7562 Flip image scanlines. 7563 */ 7564 XSetCursorState(display,windows,MagickTrue); 7565 XCheckRefreshWindows(display,windows); 7566 flip_image=FlipImage(*image,exception); 7567 if (flip_image != (Image *) NULL) 7568 { 7569 *image=DestroyImage(*image); 7570 *image=flip_image; 7571 } 7572 CatchException(exception); 7573 XSetCursorState(display,windows,MagickFalse); 7574 if (windows->image.crop_geometry != (char *) NULL) 7575 { 7576 /* 7577 Flip crop geometry. 7578 */ 7579 width=(unsigned int) (*image)->columns; 7580 height=(unsigned int) (*image)->rows; 7581 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7582 &width,&height); 7583 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7584 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7585 } 7586 if (windows->image.orphan != MagickFalse) 7587 break; 7588 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7589 break; 7590 } 7591 case RotateRightCommand: 7592 { 7593 /* 7594 Rotate image 90 degrees clockwise. 7595 */ 7596 status=XRotateImage(display,resource_info,windows,90.0,image,exception); 7597 if (status == MagickFalse) 7598 { 7599 XNoticeWidget(display,windows,"Unable to rotate X image", 7600 (*image)->filename); 7601 break; 7602 } 7603 break; 7604 } 7605 case RotateLeftCommand: 7606 { 7607 /* 7608 Rotate image 90 degrees counter-clockwise. 7609 */ 7610 status=XRotateImage(display,resource_info,windows,-90.0,image,exception); 7611 if (status == MagickFalse) 7612 { 7613 XNoticeWidget(display,windows,"Unable to rotate X image", 7614 (*image)->filename); 7615 break; 7616 } 7617 break; 7618 } 7619 case RotateCommand: 7620 { 7621 /* 7622 Rotate image. 7623 */ 7624 status=XRotateImage(display,resource_info,windows,0.0,image,exception); 7625 if (status == MagickFalse) 7626 { 7627 XNoticeWidget(display,windows,"Unable to rotate X image", 7628 (*image)->filename); 7629 break; 7630 } 7631 break; 7632 } 7633 case ShearCommand: 7634 { 7635 Image 7636 *shear_image; 7637 7638 static char 7639 geometry[MaxTextExtent] = "45.0x45.0"; 7640 7641 /* 7642 Query user for shear color and geometry. 7643 */ 7644 XColorBrowserWidget(display,windows,"Select",color); 7645 if (*color == '\0') 7646 break; 7647 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7648 geometry); 7649 if (*geometry == '\0') 7650 break; 7651 /* 7652 Shear image. 7653 */ 7654 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7655 exception); 7656 XSetCursorState(display,windows,MagickTrue); 7657 XCheckRefreshWindows(display,windows); 7658 (void) QueryColorCompliance(color,AllCompliance, 7659 &(*image)->background_color,exception); 7660 flags=ParseGeometry(geometry,&geometry_info); 7661 if ((flags & SigmaValue) == 0) 7662 geometry_info.sigma=geometry_info.rho; 7663 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7664 exception); 7665 if (shear_image != (Image *) NULL) 7666 { 7667 *image=DestroyImage(*image); 7668 *image=shear_image; 7669 } 7670 CatchException(exception); 7671 XSetCursorState(display,windows,MagickFalse); 7672 if (windows->image.orphan != MagickFalse) 7673 break; 7674 windows->image.window_changes.width=(int) (*image)->columns; 7675 windows->image.window_changes.height=(int) (*image)->rows; 7676 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7677 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7678 break; 7679 } 7680 case RollCommand: 7681 { 7682 Image 7683 *roll_image; 7684 7685 static char 7686 geometry[MaxTextExtent] = "+2+2"; 7687 7688 /* 7689 Query user for the roll geometry. 7690 */ 7691 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7692 geometry); 7693 if (*geometry == '\0') 7694 break; 7695 /* 7696 Roll image. 7697 */ 7698 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7699 exception); 7700 XSetCursorState(display,windows,MagickTrue); 7701 XCheckRefreshWindows(display,windows); 7702 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7703 exception); 7704 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7705 exception); 7706 if (roll_image != (Image *) NULL) 7707 { 7708 *image=DestroyImage(*image); 7709 *image=roll_image; 7710 } 7711 CatchException(exception); 7712 XSetCursorState(display,windows,MagickFalse); 7713 if (windows->image.orphan != MagickFalse) 7714 break; 7715 windows->image.window_changes.width=(int) (*image)->columns; 7716 windows->image.window_changes.height=(int) (*image)->rows; 7717 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7718 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7719 break; 7720 } 7721 case TrimCommand: 7722 { 7723 static char 7724 fuzz[MaxTextExtent]; 7725 7726 /* 7727 Query user for the fuzz factor. 7728 */ 7729 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0* 7730 (*image)->fuzz/(QuantumRange+1.0)); 7731 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7732 if (*fuzz == '\0') 7733 break; 7734 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0); 7735 /* 7736 Trim image. 7737 */ 7738 status=XTrimImage(display,resource_info,windows,*image,exception); 7739 if (status == MagickFalse) 7740 { 7741 XNoticeWidget(display,windows,"Unable to trim X image", 7742 (*image)->filename); 7743 break; 7744 } 7745 break; 7746 } 7747 case HueCommand: 7748 { 7749 static char 7750 hue_percent[MaxTextExtent] = "110"; 7751 7752 /* 7753 Query user for percent hue change. 7754 */ 7755 (void) XDialogWidget(display,windows,"Apply", 7756 "Enter percent change in image hue (0-200):",hue_percent); 7757 if (*hue_percent == '\0') 7758 break; 7759 /* 7760 Vary the image hue. 7761 */ 7762 XSetCursorState(display,windows,MagickTrue); 7763 XCheckRefreshWindows(display,windows); 7764 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent); 7765 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7766 MaxTextExtent); 7767 (void) ModulateImage(*image,modulate_factors,exception); 7768 XSetCursorState(display,windows,MagickFalse); 7769 if (windows->image.orphan != MagickFalse) 7770 break; 7771 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7772 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7773 break; 7774 } 7775 case SaturationCommand: 7776 { 7777 static char 7778 saturation_percent[MaxTextExtent] = "110"; 7779 7780 /* 7781 Query user for percent saturation change. 7782 */ 7783 (void) XDialogWidget(display,windows,"Apply", 7784 "Enter percent change in color saturation (0-200):",saturation_percent); 7785 if (*saturation_percent == '\0') 7786 break; 7787 /* 7788 Vary color saturation. 7789 */ 7790 XSetCursorState(display,windows,MagickTrue); 7791 XCheckRefreshWindows(display,windows); 7792 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent); 7793 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7794 MaxTextExtent); 7795 (void) ModulateImage(*image,modulate_factors,exception); 7796 XSetCursorState(display,windows,MagickFalse); 7797 if (windows->image.orphan != MagickFalse) 7798 break; 7799 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7800 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7801 break; 7802 } 7803 case BrightnessCommand: 7804 { 7805 static char 7806 brightness_percent[MaxTextExtent] = "110"; 7807 7808 /* 7809 Query user for percent brightness change. 7810 */ 7811 (void) XDialogWidget(display,windows,"Apply", 7812 "Enter percent change in color brightness (0-200):",brightness_percent); 7813 if (*brightness_percent == '\0') 7814 break; 7815 /* 7816 Vary the color brightness. 7817 */ 7818 XSetCursorState(display,windows,MagickTrue); 7819 XCheckRefreshWindows(display,windows); 7820 (void) CopyMagickString(modulate_factors,brightness_percent, 7821 MaxTextExtent); 7822 (void) ModulateImage(*image,modulate_factors,exception); 7823 XSetCursorState(display,windows,MagickFalse); 7824 if (windows->image.orphan != MagickFalse) 7825 break; 7826 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7827 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7828 break; 7829 } 7830 case GammaCommand: 7831 { 7832 static char 7833 factor[MaxTextExtent] = "1.6"; 7834 7835 /* 7836 Query user for gamma value. 7837 */ 7838 (void) XDialogWidget(display,windows,"Gamma", 7839 "Enter gamma value (e.g. 1.2):",factor); 7840 if (*factor == '\0') 7841 break; 7842 /* 7843 Gamma correct image. 7844 */ 7845 XSetCursorState(display,windows,MagickTrue); 7846 XCheckRefreshWindows(display,windows); 7847 (void) GammaImage(*image,atof(factor),exception); 7848 XSetCursorState(display,windows,MagickFalse); 7849 if (windows->image.orphan != MagickFalse) 7850 break; 7851 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7852 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7853 break; 7854 } 7855 case SpiffCommand: 7856 { 7857 /* 7858 Sharpen the image contrast. 7859 */ 7860 XSetCursorState(display,windows,MagickTrue); 7861 XCheckRefreshWindows(display,windows); 7862 (void) ContrastImage(*image,MagickTrue,exception); 7863 XSetCursorState(display,windows,MagickFalse); 7864 if (windows->image.orphan != MagickFalse) 7865 break; 7866 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7867 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7868 break; 7869 } 7870 case DullCommand: 7871 { 7872 /* 7873 Dull the image contrast. 7874 */ 7875 XSetCursorState(display,windows,MagickTrue); 7876 XCheckRefreshWindows(display,windows); 7877 (void) ContrastImage(*image,MagickFalse,exception); 7878 XSetCursorState(display,windows,MagickFalse); 7879 if (windows->image.orphan != MagickFalse) 7880 break; 7881 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7882 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7883 break; 7884 } 7885 case ContrastStretchCommand: 7886 { 7887 double 7888 black_point, 7889 white_point; 7890 7891 static char 7892 levels[MaxTextExtent] = "1%"; 7893 7894 /* 7895 Query user for gamma value. 7896 */ 7897 (void) XDialogWidget(display,windows,"Contrast Stretch", 7898 "Enter black and white points:",levels); 7899 if (*levels == '\0') 7900 break; 7901 /* 7902 Contrast stretch image. 7903 */ 7904 XSetCursorState(display,windows,MagickTrue); 7905 XCheckRefreshWindows(display,windows); 7906 flags=ParseGeometry(levels,&geometry_info); 7907 black_point=geometry_info.rho; 7908 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7909 if ((flags & PercentValue) != 0) 7910 { 7911 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7912 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7913 } 7914 white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point; 7915 (void) ContrastStretchImage(*image,black_point,white_point, 7916 exception); 7917 XSetCursorState(display,windows,MagickFalse); 7918 if (windows->image.orphan != MagickFalse) 7919 break; 7920 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7921 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7922 break; 7923 } 7924 case SigmoidalContrastCommand: 7925 { 7926 GeometryInfo 7927 geometry_info; 7928 7929 MagickStatusType 7930 flags; 7931 7932 static char 7933 levels[MaxTextExtent] = "3x50%"; 7934 7935 /* 7936 Query user for gamma value. 7937 */ 7938 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7939 "Enter contrast and midpoint:",levels); 7940 if (*levels == '\0') 7941 break; 7942 /* 7943 Contrast stretch image. 7944 */ 7945 XSetCursorState(display,windows,MagickTrue); 7946 XCheckRefreshWindows(display,windows); 7947 flags=ParseGeometry(levels,&geometry_info); 7948 if ((flags & SigmaValue) == 0) 7949 geometry_info.sigma=1.0*QuantumRange/2.0; 7950 if ((flags & PercentValue) != 0) 7951 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0; 7952 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho, 7953 geometry_info.sigma,exception); 7954 XSetCursorState(display,windows,MagickFalse); 7955 if (windows->image.orphan != MagickFalse) 7956 break; 7957 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7958 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7959 break; 7960 } 7961 case NormalizeCommand: 7962 { 7963 /* 7964 Perform histogram normalization on the image. 7965 */ 7966 XSetCursorState(display,windows,MagickTrue); 7967 XCheckRefreshWindows(display,windows); 7968 (void) NormalizeImage(*image,exception); 7969 XSetCursorState(display,windows,MagickFalse); 7970 if (windows->image.orphan != MagickFalse) 7971 break; 7972 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7973 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7974 break; 7975 } 7976 case EqualizeCommand: 7977 { 7978 /* 7979 Perform histogram equalization on the image. 7980 */ 7981 XSetCursorState(display,windows,MagickTrue); 7982 XCheckRefreshWindows(display,windows); 7983 (void) EqualizeImage(*image,exception); 7984 XSetCursorState(display,windows,MagickFalse); 7985 if (windows->image.orphan != MagickFalse) 7986 break; 7987 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7988 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7989 break; 7990 } 7991 case NegateCommand: 7992 { 7993 /* 7994 Negate colors in image. 7995 */ 7996 XSetCursorState(display,windows,MagickTrue); 7997 XCheckRefreshWindows(display,windows); 7998 (void) NegateImage(*image,MagickFalse,exception); 7999 XSetCursorState(display,windows,MagickFalse); 8000 if (windows->image.orphan != MagickFalse) 8001 break; 8002 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8003 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8004 break; 8005 } 8006 case GrayscaleCommand: 8007 { 8008 /* 8009 Convert image to grayscale. 8010 */ 8011 XSetCursorState(display,windows,MagickTrue); 8012 XCheckRefreshWindows(display,windows); 8013 (void) SetImageType(*image,(*image)->matte == MagickFalse ? 8014 GrayscaleType : GrayscaleMatteType,exception); 8015 XSetCursorState(display,windows,MagickFalse); 8016 if (windows->image.orphan != MagickFalse) 8017 break; 8018 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8019 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8020 break; 8021 } 8022 case MapCommand: 8023 { 8024 Image 8025 *affinity_image; 8026 8027 static char 8028 filename[MaxTextExtent] = "\0"; 8029 8030 /* 8031 Request image file name from user. 8032 */ 8033 XFileBrowserWidget(display,windows,"Map",filename); 8034 if (*filename == '\0') 8035 break; 8036 /* 8037 Map image. 8038 */ 8039 XSetCursorState(display,windows,MagickTrue); 8040 XCheckRefreshWindows(display,windows); 8041 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 8042 affinity_image=ReadImage(image_info,exception); 8043 if (affinity_image != (Image *) NULL) 8044 { 8045 (void) RemapImage(&quantize_info,*image,affinity_image,exception); 8046 affinity_image=DestroyImage(affinity_image); 8047 } 8048 CatchException(exception); 8049 XSetCursorState(display,windows,MagickFalse); 8050 if (windows->image.orphan != MagickFalse) 8051 break; 8052 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8053 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8054 break; 8055 } 8056 case QuantizeCommand: 8057 { 8058 int 8059 status; 8060 8061 static char 8062 colors[MaxTextExtent] = "256"; 8063 8064 /* 8065 Query user for maximum number of colors. 8066 */ 8067 status=XDialogWidget(display,windows,"Quantize", 8068 "Maximum number of colors:",colors); 8069 if (*colors == '\0') 8070 break; 8071 /* 8072 Color reduce the image. 8073 */ 8074 XSetCursorState(display,windows,MagickTrue); 8075 XCheckRefreshWindows(display,windows); 8076 quantize_info.number_colors=StringToUnsignedLong(colors); 8077 quantize_info.dither=status != 0 ? MagickTrue : MagickFalse; 8078 (void) QuantizeImage(&quantize_info,*image,exception); 8079 XSetCursorState(display,windows,MagickFalse); 8080 if (windows->image.orphan != MagickFalse) 8081 break; 8082 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8083 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8084 break; 8085 } 8086 case DespeckleCommand: 8087 { 8088 Image 8089 *despeckle_image; 8090 8091 /* 8092 Despeckle image. 8093 */ 8094 XSetCursorState(display,windows,MagickTrue); 8095 XCheckRefreshWindows(display,windows); 8096 despeckle_image=DespeckleImage(*image,exception); 8097 if (despeckle_image != (Image *) NULL) 8098 { 8099 *image=DestroyImage(*image); 8100 *image=despeckle_image; 8101 } 8102 CatchException(exception); 8103 XSetCursorState(display,windows,MagickFalse); 8104 if (windows->image.orphan != MagickFalse) 8105 break; 8106 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8107 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8108 break; 8109 } 8110 case EmbossCommand: 8111 { 8112 Image 8113 *emboss_image; 8114 8115 static char 8116 radius[MaxTextExtent] = "0.0x1.0"; 8117 8118 /* 8119 Query user for emboss radius. 8120 */ 8121 (void) XDialogWidget(display,windows,"Emboss", 8122 "Enter the emboss radius and standard deviation:",radius); 8123 if (*radius == '\0') 8124 break; 8125 /* 8126 Reduce noise in the image. 8127 */ 8128 XSetCursorState(display,windows,MagickTrue); 8129 XCheckRefreshWindows(display,windows); 8130 flags=ParseGeometry(radius,&geometry_info); 8131 if ((flags & SigmaValue) == 0) 8132 geometry_info.sigma=1.0; 8133 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma, 8134 exception); 8135 if (emboss_image != (Image *) NULL) 8136 { 8137 *image=DestroyImage(*image); 8138 *image=emboss_image; 8139 } 8140 CatchException(exception); 8141 XSetCursorState(display,windows,MagickFalse); 8142 if (windows->image.orphan != MagickFalse) 8143 break; 8144 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8145 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8146 break; 8147 } 8148 case ReduceNoiseCommand: 8149 { 8150 Image 8151 *noise_image; 8152 8153 static char 8154 radius[MaxTextExtent] = "0"; 8155 8156 /* 8157 Query user for noise radius. 8158 */ 8159 (void) XDialogWidget(display,windows,"Reduce Noise", 8160 "Enter the noise radius:",radius); 8161 if (*radius == '\0') 8162 break; 8163 /* 8164 Reduce noise in the image. 8165 */ 8166 XSetCursorState(display,windows,MagickTrue); 8167 XCheckRefreshWindows(display,windows); 8168 flags=ParseGeometry(radius,&geometry_info); 8169 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t) 8170 geometry_info.rho,(size_t) geometry_info.rho,exception); 8171 if (noise_image != (Image *) NULL) 8172 { 8173 *image=DestroyImage(*image); 8174 *image=noise_image; 8175 } 8176 CatchException(exception); 8177 XSetCursorState(display,windows,MagickFalse); 8178 if (windows->image.orphan != MagickFalse) 8179 break; 8180 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8181 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8182 break; 8183 } 8184 case AddNoiseCommand: 8185 { 8186 char 8187 **noises; 8188 8189 Image 8190 *noise_image; 8191 8192 static char 8193 noise_type[MaxTextExtent] = "Gaussian"; 8194 8195 /* 8196 Add noise to the image. 8197 */ 8198 noises=GetCommandOptions(MagickNoiseOptions); 8199 if (noises == (char **) NULL) 8200 break; 8201 XListBrowserWidget(display,windows,&windows->widget, 8202 (const char **) noises,"Add Noise", 8203 "Select a type of noise to add to your image:",noise_type); 8204 noises=DestroyStringList(noises); 8205 if (*noise_type == '\0') 8206 break; 8207 XSetCursorState(display,windows,MagickTrue); 8208 XCheckRefreshWindows(display,windows); 8209 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption( 8210 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception); 8211 if (noise_image != (Image *) NULL) 8212 { 8213 *image=DestroyImage(*image); 8214 *image=noise_image; 8215 } 8216 CatchException(exception); 8217 XSetCursorState(display,windows,MagickFalse); 8218 if (windows->image.orphan != MagickFalse) 8219 break; 8220 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8221 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8222 break; 8223 } 8224 case SharpenCommand: 8225 { 8226 Image 8227 *sharp_image; 8228 8229 static char 8230 radius[MaxTextExtent] = "0.0x1.0"; 8231 8232 /* 8233 Query user for sharpen radius. 8234 */ 8235 (void) XDialogWidget(display,windows,"Sharpen", 8236 "Enter the sharpen radius and standard deviation:",radius); 8237 if (*radius == '\0') 8238 break; 8239 /* 8240 Sharpen image scanlines. 8241 */ 8242 XSetCursorState(display,windows,MagickTrue); 8243 XCheckRefreshWindows(display,windows); 8244 flags=ParseGeometry(radius,&geometry_info); 8245 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma, 8246 geometry_info.xi,exception); 8247 if (sharp_image != (Image *) NULL) 8248 { 8249 *image=DestroyImage(*image); 8250 *image=sharp_image; 8251 } 8252 CatchException(exception); 8253 XSetCursorState(display,windows,MagickFalse); 8254 if (windows->image.orphan != MagickFalse) 8255 break; 8256 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8257 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8258 break; 8259 } 8260 case BlurCommand: 8261 { 8262 Image 8263 *blur_image; 8264 8265 static char 8266 radius[MaxTextExtent] = "0.0x1.0"; 8267 8268 /* 8269 Query user for blur radius. 8270 */ 8271 (void) XDialogWidget(display,windows,"Blur", 8272 "Enter the blur radius and standard deviation:",radius); 8273 if (*radius == '\0') 8274 break; 8275 /* 8276 Blur an image. 8277 */ 8278 XSetCursorState(display,windows,MagickTrue); 8279 XCheckRefreshWindows(display,windows); 8280 flags=ParseGeometry(radius,&geometry_info); 8281 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma, 8282 geometry_info.xi,exception); 8283 if (blur_image != (Image *) NULL) 8284 { 8285 *image=DestroyImage(*image); 8286 *image=blur_image; 8287 } 8288 CatchException(exception); 8289 XSetCursorState(display,windows,MagickFalse); 8290 if (windows->image.orphan != MagickFalse) 8291 break; 8292 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8293 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8294 break; 8295 } 8296 case ThresholdCommand: 8297 { 8298 double 8299 threshold; 8300 8301 static char 8302 factor[MaxTextExtent] = "128"; 8303 8304 /* 8305 Query user for threshold value. 8306 */ 8307 (void) XDialogWidget(display,windows,"Threshold", 8308 "Enter threshold value:",factor); 8309 if (*factor == '\0') 8310 break; 8311 /* 8312 Gamma correct image. 8313 */ 8314 XSetCursorState(display,windows,MagickTrue); 8315 XCheckRefreshWindows(display,windows); 8316 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8317 (void) BilevelImage(*image,threshold,exception); 8318 XSetCursorState(display,windows,MagickFalse); 8319 if (windows->image.orphan != MagickFalse) 8320 break; 8321 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8322 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8323 break; 8324 } 8325 case EdgeDetectCommand: 8326 { 8327 Image 8328 *edge_image; 8329 8330 static char 8331 radius[MaxTextExtent] = "0"; 8332 8333 /* 8334 Query user for edge factor. 8335 */ 8336 (void) XDialogWidget(display,windows,"Detect Edges", 8337 "Enter the edge detect radius:",radius); 8338 if (*radius == '\0') 8339 break; 8340 /* 8341 Detect edge in image. 8342 */ 8343 XSetCursorState(display,windows,MagickTrue); 8344 XCheckRefreshWindows(display,windows); 8345 flags=ParseGeometry(radius,&geometry_info); 8346 edge_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8347 exception); 8348 if (edge_image != (Image *) NULL) 8349 { 8350 *image=DestroyImage(*image); 8351 *image=edge_image; 8352 } 8353 CatchException(exception); 8354 XSetCursorState(display,windows,MagickFalse); 8355 if (windows->image.orphan != MagickFalse) 8356 break; 8357 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8358 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8359 break; 8360 } 8361 case SpreadCommand: 8362 { 8363 Image 8364 *spread_image; 8365 8366 static char 8367 amount[MaxTextExtent] = "2"; 8368 8369 /* 8370 Query user for spread amount. 8371 */ 8372 (void) XDialogWidget(display,windows,"Spread", 8373 "Enter the displacement amount:",amount); 8374 if (*amount == '\0') 8375 break; 8376 /* 8377 Displace image pixels by a random amount. 8378 */ 8379 XSetCursorState(display,windows,MagickTrue); 8380 XCheckRefreshWindows(display,windows); 8381 flags=ParseGeometry(amount,&geometry_info); 8382 spread_image=EdgeImage(*image,geometry_info.rho,geometry_info.sigma, 8383 exception); 8384 if (spread_image != (Image *) NULL) 8385 { 8386 *image=DestroyImage(*image); 8387 *image=spread_image; 8388 } 8389 CatchException(exception); 8390 XSetCursorState(display,windows,MagickFalse); 8391 if (windows->image.orphan != MagickFalse) 8392 break; 8393 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8394 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8395 break; 8396 } 8397 case ShadeCommand: 8398 { 8399 Image 8400 *shade_image; 8401 8402 int 8403 status; 8404 8405 static char 8406 geometry[MaxTextExtent] = "30x30"; 8407 8408 /* 8409 Query user for the shade geometry. 8410 */ 8411 status=XDialogWidget(display,windows,"Shade", 8412 "Enter the azimuth and elevation of the light source:",geometry); 8413 if (*geometry == '\0') 8414 break; 8415 /* 8416 Shade image pixels. 8417 */ 8418 XSetCursorState(display,windows,MagickTrue); 8419 XCheckRefreshWindows(display,windows); 8420 flags=ParseGeometry(geometry,&geometry_info); 8421 if ((flags & SigmaValue) == 0) 8422 geometry_info.sigma=1.0; 8423 shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue, 8424 geometry_info.rho,geometry_info.sigma,exception); 8425 if (shade_image != (Image *) NULL) 8426 { 8427 *image=DestroyImage(*image); 8428 *image=shade_image; 8429 } 8430 CatchException(exception); 8431 XSetCursorState(display,windows,MagickFalse); 8432 if (windows->image.orphan != MagickFalse) 8433 break; 8434 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8435 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8436 break; 8437 } 8438 case RaiseCommand: 8439 { 8440 static char 8441 bevel_width[MaxTextExtent] = "10"; 8442 8443 /* 8444 Query user for bevel width. 8445 */ 8446 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8447 if (*bevel_width == '\0') 8448 break; 8449 /* 8450 Raise an image. 8451 */ 8452 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8453 exception); 8454 XSetCursorState(display,windows,MagickTrue); 8455 XCheckRefreshWindows(display,windows); 8456 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8457 exception); 8458 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception); 8459 XSetCursorState(display,windows,MagickFalse); 8460 if (windows->image.orphan != MagickFalse) 8461 break; 8462 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8463 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8464 break; 8465 } 8466 case SegmentCommand: 8467 { 8468 static char 8469 threshold[MaxTextExtent] = "1.0x1.5"; 8470 8471 /* 8472 Query user for smoothing threshold. 8473 */ 8474 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8475 threshold); 8476 if (*threshold == '\0') 8477 break; 8478 /* 8479 Segment an image. 8480 */ 8481 XSetCursorState(display,windows,MagickTrue); 8482 XCheckRefreshWindows(display,windows); 8483 flags=ParseGeometry(threshold,&geometry_info); 8484 if ((flags & SigmaValue) == 0) 8485 geometry_info.sigma=1.0; 8486 (void) SegmentImage(*image,RGBColorspace,MagickFalse,geometry_info.rho, 8487 geometry_info.sigma,exception); 8488 XSetCursorState(display,windows,MagickFalse); 8489 if (windows->image.orphan != MagickFalse) 8490 break; 8491 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8492 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8493 break; 8494 } 8495 case SepiaToneCommand: 8496 { 8497 double 8498 threshold; 8499 8500 Image 8501 *sepia_image; 8502 8503 static char 8504 factor[MaxTextExtent] = "80%"; 8505 8506 /* 8507 Query user for sepia-tone factor. 8508 */ 8509 (void) XDialogWidget(display,windows,"Sepia Tone", 8510 "Enter the sepia tone factor (0 - 99.9%):",factor); 8511 if (*factor == '\0') 8512 break; 8513 /* 8514 Sepia tone image pixels. 8515 */ 8516 XSetCursorState(display,windows,MagickTrue); 8517 XCheckRefreshWindows(display,windows); 8518 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8519 sepia_image=SepiaToneImage(*image,threshold,exception); 8520 if (sepia_image != (Image *) NULL) 8521 { 8522 *image=DestroyImage(*image); 8523 *image=sepia_image; 8524 } 8525 CatchException(exception); 8526 XSetCursorState(display,windows,MagickFalse); 8527 if (windows->image.orphan != MagickFalse) 8528 break; 8529 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8530 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8531 break; 8532 } 8533 case SolarizeCommand: 8534 { 8535 double 8536 threshold; 8537 8538 static char 8539 factor[MaxTextExtent] = "60%"; 8540 8541 /* 8542 Query user for solarize factor. 8543 */ 8544 (void) XDialogWidget(display,windows,"Solarize", 8545 "Enter the solarize factor (0 - 99.9%):",factor); 8546 if (*factor == '\0') 8547 break; 8548 /* 8549 Solarize image pixels. 8550 */ 8551 XSetCursorState(display,windows,MagickTrue); 8552 XCheckRefreshWindows(display,windows); 8553 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8554 (void) SolarizeImage(*image,threshold,exception); 8555 XSetCursorState(display,windows,MagickFalse); 8556 if (windows->image.orphan != MagickFalse) 8557 break; 8558 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8559 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8560 break; 8561 } 8562 case SwirlCommand: 8563 { 8564 Image 8565 *swirl_image; 8566 8567 static char 8568 degrees[MaxTextExtent] = "60"; 8569 8570 /* 8571 Query user for swirl angle. 8572 */ 8573 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8574 degrees); 8575 if (*degrees == '\0') 8576 break; 8577 /* 8578 Swirl image pixels about the center. 8579 */ 8580 XSetCursorState(display,windows,MagickTrue); 8581 XCheckRefreshWindows(display,windows); 8582 flags=ParseGeometry(degrees,&geometry_info); 8583 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate, 8584 exception); 8585 if (swirl_image != (Image *) NULL) 8586 { 8587 *image=DestroyImage(*image); 8588 *image=swirl_image; 8589 } 8590 CatchException(exception); 8591 XSetCursorState(display,windows,MagickFalse); 8592 if (windows->image.orphan != MagickFalse) 8593 break; 8594 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8595 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8596 break; 8597 } 8598 case ImplodeCommand: 8599 { 8600 Image 8601 *implode_image; 8602 8603 static char 8604 factor[MaxTextExtent] = "0.3"; 8605 8606 /* 8607 Query user for implode factor. 8608 */ 8609 (void) XDialogWidget(display,windows,"Implode", 8610 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8611 if (*factor == '\0') 8612 break; 8613 /* 8614 Implode image pixels about the center. 8615 */ 8616 XSetCursorState(display,windows,MagickTrue); 8617 XCheckRefreshWindows(display,windows); 8618 flags=ParseGeometry(factor,&geometry_info); 8619 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate, 8620 exception); 8621 if (implode_image != (Image *) NULL) 8622 { 8623 *image=DestroyImage(*image); 8624 *image=implode_image; 8625 } 8626 CatchException(exception); 8627 XSetCursorState(display,windows,MagickFalse); 8628 if (windows->image.orphan != MagickFalse) 8629 break; 8630 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8631 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8632 break; 8633 } 8634 case VignetteCommand: 8635 { 8636 Image 8637 *vignette_image; 8638 8639 static char 8640 geometry[MaxTextExtent] = "0x20"; 8641 8642 /* 8643 Query user for the vignette geometry. 8644 */ 8645 (void) XDialogWidget(display,windows,"Vignette", 8646 "Enter the radius, sigma, and x and y offsets:",geometry); 8647 if (*geometry == '\0') 8648 break; 8649 /* 8650 Soften the edges of the image in vignette style 8651 */ 8652 XSetCursorState(display,windows,MagickTrue); 8653 XCheckRefreshWindows(display,windows); 8654 flags=ParseGeometry(geometry,&geometry_info); 8655 if ((flags & SigmaValue) == 0) 8656 geometry_info.sigma=1.0; 8657 if ((flags & XiValue) == 0) 8658 geometry_info.xi=0.1*(*image)->columns; 8659 if ((flags & PsiValue) == 0) 8660 geometry_info.psi=0.1*(*image)->rows; 8661 vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma, 8662 0.0,(ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) 8663 ceil(geometry_info.psi-0.5),exception); 8664 if (vignette_image != (Image *) NULL) 8665 { 8666 *image=DestroyImage(*image); 8667 *image=vignette_image; 8668 } 8669 CatchException(exception); 8670 XSetCursorState(display,windows,MagickFalse); 8671 if (windows->image.orphan != MagickFalse) 8672 break; 8673 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8674 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8675 break; 8676 } 8677 case WaveCommand: 8678 { 8679 Image 8680 *wave_image; 8681 8682 static char 8683 geometry[MaxTextExtent] = "25x150"; 8684 8685 /* 8686 Query user for the wave geometry. 8687 */ 8688 (void) XDialogWidget(display,windows,"Wave", 8689 "Enter the amplitude and length of the wave:",geometry); 8690 if (*geometry == '\0') 8691 break; 8692 /* 8693 Alter an image along a sine wave. 8694 */ 8695 XSetCursorState(display,windows,MagickTrue); 8696 XCheckRefreshWindows(display,windows); 8697 flags=ParseGeometry(geometry,&geometry_info); 8698 if ((flags & SigmaValue) == 0) 8699 geometry_info.sigma=1.0; 8700 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8701 (*image)->interpolate,exception); 8702 if (wave_image != (Image *) NULL) 8703 { 8704 *image=DestroyImage(*image); 8705 *image=wave_image; 8706 } 8707 CatchException(exception); 8708 XSetCursorState(display,windows,MagickFalse); 8709 if (windows->image.orphan != MagickFalse) 8710 break; 8711 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8712 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8713 break; 8714 } 8715 case OilPaintCommand: 8716 { 8717 Image 8718 *paint_image; 8719 8720 static char 8721 radius[MaxTextExtent] = "0"; 8722 8723 /* 8724 Query user for circular neighborhood radius. 8725 */ 8726 (void) XDialogWidget(display,windows,"Oil Paint", 8727 "Enter the mask radius:",radius); 8728 if (*radius == '\0') 8729 break; 8730 /* 8731 OilPaint image scanlines. 8732 */ 8733 XSetCursorState(display,windows,MagickTrue); 8734 XCheckRefreshWindows(display,windows); 8735 flags=ParseGeometry(radius,&geometry_info); 8736 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma, 8737 exception); 8738 if (paint_image != (Image *) NULL) 8739 { 8740 *image=DestroyImage(*image); 8741 *image=paint_image; 8742 } 8743 CatchException(exception); 8744 XSetCursorState(display,windows,MagickFalse); 8745 if (windows->image.orphan != MagickFalse) 8746 break; 8747 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8748 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8749 break; 8750 } 8751 case CharcoalDrawCommand: 8752 { 8753 Image 8754 *charcoal_image; 8755 8756 static char 8757 radius[MaxTextExtent] = "0x1"; 8758 8759 /* 8760 Query user for charcoal radius. 8761 */ 8762 (void) XDialogWidget(display,windows,"Charcoal Draw", 8763 "Enter the charcoal radius and sigma:",radius); 8764 if (*radius == '\0') 8765 break; 8766 /* 8767 Charcoal the image. 8768 */ 8769 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8770 exception); 8771 XSetCursorState(display,windows,MagickTrue); 8772 XCheckRefreshWindows(display,windows); 8773 flags=ParseGeometry(radius,&geometry_info); 8774 if ((flags & SigmaValue) == 0) 8775 geometry_info.sigma=geometry_info.rho; 8776 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8777 geometry_info.xi,exception); 8778 if (charcoal_image != (Image *) NULL) 8779 { 8780 *image=DestroyImage(*image); 8781 *image=charcoal_image; 8782 } 8783 CatchException(exception); 8784 XSetCursorState(display,windows,MagickFalse); 8785 if (windows->image.orphan != MagickFalse) 8786 break; 8787 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8788 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8789 break; 8790 } 8791 case AnnotateCommand: 8792 { 8793 /* 8794 Annotate the image with text. 8795 */ 8796 status=XAnnotateEditImage(display,resource_info,windows,*image,exception); 8797 if (status == MagickFalse) 8798 { 8799 XNoticeWidget(display,windows,"Unable to annotate X image", 8800 (*image)->filename); 8801 break; 8802 } 8803 break; 8804 } 8805 case DrawCommand: 8806 { 8807 /* 8808 Draw image. 8809 */ 8810 status=XDrawEditImage(display,resource_info,windows,image,exception); 8811 if (status == MagickFalse) 8812 { 8813 XNoticeWidget(display,windows,"Unable to draw on the X image", 8814 (*image)->filename); 8815 break; 8816 } 8817 break; 8818 } 8819 case ColorCommand: 8820 { 8821 /* 8822 Color edit. 8823 */ 8824 status=XColorEditImage(display,resource_info,windows,image,exception); 8825 if (status == MagickFalse) 8826 { 8827 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8828 (*image)->filename); 8829 break; 8830 } 8831 break; 8832 } 8833 case MatteCommand: 8834 { 8835 /* 8836 Matte edit. 8837 */ 8838 status=XMatteEditImage(display,resource_info,windows,image,exception); 8839 if (status == MagickFalse) 8840 { 8841 XNoticeWidget(display,windows,"Unable to matte edit X image", 8842 (*image)->filename); 8843 break; 8844 } 8845 break; 8846 } 8847 case CompositeCommand: 8848 { 8849 /* 8850 Composite image. 8851 */ 8852 status=XCompositeImage(display,resource_info,windows,*image, 8853 exception); 8854 if (status == MagickFalse) 8855 { 8856 XNoticeWidget(display,windows,"Unable to composite X image", 8857 (*image)->filename); 8858 break; 8859 } 8860 break; 8861 } 8862 case AddBorderCommand: 8863 { 8864 Image 8865 *border_image; 8866 8867 static char 8868 geometry[MaxTextExtent] = "6x6"; 8869 8870 /* 8871 Query user for border color and geometry. 8872 */ 8873 XColorBrowserWidget(display,windows,"Select",color); 8874 if (*color == '\0') 8875 break; 8876 (void) XDialogWidget(display,windows,"Add Border", 8877 "Enter border geometry:",geometry); 8878 if (*geometry == '\0') 8879 break; 8880 /* 8881 Add a border to the image. 8882 */ 8883 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8884 exception); 8885 XSetCursorState(display,windows,MagickTrue); 8886 XCheckRefreshWindows(display,windows); 8887 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color, 8888 exception); 8889 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8890 exception); 8891 border_image=BorderImage(*image,&page_geometry,(*image)->compose, 8892 exception); 8893 if (border_image != (Image *) NULL) 8894 { 8895 *image=DestroyImage(*image); 8896 *image=border_image; 8897 } 8898 CatchException(exception); 8899 XSetCursorState(display,windows,MagickFalse); 8900 if (windows->image.orphan != MagickFalse) 8901 break; 8902 windows->image.window_changes.width=(int) (*image)->columns; 8903 windows->image.window_changes.height=(int) (*image)->rows; 8904 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8905 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8906 break; 8907 } 8908 case AddFrameCommand: 8909 { 8910 FrameInfo 8911 frame_info; 8912 8913 Image 8914 *frame_image; 8915 8916 static char 8917 geometry[MaxTextExtent] = "6x6"; 8918 8919 /* 8920 Query user for frame color and geometry. 8921 */ 8922 XColorBrowserWidget(display,windows,"Select",color); 8923 if (*color == '\0') 8924 break; 8925 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8926 geometry); 8927 if (*geometry == '\0') 8928 break; 8929 /* 8930 Surround image with an ornamental border. 8931 */ 8932 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8933 exception); 8934 XSetCursorState(display,windows,MagickTrue); 8935 XCheckRefreshWindows(display,windows); 8936 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color, 8937 exception); 8938 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8939 exception); 8940 frame_info.width=page_geometry.width; 8941 frame_info.height=page_geometry.height; 8942 frame_info.outer_bevel=page_geometry.x; 8943 frame_info.inner_bevel=page_geometry.y; 8944 frame_info.x=(ssize_t) frame_info.width; 8945 frame_info.y=(ssize_t) frame_info.height; 8946 frame_info.width=(*image)->columns+2*frame_info.width; 8947 frame_info.height=(*image)->rows+2*frame_info.height; 8948 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception); 8949 if (frame_image != (Image *) NULL) 8950 { 8951 *image=DestroyImage(*image); 8952 *image=frame_image; 8953 } 8954 CatchException(exception); 8955 XSetCursorState(display,windows,MagickFalse); 8956 if (windows->image.orphan != MagickFalse) 8957 break; 8958 windows->image.window_changes.width=(int) (*image)->columns; 8959 windows->image.window_changes.height=(int) (*image)->rows; 8960 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8961 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8962 break; 8963 } 8964 case CommentCommand: 8965 { 8966 const char 8967 *value; 8968 8969 FILE 8970 *file; 8971 8972 int 8973 unique_file; 8974 8975 /* 8976 Edit image comment. 8977 */ 8978 unique_file=AcquireUniqueFileResource(image_info->filename); 8979 if (unique_file == -1) 8980 XNoticeWidget(display,windows,"Unable to edit image comment", 8981 image_info->filename); 8982 value=GetImageProperty(*image,"comment",exception); 8983 if (value == (char *) NULL) 8984 unique_file=close(unique_file)-1; 8985 else 8986 { 8987 register const char 8988 *p; 8989 8990 file=fdopen(unique_file,"w"); 8991 if (file == (FILE *) NULL) 8992 { 8993 XNoticeWidget(display,windows,"Unable to edit image comment", 8994 image_info->filename); 8995 break; 8996 } 8997 for (p=value; *p != '\0'; p++) 8998 (void) fputc((int) *p,file); 8999 (void) fputc('\n',file); 9000 (void) fclose(file); 9001 } 9002 XSetCursorState(display,windows,MagickTrue); 9003 XCheckRefreshWindows(display,windows); 9004 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 9005 exception); 9006 if (status == MagickFalse) 9007 XNoticeWidget(display,windows,"Unable to edit image comment", 9008 (char *) NULL); 9009 else 9010 { 9011 char 9012 *comment; 9013 9014 comment=FileToString(image_info->filename,~0UL,exception); 9015 if (comment != (char *) NULL) 9016 { 9017 (void) SetImageProperty(*image,"comment",comment,exception); 9018 (*image)->taint=MagickTrue; 9019 } 9020 } 9021 (void) RelinquishUniqueFileResource(image_info->filename); 9022 XSetCursorState(display,windows,MagickFalse); 9023 break; 9024 } 9025 case LaunchCommand: 9026 { 9027 /* 9028 Launch program. 9029 */ 9030 XSetCursorState(display,windows,MagickTrue); 9031 XCheckRefreshWindows(display,windows); 9032 (void) AcquireUniqueFilename(filename); 9033 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s", 9034 filename); 9035 status=WriteImage(image_info,*image,exception); 9036 if (status == MagickFalse) 9037 XNoticeWidget(display,windows,"Unable to launch image editor", 9038 (char *) NULL); 9039 else 9040 { 9041 nexus=ReadImage(resource_info->image_info,exception); 9042 CatchException(exception); 9043 XClientMessage(display,windows->image.id,windows->im_protocols, 9044 windows->im_next_image,CurrentTime); 9045 } 9046 (void) RelinquishUniqueFileResource(filename); 9047 XSetCursorState(display,windows,MagickFalse); 9048 break; 9049 } 9050 case RegionofInterestCommand: 9051 { 9052 /* 9053 Apply an image processing technique to a region of interest. 9054 */ 9055 (void) XROIImage(display,resource_info,windows,image,exception); 9056 break; 9057 } 9058 case InfoCommand: 9059 break; 9060 case ZoomCommand: 9061 { 9062 /* 9063 Zoom image. 9064 */ 9065 if (windows->magnify.mapped != MagickFalse) 9066 (void) XRaiseWindow(display,windows->magnify.id); 9067 else 9068 { 9069 /* 9070 Make magnify image. 9071 */ 9072 XSetCursorState(display,windows,MagickTrue); 9073 (void) XMapRaised(display,windows->magnify.id); 9074 XSetCursorState(display,windows,MagickFalse); 9075 } 9076 break; 9077 } 9078 case ShowPreviewCommand: 9079 { 9080 char 9081 **previews; 9082 9083 Image 9084 *preview_image; 9085 9086 static char 9087 preview_type[MaxTextExtent] = "Gamma"; 9088 9089 /* 9090 Select preview type from menu. 9091 */ 9092 previews=GetCommandOptions(MagickPreviewOptions); 9093 if (previews == (char **) NULL) 9094 break; 9095 XListBrowserWidget(display,windows,&windows->widget, 9096 (const char **) previews,"Preview", 9097 "Select an enhancement, effect, or F/X:",preview_type); 9098 previews=DestroyStringList(previews); 9099 if (*preview_type == '\0') 9100 break; 9101 /* 9102 Show image preview. 9103 */ 9104 XSetCursorState(display,windows,MagickTrue); 9105 XCheckRefreshWindows(display,windows); 9106 image_info->preview_type=(PreviewType) 9107 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type); 9108 image_info->group=(ssize_t) windows->image.id; 9109 (void) DeleteImageProperty(*image,"label"); 9110 (void) SetImageProperty(*image,"label","Preview",exception); 9111 (void) AcquireUniqueFilename(filename); 9112 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s", 9113 filename); 9114 status=WriteImage(image_info,*image,exception); 9115 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9116 preview_image=ReadImage(image_info,exception); 9117 (void) RelinquishUniqueFileResource(filename); 9118 if (preview_image == (Image *) NULL) 9119 break; 9120 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s", 9121 filename); 9122 status=WriteImage(image_info,preview_image,exception); 9123 preview_image=DestroyImage(preview_image); 9124 if (status == MagickFalse) 9125 XNoticeWidget(display,windows,"Unable to show image preview", 9126 (*image)->filename); 9127 XDelay(display,1500); 9128 XSetCursorState(display,windows,MagickFalse); 9129 break; 9130 } 9131 case ShowHistogramCommand: 9132 { 9133 Image 9134 *histogram_image; 9135 9136 /* 9137 Show image histogram. 9138 */ 9139 XSetCursorState(display,windows,MagickTrue); 9140 XCheckRefreshWindows(display,windows); 9141 image_info->group=(ssize_t) windows->image.id; 9142 (void) DeleteImageProperty(*image,"label"); 9143 (void) SetImageProperty(*image,"label","Histogram",exception); 9144 (void) AcquireUniqueFilename(filename); 9145 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s", 9146 filename); 9147 status=WriteImage(image_info,*image,exception); 9148 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9149 histogram_image=ReadImage(image_info,exception); 9150 (void) RelinquishUniqueFileResource(filename); 9151 if (histogram_image == (Image *) NULL) 9152 break; 9153 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent, 9154 "show:%s",filename); 9155 status=WriteImage(image_info,histogram_image,exception); 9156 histogram_image=DestroyImage(histogram_image); 9157 if (status == MagickFalse) 9158 XNoticeWidget(display,windows,"Unable to show histogram", 9159 (*image)->filename); 9160 XDelay(display,1500); 9161 XSetCursorState(display,windows,MagickFalse); 9162 break; 9163 } 9164 case ShowMatteCommand: 9165 { 9166 Image 9167 *matte_image; 9168 9169 if ((*image)->matte == MagickFalse) 9170 { 9171 XNoticeWidget(display,windows, 9172 "Image does not have any matte information",(*image)->filename); 9173 break; 9174 } 9175 /* 9176 Show image matte. 9177 */ 9178 XSetCursorState(display,windows,MagickTrue); 9179 XCheckRefreshWindows(display,windows); 9180 image_info->group=(ssize_t) windows->image.id; 9181 (void) DeleteImageProperty(*image,"label"); 9182 (void) SetImageProperty(*image,"label","Matte",exception); 9183 (void) AcquireUniqueFilename(filename); 9184 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s", 9185 filename); 9186 status=WriteImage(image_info,*image,exception); 9187 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9188 matte_image=ReadImage(image_info,exception); 9189 (void) RelinquishUniqueFileResource(filename); 9190 if (matte_image == (Image *) NULL) 9191 break; 9192 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s", 9193 filename); 9194 status=WriteImage(image_info,matte_image,exception); 9195 matte_image=DestroyImage(matte_image); 9196 if (status == MagickFalse) 9197 XNoticeWidget(display,windows,"Unable to show matte", 9198 (*image)->filename); 9199 XDelay(display,1500); 9200 XSetCursorState(display,windows,MagickFalse); 9201 break; 9202 } 9203 case BackgroundCommand: 9204 { 9205 /* 9206 Background image. 9207 */ 9208 status=XBackgroundImage(display,resource_info,windows,image,exception); 9209 if (status == MagickFalse) 9210 break; 9211 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9212 if (nexus != (Image *) NULL) 9213 XClientMessage(display,windows->image.id,windows->im_protocols, 9214 windows->im_next_image,CurrentTime); 9215 break; 9216 } 9217 case SlideShowCommand: 9218 { 9219 static char 9220 delay[MaxTextExtent] = "5"; 9221 9222 /* 9223 Display next image after pausing. 9224 */ 9225 (void) XDialogWidget(display,windows,"Slide Show", 9226 "Pause how many 1/100ths of a second between images:",delay); 9227 if (*delay == '\0') 9228 break; 9229 resource_info->delay=StringToUnsignedLong(delay); 9230 XClientMessage(display,windows->image.id,windows->im_protocols, 9231 windows->im_next_image,CurrentTime); 9232 break; 9233 } 9234 case PreferencesCommand: 9235 { 9236 /* 9237 Set user preferences. 9238 */ 9239 status=XPreferencesWidget(display,resource_info,windows); 9240 if (status == MagickFalse) 9241 break; 9242 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9243 if (nexus != (Image *) NULL) 9244 XClientMessage(display,windows->image.id,windows->im_protocols, 9245 windows->im_next_image,CurrentTime); 9246 break; 9247 } 9248 case HelpCommand: 9249 { 9250 /* 9251 User requested help. 9252 */ 9253 XTextViewWidget(display,resource_info,windows,MagickFalse, 9254 "Help Viewer - Display",DisplayHelp); 9255 break; 9256 } 9257 case BrowseDocumentationCommand: 9258 { 9259 Atom 9260 mozilla_atom; 9261 9262 Window 9263 mozilla_window, 9264 root_window; 9265 9266 /* 9267 Browse the ImageMagick documentation. 9268 */ 9269 root_window=XRootWindow(display,XDefaultScreen(display)); 9270 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); 9271 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); 9272 if (mozilla_window != (Window) NULL) 9273 { 9274 char 9275 command[MaxTextExtent], 9276 *url; 9277 9278 /* 9279 Display documentation using Netscape remote control. 9280 */ 9281 url=GetMagickHomeURL(); 9282 (void) FormatLocaleString(command,MaxTextExtent, 9283 "openurl(%s,new-tab)",url); 9284 url=DestroyString(url); 9285 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); 9286 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING, 9287 8,PropModeReplace,(unsigned char *) command,(int) strlen(command)); 9288 XSetCursorState(display,windows,MagickFalse); 9289 break; 9290 } 9291 XSetCursorState(display,windows,MagickTrue); 9292 XCheckRefreshWindows(display,windows); 9293 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL, 9294 exception); 9295 if (status == MagickFalse) 9296 XNoticeWidget(display,windows,"Unable to browse documentation", 9297 (char *) NULL); 9298 XDelay(display,1500); 9299 XSetCursorState(display,windows,MagickFalse); 9300 break; 9301 } 9302 case VersionCommand: 9303 { 9304 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), 9305 GetMagickCopyright()); 9306 break; 9307 } 9308 case SaveToUndoBufferCommand: 9309 break; 9310 default: 9311 { 9312 (void) XBell(display,0); 9313 break; 9314 } 9315 } 9316 image_info=DestroyImageInfo(image_info); 9317 return(nexus); 9318} 9319 9320/* 9321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9322% % 9323% % 9324% % 9325+ X M a g n i f y I m a g e % 9326% % 9327% % 9328% % 9329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9330% 9331% XMagnifyImage() magnifies portions of the image as indicated by the pointer. 9332% The magnified portion is displayed in a separate window. 9333% 9334% The format of the XMagnifyImage method is: 9335% 9336% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9337% ExceptionInfo *exception) 9338% 9339% A description of each parameter follows: 9340% 9341% o display: Specifies a connection to an X server; returned from 9342% XOpenDisplay. 9343% 9344% o windows: Specifies a pointer to a XWindows structure. 9345% 9346% o event: Specifies a pointer to a XEvent structure. If it is NULL, 9347% the entire image is refreshed. 9348% 9349% o exception: return any errors or warnings in this structure. 9350% 9351*/ 9352static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9353 ExceptionInfo *exception) 9354{ 9355 char 9356 text[MaxTextExtent]; 9357 9358 register int 9359 x, 9360 y; 9361 9362 size_t 9363 state; 9364 9365 /* 9366 Update magnified image until the mouse button is released. 9367 */ 9368 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor); 9369 state=DefaultState; 9370 x=event->xbutton.x; 9371 y=event->xbutton.y; 9372 windows->magnify.x=(int) windows->image.x+x; 9373 windows->magnify.y=(int) windows->image.y+y; 9374 do 9375 { 9376 /* 9377 Map and unmap Info widget as text cursor crosses its boundaries. 9378 */ 9379 if (windows->info.mapped != MagickFalse) 9380 { 9381 if ((x < (int) (windows->info.x+windows->info.width)) && 9382 (y < (int) (windows->info.y+windows->info.height))) 9383 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 9384 } 9385 else 9386 if ((x > (int) (windows->info.x+windows->info.width)) || 9387 (y > (int) (windows->info.y+windows->info.height))) 9388 (void) XMapWindow(display,windows->info.id); 9389 if (windows->info.mapped != MagickFalse) 9390 { 9391 /* 9392 Display pointer position. 9393 */ 9394 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9395 windows->magnify.x,windows->magnify.y); 9396 XInfoWidget(display,windows,text); 9397 } 9398 /* 9399 Wait for next event. 9400 */ 9401 XScreenEvent(display,windows,event,exception); 9402 switch (event->type) 9403 { 9404 case ButtonPress: 9405 break; 9406 case ButtonRelease: 9407 { 9408 /* 9409 User has finished magnifying image. 9410 */ 9411 x=event->xbutton.x; 9412 y=event->xbutton.y; 9413 state|=ExitState; 9414 break; 9415 } 9416 case Expose: 9417 break; 9418 case MotionNotify: 9419 { 9420 x=event->xmotion.x; 9421 y=event->xmotion.y; 9422 break; 9423 } 9424 default: 9425 break; 9426 } 9427 /* 9428 Check boundary conditions. 9429 */ 9430 if (x < 0) 9431 x=0; 9432 else 9433 if (x >= (int) windows->image.width) 9434 x=(int) windows->image.width-1; 9435 if (y < 0) 9436 y=0; 9437 else 9438 if (y >= (int) windows->image.height) 9439 y=(int) windows->image.height-1; 9440 } while ((state & ExitState) == 0); 9441 /* 9442 Display magnified image. 9443 */ 9444 XSetCursorState(display,windows,MagickFalse); 9445} 9446 9447/* 9448%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9449% % 9450% % 9451% % 9452+ X M a g n i f y W i n d o w C o m m a n d % 9453% % 9454% % 9455% % 9456%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9457% 9458% XMagnifyWindowCommand() moves the image within an Magnify window by one 9459% pixel as specified by the key symbol. 9460% 9461% The format of the XMagnifyWindowCommand method is: 9462% 9463% void XMagnifyWindowCommand(Display *display,XWindows *windows, 9464% const MagickStatusType state,const KeySym key_symbol, 9465% ExceptionInfo *exception) 9466% 9467% A description of each parameter follows: 9468% 9469% o display: Specifies a connection to an X server; returned from 9470% XOpenDisplay. 9471% 9472% o windows: Specifies a pointer to a XWindows structure. 9473% 9474% o state: key mask. 9475% 9476% o key_symbol: Specifies a KeySym which indicates which side of the image 9477% to trim. 9478% 9479% o exception: return any errors or warnings in this structure. 9480% 9481*/ 9482static void XMagnifyWindowCommand(Display *display,XWindows *windows, 9483 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception) 9484{ 9485 unsigned int 9486 quantum; 9487 9488 /* 9489 User specified a magnify factor or position. 9490 */ 9491 quantum=1; 9492 if ((state & Mod1Mask) != 0) 9493 quantum=10; 9494 switch ((int) key_symbol) 9495 { 9496 case QuitCommand: 9497 { 9498 (void) XWithdrawWindow(display,windows->magnify.id, 9499 windows->magnify.screen); 9500 break; 9501 } 9502 case XK_Home: 9503 case XK_KP_Home: 9504 { 9505 windows->magnify.x=(int) windows->image.width/2; 9506 windows->magnify.y=(int) windows->image.height/2; 9507 break; 9508 } 9509 case XK_Left: 9510 case XK_KP_Left: 9511 { 9512 if (windows->magnify.x > 0) 9513 windows->magnify.x-=quantum; 9514 break; 9515 } 9516 case XK_Up: 9517 case XK_KP_Up: 9518 { 9519 if (windows->magnify.y > 0) 9520 windows->magnify.y-=quantum; 9521 break; 9522 } 9523 case XK_Right: 9524 case XK_KP_Right: 9525 { 9526 if (windows->magnify.x < (int) (windows->image.ximage->width-1)) 9527 windows->magnify.x+=quantum; 9528 break; 9529 } 9530 case XK_Down: 9531 case XK_KP_Down: 9532 { 9533 if (windows->magnify.y < (int) (windows->image.ximage->height-1)) 9534 windows->magnify.y+=quantum; 9535 break; 9536 } 9537 case XK_0: 9538 case XK_1: 9539 case XK_2: 9540 case XK_3: 9541 case XK_4: 9542 case XK_5: 9543 case XK_6: 9544 case XK_7: 9545 case XK_8: 9546 case XK_9: 9547 { 9548 windows->magnify.data=(key_symbol-XK_0); 9549 break; 9550 } 9551 case XK_KP_0: 9552 case XK_KP_1: 9553 case XK_KP_2: 9554 case XK_KP_3: 9555 case XK_KP_4: 9556 case XK_KP_5: 9557 case XK_KP_6: 9558 case XK_KP_7: 9559 case XK_KP_8: 9560 case XK_KP_9: 9561 { 9562 windows->magnify.data=(key_symbol-XK_KP_0); 9563 break; 9564 } 9565 default: 9566 break; 9567 } 9568 XMakeMagnifyImage(display,windows,exception); 9569} 9570 9571/* 9572%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9573% % 9574% % 9575% % 9576+ X M a k e P a n I m a g e % 9577% % 9578% % 9579% % 9580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9581% 9582% XMakePanImage() creates a thumbnail of the image and displays it in the Pan 9583% icon window. 9584% 9585% The format of the XMakePanImage method is: 9586% 9587% void XMakePanImage(Display *display,XResourceInfo *resource_info, 9588% XWindows *windows,Image *image,ExceptionInfo *exception) 9589% 9590% A description of each parameter follows: 9591% 9592% o display: Specifies a connection to an X server; returned from 9593% XOpenDisplay. 9594% 9595% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9596% 9597% o windows: Specifies a pointer to a XWindows structure. 9598% 9599% o image: the image. 9600% 9601% o exception: return any errors or warnings in this structure. 9602% 9603*/ 9604static void XMakePanImage(Display *display,XResourceInfo *resource_info, 9605 XWindows *windows,Image *image,ExceptionInfo *exception) 9606{ 9607 MagickStatusType 9608 status; 9609 9610 /* 9611 Create and display image for panning icon. 9612 */ 9613 XSetCursorState(display,windows,MagickTrue); 9614 XCheckRefreshWindows(display,windows); 9615 windows->pan.x=(int) windows->image.x; 9616 windows->pan.y=(int) windows->image.y; 9617 status=XMakeImage(display,resource_info,&windows->pan,image, 9618 windows->pan.width,windows->pan.height,exception); 9619 if (status == MagickFalse) 9620 ThrowXWindowFatalException(ResourceLimitError, 9621 "MemoryAllocationFailed",image->filename); 9622 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 9623 windows->pan.pixmap); 9624 (void) XClearWindow(display,windows->pan.id); 9625 XDrawPanRectangle(display,windows); 9626 XSetCursorState(display,windows,MagickFalse); 9627} 9628 9629/* 9630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9631% % 9632% % 9633% % 9634+ X M a t t a E d i t I m a g e % 9635% % 9636% % 9637% % 9638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9639% 9640% XMatteEditImage() allows the user to interactively change the Matte channel 9641% of an image. If the image is PseudoClass it is promoted to DirectClass 9642% before the matte information is stored. 9643% 9644% The format of the XMatteEditImage method is: 9645% 9646% MagickBooleanType XMatteEditImage(Display *display, 9647% XResourceInfo *resource_info,XWindows *windows,Image **image, 9648% ExceptionInfo *exception) 9649% 9650% A description of each parameter follows: 9651% 9652% o display: Specifies a connection to an X server; returned from 9653% XOpenDisplay. 9654% 9655% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9656% 9657% o windows: Specifies a pointer to a XWindows structure. 9658% 9659% o image: the image; returned from ReadImage. 9660% 9661% o exception: return any errors or warnings in this structure. 9662% 9663*/ 9664static MagickBooleanType XMatteEditImage(Display *display, 9665 XResourceInfo *resource_info,XWindows *windows,Image **image, 9666 ExceptionInfo *exception) 9667{ 9668 static char 9669 matte[MaxTextExtent] = "0"; 9670 9671 static const char 9672 *MatteEditMenu[] = 9673 { 9674 "Method", 9675 "Border Color", 9676 "Fuzz", 9677 "Matte Value", 9678 "Undo", 9679 "Help", 9680 "Dismiss", 9681 (char *) NULL 9682 }; 9683 9684 static const ModeType 9685 MatteEditCommands[] = 9686 { 9687 MatteEditMethod, 9688 MatteEditBorderCommand, 9689 MatteEditFuzzCommand, 9690 MatteEditValueCommand, 9691 MatteEditUndoCommand, 9692 MatteEditHelpCommand, 9693 MatteEditDismissCommand 9694 }; 9695 9696 static PaintMethod 9697 method = PointMethod; 9698 9699 static XColor 9700 border_color = { 0, 0, 0, 0, 0, 0 }; 9701 9702 char 9703 command[MaxTextExtent], 9704 text[MaxTextExtent]; 9705 9706 Cursor 9707 cursor; 9708 9709 int 9710 entry, 9711 id, 9712 x, 9713 x_offset, 9714 y, 9715 y_offset; 9716 9717 register int 9718 i; 9719 9720 register Quantum 9721 *q; 9722 9723 unsigned int 9724 height, 9725 width; 9726 9727 size_t 9728 state; 9729 9730 XEvent 9731 event; 9732 9733 /* 9734 Map Command widget. 9735 */ 9736 (void) CloneString(&windows->command.name,"Matte Edit"); 9737 windows->command.data=4; 9738 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL); 9739 (void) XMapRaised(display,windows->command.id); 9740 XClientMessage(display,windows->image.id,windows->im_protocols, 9741 windows->im_update_widget,CurrentTime); 9742 /* 9743 Make cursor. 9744 */ 9745 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 9746 resource_info->background_color,resource_info->foreground_color); 9747 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9748 /* 9749 Track pointer until button 1 is pressed. 9750 */ 9751 XQueryPosition(display,windows->image.id,&x,&y); 9752 (void) XSelectInput(display,windows->image.id, 9753 windows->image.attributes.event_mask | PointerMotionMask); 9754 state=DefaultState; 9755 do 9756 { 9757 if (windows->info.mapped != MagickFalse) 9758 { 9759 /* 9760 Display pointer position. 9761 */ 9762 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9763 x+windows->image.x,y+windows->image.y); 9764 XInfoWidget(display,windows,text); 9765 } 9766 /* 9767 Wait for next event. 9768 */ 9769 XScreenEvent(display,windows,&event,exception); 9770 if (event.xany.window == windows->command.id) 9771 { 9772 /* 9773 Select a command from the Command widget. 9774 */ 9775 id=XCommandWidget(display,windows,MatteEditMenu,&event); 9776 if (id < 0) 9777 { 9778 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9779 continue; 9780 } 9781 switch (MatteEditCommands[id]) 9782 { 9783 case MatteEditMethod: 9784 { 9785 char 9786 **methods; 9787 9788 /* 9789 Select a method from the pop-up menu. 9790 */ 9791 methods=GetCommandOptions(MagickMethodOptions); 9792 if (methods == (char **) NULL) 9793 break; 9794 entry=XMenuWidget(display,windows,MatteEditMenu[id], 9795 (const char **) methods,command); 9796 if (entry >= 0) 9797 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 9798 MagickFalse,methods[entry]); 9799 methods=DestroyStringList(methods); 9800 break; 9801 } 9802 case MatteEditBorderCommand: 9803 { 9804 const char 9805 *ColorMenu[MaxNumberPens]; 9806 9807 int 9808 pen_number; 9809 9810 /* 9811 Initialize menu selections. 9812 */ 9813 for (i=0; i < (int) (MaxNumberPens-2); i++) 9814 ColorMenu[i]=resource_info->pen_colors[i]; 9815 ColorMenu[MaxNumberPens-2]="Browser..."; 9816 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 9817 /* 9818 Select a pen color from the pop-up menu. 9819 */ 9820 pen_number=XMenuWidget(display,windows,MatteEditMenu[id], 9821 (const char **) ColorMenu,command); 9822 if (pen_number < 0) 9823 break; 9824 if (pen_number == (MaxNumberPens-2)) 9825 { 9826 static char 9827 color_name[MaxTextExtent] = "gray"; 9828 9829 /* 9830 Select a pen color from a dialog. 9831 */ 9832 resource_info->pen_colors[pen_number]=color_name; 9833 XColorBrowserWidget(display,windows,"Select",color_name); 9834 if (*color_name == '\0') 9835 break; 9836 } 9837 /* 9838 Set border color. 9839 */ 9840 (void) XParseColor(display,windows->map_info->colormap, 9841 resource_info->pen_colors[pen_number],&border_color); 9842 break; 9843 } 9844 case MatteEditFuzzCommand: 9845 { 9846 static char 9847 fuzz[MaxTextExtent]; 9848 9849 static const char 9850 *FuzzMenu[] = 9851 { 9852 "0%", 9853 "2%", 9854 "5%", 9855 "10%", 9856 "15%", 9857 "Dialog...", 9858 (char *) NULL, 9859 }; 9860 9861 /* 9862 Select a command from the pop-up menu. 9863 */ 9864 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu, 9865 command); 9866 if (entry < 0) 9867 break; 9868 if (entry != 5) 9869 { 9870 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 9871 QuantumRange+1.0); 9872 break; 9873 } 9874 (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 9875 (void) XDialogWidget(display,windows,"Ok", 9876 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 9877 if (*fuzz == '\0') 9878 break; 9879 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 9880 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 9881 1.0); 9882 break; 9883 } 9884 case MatteEditValueCommand: 9885 { 9886 static char 9887 message[MaxTextExtent]; 9888 9889 static const char 9890 *MatteMenu[] = 9891 { 9892 "Opaque", 9893 "Transparent", 9894 "Dialog...", 9895 (char *) NULL, 9896 }; 9897 9898 /* 9899 Select a command from the pop-up menu. 9900 */ 9901 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu, 9902 command); 9903 if (entry < 0) 9904 break; 9905 if (entry != 2) 9906 { 9907 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9908 OpaqueAlpha); 9909 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9910 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9911 (Quantum) TransparentAlpha); 9912 break; 9913 } 9914 (void) FormatLocaleString(message,MaxTextExtent, 9915 "Enter matte value (0 - " QuantumFormat "):",(Quantum) 9916 QuantumRange); 9917 (void) XDialogWidget(display,windows,"Matte",message,matte); 9918 if (*matte == '\0') 9919 break; 9920 break; 9921 } 9922 case MatteEditUndoCommand: 9923 { 9924 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 9925 image,exception); 9926 break; 9927 } 9928 case MatteEditHelpCommand: 9929 { 9930 XTextViewWidget(display,resource_info,windows,MagickFalse, 9931 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9932 break; 9933 } 9934 case MatteEditDismissCommand: 9935 { 9936 /* 9937 Prematurely exit. 9938 */ 9939 state|=EscapeState; 9940 state|=ExitState; 9941 break; 9942 } 9943 default: 9944 break; 9945 } 9946 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9947 continue; 9948 } 9949 switch (event.type) 9950 { 9951 case ButtonPress: 9952 { 9953 if (event.xbutton.button != Button1) 9954 break; 9955 if ((event.xbutton.window != windows->image.id) && 9956 (event.xbutton.window != windows->magnify.id)) 9957 break; 9958 /* 9959 Update matte data. 9960 */ 9961 x=event.xbutton.x; 9962 y=event.xbutton.y; 9963 (void) XMagickCommand(display,resource_info,windows, 9964 SaveToUndoBufferCommand,image,exception); 9965 state|=UpdateConfigurationState; 9966 break; 9967 } 9968 case ButtonRelease: 9969 { 9970 if (event.xbutton.button != Button1) 9971 break; 9972 if ((event.xbutton.window != windows->image.id) && 9973 (event.xbutton.window != windows->magnify.id)) 9974 break; 9975 /* 9976 Update colormap information. 9977 */ 9978 x=event.xbutton.x; 9979 y=event.xbutton.y; 9980 XConfigureImageColormap(display,resource_info,windows,*image,exception); 9981 (void) XConfigureImage(display,resource_info,windows,*image,exception); 9982 XInfoWidget(display,windows,text); 9983 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9984 state&=(~UpdateConfigurationState); 9985 break; 9986 } 9987 case Expose: 9988 break; 9989 case KeyPress: 9990 { 9991 char 9992 command[MaxTextExtent]; 9993 9994 KeySym 9995 key_symbol; 9996 9997 if (event.xkey.window == windows->magnify.id) 9998 { 9999 Window 10000 window; 10001 10002 window=windows->magnify.id; 10003 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 10004 } 10005 if (event.xkey.window != windows->image.id) 10006 break; 10007 /* 10008 Respond to a user key press. 10009 */ 10010 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 10011 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10012 switch ((int) key_symbol) 10013 { 10014 case XK_Escape: 10015 case XK_F20: 10016 { 10017 /* 10018 Prematurely exit. 10019 */ 10020 state|=ExitState; 10021 break; 10022 } 10023 case XK_F1: 10024 case XK_Help: 10025 { 10026 XTextViewWidget(display,resource_info,windows,MagickFalse, 10027 "Help Viewer - Matte Edit",ImageMatteEditHelp); 10028 break; 10029 } 10030 default: 10031 { 10032 (void) XBell(display,0); 10033 break; 10034 } 10035 } 10036 break; 10037 } 10038 case MotionNotify: 10039 { 10040 /* 10041 Map and unmap Info widget as cursor crosses its boundaries. 10042 */ 10043 x=event.xmotion.x; 10044 y=event.xmotion.y; 10045 if (windows->info.mapped != MagickFalse) 10046 { 10047 if ((x < (int) (windows->info.x+windows->info.width)) && 10048 (y < (int) (windows->info.y+windows->info.height))) 10049 (void) XWithdrawWindow(display,windows->info.id, 10050 windows->info.screen); 10051 } 10052 else 10053 if ((x > (int) (windows->info.x+windows->info.width)) || 10054 (y > (int) (windows->info.y+windows->info.height))) 10055 (void) XMapWindow(display,windows->info.id); 10056 break; 10057 } 10058 default: 10059 break; 10060 } 10061 if (event.xany.window == windows->magnify.id) 10062 { 10063 x=windows->magnify.x-windows->image.x; 10064 y=windows->magnify.y-windows->image.y; 10065 } 10066 x_offset=x; 10067 y_offset=y; 10068 if ((state & UpdateConfigurationState) != 0) 10069 { 10070 CacheView 10071 *image_view; 10072 10073 int 10074 x, 10075 y; 10076 10077 /* 10078 Matte edit is relative to image configuration. 10079 */ 10080 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 10081 MagickTrue); 10082 XPutPixel(windows->image.ximage,x_offset,y_offset, 10083 windows->pixel_info->background_color.pixel); 10084 width=(unsigned int) (*image)->columns; 10085 height=(unsigned int) (*image)->rows; 10086 x=0; 10087 y=0; 10088 if (windows->image.crop_geometry != (char *) NULL) 10089 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width, 10090 &height); 10091 x_offset=(int) (width*(windows->image.x+x_offset)/ 10092 windows->image.ximage->width+x); 10093 y_offset=(int) (height*(windows->image.y+y_offset)/ 10094 windows->image.ximage->height+y); 10095 if ((x_offset < 0) || (y_offset < 0)) 10096 continue; 10097 if ((x_offset >= (int) (*image)->columns) || 10098 (y_offset >= (int) (*image)->rows)) 10099 continue; 10100 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10101 return(MagickFalse); 10102 (*image)->matte=MagickTrue; 10103 image_view=AcquireCacheView(*image); 10104 switch (method) 10105 { 10106 case PointMethod: 10107 default: 10108 { 10109 /* 10110 Update matte information using point algorithm. 10111 */ 10112 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset, 10113 (ssize_t) y_offset,1,1,exception); 10114 if (q == (Quantum *) NULL) 10115 break; 10116 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10117 (void) SyncCacheViewAuthenticPixels(image_view,exception); 10118 break; 10119 } 10120 case ReplaceMethod: 10121 { 10122 PixelInfo 10123 pixel, 10124 target; 10125 10126 Quantum 10127 virtual_pixel[CompositePixelChannel]; 10128 10129 /* 10130 Update matte information using replace algorithm. 10131 */ 10132 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 10133 (ssize_t) y_offset,virtual_pixel,exception); 10134 target.red=virtual_pixel[RedPixelChannel]; 10135 target.green=virtual_pixel[GreenPixelChannel]; 10136 target.blue=virtual_pixel[BluePixelChannel]; 10137 target.alpha=virtual_pixel[AlphaPixelChannel]; 10138 for (y=0; y < (int) (*image)->rows; y++) 10139 { 10140 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10141 (*image)->columns,1,exception); 10142 if (q == (Quantum *) NULL) 10143 break; 10144 for (x=0; x < (int) (*image)->columns; x++) 10145 { 10146 GetPixelInfoPixel(*image,q,&pixel); 10147 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 10148 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10149 q+=GetPixelChannels(*image); 10150 } 10151 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10152 break; 10153 } 10154 break; 10155 } 10156 case FloodfillMethod: 10157 case FillToBorderMethod: 10158 { 10159 ChannelType 10160 channel_mask; 10161 10162 DrawInfo 10163 *draw_info; 10164 10165 PixelInfo 10166 target; 10167 10168 /* 10169 Update matte information using floodfill algorithm. 10170 */ 10171 (void) GetOneVirtualPixelInfo(*image, 10172 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 10173 y_offset,&target,exception); 10174 if (method == FillToBorderMethod) 10175 { 10176 target.red=(MagickRealType) ScaleShortToQuantum( 10177 border_color.red); 10178 target.green=(MagickRealType) ScaleShortToQuantum( 10179 border_color.green); 10180 target.blue=(MagickRealType) ScaleShortToQuantum( 10181 border_color.blue); 10182 } 10183 draw_info=CloneDrawInfo(resource_info->image_info, 10184 (DrawInfo *) NULL); 10185 draw_info->fill.alpha=ClampToQuantum(StringToDouble(matte, 10186 (char **) NULL)); 10187 channel_mask=SetPixelChannelMask(*image,AlphaChannel); 10188 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 10189 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 10190 MagickFalse : MagickTrue,exception); 10191 (void) SetPixelChannelMapMask(*image,channel_mask); 10192 draw_info=DestroyDrawInfo(draw_info); 10193 break; 10194 } 10195 case ResetMethod: 10196 { 10197 /* 10198 Update matte information using reset algorithm. 10199 */ 10200 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 10201 return(MagickFalse); 10202 for (y=0; y < (int) (*image)->rows; y++) 10203 { 10204 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10205 (*image)->columns,1,exception); 10206 if (q == (Quantum *) NULL) 10207 break; 10208 for (x=0; x < (int) (*image)->columns; x++) 10209 { 10210 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10211 q+=GetPixelChannels(*image); 10212 } 10213 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 10214 break; 10215 } 10216 if (StringToLong(matte) == (long) OpaqueAlpha) 10217 (*image)->matte=MagickFalse; 10218 break; 10219 } 10220 } 10221 image_view=DestroyCacheView(image_view); 10222 state&=(~UpdateConfigurationState); 10223 } 10224 } while ((state & ExitState) == 0); 10225 (void) XSelectInput(display,windows->image.id, 10226 windows->image.attributes.event_mask); 10227 XSetCursorState(display,windows,MagickFalse); 10228 (void) XFreeCursor(display,cursor); 10229 return(MagickTrue); 10230} 10231 10232/* 10233%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10234% % 10235% % 10236% % 10237+ X O p e n I m a g e % 10238% % 10239% % 10240% % 10241%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10242% 10243% XOpenImage() loads an image from a file. 10244% 10245% The format of the XOpenImage method is: 10246% 10247% Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10248% XWindows *windows,const unsigned int command) 10249% 10250% A description of each parameter follows: 10251% 10252% o display: Specifies a connection to an X server; returned from 10253% XOpenDisplay. 10254% 10255% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10256% 10257% o windows: Specifies a pointer to a XWindows structure. 10258% 10259% o command: A value other than zero indicates that the file is selected 10260% from the command line argument list. 10261% 10262*/ 10263static Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10264 XWindows *windows,const MagickBooleanType command) 10265{ 10266 const MagickInfo 10267 *magick_info; 10268 10269 ExceptionInfo 10270 *exception; 10271 10272 Image 10273 *nexus; 10274 10275 ImageInfo 10276 *image_info; 10277 10278 static char 10279 filename[MaxTextExtent] = "\0"; 10280 10281 /* 10282 Request file name from user. 10283 */ 10284 if (command == MagickFalse) 10285 XFileBrowserWidget(display,windows,"Open",filename); 10286 else 10287 { 10288 char 10289 **filelist, 10290 **files; 10291 10292 int 10293 count, 10294 status; 10295 10296 register int 10297 i, 10298 j; 10299 10300 /* 10301 Select next image from the command line. 10302 */ 10303 status=XGetCommand(display,windows->image.id,&files,&count); 10304 if (status == 0) 10305 { 10306 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","..."); 10307 return((Image *) NULL); 10308 } 10309 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10310 if (filelist == (char **) NULL) 10311 { 10312 ThrowXWindowFatalException(ResourceLimitError, 10313 "MemoryAllocationFailed","..."); 10314 (void) XFreeStringList(files); 10315 return((Image *) NULL); 10316 } 10317 j=0; 10318 for (i=1; i < count; i++) 10319 if (*files[i] != '-') 10320 filelist[j++]=files[i]; 10321 filelist[j]=(char *) NULL; 10322 XListBrowserWidget(display,windows,&windows->widget, 10323 (const char **) filelist,"Load","Select Image to Load:",filename); 10324 filelist=(char **) RelinquishMagickMemory(filelist); 10325 (void) XFreeStringList(files); 10326 } 10327 if (*filename == '\0') 10328 return((Image *) NULL); 10329 image_info=CloneImageInfo(resource_info->image_info); 10330 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL, 10331 (void *) NULL); 10332 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10333 exception=AcquireExceptionInfo(); 10334 (void) SetImageInfo(image_info,0,exception); 10335 if (LocaleCompare(image_info->magick,"X") == 0) 10336 { 10337 char 10338 seconds[MaxTextExtent]; 10339 10340 /* 10341 User may want to delay the X server screen grab. 10342 */ 10343 (void) CopyMagickString(seconds,"0",MaxTextExtent); 10344 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:", 10345 seconds); 10346 if (*seconds == '\0') 10347 return((Image *) NULL); 10348 XDelay(display,(size_t) (1000*StringToLong(seconds))); 10349 } 10350 magick_info=GetMagickInfo(image_info->magick,exception); 10351 if ((magick_info != (const MagickInfo *) NULL) && 10352 (magick_info->raw != MagickFalse)) 10353 { 10354 char 10355 geometry[MaxTextExtent]; 10356 10357 /* 10358 Request image size from the user. 10359 */ 10360 (void) CopyMagickString(geometry,"512x512",MaxTextExtent); 10361 if (image_info->size != (char *) NULL) 10362 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent); 10363 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:", 10364 geometry); 10365 (void) CloneString(&image_info->size,geometry); 10366 } 10367 /* 10368 Load the image. 10369 */ 10370 XSetCursorState(display,windows,MagickTrue); 10371 XCheckRefreshWindows(display,windows); 10372 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10373 nexus=ReadImage(image_info,exception); 10374 CatchException(exception); 10375 XSetCursorState(display,windows,MagickFalse); 10376 if (nexus != (Image *) NULL) 10377 XClientMessage(display,windows->image.id,windows->im_protocols, 10378 windows->im_next_image,CurrentTime); 10379 else 10380 { 10381 char 10382 *text, 10383 **textlist; 10384 10385 /* 10386 Unknown image format. 10387 */ 10388 text=FileToString(filename,~0,exception); 10389 if (text == (char *) NULL) 10390 return((Image *) NULL); 10391 textlist=StringToList(text); 10392 if (textlist != (char **) NULL) 10393 { 10394 char 10395 title[MaxTextExtent]; 10396 10397 register int 10398 i; 10399 10400 (void) FormatLocaleString(title,MaxTextExtent, 10401 "Unknown format: %s",filename); 10402 XTextViewWidget(display,resource_info,windows,MagickTrue,title, 10403 (const char **) textlist); 10404 for (i=0; textlist[i] != (char *) NULL; i++) 10405 textlist[i]=DestroyString(textlist[i]); 10406 textlist=(char **) RelinquishMagickMemory(textlist); 10407 } 10408 text=DestroyString(text); 10409 } 10410 exception=DestroyExceptionInfo(exception); 10411 image_info=DestroyImageInfo(image_info); 10412 return(nexus); 10413} 10414 10415/* 10416%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10417% % 10418% % 10419% % 10420+ X P a n I m a g e % 10421% % 10422% % 10423% % 10424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10425% 10426% XPanImage() pans the image until the mouse button is released. 10427% 10428% The format of the XPanImage method is: 10429% 10430% void XPanImage(Display *display,XWindows *windows,XEvent *event, 10431% ExceptionInfo *exception) 10432% 10433% A description of each parameter follows: 10434% 10435% o display: Specifies a connection to an X server; returned from 10436% XOpenDisplay. 10437% 10438% o windows: Specifies a pointer to a XWindows structure. 10439% 10440% o event: Specifies a pointer to a XEvent structure. If it is NULL, 10441% the entire image is refreshed. 10442% 10443% o exception: return any errors or warnings in this structure. 10444% 10445*/ 10446static void XPanImage(Display *display,XWindows *windows,XEvent *event, 10447 ExceptionInfo *exception) 10448{ 10449 char 10450 text[MaxTextExtent]; 10451 10452 Cursor 10453 cursor; 10454 10455 MagickRealType 10456 x_factor, 10457 y_factor; 10458 10459 RectangleInfo 10460 pan_info; 10461 10462 size_t 10463 state; 10464 10465 /* 10466 Define cursor. 10467 */ 10468 if ((windows->image.ximage->width > (int) windows->image.width) && 10469 (windows->image.ximage->height > (int) windows->image.height)) 10470 cursor=XCreateFontCursor(display,XC_fleur); 10471 else 10472 if (windows->image.ximage->width > (int) windows->image.width) 10473 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow); 10474 else 10475 if (windows->image.ximage->height > (int) windows->image.height) 10476 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow); 10477 else 10478 cursor=XCreateFontCursor(display,XC_arrow); 10479 (void) XCheckDefineCursor(display,windows->pan.id,cursor); 10480 /* 10481 Pan image as pointer moves until the mouse button is released. 10482 */ 10483 x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width; 10484 y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height; 10485 pan_info.width=windows->pan.width*windows->image.width/ 10486 windows->image.ximage->width; 10487 pan_info.height=windows->pan.height*windows->image.height/ 10488 windows->image.ximage->height; 10489 pan_info.x=0; 10490 pan_info.y=0; 10491 state=UpdateConfigurationState; 10492 do 10493 { 10494 switch (event->type) 10495 { 10496 case ButtonPress: 10497 { 10498 /* 10499 User choose an initial pan location. 10500 */ 10501 pan_info.x=(ssize_t) event->xbutton.x; 10502 pan_info.y=(ssize_t) event->xbutton.y; 10503 state|=UpdateConfigurationState; 10504 break; 10505 } 10506 case ButtonRelease: 10507 { 10508 /* 10509 User has finished panning the image. 10510 */ 10511 pan_info.x=(ssize_t) event->xbutton.x; 10512 pan_info.y=(ssize_t) event->xbutton.y; 10513 state|=UpdateConfigurationState | ExitState; 10514 break; 10515 } 10516 case MotionNotify: 10517 { 10518 pan_info.x=(ssize_t) event->xmotion.x; 10519 pan_info.y=(ssize_t) event->xmotion.y; 10520 state|=UpdateConfigurationState; 10521 } 10522 default: 10523 break; 10524 } 10525 if ((state & UpdateConfigurationState) != 0) 10526 { 10527 /* 10528 Check boundary conditions. 10529 */ 10530 if (pan_info.x < (ssize_t) (pan_info.width/2)) 10531 pan_info.x=0; 10532 else 10533 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2))); 10534 if (pan_info.x < 0) 10535 pan_info.x=0; 10536 else 10537 if ((int) (pan_info.x+windows->image.width) > 10538 windows->image.ximage->width) 10539 pan_info.x=(ssize_t) 10540 (windows->image.ximage->width-windows->image.width); 10541 if (pan_info.y < (ssize_t) (pan_info.height/2)) 10542 pan_info.y=0; 10543 else 10544 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2))); 10545 if (pan_info.y < 0) 10546 pan_info.y=0; 10547 else 10548 if ((int) (pan_info.y+windows->image.height) > 10549 windows->image.ximage->height) 10550 pan_info.y=(ssize_t) 10551 (windows->image.ximage->height-windows->image.height); 10552 if ((windows->image.x != (int) pan_info.x) || 10553 (windows->image.y != (int) pan_info.y)) 10554 { 10555 /* 10556 Display image pan offset. 10557 */ 10558 windows->image.x=(int) pan_info.x; 10559 windows->image.y=(int) pan_info.y; 10560 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 10561 windows->image.width,windows->image.height,windows->image.x, 10562 windows->image.y); 10563 XInfoWidget(display,windows,text); 10564 /* 10565 Refresh Image window. 10566 */ 10567 XDrawPanRectangle(display,windows); 10568 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 10569 } 10570 state&=(~UpdateConfigurationState); 10571 } 10572 /* 10573 Wait for next event. 10574 */ 10575 if ((state & ExitState) == 0) 10576 XScreenEvent(display,windows,event,exception); 10577 } while ((state & ExitState) == 0); 10578 /* 10579 Restore cursor. 10580 */ 10581 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor); 10582 (void) XFreeCursor(display,cursor); 10583 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 10584} 10585 10586/* 10587%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10588% % 10589% % 10590% % 10591+ X P a s t e I m a g e % 10592% % 10593% % 10594% % 10595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10596% 10597% XPasteImage() pastes an image previously saved with XCropImage in the X 10598% window image at a location the user chooses with the pointer. 10599% 10600% The format of the XPasteImage method is: 10601% 10602% MagickBooleanType XPasteImage(Display *display, 10603% XResourceInfo *resource_info,XWindows *windows,Image *image, 10604% ExceptionInfo *exception) 10605% 10606% A description of each parameter follows: 10607% 10608% o display: Specifies a connection to an X server; returned from 10609% XOpenDisplay. 10610% 10611% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10612% 10613% o windows: Specifies a pointer to a XWindows structure. 10614% 10615% o image: the image; returned from ReadImage. 10616% 10617% o exception: return any errors or warnings in this structure. 10618% 10619*/ 10620static MagickBooleanType XPasteImage(Display *display, 10621 XResourceInfo *resource_info,XWindows *windows,Image *image, 10622 ExceptionInfo *exception) 10623{ 10624 static const char 10625 *PasteMenu[] = 10626 { 10627 "Operator", 10628 "Help", 10629 "Dismiss", 10630 (char *) NULL 10631 }; 10632 10633 static const ModeType 10634 PasteCommands[] = 10635 { 10636 PasteOperatorsCommand, 10637 PasteHelpCommand, 10638 PasteDismissCommand 10639 }; 10640 10641 static CompositeOperator 10642 compose = CopyCompositeOp; 10643 10644 char 10645 text[MaxTextExtent]; 10646 10647 Cursor 10648 cursor; 10649 10650 Image 10651 *paste_image; 10652 10653 int 10654 entry, 10655 id, 10656 x, 10657 y; 10658 10659 MagickRealType 10660 scale_factor; 10661 10662 RectangleInfo 10663 highlight_info, 10664 paste_info; 10665 10666 unsigned int 10667 height, 10668 width; 10669 10670 size_t 10671 state; 10672 10673 XEvent 10674 event; 10675 10676 /* 10677 Copy image. 10678 */ 10679 if (resource_info->copy_image == (Image *) NULL) 10680 return(MagickFalse); 10681 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception); 10682 /* 10683 Map Command widget. 10684 */ 10685 (void) CloneString(&windows->command.name,"Paste"); 10686 windows->command.data=1; 10687 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL); 10688 (void) XMapRaised(display,windows->command.id); 10689 XClientMessage(display,windows->image.id,windows->im_protocols, 10690 windows->im_update_widget,CurrentTime); 10691 /* 10692 Track pointer until button 1 is pressed. 10693 */ 10694 XSetCursorState(display,windows,MagickFalse); 10695 XQueryPosition(display,windows->image.id,&x,&y); 10696 (void) XSelectInput(display,windows->image.id, 10697 windows->image.attributes.event_mask | PointerMotionMask); 10698 paste_info.x=(ssize_t) windows->image.x+x; 10699 paste_info.y=(ssize_t) windows->image.y+y; 10700 paste_info.width=0; 10701 paste_info.height=0; 10702 cursor=XCreateFontCursor(display,XC_ul_angle); 10703 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 10704 state=DefaultState; 10705 do 10706 { 10707 if (windows->info.mapped != MagickFalse) 10708 { 10709 /* 10710 Display pointer position. 10711 */ 10712 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 10713 (long) paste_info.x,(long) paste_info.y); 10714 XInfoWidget(display,windows,text); 10715 } 10716 highlight_info=paste_info; 10717 highlight_info.x=paste_info.x-windows->image.x; 10718 highlight_info.y=paste_info.y-windows->image.y; 10719 XHighlightRectangle(display,windows->image.id, 10720 windows->image.highlight_context,&highlight_info); 10721 /* 10722 Wait for next event. 10723 */ 10724 XScreenEvent(display,windows,&event,exception); 10725 XHighlightRectangle(display,windows->image.id, 10726 windows->image.highlight_context,&highlight_info); 10727 if (event.xany.window == windows->command.id) 10728 { 10729 /* 10730 Select a command from the Command widget. 10731 */ 10732 id=XCommandWidget(display,windows,PasteMenu,&event); 10733 if (id < 0) 10734 continue; 10735 switch (PasteCommands[id]) 10736 { 10737 case PasteOperatorsCommand: 10738 { 10739 char 10740 command[MaxTextExtent], 10741 **operators; 10742 10743 /* 10744 Select a command from the pop-up menu. 10745 */ 10746 operators=GetCommandOptions(MagickComposeOptions); 10747 if (operators == (char **) NULL) 10748 break; 10749 entry=XMenuWidget(display,windows,PasteMenu[id], 10750 (const char **) operators,command); 10751 if (entry >= 0) 10752 compose=(CompositeOperator) ParseCommandOption( 10753 MagickComposeOptions,MagickFalse,operators[entry]); 10754 operators=DestroyStringList(operators); 10755 break; 10756 } 10757 case PasteHelpCommand: 10758 { 10759 XTextViewWidget(display,resource_info,windows,MagickFalse, 10760 "Help Viewer - Image Composite",ImagePasteHelp); 10761 break; 10762 } 10763 case PasteDismissCommand: 10764 { 10765 /* 10766 Prematurely exit. 10767 */ 10768 state|=EscapeState; 10769 state|=ExitState; 10770 break; 10771 } 10772 default: 10773 break; 10774 } 10775 continue; 10776 } 10777 switch (event.type) 10778 { 10779 case ButtonPress: 10780 { 10781 if (image->debug != MagickFalse) 10782 (void) LogMagickEvent(X11Event,GetMagickModule(), 10783 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 10784 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10785 if (event.xbutton.button != Button1) 10786 break; 10787 if (event.xbutton.window != windows->image.id) 10788 break; 10789 /* 10790 Paste rectangle is relative to image configuration. 10791 */ 10792 width=(unsigned int) image->columns; 10793 height=(unsigned int) image->rows; 10794 x=0; 10795 y=0; 10796 if (windows->image.crop_geometry != (char *) NULL) 10797 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 10798 &width,&height); 10799 scale_factor=(MagickRealType) windows->image.ximage->width/width; 10800 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5); 10801 scale_factor=(MagickRealType) windows->image.ximage->height/height; 10802 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5); 10803 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10804 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10805 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10806 break; 10807 } 10808 case ButtonRelease: 10809 { 10810 if (image->debug != MagickFalse) 10811 (void) LogMagickEvent(X11Event,GetMagickModule(), 10812 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 10813 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10814 if (event.xbutton.button != Button1) 10815 break; 10816 if (event.xbutton.window != windows->image.id) 10817 break; 10818 if ((paste_info.width != 0) && (paste_info.height != 0)) 10819 { 10820 /* 10821 User has selected the location of the paste image. 10822 */ 10823 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10824 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10825 state|=ExitState; 10826 } 10827 break; 10828 } 10829 case Expose: 10830 break; 10831 case KeyPress: 10832 { 10833 char 10834 command[MaxTextExtent]; 10835 10836 KeySym 10837 key_symbol; 10838 10839 int 10840 length; 10841 10842 if (event.xkey.window != windows->image.id) 10843 break; 10844 /* 10845 Respond to a user key press. 10846 */ 10847 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 10848 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10849 *(command+length)='\0'; 10850 if (image->debug != MagickFalse) 10851 (void) LogMagickEvent(X11Event,GetMagickModule(), 10852 "Key press: 0x%lx (%s)",(long) key_symbol,command); 10853 switch ((int) key_symbol) 10854 { 10855 case XK_Escape: 10856 case XK_F20: 10857 { 10858 /* 10859 Prematurely exit. 10860 */ 10861 paste_image=DestroyImage(paste_image); 10862 state|=EscapeState; 10863 state|=ExitState; 10864 break; 10865 } 10866 case XK_F1: 10867 case XK_Help: 10868 { 10869 (void) XSetFunction(display,windows->image.highlight_context, 10870 GXcopy); 10871 XTextViewWidget(display,resource_info,windows,MagickFalse, 10872 "Help Viewer - Image Composite",ImagePasteHelp); 10873 (void) XSetFunction(display,windows->image.highlight_context, 10874 GXinvert); 10875 break; 10876 } 10877 default: 10878 { 10879 (void) XBell(display,0); 10880 break; 10881 } 10882 } 10883 break; 10884 } 10885 case MotionNotify: 10886 { 10887 /* 10888 Map and unmap Info widget as text cursor crosses its boundaries. 10889 */ 10890 x=event.xmotion.x; 10891 y=event.xmotion.y; 10892 if (windows->info.mapped != MagickFalse) 10893 { 10894 if ((x < (int) (windows->info.x+windows->info.width)) && 10895 (y < (int) (windows->info.y+windows->info.height))) 10896 (void) XWithdrawWindow(display,windows->info.id, 10897 windows->info.screen); 10898 } 10899 else 10900 if ((x > (int) (windows->info.x+windows->info.width)) || 10901 (y > (int) (windows->info.y+windows->info.height))) 10902 (void) XMapWindow(display,windows->info.id); 10903 paste_info.x=(ssize_t) windows->image.x+x; 10904 paste_info.y=(ssize_t) windows->image.y+y; 10905 break; 10906 } 10907 default: 10908 { 10909 if (image->debug != MagickFalse) 10910 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 10911 event.type); 10912 break; 10913 } 10914 } 10915 } while ((state & ExitState) == 0); 10916 (void) XSelectInput(display,windows->image.id, 10917 windows->image.attributes.event_mask); 10918 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 10919 XSetCursorState(display,windows,MagickFalse); 10920 (void) XFreeCursor(display,cursor); 10921 if ((state & EscapeState) != 0) 10922 return(MagickTrue); 10923 /* 10924 Image pasting is relative to image configuration. 10925 */ 10926 XSetCursorState(display,windows,MagickTrue); 10927 XCheckRefreshWindows(display,windows); 10928 width=(unsigned int) image->columns; 10929 height=(unsigned int) image->rows; 10930 x=0; 10931 y=0; 10932 if (windows->image.crop_geometry != (char *) NULL) 10933 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 10934 scale_factor=(MagickRealType) width/windows->image.ximage->width; 10935 paste_info.x+=x; 10936 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5); 10937 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5); 10938 scale_factor=(MagickRealType) height/windows->image.ximage->height; 10939 paste_info.y+=y; 10940 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5); 10941 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5); 10942 /* 10943 Paste image with X Image window. 10944 */ 10945 (void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y, 10946 exception); 10947 paste_image=DestroyImage(paste_image); 10948 XSetCursorState(display,windows,MagickFalse); 10949 /* 10950 Update image colormap. 10951 */ 10952 XConfigureImageColormap(display,resource_info,windows,image,exception); 10953 (void) XConfigureImage(display,resource_info,windows,image,exception); 10954 return(MagickTrue); 10955} 10956 10957/* 10958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10959% % 10960% % 10961% % 10962+ X P r i n t I m a g e % 10963% % 10964% % 10965% % 10966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10967% 10968% XPrintImage() prints an image to a Postscript printer. 10969% 10970% The format of the XPrintImage method is: 10971% 10972% MagickBooleanType XPrintImage(Display *display, 10973% XResourceInfo *resource_info,XWindows *windows,Image *image, 10974% ExceptionInfo *exception) 10975% 10976% A description of each parameter follows: 10977% 10978% o display: Specifies a connection to an X server; returned from 10979% XOpenDisplay. 10980% 10981% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10982% 10983% o windows: Specifies a pointer to a XWindows structure. 10984% 10985% o image: the image. 10986% 10987% o exception: return any errors or warnings in this structure. 10988% 10989*/ 10990static MagickBooleanType XPrintImage(Display *display, 10991 XResourceInfo *resource_info,XWindows *windows,Image *image, 10992 ExceptionInfo *exception) 10993{ 10994 char 10995 filename[MaxTextExtent], 10996 geometry[MaxTextExtent]; 10997 10998 Image 10999 *print_image; 11000 11001 ImageInfo 11002 *image_info; 11003 11004 MagickStatusType 11005 status; 11006 11007 /* 11008 Request Postscript page geometry from user. 11009 */ 11010 image_info=CloneImageInfo(resource_info->image_info); 11011 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter"); 11012 if (image_info->page != (char *) NULL) 11013 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 11014 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 11015 "Select Postscript Page Geometry:",geometry); 11016 if (*geometry == '\0') 11017 return(MagickTrue); 11018 image_info->page=GetPageGeometry(geometry); 11019 /* 11020 Apply image transforms. 11021 */ 11022 XSetCursorState(display,windows,MagickTrue); 11023 XCheckRefreshWindows(display,windows); 11024 print_image=CloneImage(image,0,0,MagickTrue,exception); 11025 if (print_image == (Image *) NULL) 11026 return(MagickFalse); 11027 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 11028 windows->image.ximage->width,windows->image.ximage->height); 11029 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry, 11030 exception); 11031 /* 11032 Print image. 11033 */ 11034 (void) AcquireUniqueFilename(filename); 11035 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s", 11036 filename); 11037 status=WriteImage(image_info,print_image,exception); 11038 (void) RelinquishUniqueFileResource(filename); 11039 print_image=DestroyImage(print_image); 11040 image_info=DestroyImageInfo(image_info); 11041 XSetCursorState(display,windows,MagickFalse); 11042 return(status != 0 ? MagickTrue : MagickFalse); 11043} 11044 11045/* 11046%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11047% % 11048% % 11049% % 11050+ X R O I I m a g e % 11051% % 11052% % 11053% % 11054%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11055% 11056% XROIImage() applies an image processing technique to a region of interest. 11057% 11058% The format of the XROIImage method is: 11059% 11060% MagickBooleanType XROIImage(Display *display, 11061% XResourceInfo *resource_info,XWindows *windows,Image **image, 11062% ExceptionInfo *exception) 11063% 11064% A description of each parameter follows: 11065% 11066% o display: Specifies a connection to an X server; returned from 11067% XOpenDisplay. 11068% 11069% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11070% 11071% o windows: Specifies a pointer to a XWindows structure. 11072% 11073% o image: the image; returned from ReadImage. 11074% 11075% o exception: return any errors or warnings in this structure. 11076% 11077*/ 11078static MagickBooleanType XROIImage(Display *display, 11079 XResourceInfo *resource_info,XWindows *windows,Image **image, 11080 ExceptionInfo *exception) 11081{ 11082#define ApplyMenus 7 11083 11084 static const char 11085 *ROIMenu[] = 11086 { 11087 "Help", 11088 "Dismiss", 11089 (char *) NULL 11090 }, 11091 *ApplyMenu[] = 11092 { 11093 "File", 11094 "Edit", 11095 "Transform", 11096 "Enhance", 11097 "Effects", 11098 "F/X", 11099 "Miscellany", 11100 "Help", 11101 "Dismiss", 11102 (char *) NULL 11103 }, 11104 *FileMenu[] = 11105 { 11106 "Save...", 11107 "Print...", 11108 (char *) NULL 11109 }, 11110 *EditMenu[] = 11111 { 11112 "Undo", 11113 "Redo", 11114 (char *) NULL 11115 }, 11116 *TransformMenu[] = 11117 { 11118 "Flop", 11119 "Flip", 11120 "Rotate Right", 11121 "Rotate Left", 11122 (char *) NULL 11123 }, 11124 *EnhanceMenu[] = 11125 { 11126 "Hue...", 11127 "Saturation...", 11128 "Brightness...", 11129 "Gamma...", 11130 "Spiff", 11131 "Dull", 11132 "Contrast Stretch...", 11133 "Sigmoidal Contrast...", 11134 "Normalize", 11135 "Equalize", 11136 "Negate", 11137 "Grayscale", 11138 "Map...", 11139 "Quantize...", 11140 (char *) NULL 11141 }, 11142 *EffectsMenu[] = 11143 { 11144 "Despeckle", 11145 "Emboss", 11146 "Reduce Noise", 11147 "Add Noise", 11148 "Sharpen...", 11149 "Blur...", 11150 "Threshold...", 11151 "Edge Detect...", 11152 "Spread...", 11153 "Shade...", 11154 "Raise...", 11155 "Segment...", 11156 (char *) NULL 11157 }, 11158 *FXMenu[] = 11159 { 11160 "Solarize...", 11161 "Sepia Tone...", 11162 "Swirl...", 11163 "Implode...", 11164 "Vignette...", 11165 "Wave...", 11166 "Oil Paint...", 11167 "Charcoal Draw...", 11168 (char *) NULL 11169 }, 11170 *MiscellanyMenu[] = 11171 { 11172 "Image Info", 11173 "Zoom Image", 11174 "Show Preview...", 11175 "Show Histogram", 11176 "Show Matte", 11177 (char *) NULL 11178 }; 11179 11180 static const char 11181 **Menus[ApplyMenus] = 11182 { 11183 FileMenu, 11184 EditMenu, 11185 TransformMenu, 11186 EnhanceMenu, 11187 EffectsMenu, 11188 FXMenu, 11189 MiscellanyMenu 11190 }; 11191 11192 static const CommandType 11193 ApplyCommands[] = 11194 { 11195 NullCommand, 11196 NullCommand, 11197 NullCommand, 11198 NullCommand, 11199 NullCommand, 11200 NullCommand, 11201 NullCommand, 11202 HelpCommand, 11203 QuitCommand 11204 }, 11205 FileCommands[] = 11206 { 11207 SaveCommand, 11208 PrintCommand 11209 }, 11210 EditCommands[] = 11211 { 11212 UndoCommand, 11213 RedoCommand 11214 }, 11215 TransformCommands[] = 11216 { 11217 FlopCommand, 11218 FlipCommand, 11219 RotateRightCommand, 11220 RotateLeftCommand 11221 }, 11222 EnhanceCommands[] = 11223 { 11224 HueCommand, 11225 SaturationCommand, 11226 BrightnessCommand, 11227 GammaCommand, 11228 SpiffCommand, 11229 DullCommand, 11230 ContrastStretchCommand, 11231 SigmoidalContrastCommand, 11232 NormalizeCommand, 11233 EqualizeCommand, 11234 NegateCommand, 11235 GrayscaleCommand, 11236 MapCommand, 11237 QuantizeCommand 11238 }, 11239 EffectsCommands[] = 11240 { 11241 DespeckleCommand, 11242 EmbossCommand, 11243 ReduceNoiseCommand, 11244 AddNoiseCommand, 11245 SharpenCommand, 11246 BlurCommand, 11247 EdgeDetectCommand, 11248 SpreadCommand, 11249 ShadeCommand, 11250 RaiseCommand, 11251 SegmentCommand 11252 }, 11253 FXCommands[] = 11254 { 11255 SolarizeCommand, 11256 SepiaToneCommand, 11257 SwirlCommand, 11258 ImplodeCommand, 11259 VignetteCommand, 11260 WaveCommand, 11261 OilPaintCommand, 11262 CharcoalDrawCommand 11263 }, 11264 MiscellanyCommands[] = 11265 { 11266 InfoCommand, 11267 ZoomCommand, 11268 ShowPreviewCommand, 11269 ShowHistogramCommand, 11270 ShowMatteCommand 11271 }, 11272 ROICommands[] = 11273 { 11274 ROIHelpCommand, 11275 ROIDismissCommand 11276 }; 11277 11278 static const CommandType 11279 *Commands[ApplyMenus] = 11280 { 11281 FileCommands, 11282 EditCommands, 11283 TransformCommands, 11284 EnhanceCommands, 11285 EffectsCommands, 11286 FXCommands, 11287 MiscellanyCommands 11288 }; 11289 11290 char 11291 command[MaxTextExtent], 11292 text[MaxTextExtent]; 11293 11294 CommandType 11295 command_type; 11296 11297 Cursor 11298 cursor; 11299 11300 Image 11301 *roi_image; 11302 11303 int 11304 entry, 11305 id, 11306 x, 11307 y; 11308 11309 MagickRealType 11310 scale_factor; 11311 11312 MagickProgressMonitor 11313 progress_monitor; 11314 11315 RectangleInfo 11316 crop_info, 11317 highlight_info, 11318 roi_info; 11319 11320 unsigned int 11321 height, 11322 width; 11323 11324 size_t 11325 state; 11326 11327 XEvent 11328 event; 11329 11330 /* 11331 Map Command widget. 11332 */ 11333 (void) CloneString(&windows->command.name,"ROI"); 11334 windows->command.data=0; 11335 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL); 11336 (void) XMapRaised(display,windows->command.id); 11337 XClientMessage(display,windows->image.id,windows->im_protocols, 11338 windows->im_update_widget,CurrentTime); 11339 /* 11340 Track pointer until button 1 is pressed. 11341 */ 11342 XQueryPosition(display,windows->image.id,&x,&y); 11343 (void) XSelectInput(display,windows->image.id, 11344 windows->image.attributes.event_mask | PointerMotionMask); 11345 roi_info.x=(ssize_t) windows->image.x+x; 11346 roi_info.y=(ssize_t) windows->image.y+y; 11347 roi_info.width=0; 11348 roi_info.height=0; 11349 cursor=XCreateFontCursor(display,XC_fleur); 11350 state=DefaultState; 11351 do 11352 { 11353 if (windows->info.mapped != MagickFalse) 11354 { 11355 /* 11356 Display pointer position. 11357 */ 11358 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 11359 (long) roi_info.x,(long) roi_info.y); 11360 XInfoWidget(display,windows,text); 11361 } 11362 /* 11363 Wait for next event. 11364 */ 11365 XScreenEvent(display,windows,&event,exception); 11366 if (event.xany.window == windows->command.id) 11367 { 11368 /* 11369 Select a command from the Command widget. 11370 */ 11371 id=XCommandWidget(display,windows,ROIMenu,&event); 11372 if (id < 0) 11373 continue; 11374 switch (ROICommands[id]) 11375 { 11376 case ROIHelpCommand: 11377 { 11378 XTextViewWidget(display,resource_info,windows,MagickFalse, 11379 "Help Viewer - Region of Interest",ImageROIHelp); 11380 break; 11381 } 11382 case ROIDismissCommand: 11383 { 11384 /* 11385 Prematurely exit. 11386 */ 11387 state|=EscapeState; 11388 state|=ExitState; 11389 break; 11390 } 11391 default: 11392 break; 11393 } 11394 continue; 11395 } 11396 switch (event.type) 11397 { 11398 case ButtonPress: 11399 { 11400 if (event.xbutton.button != Button1) 11401 break; 11402 if (event.xbutton.window != windows->image.id) 11403 break; 11404 /* 11405 Note first corner of region of interest rectangle-- exit loop. 11406 */ 11407 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11408 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11409 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11410 state|=ExitState; 11411 break; 11412 } 11413 case ButtonRelease: 11414 break; 11415 case Expose: 11416 break; 11417 case KeyPress: 11418 { 11419 KeySym 11420 key_symbol; 11421 11422 if (event.xkey.window != windows->image.id) 11423 break; 11424 /* 11425 Respond to a user key press. 11426 */ 11427 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11428 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11429 switch ((int) key_symbol) 11430 { 11431 case XK_Escape: 11432 case XK_F20: 11433 { 11434 /* 11435 Prematurely exit. 11436 */ 11437 state|=EscapeState; 11438 state|=ExitState; 11439 break; 11440 } 11441 case XK_F1: 11442 case XK_Help: 11443 { 11444 XTextViewWidget(display,resource_info,windows,MagickFalse, 11445 "Help Viewer - Region of Interest",ImageROIHelp); 11446 break; 11447 } 11448 default: 11449 { 11450 (void) XBell(display,0); 11451 break; 11452 } 11453 } 11454 break; 11455 } 11456 case MotionNotify: 11457 { 11458 /* 11459 Map and unmap Info widget as text cursor crosses its boundaries. 11460 */ 11461 x=event.xmotion.x; 11462 y=event.xmotion.y; 11463 if (windows->info.mapped != MagickFalse) 11464 { 11465 if ((x < (int) (windows->info.x+windows->info.width)) && 11466 (y < (int) (windows->info.y+windows->info.height))) 11467 (void) XWithdrawWindow(display,windows->info.id, 11468 windows->info.screen); 11469 } 11470 else 11471 if ((x > (int) (windows->info.x+windows->info.width)) || 11472 (y > (int) (windows->info.y+windows->info.height))) 11473 (void) XMapWindow(display,windows->info.id); 11474 roi_info.x=(ssize_t) windows->image.x+x; 11475 roi_info.y=(ssize_t) windows->image.y+y; 11476 break; 11477 } 11478 default: 11479 break; 11480 } 11481 } while ((state & ExitState) == 0); 11482 (void) XSelectInput(display,windows->image.id, 11483 windows->image.attributes.event_mask); 11484 if ((state & EscapeState) != 0) 11485 { 11486 /* 11487 User want to exit without region of interest. 11488 */ 11489 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11490 (void) XFreeCursor(display,cursor); 11491 return(MagickTrue); 11492 } 11493 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11494 do 11495 { 11496 /* 11497 Size rectangle as pointer moves until the mouse button is released. 11498 */ 11499 x=(int) roi_info.x; 11500 y=(int) roi_info.y; 11501 roi_info.width=0; 11502 roi_info.height=0; 11503 state=DefaultState; 11504 do 11505 { 11506 highlight_info=roi_info; 11507 highlight_info.x=roi_info.x-windows->image.x; 11508 highlight_info.y=roi_info.y-windows->image.y; 11509 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11510 { 11511 /* 11512 Display info and draw region of interest rectangle. 11513 */ 11514 if (windows->info.mapped == MagickFalse) 11515 (void) XMapWindow(display,windows->info.id); 11516 (void) FormatLocaleString(text,MaxTextExtent, 11517 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11518 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11519 XInfoWidget(display,windows,text); 11520 XHighlightRectangle(display,windows->image.id, 11521 windows->image.highlight_context,&highlight_info); 11522 } 11523 else 11524 if (windows->info.mapped != MagickFalse) 11525 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11526 /* 11527 Wait for next event. 11528 */ 11529 XScreenEvent(display,windows,&event,exception); 11530 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11531 XHighlightRectangle(display,windows->image.id, 11532 windows->image.highlight_context,&highlight_info); 11533 switch (event.type) 11534 { 11535 case ButtonPress: 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 break; 11540 } 11541 case ButtonRelease: 11542 { 11543 /* 11544 User has committed to region of interest rectangle. 11545 */ 11546 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11547 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11548 XSetCursorState(display,windows,MagickFalse); 11549 state|=ExitState; 11550 if (LocaleCompare(windows->command.name,"Apply") == 0) 11551 break; 11552 (void) CloneString(&windows->command.name,"Apply"); 11553 windows->command.data=ApplyMenus; 11554 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL); 11555 break; 11556 } 11557 case Expose: 11558 break; 11559 case MotionNotify: 11560 { 11561 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11562 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11563 } 11564 default: 11565 break; 11566 } 11567 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) || 11568 ((state & ExitState) != 0)) 11569 { 11570 /* 11571 Check boundary conditions. 11572 */ 11573 if (roi_info.x < 0) 11574 roi_info.x=0; 11575 else 11576 if (roi_info.x > (ssize_t) windows->image.ximage->width) 11577 roi_info.x=(ssize_t) windows->image.ximage->width; 11578 if ((int) roi_info.x < x) 11579 roi_info.width=(unsigned int) (x-roi_info.x); 11580 else 11581 { 11582 roi_info.width=(unsigned int) (roi_info.x-x); 11583 roi_info.x=(ssize_t) x; 11584 } 11585 if (roi_info.y < 0) 11586 roi_info.y=0; 11587 else 11588 if (roi_info.y > (ssize_t) windows->image.ximage->height) 11589 roi_info.y=(ssize_t) windows->image.ximage->height; 11590 if ((int) roi_info.y < y) 11591 roi_info.height=(unsigned int) (y-roi_info.y); 11592 else 11593 { 11594 roi_info.height=(unsigned int) (roi_info.y-y); 11595 roi_info.y=(ssize_t) y; 11596 } 11597 } 11598 } while ((state & ExitState) == 0); 11599 /* 11600 Wait for user to grab a corner of the rectangle or press return. 11601 */ 11602 state=DefaultState; 11603 command_type=NullCommand; 11604 (void) XMapWindow(display,windows->info.id); 11605 do 11606 { 11607 if (windows->info.mapped != MagickFalse) 11608 { 11609 /* 11610 Display pointer position. 11611 */ 11612 (void) FormatLocaleString(text,MaxTextExtent, 11613 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11614 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11615 XInfoWidget(display,windows,text); 11616 } 11617 highlight_info=roi_info; 11618 highlight_info.x=roi_info.x-windows->image.x; 11619 highlight_info.y=roi_info.y-windows->image.y; 11620 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11621 { 11622 state|=EscapeState; 11623 state|=ExitState; 11624 break; 11625 } 11626 if ((state & UpdateRegionState) != 0) 11627 { 11628 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11629 switch (command_type) 11630 { 11631 case UndoCommand: 11632 case RedoCommand: 11633 { 11634 (void) XMagickCommand(display,resource_info,windows,command_type, 11635 image,exception); 11636 break; 11637 } 11638 default: 11639 { 11640 /* 11641 Region of interest is relative to image configuration. 11642 */ 11643 progress_monitor=SetImageProgressMonitor(*image, 11644 (MagickProgressMonitor) NULL,(*image)->client_data); 11645 crop_info=roi_info; 11646 width=(unsigned int) (*image)->columns; 11647 height=(unsigned int) (*image)->rows; 11648 x=0; 11649 y=0; 11650 if (windows->image.crop_geometry != (char *) NULL) 11651 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11652 &width,&height); 11653 scale_factor=(MagickRealType) width/windows->image.ximage->width; 11654 crop_info.x+=x; 11655 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11656 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11657 scale_factor=(MagickRealType) 11658 height/windows->image.ximage->height; 11659 crop_info.y+=y; 11660 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11661 crop_info.height=(unsigned int) 11662 (scale_factor*crop_info.height+0.5); 11663 roi_image=CropImage(*image,&crop_info,exception); 11664 (void) SetImageProgressMonitor(*image,progress_monitor, 11665 (*image)->client_data); 11666 if (roi_image == (Image *) NULL) 11667 continue; 11668 /* 11669 Apply image processing technique to the region of interest. 11670 */ 11671 windows->image.orphan=MagickTrue; 11672 (void) XMagickCommand(display,resource_info,windows,command_type, 11673 &roi_image,exception); 11674 progress_monitor=SetImageProgressMonitor(*image, 11675 (MagickProgressMonitor) NULL,(*image)->client_data); 11676 (void) XMagickCommand(display,resource_info,windows, 11677 SaveToUndoBufferCommand,image,exception); 11678 windows->image.orphan=MagickFalse; 11679 (void) CompositeImage(*image,CopyCompositeOp,roi_image, 11680 crop_info.x,crop_info.y,exception); 11681 roi_image=DestroyImage(roi_image); 11682 (void) SetImageProgressMonitor(*image,progress_monitor, 11683 (*image)->client_data); 11684 break; 11685 } 11686 } 11687 if (command_type != InfoCommand) 11688 { 11689 XConfigureImageColormap(display,resource_info,windows,*image, 11690 exception); 11691 (void) XConfigureImage(display,resource_info,windows,*image, 11692 exception); 11693 } 11694 XCheckRefreshWindows(display,windows); 11695 XInfoWidget(display,windows,text); 11696 (void) XSetFunction(display,windows->image.highlight_context, 11697 GXinvert); 11698 state&=(~UpdateRegionState); 11699 } 11700 XHighlightRectangle(display,windows->image.id, 11701 windows->image.highlight_context,&highlight_info); 11702 XScreenEvent(display,windows,&event,exception); 11703 if (event.xany.window == windows->command.id) 11704 { 11705 /* 11706 Select a command from the Command widget. 11707 */ 11708 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11709 command_type=NullCommand; 11710 id=XCommandWidget(display,windows,ApplyMenu,&event); 11711 if (id >= 0) 11712 { 11713 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent); 11714 command_type=ApplyCommands[id]; 11715 if (id < ApplyMenus) 11716 { 11717 /* 11718 Select a command from a pop-up menu. 11719 */ 11720 entry=XMenuWidget(display,windows,ApplyMenu[id], 11721 (const char **) Menus[id],command); 11722 if (entry >= 0) 11723 { 11724 (void) CopyMagickString(command,Menus[id][entry], 11725 MaxTextExtent); 11726 command_type=Commands[id][entry]; 11727 } 11728 } 11729 } 11730 (void) XSetFunction(display,windows->image.highlight_context, 11731 GXinvert); 11732 XHighlightRectangle(display,windows->image.id, 11733 windows->image.highlight_context,&highlight_info); 11734 if (command_type == HelpCommand) 11735 { 11736 (void) XSetFunction(display,windows->image.highlight_context, 11737 GXcopy); 11738 XTextViewWidget(display,resource_info,windows,MagickFalse, 11739 "Help Viewer - Region of Interest",ImageROIHelp); 11740 (void) XSetFunction(display,windows->image.highlight_context, 11741 GXinvert); 11742 continue; 11743 } 11744 if (command_type == QuitCommand) 11745 { 11746 /* 11747 exit. 11748 */ 11749 state|=EscapeState; 11750 state|=ExitState; 11751 continue; 11752 } 11753 if (command_type != NullCommand) 11754 state|=UpdateRegionState; 11755 continue; 11756 } 11757 XHighlightRectangle(display,windows->image.id, 11758 windows->image.highlight_context,&highlight_info); 11759 switch (event.type) 11760 { 11761 case ButtonPress: 11762 { 11763 x=windows->image.x; 11764 y=windows->image.y; 11765 if (event.xbutton.button != Button1) 11766 break; 11767 if (event.xbutton.window != windows->image.id) 11768 break; 11769 x=windows->image.x+event.xbutton.x; 11770 y=windows->image.y+event.xbutton.y; 11771 if ((x < (int) (roi_info.x+RoiDelta)) && 11772 (x > (int) (roi_info.x-RoiDelta)) && 11773 (y < (int) (roi_info.y+RoiDelta)) && 11774 (y > (int) (roi_info.y-RoiDelta))) 11775 { 11776 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11777 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11778 state|=UpdateConfigurationState; 11779 break; 11780 } 11781 if ((x < (int) (roi_info.x+RoiDelta)) && 11782 (x > (int) (roi_info.x-RoiDelta)) && 11783 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11784 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11785 { 11786 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 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+RoiDelta)) && 11793 (y > (int) (roi_info.y-RoiDelta))) 11794 { 11795 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11796 state|=UpdateConfigurationState; 11797 break; 11798 } 11799 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11800 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11801 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11802 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11803 { 11804 state|=UpdateConfigurationState; 11805 break; 11806 } 11807 } 11808 case ButtonRelease: 11809 { 11810 if (event.xbutton.window == windows->pan.id) 11811 if ((highlight_info.x != crop_info.x-windows->image.x) || 11812 (highlight_info.y != crop_info.y-windows->image.y)) 11813 XHighlightRectangle(display,windows->image.id, 11814 windows->image.highlight_context,&highlight_info); 11815 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11816 event.xbutton.time); 11817 break; 11818 } 11819 case Expose: 11820 { 11821 if (event.xexpose.window == windows->image.id) 11822 if (event.xexpose.count == 0) 11823 { 11824 event.xexpose.x=(int) highlight_info.x; 11825 event.xexpose.y=(int) highlight_info.y; 11826 event.xexpose.width=(int) highlight_info.width; 11827 event.xexpose.height=(int) highlight_info.height; 11828 XRefreshWindow(display,&windows->image,&event); 11829 } 11830 if (event.xexpose.window == windows->info.id) 11831 if (event.xexpose.count == 0) 11832 XInfoWidget(display,windows,text); 11833 break; 11834 } 11835 case KeyPress: 11836 { 11837 KeySym 11838 key_symbol; 11839 11840 if (event.xkey.window != windows->image.id) 11841 break; 11842 /* 11843 Respond to a user key press. 11844 */ 11845 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11846 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11847 switch ((int) key_symbol) 11848 { 11849 case XK_Shift_L: 11850 case XK_Shift_R: 11851 break; 11852 case XK_Escape: 11853 case XK_F20: 11854 state|=EscapeState; 11855 case XK_Return: 11856 { 11857 state|=ExitState; 11858 break; 11859 } 11860 case XK_Home: 11861 case XK_KP_Home: 11862 { 11863 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11864 roi_info.y=(ssize_t) (windows->image.height/2L- 11865 roi_info.height/2L); 11866 break; 11867 } 11868 case XK_Left: 11869 case XK_KP_Left: 11870 { 11871 roi_info.x--; 11872 break; 11873 } 11874 case XK_Up: 11875 case XK_KP_Up: 11876 case XK_Next: 11877 { 11878 roi_info.y--; 11879 break; 11880 } 11881 case XK_Right: 11882 case XK_KP_Right: 11883 { 11884 roi_info.x++; 11885 break; 11886 } 11887 case XK_Prior: 11888 case XK_Down: 11889 case XK_KP_Down: 11890 { 11891 roi_info.y++; 11892 break; 11893 } 11894 case XK_F1: 11895 case XK_Help: 11896 { 11897 (void) XSetFunction(display,windows->image.highlight_context, 11898 GXcopy); 11899 XTextViewWidget(display,resource_info,windows,MagickFalse, 11900 "Help Viewer - Region of Interest",ImageROIHelp); 11901 (void) XSetFunction(display,windows->image.highlight_context, 11902 GXinvert); 11903 break; 11904 } 11905 default: 11906 { 11907 command_type=XImageWindowCommand(display,resource_info,windows, 11908 event.xkey.state,key_symbol,image,exception); 11909 if (command_type != NullCommand) 11910 state|=UpdateRegionState; 11911 break; 11912 } 11913 } 11914 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11915 event.xkey.time); 11916 break; 11917 } 11918 case KeyRelease: 11919 break; 11920 case MotionNotify: 11921 { 11922 if (event.xbutton.window != windows->image.id) 11923 break; 11924 /* 11925 Map and unmap Info widget as text cursor crosses its boundaries. 11926 */ 11927 x=event.xmotion.x; 11928 y=event.xmotion.y; 11929 if (windows->info.mapped != MagickFalse) 11930 { 11931 if ((x < (int) (windows->info.x+windows->info.width)) && 11932 (y < (int) (windows->info.y+windows->info.height))) 11933 (void) XWithdrawWindow(display,windows->info.id, 11934 windows->info.screen); 11935 } 11936 else 11937 if ((x > (int) (windows->info.x+windows->info.width)) || 11938 (y > (int) (windows->info.y+windows->info.height))) 11939 (void) XMapWindow(display,windows->info.id); 11940 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11941 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11942 break; 11943 } 11944 case SelectionRequest: 11945 { 11946 XSelectionEvent 11947 notify; 11948 11949 XSelectionRequestEvent 11950 *request; 11951 11952 /* 11953 Set primary selection. 11954 */ 11955 (void) FormatLocaleString(text,MaxTextExtent, 11956 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11957 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11958 request=(&(event.xselectionrequest)); 11959 (void) XChangeProperty(request->display,request->requestor, 11960 request->property,request->target,8,PropModeReplace, 11961 (unsigned char *) text,(int) strlen(text)); 11962 notify.type=SelectionNotify; 11963 notify.display=request->display; 11964 notify.requestor=request->requestor; 11965 notify.selection=request->selection; 11966 notify.target=request->target; 11967 notify.time=request->time; 11968 if (request->property == None) 11969 notify.property=request->target; 11970 else 11971 notify.property=request->property; 11972 (void) XSendEvent(request->display,request->requestor,False,0, 11973 (XEvent *) ¬ify); 11974 } 11975 default: 11976 break; 11977 } 11978 if ((state & UpdateConfigurationState) != 0) 11979 { 11980 (void) XPutBackEvent(display,&event); 11981 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11982 break; 11983 } 11984 } while ((state & ExitState) == 0); 11985 } while ((state & ExitState) == 0); 11986 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11987 XSetCursorState(display,windows,MagickFalse); 11988 if ((state & EscapeState) != 0) 11989 return(MagickTrue); 11990 return(MagickTrue); 11991} 11992 11993/* 11994%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11995% % 11996% % 11997% % 11998+ X R o t a t e I m a g e % 11999% % 12000% % 12001% % 12002%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12003% 12004% XRotateImage() rotates the X image. If the degrees parameter if zero, the 12005% rotation angle is computed from the slope of a line drawn by the user. 12006% 12007% The format of the XRotateImage method is: 12008% 12009% MagickBooleanType XRotateImage(Display *display, 12010% XResourceInfo *resource_info,XWindows *windows,double degrees, 12011% Image **image,ExceptionInfo *exception) 12012% 12013% A description of each parameter follows: 12014% 12015% o display: Specifies a connection to an X server; returned from 12016% XOpenDisplay. 12017% 12018% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12019% 12020% o windows: Specifies a pointer to a XWindows structure. 12021% 12022% o degrees: Specifies the number of degrees to rotate the image. 12023% 12024% o image: the image. 12025% 12026% o exception: return any errors or warnings in this structure. 12027% 12028*/ 12029static MagickBooleanType XRotateImage(Display *display, 12030 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image, 12031 ExceptionInfo *exception) 12032{ 12033 static const char 12034 *RotateMenu[] = 12035 { 12036 "Pixel Color", 12037 "Direction", 12038 "Help", 12039 "Dismiss", 12040 (char *) NULL 12041 }; 12042 12043 static ModeType 12044 direction = HorizontalRotateCommand; 12045 12046 static const ModeType 12047 DirectionCommands[] = 12048 { 12049 HorizontalRotateCommand, 12050 VerticalRotateCommand 12051 }, 12052 RotateCommands[] = 12053 { 12054 RotateColorCommand, 12055 RotateDirectionCommand, 12056 RotateHelpCommand, 12057 RotateDismissCommand 12058 }; 12059 12060 static unsigned int 12061 pen_id = 0; 12062 12063 char 12064 command[MaxTextExtent], 12065 text[MaxTextExtent]; 12066 12067 Image 12068 *rotate_image; 12069 12070 int 12071 id, 12072 x, 12073 y; 12074 12075 MagickRealType 12076 normalized_degrees; 12077 12078 register int 12079 i; 12080 12081 unsigned int 12082 height, 12083 rotations, 12084 width; 12085 12086 if (degrees == 0.0) 12087 { 12088 unsigned int 12089 distance; 12090 12091 size_t 12092 state; 12093 12094 XEvent 12095 event; 12096 12097 XSegment 12098 rotate_info; 12099 12100 /* 12101 Map Command widget. 12102 */ 12103 (void) CloneString(&windows->command.name,"Rotate"); 12104 windows->command.data=2; 12105 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 12106 (void) XMapRaised(display,windows->command.id); 12107 XClientMessage(display,windows->image.id,windows->im_protocols, 12108 windows->im_update_widget,CurrentTime); 12109 /* 12110 Wait for first button press. 12111 */ 12112 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12113 XQueryPosition(display,windows->image.id,&x,&y); 12114 rotate_info.x1=x; 12115 rotate_info.y1=y; 12116 rotate_info.x2=x; 12117 rotate_info.y2=y; 12118 state=DefaultState; 12119 do 12120 { 12121 XHighlightLine(display,windows->image.id, 12122 windows->image.highlight_context,&rotate_info); 12123 /* 12124 Wait for next event. 12125 */ 12126 XScreenEvent(display,windows,&event,exception); 12127 XHighlightLine(display,windows->image.id, 12128 windows->image.highlight_context,&rotate_info); 12129 if (event.xany.window == windows->command.id) 12130 { 12131 /* 12132 Select a command from the Command widget. 12133 */ 12134 id=XCommandWidget(display,windows,RotateMenu,&event); 12135 if (id < 0) 12136 continue; 12137 (void) XSetFunction(display,windows->image.highlight_context, 12138 GXcopy); 12139 switch (RotateCommands[id]) 12140 { 12141 case RotateColorCommand: 12142 { 12143 const char 12144 *ColorMenu[MaxNumberPens]; 12145 12146 int 12147 pen_number; 12148 12149 XColor 12150 color; 12151 12152 /* 12153 Initialize menu selections. 12154 */ 12155 for (i=0; i < (int) (MaxNumberPens-2); i++) 12156 ColorMenu[i]=resource_info->pen_colors[i]; 12157 ColorMenu[MaxNumberPens-2]="Browser..."; 12158 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12159 /* 12160 Select a pen color from the pop-up menu. 12161 */ 12162 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12163 (const char **) ColorMenu,command); 12164 if (pen_number < 0) 12165 break; 12166 if (pen_number == (MaxNumberPens-2)) 12167 { 12168 static char 12169 color_name[MaxTextExtent] = "gray"; 12170 12171 /* 12172 Select a pen color from a dialog. 12173 */ 12174 resource_info->pen_colors[pen_number]=color_name; 12175 XColorBrowserWidget(display,windows,"Select",color_name); 12176 if (*color_name == '\0') 12177 break; 12178 } 12179 /* 12180 Set pen color. 12181 */ 12182 (void) XParseColor(display,windows->map_info->colormap, 12183 resource_info->pen_colors[pen_number],&color); 12184 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12185 (unsigned int) MaxColors,&color); 12186 windows->pixel_info->pen_colors[pen_number]=color; 12187 pen_id=(unsigned int) pen_number; 12188 break; 12189 } 12190 case RotateDirectionCommand: 12191 { 12192 static const char 12193 *Directions[] = 12194 { 12195 "horizontal", 12196 "vertical", 12197 (char *) NULL, 12198 }; 12199 12200 /* 12201 Select a command from the pop-up menu. 12202 */ 12203 id=XMenuWidget(display,windows,RotateMenu[id], 12204 Directions,command); 12205 if (id >= 0) 12206 direction=DirectionCommands[id]; 12207 break; 12208 } 12209 case RotateHelpCommand: 12210 { 12211 XTextViewWidget(display,resource_info,windows,MagickFalse, 12212 "Help Viewer - Image Rotation",ImageRotateHelp); 12213 break; 12214 } 12215 case RotateDismissCommand: 12216 { 12217 /* 12218 Prematurely exit. 12219 */ 12220 state|=EscapeState; 12221 state|=ExitState; 12222 break; 12223 } 12224 default: 12225 break; 12226 } 12227 (void) XSetFunction(display,windows->image.highlight_context, 12228 GXinvert); 12229 continue; 12230 } 12231 switch (event.type) 12232 { 12233 case ButtonPress: 12234 { 12235 if (event.xbutton.button != Button1) 12236 break; 12237 if (event.xbutton.window != windows->image.id) 12238 break; 12239 /* 12240 exit loop. 12241 */ 12242 (void) XSetFunction(display,windows->image.highlight_context, 12243 GXcopy); 12244 rotate_info.x1=event.xbutton.x; 12245 rotate_info.y1=event.xbutton.y; 12246 state|=ExitState; 12247 break; 12248 } 12249 case ButtonRelease: 12250 break; 12251 case Expose: 12252 break; 12253 case KeyPress: 12254 { 12255 char 12256 command[MaxTextExtent]; 12257 12258 KeySym 12259 key_symbol; 12260 12261 if (event.xkey.window != windows->image.id) 12262 break; 12263 /* 12264 Respond to a user key press. 12265 */ 12266 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12267 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12268 switch ((int) key_symbol) 12269 { 12270 case XK_Escape: 12271 case XK_F20: 12272 { 12273 /* 12274 Prematurely exit. 12275 */ 12276 state|=EscapeState; 12277 state|=ExitState; 12278 break; 12279 } 12280 case XK_F1: 12281 case XK_Help: 12282 { 12283 (void) XSetFunction(display,windows->image.highlight_context, 12284 GXcopy); 12285 XTextViewWidget(display,resource_info,windows,MagickFalse, 12286 "Help Viewer - Image Rotation",ImageRotateHelp); 12287 (void) XSetFunction(display,windows->image.highlight_context, 12288 GXinvert); 12289 break; 12290 } 12291 default: 12292 { 12293 (void) XBell(display,0); 12294 break; 12295 } 12296 } 12297 break; 12298 } 12299 case MotionNotify: 12300 { 12301 rotate_info.x1=event.xmotion.x; 12302 rotate_info.y1=event.xmotion.y; 12303 } 12304 } 12305 rotate_info.x2=rotate_info.x1; 12306 rotate_info.y2=rotate_info.y1; 12307 if (direction == HorizontalRotateCommand) 12308 rotate_info.x2+=32; 12309 else 12310 rotate_info.y2-=32; 12311 } while ((state & ExitState) == 0); 12312 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12313 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12314 if ((state & EscapeState) != 0) 12315 return(MagickTrue); 12316 /* 12317 Draw line as pointer moves until the mouse button is released. 12318 */ 12319 distance=0; 12320 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12321 state=DefaultState; 12322 do 12323 { 12324 if (distance > 9) 12325 { 12326 /* 12327 Display info and draw rotation line. 12328 */ 12329 if (windows->info.mapped == MagickFalse) 12330 (void) XMapWindow(display,windows->info.id); 12331 (void) FormatLocaleString(text,MaxTextExtent," %g", 12332 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12333 XInfoWidget(display,windows,text); 12334 XHighlightLine(display,windows->image.id, 12335 windows->image.highlight_context,&rotate_info); 12336 } 12337 else 12338 if (windows->info.mapped != MagickFalse) 12339 (void) XWithdrawWindow(display,windows->info.id, 12340 windows->info.screen); 12341 /* 12342 Wait for next event. 12343 */ 12344 XScreenEvent(display,windows,&event,exception); 12345 if (distance > 9) 12346 XHighlightLine(display,windows->image.id, 12347 windows->image.highlight_context,&rotate_info); 12348 switch (event.type) 12349 { 12350 case ButtonPress: 12351 break; 12352 case ButtonRelease: 12353 { 12354 /* 12355 User has committed to rotation line. 12356 */ 12357 rotate_info.x2=event.xbutton.x; 12358 rotate_info.y2=event.xbutton.y; 12359 state|=ExitState; 12360 break; 12361 } 12362 case Expose: 12363 break; 12364 case MotionNotify: 12365 { 12366 rotate_info.x2=event.xmotion.x; 12367 rotate_info.y2=event.xmotion.y; 12368 } 12369 default: 12370 break; 12371 } 12372 /* 12373 Check boundary conditions. 12374 */ 12375 if (rotate_info.x2 < 0) 12376 rotate_info.x2=0; 12377 else 12378 if (rotate_info.x2 > (int) windows->image.width) 12379 rotate_info.x2=(short) windows->image.width; 12380 if (rotate_info.y2 < 0) 12381 rotate_info.y2=0; 12382 else 12383 if (rotate_info.y2 > (int) windows->image.height) 12384 rotate_info.y2=(short) windows->image.height; 12385 /* 12386 Compute rotation angle from the slope of the line. 12387 */ 12388 degrees=0.0; 12389 distance=(unsigned int) 12390 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12391 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12392 if (distance > 9) 12393 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12394 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12395 } while ((state & ExitState) == 0); 12396 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12397 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12398 if (distance <= 9) 12399 return(MagickTrue); 12400 } 12401 if (direction == VerticalRotateCommand) 12402 degrees-=90.0; 12403 if (degrees == 0.0) 12404 return(MagickTrue); 12405 /* 12406 Rotate image. 12407 */ 12408 normalized_degrees=degrees; 12409 while (normalized_degrees < -45.0) 12410 normalized_degrees+=360.0; 12411 for (rotations=0; normalized_degrees > 45.0; rotations++) 12412 normalized_degrees-=90.0; 12413 if (normalized_degrees != 0.0) 12414 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 12415 exception); 12416 XSetCursorState(display,windows,MagickTrue); 12417 XCheckRefreshWindows(display,windows); 12418 (*image)->background_color.red=ScaleShortToQuantum( 12419 windows->pixel_info->pen_colors[pen_id].red); 12420 (*image)->background_color.green=ScaleShortToQuantum( 12421 windows->pixel_info->pen_colors[pen_id].green); 12422 (*image)->background_color.blue=ScaleShortToQuantum( 12423 windows->pixel_info->pen_colors[pen_id].blue); 12424 rotate_image=RotateImage(*image,degrees,exception); 12425 XSetCursorState(display,windows,MagickFalse); 12426 if (rotate_image == (Image *) NULL) 12427 return(MagickFalse); 12428 *image=DestroyImage(*image); 12429 *image=rotate_image; 12430 if (windows->image.crop_geometry != (char *) NULL) 12431 { 12432 /* 12433 Rotate crop geometry. 12434 */ 12435 width=(unsigned int) (*image)->columns; 12436 height=(unsigned int) (*image)->rows; 12437 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12438 switch (rotations % 4) 12439 { 12440 default: 12441 case 0: 12442 break; 12443 case 1: 12444 { 12445 /* 12446 Rotate 90 degrees. 12447 */ 12448 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12449 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12450 (int) height-y,x); 12451 break; 12452 } 12453 case 2: 12454 { 12455 /* 12456 Rotate 180 degrees. 12457 */ 12458 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12459 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12460 break; 12461 } 12462 case 3: 12463 { 12464 /* 12465 Rotate 270 degrees. 12466 */ 12467 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12468 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12469 break; 12470 } 12471 } 12472 } 12473 if (windows->image.orphan != MagickFalse) 12474 return(MagickTrue); 12475 if (normalized_degrees != 0.0) 12476 { 12477 /* 12478 Update image colormap. 12479 */ 12480 windows->image.window_changes.width=(int) (*image)->columns; 12481 windows->image.window_changes.height=(int) (*image)->rows; 12482 if (windows->image.crop_geometry != (char *) NULL) 12483 { 12484 /* 12485 Obtain dimensions of image from crop geometry. 12486 */ 12487 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12488 &width,&height); 12489 windows->image.window_changes.width=(int) width; 12490 windows->image.window_changes.height=(int) height; 12491 } 12492 XConfigureImageColormap(display,resource_info,windows,*image,exception); 12493 } 12494 else 12495 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12496 { 12497 windows->image.window_changes.width=windows->image.ximage->height; 12498 windows->image.window_changes.height=windows->image.ximage->width; 12499 } 12500 /* 12501 Update image configuration. 12502 */ 12503 (void) XConfigureImage(display,resource_info,windows,*image,exception); 12504 return(MagickTrue); 12505} 12506 12507/* 12508%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12509% % 12510% % 12511% % 12512+ X S a v e I m a g e % 12513% % 12514% % 12515% % 12516%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12517% 12518% XSaveImage() saves an image to a file. 12519% 12520% The format of the XSaveImage method is: 12521% 12522% MagickBooleanType XSaveImage(Display *display, 12523% XResourceInfo *resource_info,XWindows *windows,Image *image, 12524% ExceptionInfo *exception) 12525% 12526% A description of each parameter follows: 12527% 12528% o display: Specifies a connection to an X server; returned from 12529% XOpenDisplay. 12530% 12531% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12532% 12533% o windows: Specifies a pointer to a XWindows structure. 12534% 12535% o image: the image. 12536% 12537% o exception: return any errors or warnings in this structure. 12538% 12539*/ 12540static MagickBooleanType XSaveImage(Display *display, 12541 XResourceInfo *resource_info,XWindows *windows,Image *image, 12542 ExceptionInfo *exception) 12543{ 12544 char 12545 filename[MaxTextExtent], 12546 geometry[MaxTextExtent]; 12547 12548 Image 12549 *save_image; 12550 12551 ImageInfo 12552 *image_info; 12553 12554 MagickStatusType 12555 status; 12556 12557 /* 12558 Request file name from user. 12559 */ 12560 if (resource_info->write_filename != (char *) NULL) 12561 (void) CopyMagickString(filename,resource_info->write_filename, 12562 MaxTextExtent); 12563 else 12564 { 12565 char 12566 path[MaxTextExtent]; 12567 12568 int 12569 status; 12570 12571 GetPathComponent(image->filename,HeadPath,path); 12572 GetPathComponent(image->filename,TailPath,filename); 12573 if (*path != '\0') 12574 { 12575 status=chdir(path); 12576 if (status == -1) 12577 (void) ThrowMagickException(exception,GetMagickModule(), 12578 FileOpenError,"UnableToOpenFile","%s",path); 12579 } 12580 } 12581 XFileBrowserWidget(display,windows,"Save",filename); 12582 if (*filename == '\0') 12583 return(MagickTrue); 12584 if (IsPathAccessible(filename) != MagickFalse) 12585 { 12586 int 12587 status; 12588 12589 /* 12590 File exists-- seek user's permission before overwriting. 12591 */ 12592 status=XConfirmWidget(display,windows,"Overwrite",filename); 12593 if (status <= 0) 12594 return(MagickTrue); 12595 } 12596 image_info=CloneImageInfo(resource_info->image_info); 12597 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 12598 (void) SetImageInfo(image_info,1,exception); 12599 if ((LocaleCompare(image_info->magick,"JPEG") == 0) || 12600 (LocaleCompare(image_info->magick,"JPG") == 0)) 12601 { 12602 char 12603 quality[MaxTextExtent]; 12604 12605 int 12606 status; 12607 12608 /* 12609 Request JPEG quality from user. 12610 */ 12611 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double) 12612 image->quality); 12613 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", 12614 quality); 12615 if (*quality == '\0') 12616 return(MagickTrue); 12617 image->quality=StringToUnsignedLong(quality); 12618 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace; 12619 } 12620 if ((LocaleCompare(image_info->magick,"EPS") == 0) || 12621 (LocaleCompare(image_info->magick,"PDF") == 0) || 12622 (LocaleCompare(image_info->magick,"PS") == 0) || 12623 (LocaleCompare(image_info->magick,"PS2") == 0)) 12624 { 12625 char 12626 geometry[MaxTextExtent]; 12627 12628 /* 12629 Request page geometry from user. 12630 */ 12631 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12632 if (LocaleCompare(image_info->magick,"PDF") == 0) 12633 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12634 if (image_info->page != (char *) NULL) 12635 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 12636 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 12637 "Select page geometry:",geometry); 12638 if (*geometry != '\0') 12639 image_info->page=GetPageGeometry(geometry); 12640 } 12641 /* 12642 Apply image transforms. 12643 */ 12644 XSetCursorState(display,windows,MagickTrue); 12645 XCheckRefreshWindows(display,windows); 12646 save_image=CloneImage(image,0,0,MagickTrue,exception); 12647 if (save_image == (Image *) NULL) 12648 return(MagickFalse); 12649 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 12650 windows->image.ximage->width,windows->image.ximage->height); 12651 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry, 12652 exception); 12653 /* 12654 Write image. 12655 */ 12656 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent); 12657 status=WriteImage(image_info,save_image,exception); 12658 if (status != MagickFalse) 12659 image->taint=MagickFalse; 12660 save_image=DestroyImage(save_image); 12661 image_info=DestroyImageInfo(image_info); 12662 XSetCursorState(display,windows,MagickFalse); 12663 return(status != 0 ? MagickTrue : MagickFalse); 12664} 12665 12666/* 12667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12668% % 12669% % 12670% % 12671+ X S c r e e n E v e n t % 12672% % 12673% % 12674% % 12675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12676% 12677% XScreenEvent() handles global events associated with the Pan and Magnify 12678% windows. 12679% 12680% The format of the XScreenEvent function is: 12681% 12682% void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12683% ExceptionInfo *exception) 12684% 12685% A description of each parameter follows: 12686% 12687% o display: Specifies a pointer to the Display structure; returned from 12688% XOpenDisplay. 12689% 12690% o windows: Specifies a pointer to a XWindows structure. 12691% 12692% o event: Specifies a pointer to a X11 XEvent structure. 12693% 12694% o exception: return any errors or warnings in this structure. 12695% 12696*/ 12697 12698#if defined(__cplusplus) || defined(c_plusplus) 12699extern "C" { 12700#endif 12701 12702static int XPredicate(Display *magick_unused(display),XEvent *event,char *data) 12703{ 12704 register XWindows 12705 *windows; 12706 12707 windows=(XWindows *) data; 12708 if ((event->type == ClientMessage) && 12709 (event->xclient.window == windows->image.id)) 12710 return(MagickFalse); 12711 return(MagickTrue); 12712} 12713 12714#if defined(__cplusplus) || defined(c_plusplus) 12715} 12716#endif 12717 12718static void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12719 ExceptionInfo *exception) 12720{ 12721 register int 12722 x, 12723 y; 12724 12725 (void) XIfEvent(display,event,XPredicate,(char *) windows); 12726 if (event->xany.window == windows->command.id) 12727 return; 12728 switch (event->type) 12729 { 12730 case ButtonPress: 12731 case ButtonRelease: 12732 { 12733 if ((event->xbutton.button == Button3) && 12734 (event->xbutton.state & Mod1Mask)) 12735 { 12736 /* 12737 Convert Alt-Button3 to Button2. 12738 */ 12739 event->xbutton.button=Button2; 12740 event->xbutton.state&=(~Mod1Mask); 12741 } 12742 if (event->xbutton.window == windows->backdrop.id) 12743 { 12744 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent, 12745 event->xbutton.time); 12746 break; 12747 } 12748 if (event->xbutton.window == windows->pan.id) 12749 { 12750 XPanImage(display,windows,event,exception); 12751 break; 12752 } 12753 if (event->xbutton.window == windows->image.id) 12754 if (event->xbutton.button == Button2) 12755 { 12756 /* 12757 Update magnified image. 12758 */ 12759 x=event->xbutton.x; 12760 y=event->xbutton.y; 12761 if (x < 0) 12762 x=0; 12763 else 12764 if (x >= (int) windows->image.width) 12765 x=(int) (windows->image.width-1); 12766 windows->magnify.x=(int) windows->image.x+x; 12767 if (y < 0) 12768 y=0; 12769 else 12770 if (y >= (int) windows->image.height) 12771 y=(int) (windows->image.height-1); 12772 windows->magnify.y=windows->image.y+y; 12773 if (windows->magnify.mapped == MagickFalse) 12774 (void) XMapRaised(display,windows->magnify.id); 12775 XMakeMagnifyImage(display,windows,exception); 12776 if (event->type == ButtonRelease) 12777 (void) XWithdrawWindow(display,windows->info.id, 12778 windows->info.screen); 12779 break; 12780 } 12781 break; 12782 } 12783 case ClientMessage: 12784 { 12785 /* 12786 If client window delete message, exit. 12787 */ 12788 if (event->xclient.message_type != windows->wm_protocols) 12789 break; 12790 if (*event->xclient.data.l != (long) windows->wm_delete_window) 12791 break; 12792 if (event->xclient.window == windows->magnify.id) 12793 { 12794 (void) XWithdrawWindow(display,windows->magnify.id, 12795 windows->magnify.screen); 12796 break; 12797 } 12798 break; 12799 } 12800 case ConfigureNotify: 12801 { 12802 if (event->xconfigure.window == windows->magnify.id) 12803 { 12804 unsigned int 12805 magnify; 12806 12807 /* 12808 Magnify window has a new configuration. 12809 */ 12810 windows->magnify.width=(unsigned int) event->xconfigure.width; 12811 windows->magnify.height=(unsigned int) event->xconfigure.height; 12812 if (windows->magnify.mapped == MagickFalse) 12813 break; 12814 magnify=1; 12815 while ((int) magnify <= event->xconfigure.width) 12816 magnify<<=1; 12817 while ((int) magnify <= event->xconfigure.height) 12818 magnify<<=1; 12819 magnify>>=1; 12820 if (((int) magnify != event->xconfigure.width) || 12821 ((int) magnify != event->xconfigure.height)) 12822 { 12823 XWindowChanges 12824 window_changes; 12825 12826 window_changes.width=(int) magnify; 12827 window_changes.height=(int) magnify; 12828 (void) XReconfigureWMWindow(display,windows->magnify.id, 12829 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 12830 &window_changes); 12831 break; 12832 } 12833 XMakeMagnifyImage(display,windows,exception); 12834 break; 12835 } 12836 break; 12837 } 12838 case Expose: 12839 { 12840 if (event->xexpose.window == windows->image.id) 12841 { 12842 XRefreshWindow(display,&windows->image,event); 12843 break; 12844 } 12845 if (event->xexpose.window == windows->pan.id) 12846 if (event->xexpose.count == 0) 12847 { 12848 XDrawPanRectangle(display,windows); 12849 break; 12850 } 12851 if (event->xexpose.window == windows->magnify.id) 12852 if (event->xexpose.count == 0) 12853 { 12854 XMakeMagnifyImage(display,windows,exception); 12855 break; 12856 } 12857 break; 12858 } 12859 case KeyPress: 12860 { 12861 char 12862 command[MaxTextExtent]; 12863 12864 KeySym 12865 key_symbol; 12866 12867 if (event->xkey.window != windows->magnify.id) 12868 break; 12869 /* 12870 Respond to a user key press. 12871 */ 12872 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int) 12873 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12874 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol, 12875 exception); 12876 break; 12877 } 12878 case MapNotify: 12879 { 12880 if (event->xmap.window == windows->magnify.id) 12881 { 12882 windows->magnify.mapped=MagickTrue; 12883 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12884 break; 12885 } 12886 if (event->xmap.window == windows->info.id) 12887 { 12888 windows->info.mapped=MagickTrue; 12889 break; 12890 } 12891 break; 12892 } 12893 case MotionNotify: 12894 { 12895 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; 12896 if (event->xmotion.window == windows->image.id) 12897 if (windows->magnify.mapped != MagickFalse) 12898 { 12899 /* 12900 Update magnified image. 12901 */ 12902 x=event->xmotion.x; 12903 y=event->xmotion.y; 12904 if (x < 0) 12905 x=0; 12906 else 12907 if (x >= (int) windows->image.width) 12908 x=(int) (windows->image.width-1); 12909 windows->magnify.x=(int) windows->image.x+x; 12910 if (y < 0) 12911 y=0; 12912 else 12913 if (y >= (int) windows->image.height) 12914 y=(int) (windows->image.height-1); 12915 windows->magnify.y=windows->image.y+y; 12916 XMakeMagnifyImage(display,windows,exception); 12917 } 12918 break; 12919 } 12920 case UnmapNotify: 12921 { 12922 if (event->xunmap.window == windows->magnify.id) 12923 { 12924 windows->magnify.mapped=MagickFalse; 12925 break; 12926 } 12927 if (event->xunmap.window == windows->info.id) 12928 { 12929 windows->info.mapped=MagickFalse; 12930 break; 12931 } 12932 break; 12933 } 12934 default: 12935 break; 12936 } 12937} 12938 12939/* 12940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12941% % 12942% % 12943% % 12944+ X S e t C r o p G e o m e t r y % 12945% % 12946% % 12947% % 12948%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12949% 12950% XSetCropGeometry() accepts a cropping geometry relative to the Image window 12951% and translates it to a cropping geometry relative to the image. 12952% 12953% The format of the XSetCropGeometry method is: 12954% 12955% void XSetCropGeometry(Display *display,XWindows *windows, 12956% RectangleInfo *crop_info,Image *image) 12957% 12958% A description of each parameter follows: 12959% 12960% o display: Specifies a connection to an X server; returned from 12961% XOpenDisplay. 12962% 12963% o windows: Specifies a pointer to a XWindows structure. 12964% 12965% o crop_info: A pointer to a RectangleInfo that defines a region of the 12966% Image window to crop. 12967% 12968% o image: the image. 12969% 12970*/ 12971static void XSetCropGeometry(Display *display,XWindows *windows, 12972 RectangleInfo *crop_info,Image *image) 12973{ 12974 char 12975 text[MaxTextExtent]; 12976 12977 int 12978 x, 12979 y; 12980 12981 MagickRealType 12982 scale_factor; 12983 12984 unsigned int 12985 height, 12986 width; 12987 12988 if (windows->info.mapped != MagickFalse) 12989 { 12990 /* 12991 Display info on cropping rectangle. 12992 */ 12993 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g", 12994 (double) crop_info->width,(double) crop_info->height,(double) 12995 crop_info->x,(double) crop_info->y); 12996 XInfoWidget(display,windows,text); 12997 } 12998 /* 12999 Cropping geometry is relative to any previous crop geometry. 13000 */ 13001 x=0; 13002 y=0; 13003 width=(unsigned int) image->columns; 13004 height=(unsigned int) image->rows; 13005 if (windows->image.crop_geometry != (char *) NULL) 13006 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13007 else 13008 windows->image.crop_geometry=AcquireString((char *) NULL); 13009 /* 13010 Define the crop geometry string from the cropping rectangle. 13011 */ 13012 scale_factor=(MagickRealType) width/windows->image.ximage->width; 13013 if (crop_info->x > 0) 13014 x+=(int) (scale_factor*crop_info->x+0.5); 13015 width=(unsigned int) (scale_factor*crop_info->width+0.5); 13016 if (width == 0) 13017 width=1; 13018 scale_factor=(MagickRealType) height/windows->image.ximage->height; 13019 if (crop_info->y > 0) 13020 y+=(int) (scale_factor*crop_info->y+0.5); 13021 height=(unsigned int) (scale_factor*crop_info->height+0.5); 13022 if (height == 0) 13023 height=1; 13024 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 13025 "%ux%u%+d%+d",width,height,x,y); 13026} 13027 13028/* 13029%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13030% % 13031% % 13032% % 13033+ X T i l e I m a g e % 13034% % 13035% % 13036% % 13037%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13038% 13039% XTileImage() loads or deletes a selected tile from a visual image directory. 13040% The load or delete command is chosen from a menu. 13041% 13042% The format of the XTileImage method is: 13043% 13044% Image *XTileImage(Display *display,XResourceInfo *resource_info, 13045% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13046% 13047% A description of each parameter follows: 13048% 13049% o tile_image: XTileImage reads or deletes the tile image 13050% and returns it. A null image is returned if an error occurs. 13051% 13052% o display: Specifies a connection to an X server; returned from 13053% XOpenDisplay. 13054% 13055% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13056% 13057% o windows: Specifies a pointer to a XWindows structure. 13058% 13059% o image: the image; returned from ReadImage. 13060% 13061% o event: Specifies a pointer to a XEvent structure. If it is NULL, 13062% the entire image is refreshed. 13063% 13064% o exception: return any errors or warnings in this structure. 13065% 13066*/ 13067static Image *XTileImage(Display *display,XResourceInfo *resource_info, 13068 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13069{ 13070 static const char 13071 *VerbMenu[] = 13072 { 13073 "Load", 13074 "Next", 13075 "Former", 13076 "Delete", 13077 "Update", 13078 (char *) NULL, 13079 }; 13080 13081 static const ModeType 13082 TileCommands[] = 13083 { 13084 TileLoadCommand, 13085 TileNextCommand, 13086 TileFormerCommand, 13087 TileDeleteCommand, 13088 TileUpdateCommand 13089 }; 13090 13091 char 13092 command[MaxTextExtent], 13093 filename[MaxTextExtent]; 13094 13095 Image 13096 *tile_image; 13097 13098 int 13099 id, 13100 status, 13101 tile, 13102 x, 13103 y; 13104 13105 MagickRealType 13106 scale_factor; 13107 13108 register char 13109 *p, 13110 *q; 13111 13112 register int 13113 i; 13114 13115 unsigned int 13116 height, 13117 width; 13118 13119 /* 13120 Tile image is relative to montage image configuration. 13121 */ 13122 x=0; 13123 y=0; 13124 width=(unsigned int) image->columns; 13125 height=(unsigned int) image->rows; 13126 if (windows->image.crop_geometry != (char *) NULL) 13127 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13128 scale_factor=(MagickRealType) width/windows->image.ximage->width; 13129 event->xbutton.x+=windows->image.x; 13130 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5); 13131 scale_factor=(MagickRealType) height/windows->image.ximage->height; 13132 event->xbutton.y+=windows->image.y; 13133 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5); 13134 /* 13135 Determine size and location of each tile in the visual image directory. 13136 */ 13137 width=(unsigned int) image->columns; 13138 height=(unsigned int) image->rows; 13139 x=0; 13140 y=0; 13141 (void) XParseGeometry(image->montage,&x,&y,&width,&height); 13142 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+ 13143 (event->xbutton.x-x)/width; 13144 if (tile < 0) 13145 { 13146 /* 13147 Button press is outside any tile. 13148 */ 13149 (void) XBell(display,0); 13150 return((Image *) NULL); 13151 } 13152 /* 13153 Determine file name from the tile directory. 13154 */ 13155 p=image->directory; 13156 for (i=tile; (i != 0) && (*p != '\0'); ) 13157 { 13158 if (*p == '\n') 13159 i--; 13160 p++; 13161 } 13162 if (*p == '\0') 13163 { 13164 /* 13165 Button press is outside any tile. 13166 */ 13167 (void) XBell(display,0); 13168 return((Image *) NULL); 13169 } 13170 /* 13171 Select a command from the pop-up menu. 13172 */ 13173 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command); 13174 if (id < 0) 13175 return((Image *) NULL); 13176 q=p; 13177 while ((*q != '\n') && (*q != '\0')) 13178 q++; 13179 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13180 /* 13181 Perform command for the selected tile. 13182 */ 13183 XSetCursorState(display,windows,MagickTrue); 13184 XCheckRefreshWindows(display,windows); 13185 tile_image=NewImageList(); 13186 switch (TileCommands[id]) 13187 { 13188 case TileLoadCommand: 13189 { 13190 /* 13191 Load tile image. 13192 */ 13193 XCheckRefreshWindows(display,windows); 13194 (void) CopyMagickString(resource_info->image_info->magick,"MIFF", 13195 MaxTextExtent); 13196 (void) CopyMagickString(resource_info->image_info->filename,filename, 13197 MaxTextExtent); 13198 tile_image=ReadImage(resource_info->image_info,exception); 13199 CatchException(exception); 13200 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13201 break; 13202 } 13203 case TileNextCommand: 13204 { 13205 /* 13206 Display next image. 13207 */ 13208 XClientMessage(display,windows->image.id,windows->im_protocols, 13209 windows->im_next_image,CurrentTime); 13210 break; 13211 } 13212 case TileFormerCommand: 13213 { 13214 /* 13215 Display former image. 13216 */ 13217 XClientMessage(display,windows->image.id,windows->im_protocols, 13218 windows->im_former_image,CurrentTime); 13219 break; 13220 } 13221 case TileDeleteCommand: 13222 { 13223 /* 13224 Delete tile image. 13225 */ 13226 if (IsPathAccessible(filename) == MagickFalse) 13227 { 13228 XNoticeWidget(display,windows,"Image file does not exist:",filename); 13229 break; 13230 } 13231 status=XConfirmWidget(display,windows,"Really delete tile",filename); 13232 if (status <= 0) 13233 break; 13234 status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse; 13235 if (status != MagickFalse) 13236 { 13237 XNoticeWidget(display,windows,"Unable to delete image file:", 13238 filename); 13239 break; 13240 } 13241 } 13242 case TileUpdateCommand: 13243 { 13244 int 13245 x_offset, 13246 y_offset; 13247 13248 PixelInfo 13249 pixel; 13250 13251 Quantum 13252 virtual_pixel[CompositePixelChannel]; 13253 13254 register int 13255 j; 13256 13257 register Quantum 13258 *s; 13259 13260 /* 13261 Ensure all the images exist. 13262 */ 13263 tile=0; 13264 GetPixelInfo(image,&pixel); 13265 for (p=image->directory; *p != '\0'; p++) 13266 { 13267 CacheView 13268 *image_view; 13269 13270 q=p; 13271 while ((*q != '\n') && (*q != '\0')) 13272 q++; 13273 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13274 p=q; 13275 if (IsPathAccessible(filename) != MagickFalse) 13276 { 13277 tile++; 13278 continue; 13279 } 13280 /* 13281 Overwrite tile with background color. 13282 */ 13283 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x); 13284 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y); 13285 image_view=AcquireCacheView(image); 13286 (void) GetOneCacheViewVirtualPixel(image_view,0,0,virtual_pixel, 13287 exception); 13288 pixel.red=virtual_pixel[RedPixelChannel]; 13289 pixel.green=virtual_pixel[GreenPixelChannel]; 13290 pixel.blue=virtual_pixel[BluePixelChannel]; 13291 pixel.alpha=virtual_pixel[AlphaPixelChannel]; 13292 for (i=0; i < (int) height; i++) 13293 { 13294 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t) 13295 y_offset+i,width,1,exception); 13296 if (s == (Quantum *) NULL) 13297 break; 13298 for (j=0; j < (int) width; j++) 13299 { 13300 SetPixelInfoPixel(image,&pixel,s); 13301 s+=GetPixelChannels(image); 13302 } 13303 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 13304 break; 13305 } 13306 image_view=DestroyCacheView(image_view); 13307 tile++; 13308 } 13309 windows->image.window_changes.width=(int) image->columns; 13310 windows->image.window_changes.height=(int) image->rows; 13311 XConfigureImageColormap(display,resource_info,windows,image,exception); 13312 (void) XConfigureImage(display,resource_info,windows,image,exception); 13313 break; 13314 } 13315 default: 13316 break; 13317 } 13318 XSetCursorState(display,windows,MagickFalse); 13319 return(tile_image); 13320} 13321 13322/* 13323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13324% % 13325% % 13326% % 13327+ X T r a n s l a t e I m a g e % 13328% % 13329% % 13330% % 13331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13332% 13333% XTranslateImage() translates the image within an Image window by one pixel 13334% as specified by the key symbol. If the image has a `montage string the 13335% translation is respect to the width and height contained within the string. 13336% 13337% The format of the XTranslateImage method is: 13338% 13339% void XTranslateImage(Display *display,XWindows *windows, 13340% Image *image,const KeySym key_symbol) 13341% 13342% A description of each parameter follows: 13343% 13344% o display: Specifies a connection to an X server; returned from 13345% XOpenDisplay. 13346% 13347% o windows: Specifies a pointer to a XWindows structure. 13348% 13349% o image: the image. 13350% 13351% o key_symbol: Specifies a KeySym which indicates which side of the image 13352% to trim. 13353% 13354*/ 13355static void XTranslateImage(Display *display,XWindows *windows, 13356 Image *image,const KeySym key_symbol) 13357{ 13358 char 13359 text[MaxTextExtent]; 13360 13361 int 13362 x, 13363 y; 13364 13365 unsigned int 13366 x_offset, 13367 y_offset; 13368 13369 /* 13370 User specified a pan position offset. 13371 */ 13372 x_offset=windows->image.width; 13373 y_offset=windows->image.height; 13374 if (image->montage != (char *) NULL) 13375 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset); 13376 switch ((int) key_symbol) 13377 { 13378 case XK_Home: 13379 case XK_KP_Home: 13380 { 13381 windows->image.x=(int) windows->image.width/2; 13382 windows->image.y=(int) windows->image.height/2; 13383 break; 13384 } 13385 case XK_Left: 13386 case XK_KP_Left: 13387 { 13388 windows->image.x-=x_offset; 13389 break; 13390 } 13391 case XK_Next: 13392 case XK_Up: 13393 case XK_KP_Up: 13394 { 13395 windows->image.y-=y_offset; 13396 break; 13397 } 13398 case XK_Right: 13399 case XK_KP_Right: 13400 { 13401 windows->image.x+=x_offset; 13402 break; 13403 } 13404 case XK_Prior: 13405 case XK_Down: 13406 case XK_KP_Down: 13407 { 13408 windows->image.y+=y_offset; 13409 break; 13410 } 13411 default: 13412 return; 13413 } 13414 /* 13415 Check boundary conditions. 13416 */ 13417 if (windows->image.x < 0) 13418 windows->image.x=0; 13419 else 13420 if ((int) (windows->image.x+windows->image.width) > 13421 windows->image.ximage->width) 13422 windows->image.x=(int) windows->image.ximage->width-windows->image.width; 13423 if (windows->image.y < 0) 13424 windows->image.y=0; 13425 else 13426 if ((int) (windows->image.y+windows->image.height) > 13427 windows->image.ximage->height) 13428 windows->image.y=(int) windows->image.ximage->height-windows->image.height; 13429 /* 13430 Refresh Image window. 13431 */ 13432 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 13433 windows->image.width,windows->image.height,windows->image.x, 13434 windows->image.y); 13435 XInfoWidget(display,windows,text); 13436 XCheckRefreshWindows(display,windows); 13437 XDrawPanRectangle(display,windows); 13438 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 13439 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13440} 13441 13442/* 13443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13444% % 13445% % 13446% % 13447+ X T r i m I m a g e % 13448% % 13449% % 13450% % 13451%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13452% 13453% XTrimImage() trims the edges from the Image window. 13454% 13455% The format of the XTrimImage method is: 13456% 13457% MagickBooleanType XTrimImage(Display *display, 13458% XResourceInfo *resource_info,XWindows *windows,Image *image, 13459% ExceptionInfo *exception) 13460% 13461% A description of each parameter follows: 13462% 13463% o display: Specifies a connection to an X server; returned from 13464% XOpenDisplay. 13465% 13466% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13467% 13468% o windows: Specifies a pointer to a XWindows structure. 13469% 13470% o image: the image. 13471% 13472% o exception: return any errors or warnings in this structure. 13473% 13474*/ 13475static MagickBooleanType XTrimImage(Display *display, 13476 XResourceInfo *resource_info,XWindows *windows,Image *image, 13477 ExceptionInfo *exception) 13478{ 13479 RectangleInfo 13480 trim_info; 13481 13482 register int 13483 x, 13484 y; 13485 13486 size_t 13487 background, 13488 pixel; 13489 13490 /* 13491 Trim edges from image. 13492 */ 13493 XSetCursorState(display,windows,MagickTrue); 13494 XCheckRefreshWindows(display,windows); 13495 /* 13496 Crop the left edge. 13497 */ 13498 background=XGetPixel(windows->image.ximage,0,0); 13499 trim_info.width=(size_t) windows->image.ximage->width; 13500 for (x=0; x < windows->image.ximage->width; x++) 13501 { 13502 for (y=0; y < windows->image.ximage->height; y++) 13503 { 13504 pixel=XGetPixel(windows->image.ximage,x,y); 13505 if (pixel != background) 13506 break; 13507 } 13508 if (y < windows->image.ximage->height) 13509 break; 13510 } 13511 trim_info.x=(ssize_t) x; 13512 if (trim_info.x == (ssize_t) windows->image.ximage->width) 13513 { 13514 XSetCursorState(display,windows,MagickFalse); 13515 return(MagickFalse); 13516 } 13517 /* 13518 Crop the right edge. 13519 */ 13520 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0); 13521 for (x=windows->image.ximage->width-1; x != 0; x--) 13522 { 13523 for (y=0; y < windows->image.ximage->height; y++) 13524 { 13525 pixel=XGetPixel(windows->image.ximage,x,y); 13526 if (pixel != background) 13527 break; 13528 } 13529 if (y < windows->image.ximage->height) 13530 break; 13531 } 13532 trim_info.width=(size_t) (x-trim_info.x+1); 13533 /* 13534 Crop the top edge. 13535 */ 13536 background=XGetPixel(windows->image.ximage,0,0); 13537 trim_info.height=(size_t) windows->image.ximage->height; 13538 for (y=0; y < windows->image.ximage->height; y++) 13539 { 13540 for (x=0; x < windows->image.ximage->width; x++) 13541 { 13542 pixel=XGetPixel(windows->image.ximage,x,y); 13543 if (pixel != background) 13544 break; 13545 } 13546 if (x < windows->image.ximage->width) 13547 break; 13548 } 13549 trim_info.y=(ssize_t) y; 13550 /* 13551 Crop the bottom edge. 13552 */ 13553 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1); 13554 for (y=windows->image.ximage->height-1; y != 0; y--) 13555 { 13556 for (x=0; x < windows->image.ximage->width; x++) 13557 { 13558 pixel=XGetPixel(windows->image.ximage,x,y); 13559 if (pixel != background) 13560 break; 13561 } 13562 if (x < windows->image.ximage->width) 13563 break; 13564 } 13565 trim_info.height=(size_t) y-trim_info.y+1; 13566 if (((unsigned int) trim_info.width != windows->image.width) || 13567 ((unsigned int) trim_info.height != windows->image.height)) 13568 { 13569 /* 13570 Reconfigure Image window as defined by the trimming rectangle. 13571 */ 13572 XSetCropGeometry(display,windows,&trim_info,image); 13573 windows->image.window_changes.width=(int) trim_info.width; 13574 windows->image.window_changes.height=(int) trim_info.height; 13575 (void) XConfigureImage(display,resource_info,windows,image,exception); 13576 } 13577 XSetCursorState(display,windows,MagickFalse); 13578 return(MagickTrue); 13579} 13580 13581/* 13582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13583% % 13584% % 13585% % 13586+ X V i s u a l D i r e c t o r y I m a g e % 13587% % 13588% % 13589% % 13590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13591% 13592% XVisualDirectoryImage() creates a Visual Image Directory. 13593% 13594% The format of the XVisualDirectoryImage method is: 13595% 13596% Image *XVisualDirectoryImage(Display *display, 13597% XResourceInfo *resource_info,XWindows *windows, 13598% ExceptionInfo *exception) 13599% 13600% A description of each parameter follows: 13601% 13602% o display: Specifies a connection to an X server; returned from 13603% XOpenDisplay. 13604% 13605% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13606% 13607% o windows: Specifies a pointer to a XWindows structure. 13608% 13609% o exception: return any errors or warnings in this structure. 13610% 13611*/ 13612static Image *XVisualDirectoryImage(Display *display, 13613 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception) 13614{ 13615#define TileImageTag "Scale/Image" 13616#define XClientName "montage" 13617 13618 char 13619 **filelist; 13620 13621 Image 13622 *images, 13623 *montage_image, 13624 *next_image, 13625 *thumbnail_image; 13626 13627 ImageInfo 13628 *read_info; 13629 13630 int 13631 number_files; 13632 13633 MagickBooleanType 13634 backdrop; 13635 13636 MagickStatusType 13637 status; 13638 13639 MontageInfo 13640 *montage_info; 13641 13642 RectangleInfo 13643 geometry; 13644 13645 register int 13646 i; 13647 13648 static char 13649 filename[MaxTextExtent] = "\0", 13650 filenames[MaxTextExtent] = "*"; 13651 13652 XResourceInfo 13653 background_resources; 13654 13655 /* 13656 Request file name from user. 13657 */ 13658 XFileBrowserWidget(display,windows,"Directory",filenames); 13659 if (*filenames == '\0') 13660 return((Image *) NULL); 13661 /* 13662 Expand the filenames. 13663 */ 13664 filelist=(char **) AcquireMagickMemory(sizeof(*filelist)); 13665 if (filelist == (char **) NULL) 13666 { 13667 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13668 filenames); 13669 return((Image *) NULL); 13670 } 13671 number_files=1; 13672 filelist[0]=filenames; 13673 status=ExpandFilenames(&number_files,&filelist); 13674 if ((status == MagickFalse) || (number_files == 0)) 13675 { 13676 if (number_files == 0) 13677 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames) 13678 else 13679 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13680 filenames); 13681 return((Image *) NULL); 13682 } 13683 /* 13684 Set image background resources. 13685 */ 13686 background_resources=(*resource_info); 13687 background_resources.window_id=AcquireString(""); 13688 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent, 13689 "0x%lx",windows->image.id); 13690 background_resources.backdrop=MagickTrue; 13691 /* 13692 Read each image and convert them to a tile. 13693 */ 13694 backdrop=(windows->visual_info->klass == TrueColor) || 13695 (windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse; 13696 read_info=CloneImageInfo(resource_info->image_info); 13697 (void) SetImageOption(read_info,"jpeg:size","120x120"); 13698 (void) CloneString(&read_info->size,DefaultTileGeometry); 13699 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 13700 (void *) NULL); 13701 images=NewImageList(); 13702 XSetCursorState(display,windows,MagickTrue); 13703 XCheckRefreshWindows(display,windows); 13704 for (i=0; i < (int) number_files; i++) 13705 { 13706 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent); 13707 filelist[i]=DestroyString(filelist[i]); 13708 *read_info->magick='\0'; 13709 next_image=ReadImage(read_info,exception); 13710 CatchException(exception); 13711 if (next_image != (Image *) NULL) 13712 { 13713 (void) DeleteImageProperty(next_image,"label"); 13714 (void) SetImageProperty(next_image,"label",InterpretImageProperties( 13715 read_info,next_image,DefaultTileLabel,exception),exception); 13716 (void) ParseRegionGeometry(next_image,read_info->size,&geometry, 13717 exception); 13718 thumbnail_image=ThumbnailImage(next_image,geometry.width, 13719 geometry.height,exception); 13720 if (thumbnail_image != (Image *) NULL) 13721 { 13722 next_image=DestroyImage(next_image); 13723 next_image=thumbnail_image; 13724 } 13725 if (backdrop) 13726 { 13727 (void) XDisplayBackgroundImage(display,&background_resources, 13728 next_image,exception); 13729 XSetCursorState(display,windows,MagickTrue); 13730 } 13731 AppendImageToList(&images,next_image); 13732 if (images->progress_monitor != (MagickProgressMonitor) NULL) 13733 { 13734 MagickBooleanType 13735 proceed; 13736 13737 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i, 13738 (MagickSizeType) number_files); 13739 if (proceed == MagickFalse) 13740 break; 13741 } 13742 } 13743 } 13744 filelist=(char **) RelinquishMagickMemory(filelist); 13745 if (images == (Image *) NULL) 13746 { 13747 read_info=DestroyImageInfo(read_info); 13748 XSetCursorState(display,windows,MagickFalse); 13749 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames); 13750 return((Image *) NULL); 13751 } 13752 /* 13753 Create the Visual Image Directory. 13754 */ 13755 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL); 13756 montage_info->pointsize=10; 13757 if (resource_info->font != (char *) NULL) 13758 (void) CloneString(&montage_info->font,resource_info->font); 13759 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent); 13760 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList( 13761 images),exception); 13762 images=DestroyImageList(images); 13763 montage_info=DestroyMontageInfo(montage_info); 13764 read_info=DestroyImageInfo(read_info); 13765 XSetCursorState(display,windows,MagickFalse); 13766 if (montage_image == (Image *) NULL) 13767 return(montage_image); 13768 XClientMessage(display,windows->image.id,windows->im_protocols, 13769 windows->im_next_image,CurrentTime); 13770 return(montage_image); 13771} 13772 13773/* 13774%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13775% % 13776% % 13777% % 13778% X D i s p l a y B a c k g r o u n d I m a g e % 13779% % 13780% % 13781% % 13782%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13783% 13784% XDisplayBackgroundImage() displays an image in the background of a window. 13785% 13786% The format of the XDisplayBackgroundImage method is: 13787% 13788% MagickBooleanType XDisplayBackgroundImage(Display *display, 13789% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13790% 13791% A description of each parameter follows: 13792% 13793% o display: Specifies a connection to an X server; returned from 13794% XOpenDisplay. 13795% 13796% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13797% 13798% o image: the image. 13799% 13800% o exception: return any errors or warnings in this structure. 13801% 13802*/ 13803MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display, 13804 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13805{ 13806 char 13807 geometry[MaxTextExtent], 13808 visual_type[MaxTextExtent]; 13809 13810 int 13811 height, 13812 status, 13813 width; 13814 13815 RectangleInfo 13816 geometry_info; 13817 13818 static XPixelInfo 13819 pixel; 13820 13821 static XStandardColormap 13822 *map_info; 13823 13824 static XVisualInfo 13825 *visual_info = (XVisualInfo *) NULL; 13826 13827 static XWindowInfo 13828 window_info; 13829 13830 size_t 13831 delay; 13832 13833 Window 13834 root_window; 13835 13836 XGCValues 13837 context_values; 13838 13839 XResourceInfo 13840 resources; 13841 13842 XWindowAttributes 13843 window_attributes; 13844 13845 /* 13846 Determine target window. 13847 */ 13848 assert(image != (Image *) NULL); 13849 assert(image->signature == MagickSignature); 13850 if (image->debug != MagickFalse) 13851 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 13852 resources=(*resource_info); 13853 window_info.id=(Window) NULL; 13854 root_window=XRootWindow(display,XDefaultScreen(display)); 13855 if (LocaleCompare(resources.window_id,"root") == 0) 13856 window_info.id=root_window; 13857 else 13858 { 13859 if (isdigit((unsigned char) *resources.window_id) != 0) 13860 window_info.id=XWindowByID(display,root_window, 13861 (Window) strtol((char *) resources.window_id,(char **) NULL,0)); 13862 if (window_info.id == (Window) NULL) 13863 window_info.id=XWindowByName(display,root_window,resources.window_id); 13864 } 13865 if (window_info.id == (Window) NULL) 13866 { 13867 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists", 13868 resources.window_id); 13869 return(MagickFalse); 13870 } 13871 /* 13872 Determine window visual id. 13873 */ 13874 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); 13875 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); 13876 (void) CopyMagickString(visual_type,"default",MaxTextExtent); 13877 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13878 if (status != 0) 13879 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx", 13880 XVisualIDFromVisual(window_attributes.visual)); 13881 if (visual_info == (XVisualInfo *) NULL) 13882 { 13883 /* 13884 Allocate standard colormap. 13885 */ 13886 map_info=XAllocStandardColormap(); 13887 if (map_info == (XStandardColormap *) NULL) 13888 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", 13889 image->filename); 13890 map_info->colormap=(Colormap) NULL; 13891 pixel.pixels=(unsigned long *) NULL; 13892 /* 13893 Initialize visual info. 13894 */ 13895 resources.map_type=(char *) NULL; 13896 resources.visual_type=visual_type; 13897 visual_info=XBestVisualInfo(display,map_info,&resources); 13898 if (visual_info == (XVisualInfo *) NULL) 13899 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", 13900 resources.visual_type); 13901 /* 13902 Initialize window info. 13903 */ 13904 window_info.ximage=(XImage *) NULL; 13905 window_info.matte_image=(XImage *) NULL; 13906 window_info.pixmap=(Pixmap) NULL; 13907 window_info.matte_pixmap=(Pixmap) NULL; 13908 } 13909 /* 13910 Free previous root colors. 13911 */ 13912 if (window_info.id == root_window) 13913 (void) XDestroyWindowColors(display,root_window); 13914 /* 13915 Initialize Standard Colormap. 13916 */ 13917 resources.colormap=SharedColormap; 13918 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel, 13919 exception); 13920 /* 13921 Graphic context superclass. 13922 */ 13923 context_values.background=pixel.background_color.pixel; 13924 context_values.foreground=pixel.foreground_color.pixel; 13925 pixel.annotate_context=XCreateGC(display,window_info.id, 13926 (size_t) (GCBackground | GCForeground),&context_values); 13927 if (pixel.annotate_context == (GC) NULL) 13928 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 13929 image->filename); 13930 /* 13931 Initialize Image window attributes. 13932 */ 13933 window_info.name=AcquireString("\0"); 13934 window_info.icon_name=AcquireString("\0"); 13935 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, 13936 &resources,&window_info); 13937 /* 13938 Create the X image. 13939 */ 13940 window_info.width=(unsigned int) image->columns; 13941 window_info.height=(unsigned int) image->rows; 13942 if ((image->columns != window_info.width) || 13943 (image->rows != window_info.height)) 13944 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13945 image->filename); 13946 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>", 13947 window_attributes.width,window_attributes.height); 13948 geometry_info.width=window_info.width; 13949 geometry_info.height=window_info.height; 13950 geometry_info.x=(ssize_t) window_info.x; 13951 geometry_info.y=(ssize_t) window_info.y; 13952 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 13953 &geometry_info.width,&geometry_info.height); 13954 window_info.width=(unsigned int) geometry_info.width; 13955 window_info.height=(unsigned int) geometry_info.height; 13956 window_info.x=(int) geometry_info.x; 13957 window_info.y=(int) geometry_info.y; 13958 status=XMakeImage(display,&resources,&window_info,image,window_info.width, 13959 window_info.height,exception); 13960 if (status == MagickFalse) 13961 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13962 image->filename); 13963 window_info.x=0; 13964 window_info.y=0; 13965 if (image->debug != MagickFalse) 13966 { 13967 (void) LogMagickEvent(X11Event,GetMagickModule(), 13968 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene, 13969 (double) image->columns,(double) image->rows); 13970 if (image->colors != 0) 13971 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 13972 image->colors); 13973 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick); 13974 } 13975 /* 13976 Adjust image dimensions as specified by backdrop or geometry options. 13977 */ 13978 width=(int) window_info.width; 13979 height=(int) window_info.height; 13980 if (resources.backdrop != MagickFalse) 13981 { 13982 /* 13983 Center image on window. 13984 */ 13985 window_info.x=(window_attributes.width/2)- 13986 (window_info.ximage->width/2); 13987 window_info.y=(window_attributes.height/2)- 13988 (window_info.ximage->height/2); 13989 width=window_attributes.width; 13990 height=window_attributes.height; 13991 } 13992 if ((resources.image_geometry != (char *) NULL) && 13993 (*resources.image_geometry != '\0')) 13994 { 13995 char 13996 default_geometry[MaxTextExtent]; 13997 13998 int 13999 flags, 14000 gravity; 14001 14002 XSizeHints 14003 *size_hints; 14004 14005 /* 14006 User specified geometry. 14007 */ 14008 size_hints=XAllocSizeHints(); 14009 if (size_hints == (XSizeHints *) NULL) 14010 ThrowXWindowFatalException(ResourceLimitFatalError, 14011 "MemoryAllocationFailed",image->filename); 14012 size_hints->flags=0L; 14013 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d", 14014 width,height); 14015 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, 14016 default_geometry,window_info.border_width,size_hints,&window_info.x, 14017 &window_info.y,&width,&height,&gravity); 14018 if (flags & (XValue | YValue)) 14019 { 14020 width=window_attributes.width; 14021 height=window_attributes.height; 14022 } 14023 (void) XFree((void *) size_hints); 14024 } 14025 /* 14026 Create the X pixmap. 14027 */ 14028 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, 14029 (unsigned int) height,window_info.depth); 14030 if (window_info.pixmap == (Pixmap) NULL) 14031 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", 14032 image->filename); 14033 /* 14034 Display pixmap on the window. 14035 */ 14036 if (((unsigned int) width > window_info.width) || 14037 ((unsigned int) height > window_info.height)) 14038 (void) XFillRectangle(display,window_info.pixmap, 14039 window_info.annotate_context,0,0,(unsigned int) width, 14040 (unsigned int) height); 14041 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, 14042 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int) 14043 window_info.width,(unsigned int) window_info.height); 14044 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); 14045 (void) XClearWindow(display,window_info.id); 14046 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); 14047 XDelay(display,delay == 0UL ? 10UL : delay); 14048 (void) XSync(display,MagickFalse); 14049 return(window_info.id == root_window ? MagickTrue : MagickFalse); 14050} 14051 14052/* 14053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14054% % 14055% % 14056% % 14057+ X D i s p l a y I m a g e % 14058% % 14059% % 14060% % 14061%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14062% 14063% XDisplayImage() displays an image via X11. A new image is created and 14064% returned if the user interactively transforms the displayed image. 14065% 14066% The format of the XDisplayImage method is: 14067% 14068% Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14069% char **argv,int argc,Image **image,size_t *state, 14070% ExceptionInfo *exception) 14071% 14072% A description of each parameter follows: 14073% 14074% o nexus: Method XDisplayImage returns an image when the 14075% user chooses 'Open Image' from the command menu or picks a tile 14076% from the image directory. Otherwise a null image is returned. 14077% 14078% o display: Specifies a connection to an X server; returned from 14079% XOpenDisplay. 14080% 14081% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 14082% 14083% o argv: Specifies the application's argument list. 14084% 14085% o argc: Specifies the number of arguments. 14086% 14087% o image: Specifies an address to an address of an Image structure; 14088% 14089% o exception: return any errors or warnings in this structure. 14090% 14091*/ 14092MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14093 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception) 14094{ 14095#define MagnifySize 256 /* must be a power of 2 */ 14096#define MagickMenus 10 14097#define MagickTitle "Commands" 14098 14099 static const char 14100 *CommandMenu[] = 14101 { 14102 "File", 14103 "Edit", 14104 "View", 14105 "Transform", 14106 "Enhance", 14107 "Effects", 14108 "F/X", 14109 "Image Edit", 14110 "Miscellany", 14111 "Help", 14112 (char *) NULL 14113 }, 14114 *FileMenu[] = 14115 { 14116 "Open...", 14117 "Next", 14118 "Former", 14119 "Select...", 14120 "Save...", 14121 "Print...", 14122 "Delete...", 14123 "New...", 14124 "Visual Directory...", 14125 "Quit", 14126 (char *) NULL 14127 }, 14128 *EditMenu[] = 14129 { 14130 "Undo", 14131 "Redo", 14132 "Cut", 14133 "Copy", 14134 "Paste", 14135 (char *) NULL 14136 }, 14137 *ViewMenu[] = 14138 { 14139 "Half Size", 14140 "Original Size", 14141 "Double Size", 14142 "Resize...", 14143 "Apply", 14144 "Refresh", 14145 "Restore", 14146 (char *) NULL 14147 }, 14148 *TransformMenu[] = 14149 { 14150 "Crop", 14151 "Chop", 14152 "Flop", 14153 "Flip", 14154 "Rotate Right", 14155 "Rotate Left", 14156 "Rotate...", 14157 "Shear...", 14158 "Roll...", 14159 "Trim Edges", 14160 (char *) NULL 14161 }, 14162 *EnhanceMenu[] = 14163 { 14164 "Hue...", 14165 "Saturation...", 14166 "Brightness...", 14167 "Gamma...", 14168 "Spiff", 14169 "Dull", 14170 "Contrast Stretch...", 14171 "Sigmoidal Contrast...", 14172 "Normalize", 14173 "Equalize", 14174 "Negate", 14175 "Grayscale", 14176 "Map...", 14177 "Quantize...", 14178 (char *) NULL 14179 }, 14180 *EffectsMenu[] = 14181 { 14182 "Despeckle", 14183 "Emboss", 14184 "Reduce Noise", 14185 "Add Noise...", 14186 "Sharpen...", 14187 "Blur...", 14188 "Threshold...", 14189 "Edge Detect...", 14190 "Spread...", 14191 "Shade...", 14192 "Raise...", 14193 "Segment...", 14194 (char *) NULL 14195 }, 14196 *FXMenu[] = 14197 { 14198 "Solarize...", 14199 "Sepia Tone...", 14200 "Swirl...", 14201 "Implode...", 14202 "Vignette...", 14203 "Wave...", 14204 "Oil Paint...", 14205 "Charcoal Draw...", 14206 (char *) NULL 14207 }, 14208 *ImageEditMenu[] = 14209 { 14210 "Annotate...", 14211 "Draw...", 14212 "Color...", 14213 "Matte...", 14214 "Composite...", 14215 "Add Border...", 14216 "Add Frame...", 14217 "Comment...", 14218 "Launch...", 14219 "Region of Interest...", 14220 (char *) NULL 14221 }, 14222 *MiscellanyMenu[] = 14223 { 14224 "Image Info", 14225 "Zoom Image", 14226 "Show Preview...", 14227 "Show Histogram", 14228 "Show Matte", 14229 "Background...", 14230 "Slide Show...", 14231 "Preferences...", 14232 (char *) NULL 14233 }, 14234 *HelpMenu[] = 14235 { 14236 "Overview", 14237 "Browse Documentation", 14238 "About Display", 14239 (char *) NULL 14240 }, 14241 *ShortCutsMenu[] = 14242 { 14243 "Next", 14244 "Former", 14245 "Open...", 14246 "Save...", 14247 "Print...", 14248 "Undo", 14249 "Restore", 14250 "Image Info", 14251 "Quit", 14252 (char *) NULL 14253 }, 14254 *VirtualMenu[] = 14255 { 14256 "Image Info", 14257 "Print", 14258 "Next", 14259 "Quit", 14260 (char *) NULL 14261 }; 14262 14263 static const char 14264 **Menus[MagickMenus] = 14265 { 14266 FileMenu, 14267 EditMenu, 14268 ViewMenu, 14269 TransformMenu, 14270 EnhanceMenu, 14271 EffectsMenu, 14272 FXMenu, 14273 ImageEditMenu, 14274 MiscellanyMenu, 14275 HelpMenu 14276 }; 14277 14278 static CommandType 14279 CommandMenus[] = 14280 { 14281 NullCommand, 14282 NullCommand, 14283 NullCommand, 14284 NullCommand, 14285 NullCommand, 14286 NullCommand, 14287 NullCommand, 14288 NullCommand, 14289 NullCommand, 14290 NullCommand, 14291 }, 14292 FileCommands[] = 14293 { 14294 OpenCommand, 14295 NextCommand, 14296 FormerCommand, 14297 SelectCommand, 14298 SaveCommand, 14299 PrintCommand, 14300 DeleteCommand, 14301 NewCommand, 14302 VisualDirectoryCommand, 14303 QuitCommand 14304 }, 14305 EditCommands[] = 14306 { 14307 UndoCommand, 14308 RedoCommand, 14309 CutCommand, 14310 CopyCommand, 14311 PasteCommand 14312 }, 14313 ViewCommands[] = 14314 { 14315 HalfSizeCommand, 14316 OriginalSizeCommand, 14317 DoubleSizeCommand, 14318 ResizeCommand, 14319 ApplyCommand, 14320 RefreshCommand, 14321 RestoreCommand 14322 }, 14323 TransformCommands[] = 14324 { 14325 CropCommand, 14326 ChopCommand, 14327 FlopCommand, 14328 FlipCommand, 14329 RotateRightCommand, 14330 RotateLeftCommand, 14331 RotateCommand, 14332 ShearCommand, 14333 RollCommand, 14334 TrimCommand 14335 }, 14336 EnhanceCommands[] = 14337 { 14338 HueCommand, 14339 SaturationCommand, 14340 BrightnessCommand, 14341 GammaCommand, 14342 SpiffCommand, 14343 DullCommand, 14344 ContrastStretchCommand, 14345 SigmoidalContrastCommand, 14346 NormalizeCommand, 14347 EqualizeCommand, 14348 NegateCommand, 14349 GrayscaleCommand, 14350 MapCommand, 14351 QuantizeCommand 14352 }, 14353 EffectsCommands[] = 14354 { 14355 DespeckleCommand, 14356 EmbossCommand, 14357 ReduceNoiseCommand, 14358 AddNoiseCommand, 14359 SharpenCommand, 14360 BlurCommand, 14361 ThresholdCommand, 14362 EdgeDetectCommand, 14363 SpreadCommand, 14364 ShadeCommand, 14365 RaiseCommand, 14366 SegmentCommand 14367 }, 14368 FXCommands[] = 14369 { 14370 SolarizeCommand, 14371 SepiaToneCommand, 14372 SwirlCommand, 14373 ImplodeCommand, 14374 VignetteCommand, 14375 WaveCommand, 14376 OilPaintCommand, 14377 CharcoalDrawCommand 14378 }, 14379 ImageEditCommands[] = 14380 { 14381 AnnotateCommand, 14382 DrawCommand, 14383 ColorCommand, 14384 MatteCommand, 14385 CompositeCommand, 14386 AddBorderCommand, 14387 AddFrameCommand, 14388 CommentCommand, 14389 LaunchCommand, 14390 RegionofInterestCommand 14391 }, 14392 MiscellanyCommands[] = 14393 { 14394 InfoCommand, 14395 ZoomCommand, 14396 ShowPreviewCommand, 14397 ShowHistogramCommand, 14398 ShowMatteCommand, 14399 BackgroundCommand, 14400 SlideShowCommand, 14401 PreferencesCommand 14402 }, 14403 HelpCommands[] = 14404 { 14405 HelpCommand, 14406 BrowseDocumentationCommand, 14407 VersionCommand 14408 }, 14409 ShortCutsCommands[] = 14410 { 14411 NextCommand, 14412 FormerCommand, 14413 OpenCommand, 14414 SaveCommand, 14415 PrintCommand, 14416 UndoCommand, 14417 RestoreCommand, 14418 InfoCommand, 14419 QuitCommand 14420 }, 14421 VirtualCommands[] = 14422 { 14423 InfoCommand, 14424 PrintCommand, 14425 NextCommand, 14426 QuitCommand 14427 }; 14428 14429 static CommandType 14430 *Commands[MagickMenus] = 14431 { 14432 FileCommands, 14433 EditCommands, 14434 ViewCommands, 14435 TransformCommands, 14436 EnhanceCommands, 14437 EffectsCommands, 14438 FXCommands, 14439 ImageEditCommands, 14440 MiscellanyCommands, 14441 HelpCommands 14442 }; 14443 14444 char 14445 command[MaxTextExtent], 14446 *directory, 14447 geometry[MaxTextExtent], 14448 resource_name[MaxTextExtent]; 14449 14450 CommandType 14451 command_type; 14452 14453 Image 14454 *display_image, 14455 *nexus; 14456 14457 int 14458 entry, 14459 id; 14460 14461 KeySym 14462 key_symbol; 14463 14464 MagickStatusType 14465 context_mask, 14466 status; 14467 14468 RectangleInfo 14469 geometry_info; 14470 14471 register int 14472 i; 14473 14474 static char 14475 working_directory[MaxTextExtent]; 14476 14477 static XPoint 14478 vid_info; 14479 14480 static XWindowInfo 14481 *magick_windows[MaxXWindows]; 14482 14483 static unsigned int 14484 number_windows; 14485 14486 struct stat 14487 attributes; 14488 14489 time_t 14490 timer, 14491 timestamp, 14492 update_time; 14493 14494 unsigned int 14495 height, 14496 width; 14497 14498 size_t 14499 delay; 14500 14501 WarningHandler 14502 warning_handler; 14503 14504 Window 14505 root_window; 14506 14507 XClassHint 14508 *class_hints; 14509 14510 XEvent 14511 event; 14512 14513 XFontStruct 14514 *font_info; 14515 14516 XGCValues 14517 context_values; 14518 14519 XPixelInfo 14520 *icon_pixel, 14521 *pixel; 14522 14523 XResourceInfo 14524 *icon_resources; 14525 14526 XStandardColormap 14527 *icon_map, 14528 *map_info; 14529 14530 XVisualInfo 14531 *icon_visual, 14532 *visual_info; 14533 14534 XWindowChanges 14535 window_changes; 14536 14537 XWindows 14538 *windows; 14539 14540 XWMHints 14541 *manager_hints; 14542 14543 assert(image != (Image **) NULL); 14544 assert((*image)->signature == MagickSignature); 14545 if ((*image)->debug != MagickFalse) 14546 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 14547 display_image=(*image); 14548 warning_handler=(WarningHandler) NULL; 14549 windows=XSetWindows((XWindows *) ~0); 14550 if (windows != (XWindows *) NULL) 14551 { 14552 int 14553 status; 14554 14555 status=chdir(working_directory); 14556 if (status == -1) 14557 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 14558 "UnableToOpenFile","%s",working_directory); 14559 warning_handler=resource_info->display_warnings ? 14560 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14561 warning_handler=resource_info->display_warnings ? 14562 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14563 } 14564 else 14565 { 14566 /* 14567 Allocate windows structure. 14568 */ 14569 resource_info->colors=display_image->colors; 14570 windows=XSetWindows(XInitializeWindows(display,resource_info)); 14571 if (windows == (XWindows *) NULL) 14572 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow", 14573 (*image)->filename); 14574 /* 14575 Initialize window id's. 14576 */ 14577 number_windows=0; 14578 magick_windows[number_windows++]=(&windows->icon); 14579 magick_windows[number_windows++]=(&windows->backdrop); 14580 magick_windows[number_windows++]=(&windows->image); 14581 magick_windows[number_windows++]=(&windows->info); 14582 magick_windows[number_windows++]=(&windows->command); 14583 magick_windows[number_windows++]=(&windows->widget); 14584 magick_windows[number_windows++]=(&windows->popup); 14585 magick_windows[number_windows++]=(&windows->magnify); 14586 magick_windows[number_windows++]=(&windows->pan); 14587 for (i=0; i < (int) number_windows; i++) 14588 magick_windows[i]->id=(Window) NULL; 14589 vid_info.x=0; 14590 vid_info.y=0; 14591 } 14592 /* 14593 Initialize font info. 14594 */ 14595 if (windows->font_info != (XFontStruct *) NULL) 14596 (void) XFreeFont(display,windows->font_info); 14597 windows->font_info=XBestFont(display,resource_info,MagickFalse); 14598 if (windows->font_info == (XFontStruct *) NULL) 14599 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", 14600 resource_info->font); 14601 /* 14602 Initialize Standard Colormap. 14603 */ 14604 map_info=windows->map_info; 14605 icon_map=windows->icon_map; 14606 visual_info=windows->visual_info; 14607 icon_visual=windows->icon_visual; 14608 pixel=windows->pixel_info; 14609 icon_pixel=windows->icon_pixel; 14610 font_info=windows->font_info; 14611 icon_resources=windows->icon_resources; 14612 class_hints=windows->class_hints; 14613 manager_hints=windows->manager_hints; 14614 root_window=XRootWindow(display,visual_info->screen); 14615 nexus=NewImageList(); 14616 if (display_image->debug != MagickFalse) 14617 { 14618 (void) LogMagickEvent(X11Event,GetMagickModule(), 14619 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename, 14620 (double) display_image->scene,(double) display_image->columns, 14621 (double) display_image->rows); 14622 if (display_image->colors != 0) 14623 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 14624 display_image->colors); 14625 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", 14626 display_image->magick); 14627 } 14628 XMakeStandardColormap(display,visual_info,resource_info,display_image, 14629 map_info,pixel,exception); 14630 display_image->taint=MagickFalse; 14631 /* 14632 Initialize graphic context. 14633 */ 14634 windows->context.id=(Window) NULL; 14635 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14636 resource_info,&windows->context); 14637 (void) CloneString(&class_hints->res_name,resource_info->client_name); 14638 (void) CloneString(&class_hints->res_class,resource_info->client_name); 14639 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]); 14640 manager_hints->flags=InputHint | StateHint; 14641 manager_hints->input=MagickFalse; 14642 manager_hints->initial_state=WithdrawnState; 14643 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14644 &windows->context); 14645 if (display_image->debug != MagickFalse) 14646 (void) LogMagickEvent(X11Event,GetMagickModule(), 14647 "Window id: 0x%lx (context)",windows->context.id); 14648 context_values.background=pixel->background_color.pixel; 14649 context_values.font=font_info->fid; 14650 context_values.foreground=pixel->foreground_color.pixel; 14651 context_values.graphics_exposures=MagickFalse; 14652 context_mask=(MagickStatusType) 14653 (GCBackground | GCFont | GCForeground | GCGraphicsExposures); 14654 if (pixel->annotate_context != (GC) NULL) 14655 (void) XFreeGC(display,pixel->annotate_context); 14656 pixel->annotate_context=XCreateGC(display,windows->context.id, 14657 context_mask,&context_values); 14658 if (pixel->annotate_context == (GC) NULL) 14659 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14660 display_image->filename); 14661 context_values.background=pixel->depth_color.pixel; 14662 if (pixel->widget_context != (GC) NULL) 14663 (void) XFreeGC(display,pixel->widget_context); 14664 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask, 14665 &context_values); 14666 if (pixel->widget_context == (GC) NULL) 14667 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14668 display_image->filename); 14669 context_values.background=pixel->foreground_color.pixel; 14670 context_values.foreground=pixel->background_color.pixel; 14671 context_values.plane_mask=context_values.background ^ 14672 context_values.foreground; 14673 if (pixel->highlight_context != (GC) NULL) 14674 (void) XFreeGC(display,pixel->highlight_context); 14675 pixel->highlight_context=XCreateGC(display,windows->context.id, 14676 (size_t) (context_mask | GCPlaneMask),&context_values); 14677 if (pixel->highlight_context == (GC) NULL) 14678 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14679 display_image->filename); 14680 (void) XDestroyWindow(display,windows->context.id); 14681 /* 14682 Initialize icon window. 14683 */ 14684 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, 14685 icon_resources,&windows->icon); 14686 windows->icon.geometry=resource_info->icon_geometry; 14687 XBestIconSize(display,&windows->icon,display_image); 14688 windows->icon.attributes.colormap=XDefaultColormap(display, 14689 icon_visual->screen); 14690 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; 14691 manager_hints->flags=InputHint | StateHint; 14692 manager_hints->input=MagickFalse; 14693 manager_hints->initial_state=IconicState; 14694 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14695 &windows->icon); 14696 if (display_image->debug != MagickFalse) 14697 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", 14698 windows->icon.id); 14699 /* 14700 Initialize graphic context for icon window. 14701 */ 14702 if (icon_pixel->annotate_context != (GC) NULL) 14703 (void) XFreeGC(display,icon_pixel->annotate_context); 14704 context_values.background=icon_pixel->background_color.pixel; 14705 context_values.foreground=icon_pixel->foreground_color.pixel; 14706 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, 14707 (size_t) (GCBackground | GCForeground),&context_values); 14708 if (icon_pixel->annotate_context == (GC) NULL) 14709 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14710 display_image->filename); 14711 windows->icon.annotate_context=icon_pixel->annotate_context; 14712 /* 14713 Initialize Image window. 14714 */ 14715 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14716 &windows->image); 14717 windows->image.shape=MagickTrue; /* non-rectangular shape hint */ 14718 if (resource_info->use_shared_memory == MagickFalse) 14719 windows->image.shared_memory=MagickFalse; 14720 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState)) 14721 { 14722 char 14723 *title; 14724 14725 title=InterpretImageProperties(resource_info->image_info,display_image, 14726 resource_info->title,exception); 14727 (void) CopyMagickString(windows->image.name,title,MaxTextExtent); 14728 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent); 14729 title=DestroyString(title); 14730 } 14731 else 14732 { 14733 char 14734 filename[MaxTextExtent]; 14735 14736 /* 14737 Window name is the base of the filename. 14738 */ 14739 GetPathComponent(display_image->magick_filename,TailPath,filename); 14740 if (display_image->scene == 0) 14741 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14742 "%s: %s",MagickPackageName,filename); 14743 else 14744 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14745 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename, 14746 (double) display_image->scene,(double) GetImageListLength( 14747 display_image)); 14748 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent); 14749 } 14750 if (resource_info->immutable) 14751 windows->image.immutable=MagickTrue; 14752 windows->image.use_pixmap=resource_info->use_pixmap; 14753 windows->image.geometry=resource_info->image_geometry; 14754 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 14755 XDisplayWidth(display,visual_info->screen), 14756 XDisplayHeight(display,visual_info->screen)); 14757 geometry_info.width=display_image->columns; 14758 geometry_info.height=display_image->rows; 14759 geometry_info.x=0; 14760 geometry_info.y=0; 14761 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 14762 &geometry_info.width,&geometry_info.height); 14763 windows->image.width=(unsigned int) geometry_info.width; 14764 windows->image.height=(unsigned int) geometry_info.height; 14765 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14766 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14767 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14768 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; 14769 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14770 resource_info,&windows->backdrop); 14771 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) 14772 { 14773 /* 14774 Initialize backdrop window. 14775 */ 14776 windows->backdrop.x=0; 14777 windows->backdrop.y=0; 14778 (void) CloneString(&windows->backdrop.name,"Backdrop"); 14779 windows->backdrop.flags=(size_t) (USSize | USPosition); 14780 windows->backdrop.width=(unsigned int) 14781 XDisplayWidth(display,visual_info->screen); 14782 windows->backdrop.height=(unsigned int) 14783 XDisplayHeight(display,visual_info->screen); 14784 windows->backdrop.border_width=0; 14785 windows->backdrop.immutable=MagickTrue; 14786 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | 14787 ButtonReleaseMask; 14788 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | 14789 StructureNotifyMask; 14790 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14791 manager_hints->icon_window=windows->icon.id; 14792 manager_hints->input=MagickTrue; 14793 manager_hints->initial_state=resource_info->iconic ? IconicState : 14794 NormalState; 14795 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14796 &windows->backdrop); 14797 if (display_image->debug != MagickFalse) 14798 (void) LogMagickEvent(X11Event,GetMagickModule(), 14799 "Window id: 0x%lx (backdrop)",windows->backdrop.id); 14800 (void) XMapWindow(display,windows->backdrop.id); 14801 (void) XClearWindow(display,windows->backdrop.id); 14802 if (windows->image.id != (Window) NULL) 14803 { 14804 (void) XDestroyWindow(display,windows->image.id); 14805 windows->image.id=(Window) NULL; 14806 } 14807 /* 14808 Position image in the center the backdrop. 14809 */ 14810 windows->image.flags|=USPosition; 14811 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- 14812 (windows->image.width/2); 14813 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- 14814 (windows->image.height/2); 14815 } 14816 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14817 manager_hints->icon_window=windows->icon.id; 14818 manager_hints->input=MagickTrue; 14819 manager_hints->initial_state=resource_info->iconic ? IconicState : 14820 NormalState; 14821 if (windows->group_leader.id != (Window) NULL) 14822 { 14823 /* 14824 Follow the leader. 14825 */ 14826 manager_hints->flags|=WindowGroupHint; 14827 manager_hints->window_group=windows->group_leader.id; 14828 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); 14829 if (display_image->debug != MagickFalse) 14830 (void) LogMagickEvent(X11Event,GetMagickModule(), 14831 "Window id: 0x%lx (group leader)",windows->group_leader.id); 14832 } 14833 XMakeWindow(display, 14834 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), 14835 argv,argc,class_hints,manager_hints,&windows->image); 14836 (void) XChangeProperty(display,windows->image.id,windows->im_protocols, 14837 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); 14838 if (windows->group_leader.id != (Window) NULL) 14839 (void) XSetTransientForHint(display,windows->image.id, 14840 windows->group_leader.id); 14841 if (display_image->debug != MagickFalse) 14842 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", 14843 windows->image.id); 14844 /* 14845 Initialize Info widget. 14846 */ 14847 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14848 &windows->info); 14849 (void) CloneString(&windows->info.name,"Info"); 14850 (void) CloneString(&windows->info.icon_name,"Info"); 14851 windows->info.border_width=1; 14852 windows->info.x=2; 14853 windows->info.y=2; 14854 windows->info.flags|=PPosition; 14855 windows->info.attributes.win_gravity=UnmapGravity; 14856 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | 14857 StructureNotifyMask; 14858 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14859 manager_hints->input=MagickFalse; 14860 manager_hints->initial_state=NormalState; 14861 manager_hints->window_group=windows->image.id; 14862 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, 14863 &windows->info); 14864 windows->info.highlight_stipple=XCreateBitmapFromData(display, 14865 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14866 windows->info.shadow_stipple=XCreateBitmapFromData(display, 14867 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14868 (void) XSetTransientForHint(display,windows->info.id,windows->image.id); 14869 if (windows->image.mapped != MagickFalse) 14870 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14871 if (display_image->debug != MagickFalse) 14872 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", 14873 windows->info.id); 14874 /* 14875 Initialize Command widget. 14876 */ 14877 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14878 resource_info,&windows->command); 14879 windows->command.data=MagickMenus; 14880 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); 14881 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command", 14882 resource_info->client_name); 14883 windows->command.geometry=XGetResourceClass(resource_info->resource_database, 14884 resource_name,"geometry",(char *) NULL); 14885 (void) CloneString(&windows->command.name,MagickTitle); 14886 windows->command.border_width=0; 14887 windows->command.flags|=PPosition; 14888 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14889 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | 14890 OwnerGrabButtonMask | StructureNotifyMask; 14891 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14892 manager_hints->input=MagickTrue; 14893 manager_hints->initial_state=NormalState; 14894 manager_hints->window_group=windows->image.id; 14895 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14896 &windows->command); 14897 windows->command.highlight_stipple=XCreateBitmapFromData(display, 14898 windows->command.id,(char *) HighlightBitmap,HighlightWidth, 14899 HighlightHeight); 14900 windows->command.shadow_stipple=XCreateBitmapFromData(display, 14901 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14902 (void) XSetTransientForHint(display,windows->command.id,windows->image.id); 14903 if (windows->command.mapped != MagickFalse) 14904 (void) XMapRaised(display,windows->command.id); 14905 if (display_image->debug != MagickFalse) 14906 (void) LogMagickEvent(X11Event,GetMagickModule(), 14907 "Window id: 0x%lx (command)",windows->command.id); 14908 /* 14909 Initialize Widget window. 14910 */ 14911 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14912 resource_info,&windows->widget); 14913 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget", 14914 resource_info->client_name); 14915 windows->widget.geometry=XGetResourceClass(resource_info->resource_database, 14916 resource_name,"geometry",(char *) NULL); 14917 windows->widget.border_width=0; 14918 windows->widget.flags|=PPosition; 14919 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14920 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14921 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14922 StructureNotifyMask; 14923 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14924 manager_hints->input=MagickTrue; 14925 manager_hints->initial_state=NormalState; 14926 manager_hints->window_group=windows->image.id; 14927 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14928 &windows->widget); 14929 windows->widget.highlight_stipple=XCreateBitmapFromData(display, 14930 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14931 windows->widget.shadow_stipple=XCreateBitmapFromData(display, 14932 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14933 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); 14934 if (display_image->debug != MagickFalse) 14935 (void) LogMagickEvent(X11Event,GetMagickModule(), 14936 "Window id: 0x%lx (widget)",windows->widget.id); 14937 /* 14938 Initialize popup window. 14939 */ 14940 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14941 resource_info,&windows->popup); 14942 windows->popup.border_width=0; 14943 windows->popup.flags|=PPosition; 14944 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14945 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14946 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask; 14947 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14948 manager_hints->input=MagickTrue; 14949 manager_hints->initial_state=NormalState; 14950 manager_hints->window_group=windows->image.id; 14951 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14952 &windows->popup); 14953 windows->popup.highlight_stipple=XCreateBitmapFromData(display, 14954 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14955 windows->popup.shadow_stipple=XCreateBitmapFromData(display, 14956 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14957 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); 14958 if (display_image->debug != MagickFalse) 14959 (void) LogMagickEvent(X11Event,GetMagickModule(), 14960 "Window id: 0x%lx (pop up)",windows->popup.id); 14961 /* 14962 Initialize Magnify window and cursor. 14963 */ 14964 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14965 resource_info,&windows->magnify); 14966 if (resource_info->use_shared_memory == MagickFalse) 14967 windows->magnify.shared_memory=MagickFalse; 14968 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify", 14969 resource_info->client_name); 14970 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database, 14971 resource_name,"geometry",(char *) NULL); 14972 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX", 14973 resource_info->magnify); 14974 if (windows->magnify.cursor != (Cursor) NULL) 14975 (void) XFreeCursor(display,windows->magnify.cursor); 14976 windows->magnify.cursor=XMakeCursor(display,windows->image.id, 14977 map_info->colormap,resource_info->background_color, 14978 resource_info->foreground_color); 14979 if (windows->magnify.cursor == (Cursor) NULL) 14980 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor", 14981 display_image->filename); 14982 windows->magnify.width=MagnifySize; 14983 windows->magnify.height=MagnifySize; 14984 windows->magnify.flags|=PPosition; 14985 windows->magnify.min_width=MagnifySize; 14986 windows->magnify.min_height=MagnifySize; 14987 windows->magnify.width_inc=MagnifySize; 14988 windows->magnify.height_inc=MagnifySize; 14989 windows->magnify.data=resource_info->magnify; 14990 windows->magnify.attributes.cursor=windows->magnify.cursor; 14991 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask | 14992 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask | 14993 StructureNotifyMask; 14994 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14995 manager_hints->input=MagickTrue; 14996 manager_hints->initial_state=NormalState; 14997 manager_hints->window_group=windows->image.id; 14998 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14999 &windows->magnify); 15000 if (display_image->debug != MagickFalse) 15001 (void) LogMagickEvent(X11Event,GetMagickModule(), 15002 "Window id: 0x%lx (magnify)",windows->magnify.id); 15003 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id); 15004 /* 15005 Initialize panning window. 15006 */ 15007 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 15008 resource_info,&windows->pan); 15009 (void) CloneString(&windows->pan.name,"Pan Icon"); 15010 windows->pan.width=windows->icon.width; 15011 windows->pan.height=windows->icon.height; 15012 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan", 15013 resource_info->client_name); 15014 windows->pan.geometry=XGetResourceClass(resource_info->resource_database, 15015 resource_name,"geometry",(char *) NULL); 15016 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 15017 &windows->pan.width,&windows->pan.height); 15018 windows->pan.flags|=PPosition; 15019 windows->pan.immutable=MagickTrue; 15020 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 15021 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask | 15022 StructureNotifyMask; 15023 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 15024 manager_hints->input=MagickFalse; 15025 manager_hints->initial_state=NormalState; 15026 manager_hints->window_group=windows->image.id; 15027 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 15028 &windows->pan); 15029 if (display_image->debug != MagickFalse) 15030 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)", 15031 windows->pan.id); 15032 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id); 15033 if (windows->info.mapped != MagickFalse) 15034 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15035 if ((windows->image.mapped == MagickFalse) || 15036 (windows->backdrop.id != (Window) NULL)) 15037 (void) XMapWindow(display,windows->image.id); 15038 /* 15039 Set our progress monitor and warning handlers. 15040 */ 15041 if (warning_handler == (WarningHandler) NULL) 15042 { 15043 warning_handler=resource_info->display_warnings ? 15044 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 15045 warning_handler=resource_info->display_warnings ? 15046 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 15047 } 15048 /* 15049 Initialize Image and Magnify X images. 15050 */ 15051 windows->image.x=0; 15052 windows->image.y=0; 15053 windows->magnify.shape=MagickFalse; 15054 width=(unsigned int) display_image->columns; 15055 height=(unsigned int) display_image->rows; 15056 if ((display_image->columns != width) || (display_image->rows != height)) 15057 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15058 display_image->filename); 15059 status=XMakeImage(display,resource_info,&windows->image,display_image, 15060 width,height,exception); 15061 if (status == MagickFalse) 15062 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15063 display_image->filename); 15064 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL, 15065 windows->magnify.width,windows->magnify.height,exception); 15066 if (status == MagickFalse) 15067 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15068 display_image->filename); 15069 if (windows->magnify.mapped != MagickFalse) 15070 (void) XMapRaised(display,windows->magnify.id); 15071 if (windows->pan.mapped != MagickFalse) 15072 (void) XMapRaised(display,windows->pan.id); 15073 windows->image.window_changes.width=(int) display_image->columns; 15074 windows->image.window_changes.height=(int) display_image->rows; 15075 (void) XConfigureImage(display,resource_info,windows,display_image,exception); 15076 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15077 (void) XSync(display,MagickFalse); 15078 /* 15079 Respond to events. 15080 */ 15081 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L); 15082 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15083 update_time=0; 15084 if (resource_info->update != MagickFalse) 15085 { 15086 MagickBooleanType 15087 status; 15088 15089 /* 15090 Determine when file data was last modified. 15091 */ 15092 status=GetPathAttributes(display_image->filename,&attributes); 15093 if (status != MagickFalse) 15094 update_time=attributes.st_mtime; 15095 } 15096 *state&=(~FormerImageState); 15097 *state&=(~MontageImageState); 15098 *state&=(~NextImageState); 15099 do 15100 { 15101 /* 15102 Handle a window event. 15103 */ 15104 if (windows->image.mapped != MagickFalse) 15105 if ((display_image->delay != 0) || (resource_info->update != 0)) 15106 { 15107 if (timer < time((time_t *) NULL)) 15108 { 15109 if (resource_info->update == MagickFalse) 15110 *state|=NextImageState | ExitState; 15111 else 15112 { 15113 MagickBooleanType 15114 status; 15115 15116 /* 15117 Determine if image file was modified. 15118 */ 15119 status=GetPathAttributes(display_image->filename,&attributes); 15120 if (status != MagickFalse) 15121 if (update_time != attributes.st_mtime) 15122 { 15123 /* 15124 Redisplay image. 15125 */ 15126 (void) FormatLocaleString( 15127 resource_info->image_info->filename,MaxTextExtent, 15128 "%s:%s",display_image->magick, 15129 display_image->filename); 15130 nexus=ReadImage(resource_info->image_info,exception); 15131 if (nexus != (Image *) NULL) 15132 { 15133 nexus=DestroyImage(nexus); 15134 *state|=NextImageState | ExitState; 15135 } 15136 } 15137 delay=display_image->delay/MagickMax( 15138 display_image->ticks_per_second,1L); 15139 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15140 } 15141 } 15142 if (XEventsQueued(display,QueuedAfterFlush) == 0) 15143 { 15144 /* 15145 Do not block if delay > 0. 15146 */ 15147 XDelay(display,SuspendTime << 2); 15148 continue; 15149 } 15150 } 15151 timestamp=time((time_t *) NULL); 15152 (void) XNextEvent(display,&event); 15153 if (windows->image.stasis == MagickFalse) 15154 windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15155 MagickTrue : MagickFalse; 15156 if (windows->magnify.stasis == MagickFalse) 15157 windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ? 15158 MagickTrue : MagickFalse; 15159 if (event.xany.window == windows->command.id) 15160 { 15161 /* 15162 Select a command from the Command widget. 15163 */ 15164 id=XCommandWidget(display,windows,CommandMenu,&event); 15165 if (id < 0) 15166 continue; 15167 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent); 15168 command_type=CommandMenus[id]; 15169 if (id < MagickMenus) 15170 { 15171 /* 15172 Select a command from a pop-up menu. 15173 */ 15174 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15175 command); 15176 if (entry < 0) 15177 continue; 15178 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent); 15179 command_type=Commands[id][entry]; 15180 } 15181 if (command_type != NullCommand) 15182 nexus=XMagickCommand(display,resource_info,windows,command_type, 15183 &display_image,exception); 15184 continue; 15185 } 15186 switch (event.type) 15187 { 15188 case ButtonPress: 15189 { 15190 if (display_image->debug != MagickFalse) 15191 (void) LogMagickEvent(X11Event,GetMagickModule(), 15192 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15193 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15194 if ((event.xbutton.button == Button3) && 15195 (event.xbutton.state & Mod1Mask)) 15196 { 15197 /* 15198 Convert Alt-Button3 to Button2. 15199 */ 15200 event.xbutton.button=Button2; 15201 event.xbutton.state&=(~Mod1Mask); 15202 } 15203 if (event.xbutton.window == windows->backdrop.id) 15204 { 15205 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15206 event.xbutton.time); 15207 break; 15208 } 15209 if (event.xbutton.window == windows->image.id) 15210 { 15211 switch (event.xbutton.button) 15212 { 15213 case Button1: 15214 { 15215 if (resource_info->immutable) 15216 { 15217 /* 15218 Select a command from the Virtual menu. 15219 */ 15220 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15221 command); 15222 if (entry >= 0) 15223 nexus=XMagickCommand(display,resource_info,windows, 15224 VirtualCommands[entry],&display_image,exception); 15225 break; 15226 } 15227 /* 15228 Map/unmap Command widget. 15229 */ 15230 if (windows->command.mapped != MagickFalse) 15231 (void) XWithdrawWindow(display,windows->command.id, 15232 windows->command.screen); 15233 else 15234 { 15235 (void) XCommandWidget(display,windows,CommandMenu, 15236 (XEvent *) NULL); 15237 (void) XMapRaised(display,windows->command.id); 15238 } 15239 break; 15240 } 15241 case Button2: 15242 { 15243 /* 15244 User pressed the image magnify button. 15245 */ 15246 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15247 &display_image,exception); 15248 XMagnifyImage(display,windows,&event,exception); 15249 break; 15250 } 15251 case Button3: 15252 { 15253 if (resource_info->immutable) 15254 { 15255 /* 15256 Select a command from the Virtual menu. 15257 */ 15258 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15259 command); 15260 if (entry >= 0) 15261 nexus=XMagickCommand(display,resource_info,windows, 15262 VirtualCommands[entry],&display_image,exception); 15263 break; 15264 } 15265 if (display_image->montage != (char *) NULL) 15266 { 15267 /* 15268 Open or delete a tile from a visual image directory. 15269 */ 15270 nexus=XTileImage(display,resource_info,windows, 15271 display_image,&event,exception); 15272 if (nexus != (Image *) NULL) 15273 *state|=MontageImageState | NextImageState | ExitState; 15274 vid_info.x=(short int) windows->image.x; 15275 vid_info.y=(short int) windows->image.y; 15276 break; 15277 } 15278 /* 15279 Select a command from the Short Cuts menu. 15280 */ 15281 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15282 command); 15283 if (entry >= 0) 15284 nexus=XMagickCommand(display,resource_info,windows, 15285 ShortCutsCommands[entry],&display_image,exception); 15286 break; 15287 } 15288 case Button4: 15289 { 15290 /* 15291 Wheel up. 15292 */ 15293 XTranslateImage(display,windows,*image,XK_Up); 15294 break; 15295 } 15296 case Button5: 15297 { 15298 /* 15299 Wheel down. 15300 */ 15301 XTranslateImage(display,windows,*image,XK_Down); 15302 break; 15303 } 15304 default: 15305 break; 15306 } 15307 break; 15308 } 15309 if (event.xbutton.window == windows->magnify.id) 15310 { 15311 int 15312 factor; 15313 15314 static const char 15315 *MagnifyMenu[] = 15316 { 15317 "2", 15318 "4", 15319 "5", 15320 "6", 15321 "7", 15322 "8", 15323 "9", 15324 "3", 15325 (char *) NULL, 15326 }; 15327 15328 static KeySym 15329 MagnifyCommands[] = 15330 { 15331 XK_2, 15332 XK_4, 15333 XK_5, 15334 XK_6, 15335 XK_7, 15336 XK_8, 15337 XK_9, 15338 XK_3 15339 }; 15340 15341 /* 15342 Select a magnify factor from the pop-up menu. 15343 */ 15344 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15345 if (factor >= 0) 15346 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor], 15347 exception); 15348 break; 15349 } 15350 if (event.xbutton.window == windows->pan.id) 15351 { 15352 switch (event.xbutton.button) 15353 { 15354 case Button4: 15355 { 15356 /* 15357 Wheel up. 15358 */ 15359 XTranslateImage(display,windows,*image,XK_Up); 15360 break; 15361 } 15362 case Button5: 15363 { 15364 /* 15365 Wheel down. 15366 */ 15367 XTranslateImage(display,windows,*image,XK_Down); 15368 break; 15369 } 15370 default: 15371 { 15372 XPanImage(display,windows,&event,exception); 15373 break; 15374 } 15375 } 15376 break; 15377 } 15378 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15379 1L); 15380 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15381 break; 15382 } 15383 case ButtonRelease: 15384 { 15385 if (display_image->debug != MagickFalse) 15386 (void) LogMagickEvent(X11Event,GetMagickModule(), 15387 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15388 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15389 break; 15390 } 15391 case ClientMessage: 15392 { 15393 if (display_image->debug != MagickFalse) 15394 (void) LogMagickEvent(X11Event,GetMagickModule(), 15395 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15396 event.xclient.message_type,event.xclient.format,(unsigned long) 15397 event.xclient.data.l[0]); 15398 if (event.xclient.message_type == windows->im_protocols) 15399 { 15400 if (*event.xclient.data.l == (long) windows->im_update_widget) 15401 { 15402 (void) CloneString(&windows->command.name,MagickTitle); 15403 windows->command.data=MagickMenus; 15404 (void) XCommandWidget(display,windows,CommandMenu, 15405 (XEvent *) NULL); 15406 break; 15407 } 15408 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15409 { 15410 /* 15411 Update graphic context and window colormap. 15412 */ 15413 for (i=0; i < (int) number_windows; i++) 15414 { 15415 if (magick_windows[i]->id == windows->icon.id) 15416 continue; 15417 context_values.background=pixel->background_color.pixel; 15418 context_values.foreground=pixel->foreground_color.pixel; 15419 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15420 context_mask,&context_values); 15421 (void) XChangeGC(display,magick_windows[i]->widget_context, 15422 context_mask,&context_values); 15423 context_values.background=pixel->foreground_color.pixel; 15424 context_values.foreground=pixel->background_color.pixel; 15425 context_values.plane_mask=context_values.background ^ 15426 context_values.foreground; 15427 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15428 (size_t) (context_mask | GCPlaneMask), 15429 &context_values); 15430 magick_windows[i]->attributes.background_pixel= 15431 pixel->background_color.pixel; 15432 magick_windows[i]->attributes.border_pixel= 15433 pixel->border_color.pixel; 15434 magick_windows[i]->attributes.colormap=map_info->colormap; 15435 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15436 (unsigned long) magick_windows[i]->mask, 15437 &magick_windows[i]->attributes); 15438 } 15439 if (windows->pan.mapped != MagickFalse) 15440 { 15441 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15442 windows->pan.pixmap); 15443 (void) XClearWindow(display,windows->pan.id); 15444 XDrawPanRectangle(display,windows); 15445 } 15446 if (windows->backdrop.id != (Window) NULL) 15447 (void) XInstallColormap(display,map_info->colormap); 15448 break; 15449 } 15450 if (*event.xclient.data.l == (long) windows->im_former_image) 15451 { 15452 *state|=FormerImageState | ExitState; 15453 break; 15454 } 15455 if (*event.xclient.data.l == (long) windows->im_next_image) 15456 { 15457 *state|=NextImageState | ExitState; 15458 break; 15459 } 15460 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15461 { 15462 *state|=RetainColorsState; 15463 break; 15464 } 15465 if (*event.xclient.data.l == (long) windows->im_exit) 15466 { 15467 *state|=ExitState; 15468 break; 15469 } 15470 break; 15471 } 15472 if (event.xclient.message_type == windows->dnd_protocols) 15473 { 15474 Atom 15475 selection, 15476 type; 15477 15478 int 15479 format, 15480 status; 15481 15482 unsigned char 15483 *data; 15484 15485 unsigned long 15486 after, 15487 length; 15488 15489 /* 15490 Display image named by the Drag-and-Drop selection. 15491 */ 15492 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15493 break; 15494 selection=XInternAtom(display,"DndSelection",MagickFalse); 15495 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15496 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15497 &length,&after,&data); 15498 if ((status != Success) || (length == 0)) 15499 break; 15500 if (*event.xclient.data.l == 2) 15501 { 15502 /* 15503 Offix DND. 15504 */ 15505 (void) CopyMagickString(resource_info->image_info->filename, 15506 (char *) data,MaxTextExtent); 15507 } 15508 else 15509 { 15510 /* 15511 XDND. 15512 */ 15513 if (strncmp((char *) data, "file:", 5) != 0) 15514 { 15515 (void) XFree((void *) data); 15516 break; 15517 } 15518 (void) CopyMagickString(resource_info->image_info->filename, 15519 ((char *) data)+5,MaxTextExtent); 15520 } 15521 nexus=ReadImage(resource_info->image_info,exception); 15522 CatchException(exception); 15523 if (nexus != (Image *) NULL) 15524 *state|=NextImageState | ExitState; 15525 (void) XFree((void *) data); 15526 break; 15527 } 15528 /* 15529 If client window delete message, exit. 15530 */ 15531 if (event.xclient.message_type != windows->wm_protocols) 15532 break; 15533 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15534 break; 15535 (void) XWithdrawWindow(display,event.xclient.window, 15536 visual_info->screen); 15537 if (event.xclient.window == windows->image.id) 15538 { 15539 *state|=ExitState; 15540 break; 15541 } 15542 if (event.xclient.window == windows->pan.id) 15543 { 15544 /* 15545 Restore original image size when pan window is deleted. 15546 */ 15547 windows->image.window_changes.width=windows->image.ximage->width; 15548 windows->image.window_changes.height=windows->image.ximage->height; 15549 (void) XConfigureImage(display,resource_info,windows, 15550 display_image,exception); 15551 } 15552 break; 15553 } 15554 case ConfigureNotify: 15555 { 15556 if (display_image->debug != MagickFalse) 15557 (void) LogMagickEvent(X11Event,GetMagickModule(), 15558 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15559 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15560 event.xconfigure.y,event.xconfigure.send_event); 15561 if (event.xconfigure.window == windows->image.id) 15562 { 15563 /* 15564 Image window has a new configuration. 15565 */ 15566 if (event.xconfigure.send_event != 0) 15567 { 15568 XWindowChanges 15569 window_changes; 15570 15571 /* 15572 Position the transient windows relative of the Image window. 15573 */ 15574 if (windows->command.geometry == (char *) NULL) 15575 if (windows->command.mapped == MagickFalse) 15576 { 15577 windows->command.x=event.xconfigure.x- 15578 windows->command.width-25; 15579 windows->command.y=event.xconfigure.y; 15580 XConstrainWindowPosition(display,&windows->command); 15581 window_changes.x=windows->command.x; 15582 window_changes.y=windows->command.y; 15583 (void) XReconfigureWMWindow(display,windows->command.id, 15584 windows->command.screen,(unsigned int) (CWX | CWY), 15585 &window_changes); 15586 } 15587 if (windows->widget.geometry == (char *) NULL) 15588 if (windows->widget.mapped == MagickFalse) 15589 { 15590 windows->widget.x=event.xconfigure.x+ 15591 event.xconfigure.width/10; 15592 windows->widget.y=event.xconfigure.y+ 15593 event.xconfigure.height/10; 15594 XConstrainWindowPosition(display,&windows->widget); 15595 window_changes.x=windows->widget.x; 15596 window_changes.y=windows->widget.y; 15597 (void) XReconfigureWMWindow(display,windows->widget.id, 15598 windows->widget.screen,(unsigned int) (CWX | CWY), 15599 &window_changes); 15600 } 15601 if (windows->magnify.geometry == (char *) NULL) 15602 if (windows->magnify.mapped == MagickFalse) 15603 { 15604 windows->magnify.x=event.xconfigure.x+ 15605 event.xconfigure.width+25; 15606 windows->magnify.y=event.xconfigure.y; 15607 XConstrainWindowPosition(display,&windows->magnify); 15608 window_changes.x=windows->magnify.x; 15609 window_changes.y=windows->magnify.y; 15610 (void) XReconfigureWMWindow(display,windows->magnify.id, 15611 windows->magnify.screen,(unsigned int) (CWX | CWY), 15612 &window_changes); 15613 } 15614 if (windows->pan.geometry == (char *) NULL) 15615 if (windows->pan.mapped == MagickFalse) 15616 { 15617 windows->pan.x=event.xconfigure.x+ 15618 event.xconfigure.width+25; 15619 windows->pan.y=event.xconfigure.y+ 15620 windows->magnify.height+50; 15621 XConstrainWindowPosition(display,&windows->pan); 15622 window_changes.x=windows->pan.x; 15623 window_changes.y=windows->pan.y; 15624 (void) XReconfigureWMWindow(display,windows->pan.id, 15625 windows->pan.screen,(unsigned int) (CWX | CWY), 15626 &window_changes); 15627 } 15628 } 15629 if ((event.xconfigure.width == (int) windows->image.width) && 15630 (event.xconfigure.height == (int) windows->image.height)) 15631 break; 15632 windows->image.width=(unsigned int) event.xconfigure.width; 15633 windows->image.height=(unsigned int) event.xconfigure.height; 15634 windows->image.x=0; 15635 windows->image.y=0; 15636 if (display_image->montage != (char *) NULL) 15637 { 15638 windows->image.x=vid_info.x; 15639 windows->image.y=vid_info.y; 15640 } 15641 if ((windows->image.mapped != MagickFalse) && 15642 (windows->image.stasis != MagickFalse)) 15643 { 15644 /* 15645 Update image window configuration. 15646 */ 15647 windows->image.window_changes.width=event.xconfigure.width; 15648 windows->image.window_changes.height=event.xconfigure.height; 15649 (void) XConfigureImage(display,resource_info,windows, 15650 display_image,exception); 15651 } 15652 /* 15653 Update pan window configuration. 15654 */ 15655 if ((event.xconfigure.width < windows->image.ximage->width) || 15656 (event.xconfigure.height < windows->image.ximage->height)) 15657 { 15658 (void) XMapRaised(display,windows->pan.id); 15659 XDrawPanRectangle(display,windows); 15660 } 15661 else 15662 if (windows->pan.mapped != MagickFalse) 15663 (void) XWithdrawWindow(display,windows->pan.id, 15664 windows->pan.screen); 15665 break; 15666 } 15667 if (event.xconfigure.window == windows->magnify.id) 15668 { 15669 unsigned int 15670 magnify; 15671 15672 /* 15673 Magnify window has a new configuration. 15674 */ 15675 windows->magnify.width=(unsigned int) event.xconfigure.width; 15676 windows->magnify.height=(unsigned int) event.xconfigure.height; 15677 if (windows->magnify.mapped == MagickFalse) 15678 break; 15679 magnify=1; 15680 while ((int) magnify <= event.xconfigure.width) 15681 magnify<<=1; 15682 while ((int) magnify <= event.xconfigure.height) 15683 magnify<<=1; 15684 magnify>>=1; 15685 if (((int) magnify != event.xconfigure.width) || 15686 ((int) magnify != event.xconfigure.height)) 15687 { 15688 window_changes.width=(int) magnify; 15689 window_changes.height=(int) magnify; 15690 (void) XReconfigureWMWindow(display,windows->magnify.id, 15691 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15692 &window_changes); 15693 break; 15694 } 15695 if ((windows->magnify.mapped != MagickFalse) && 15696 (windows->magnify.stasis != MagickFalse)) 15697 { 15698 status=XMakeImage(display,resource_info,&windows->magnify, 15699 display_image,windows->magnify.width,windows->magnify.height, 15700 exception); 15701 XMakeMagnifyImage(display,windows,exception); 15702 } 15703 break; 15704 } 15705 if ((windows->magnify.mapped != MagickFalse) && 15706 (event.xconfigure.window == windows->pan.id)) 15707 { 15708 /* 15709 Pan icon window has a new configuration. 15710 */ 15711 if (event.xconfigure.send_event != 0) 15712 { 15713 windows->pan.x=event.xconfigure.x; 15714 windows->pan.y=event.xconfigure.y; 15715 } 15716 windows->pan.width=(unsigned int) event.xconfigure.width; 15717 windows->pan.height=(unsigned int) event.xconfigure.height; 15718 break; 15719 } 15720 if (event.xconfigure.window == windows->icon.id) 15721 { 15722 /* 15723 Icon window has a new configuration. 15724 */ 15725 windows->icon.width=(unsigned int) event.xconfigure.width; 15726 windows->icon.height=(unsigned int) event.xconfigure.height; 15727 break; 15728 } 15729 break; 15730 } 15731 case DestroyNotify: 15732 { 15733 /* 15734 Group leader has exited. 15735 */ 15736 if (display_image->debug != MagickFalse) 15737 (void) LogMagickEvent(X11Event,GetMagickModule(), 15738 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15739 if (event.xdestroywindow.window == windows->group_leader.id) 15740 { 15741 *state|=ExitState; 15742 break; 15743 } 15744 break; 15745 } 15746 case EnterNotify: 15747 { 15748 /* 15749 Selectively install colormap. 15750 */ 15751 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15752 if (event.xcrossing.mode != NotifyUngrab) 15753 XInstallColormap(display,map_info->colormap); 15754 break; 15755 } 15756 case Expose: 15757 { 15758 if (display_image->debug != MagickFalse) 15759 (void) LogMagickEvent(X11Event,GetMagickModule(), 15760 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15761 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15762 event.xexpose.y); 15763 /* 15764 Refresh windows that are now exposed. 15765 */ 15766 if ((event.xexpose.window == windows->image.id) && 15767 (windows->image.mapped != MagickFalse)) 15768 { 15769 XRefreshWindow(display,&windows->image,&event); 15770 delay=display_image->delay/MagickMax( 15771 display_image->ticks_per_second,1L); 15772 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15773 break; 15774 } 15775 if ((event.xexpose.window == windows->magnify.id) && 15776 (windows->magnify.mapped != MagickFalse)) 15777 { 15778 XMakeMagnifyImage(display,windows,exception); 15779 break; 15780 } 15781 if (event.xexpose.window == windows->pan.id) 15782 { 15783 XDrawPanRectangle(display,windows); 15784 break; 15785 } 15786 if (event.xexpose.window == windows->icon.id) 15787 { 15788 XRefreshWindow(display,&windows->icon,&event); 15789 break; 15790 } 15791 break; 15792 } 15793 case KeyPress: 15794 { 15795 int 15796 length; 15797 15798 /* 15799 Respond to a user key press. 15800 */ 15801 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15802 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15803 *(command+length)='\0'; 15804 if (display_image->debug != MagickFalse) 15805 (void) LogMagickEvent(X11Event,GetMagickModule(), 15806 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15807 key_symbol,command); 15808 if (event.xkey.window == windows->image.id) 15809 { 15810 command_type=XImageWindowCommand(display,resource_info,windows, 15811 event.xkey.state,key_symbol,&display_image,exception); 15812 if (command_type != NullCommand) 15813 nexus=XMagickCommand(display,resource_info,windows,command_type, 15814 &display_image,exception); 15815 } 15816 if (event.xkey.window == windows->magnify.id) 15817 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol, 15818 exception); 15819 if (event.xkey.window == windows->pan.id) 15820 { 15821 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15822 (void) XWithdrawWindow(display,windows->pan.id, 15823 windows->pan.screen); 15824 else 15825 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15826 XTextViewWidget(display,resource_info,windows,MagickFalse, 15827 "Help Viewer - Image Pan",ImagePanHelp); 15828 else 15829 XTranslateImage(display,windows,*image,key_symbol); 15830 } 15831 delay=display_image->delay/MagickMax( 15832 display_image->ticks_per_second,1L); 15833 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15834 break; 15835 } 15836 case KeyRelease: 15837 { 15838 /* 15839 Respond to a user key release. 15840 */ 15841 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15842 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15843 if (display_image->debug != MagickFalse) 15844 (void) LogMagickEvent(X11Event,GetMagickModule(), 15845 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15846 break; 15847 } 15848 case LeaveNotify: 15849 { 15850 /* 15851 Selectively uninstall colormap. 15852 */ 15853 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15854 if (event.xcrossing.mode != NotifyUngrab) 15855 XUninstallColormap(display,map_info->colormap); 15856 break; 15857 } 15858 case MapNotify: 15859 { 15860 if (display_image->debug != MagickFalse) 15861 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15862 event.xmap.window); 15863 if (event.xmap.window == windows->backdrop.id) 15864 { 15865 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15866 CurrentTime); 15867 windows->backdrop.mapped=MagickTrue; 15868 break; 15869 } 15870 if (event.xmap.window == windows->image.id) 15871 { 15872 if (windows->backdrop.id != (Window) NULL) 15873 (void) XInstallColormap(display,map_info->colormap); 15874 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15875 { 15876 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15877 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15878 } 15879 if (((int) windows->image.width < windows->image.ximage->width) || 15880 ((int) windows->image.height < windows->image.ximage->height)) 15881 (void) XMapRaised(display,windows->pan.id); 15882 windows->image.mapped=MagickTrue; 15883 break; 15884 } 15885 if (event.xmap.window == windows->magnify.id) 15886 { 15887 XMakeMagnifyImage(display,windows,exception); 15888 windows->magnify.mapped=MagickTrue; 15889 (void) XWithdrawWindow(display,windows->info.id, 15890 windows->info.screen); 15891 break; 15892 } 15893 if (event.xmap.window == windows->pan.id) 15894 { 15895 XMakePanImage(display,resource_info,windows,display_image, 15896 exception); 15897 windows->pan.mapped=MagickTrue; 15898 break; 15899 } 15900 if (event.xmap.window == windows->info.id) 15901 { 15902 windows->info.mapped=MagickTrue; 15903 break; 15904 } 15905 if (event.xmap.window == windows->icon.id) 15906 { 15907 MagickBooleanType 15908 taint; 15909 15910 /* 15911 Create an icon image. 15912 */ 15913 taint=display_image->taint; 15914 XMakeStandardColormap(display,icon_visual,icon_resources, 15915 display_image,icon_map,icon_pixel,exception); 15916 (void) XMakeImage(display,icon_resources,&windows->icon, 15917 display_image,windows->icon.width,windows->icon.height, 15918 exception); 15919 display_image->taint=taint; 15920 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15921 windows->icon.pixmap); 15922 (void) XClearWindow(display,windows->icon.id); 15923 (void) XWithdrawWindow(display,windows->info.id, 15924 windows->info.screen); 15925 windows->icon.mapped=MagickTrue; 15926 break; 15927 } 15928 if (event.xmap.window == windows->command.id) 15929 { 15930 windows->command.mapped=MagickTrue; 15931 break; 15932 } 15933 if (event.xmap.window == windows->popup.id) 15934 { 15935 windows->popup.mapped=MagickTrue; 15936 break; 15937 } 15938 if (event.xmap.window == windows->widget.id) 15939 { 15940 windows->widget.mapped=MagickTrue; 15941 break; 15942 } 15943 break; 15944 } 15945 case MappingNotify: 15946 { 15947 (void) XRefreshKeyboardMapping(&event.xmapping); 15948 break; 15949 } 15950 case NoExpose: 15951 break; 15952 case PropertyNotify: 15953 { 15954 Atom 15955 type; 15956 15957 int 15958 format, 15959 status; 15960 15961 unsigned char 15962 *data; 15963 15964 unsigned long 15965 after, 15966 length; 15967 15968 if (display_image->debug != MagickFalse) 15969 (void) LogMagickEvent(X11Event,GetMagickModule(), 15970 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15971 event.xproperty.atom,event.xproperty.state); 15972 if (event.xproperty.atom != windows->im_remote_command) 15973 break; 15974 /* 15975 Display image named by the remote command protocol. 15976 */ 15977 status=XGetWindowProperty(display,event.xproperty.window, 15978 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom) 15979 AnyPropertyType,&type,&format,&length,&after,&data); 15980 if ((status != Success) || (length == 0)) 15981 break; 15982 if (LocaleCompare((char *) data,"-quit") == 0) 15983 { 15984 XClientMessage(display,windows->image.id,windows->im_protocols, 15985 windows->im_exit,CurrentTime); 15986 (void) XFree((void *) data); 15987 break; 15988 } 15989 (void) CopyMagickString(resource_info->image_info->filename, 15990 (char *) data,MaxTextExtent); 15991 (void) XFree((void *) data); 15992 nexus=ReadImage(resource_info->image_info,exception); 15993 CatchException(exception); 15994 if (nexus != (Image *) NULL) 15995 *state|=NextImageState | ExitState; 15996 break; 15997 } 15998 case ReparentNotify: 15999 { 16000 if (display_image->debug != MagickFalse) 16001 (void) LogMagickEvent(X11Event,GetMagickModule(), 16002 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 16003 event.xreparent.window); 16004 break; 16005 } 16006 case UnmapNotify: 16007 { 16008 if (display_image->debug != MagickFalse) 16009 (void) LogMagickEvent(X11Event,GetMagickModule(), 16010 "Unmap Notify: 0x%lx",event.xunmap.window); 16011 if (event.xunmap.window == windows->backdrop.id) 16012 { 16013 windows->backdrop.mapped=MagickFalse; 16014 break; 16015 } 16016 if (event.xunmap.window == windows->image.id) 16017 { 16018 windows->image.mapped=MagickFalse; 16019 break; 16020 } 16021 if (event.xunmap.window == windows->magnify.id) 16022 { 16023 windows->magnify.mapped=MagickFalse; 16024 break; 16025 } 16026 if (event.xunmap.window == windows->pan.id) 16027 { 16028 windows->pan.mapped=MagickFalse; 16029 break; 16030 } 16031 if (event.xunmap.window == windows->info.id) 16032 { 16033 windows->info.mapped=MagickFalse; 16034 break; 16035 } 16036 if (event.xunmap.window == windows->icon.id) 16037 { 16038 if (map_info->colormap == icon_map->colormap) 16039 XConfigureImageColormap(display,resource_info,windows, 16040 display_image,exception); 16041 (void) XFreeStandardColormap(display,icon_visual,icon_map, 16042 icon_pixel); 16043 windows->icon.mapped=MagickFalse; 16044 break; 16045 } 16046 if (event.xunmap.window == windows->command.id) 16047 { 16048 windows->command.mapped=MagickFalse; 16049 break; 16050 } 16051 if (event.xunmap.window == windows->popup.id) 16052 { 16053 if (windows->backdrop.id != (Window) NULL) 16054 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16055 CurrentTime); 16056 windows->popup.mapped=MagickFalse; 16057 break; 16058 } 16059 if (event.xunmap.window == windows->widget.id) 16060 { 16061 if (windows->backdrop.id != (Window) NULL) 16062 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16063 CurrentTime); 16064 windows->widget.mapped=MagickFalse; 16065 break; 16066 } 16067 break; 16068 } 16069 default: 16070 { 16071 if (display_image->debug != MagickFalse) 16072 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 16073 event.type); 16074 break; 16075 } 16076 } 16077 } while (!(*state & ExitState)); 16078 if ((*state & ExitState) == 0) 16079 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 16080 &display_image,exception); 16081 else 16082 if (resource_info->confirm_edit != MagickFalse) 16083 { 16084 /* 16085 Query user if image has changed. 16086 */ 16087 if ((resource_info->immutable == MagickFalse) && 16088 (display_image->taint != MagickFalse)) 16089 { 16090 int 16091 status; 16092 16093 status=XConfirmWidget(display,windows,"Your image changed.", 16094 "Do you want to save it"); 16095 if (status == 0) 16096 *state&=(~ExitState); 16097 else 16098 if (status > 0) 16099 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 16100 &display_image,exception); 16101 } 16102 } 16103 if ((windows->visual_info->klass == GrayScale) || 16104 (windows->visual_info->klass == PseudoColor) || 16105 (windows->visual_info->klass == DirectColor)) 16106 { 16107 /* 16108 Withdraw pan and Magnify window. 16109 */ 16110 if (windows->info.mapped != MagickFalse) 16111 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 16112 if (windows->magnify.mapped != MagickFalse) 16113 (void) XWithdrawWindow(display,windows->magnify.id, 16114 windows->magnify.screen); 16115 if (windows->command.mapped != MagickFalse) 16116 (void) XWithdrawWindow(display,windows->command.id, 16117 windows->command.screen); 16118 } 16119 if (windows->pan.mapped != MagickFalse) 16120 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 16121 if (resource_info->backdrop == MagickFalse) 16122 if (windows->backdrop.mapped) 16123 { 16124 (void) XWithdrawWindow(display,windows->backdrop.id, 16125 windows->backdrop.screen); 16126 (void) XDestroyWindow(display,windows->backdrop.id); 16127 windows->backdrop.id=(Window) NULL; 16128 (void) XWithdrawWindow(display,windows->image.id, 16129 windows->image.screen); 16130 (void) XDestroyWindow(display,windows->image.id); 16131 windows->image.id=(Window) NULL; 16132 } 16133 XSetCursorState(display,windows,MagickTrue); 16134 XCheckRefreshWindows(display,windows); 16135 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 16136 *state&=(~ExitState); 16137 if (*state & ExitState) 16138 { 16139 /* 16140 Free Standard Colormap. 16141 */ 16142 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 16143 if (resource_info->map_type == (char *) NULL) 16144 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 16145 /* 16146 Free X resources. 16147 */ 16148 if (resource_info->copy_image != (Image *) NULL) 16149 { 16150 resource_info->copy_image=DestroyImage(resource_info->copy_image); 16151 resource_info->copy_image=NewImageList(); 16152 } 16153 DestroyXResources(); 16154 } 16155 (void) XSync(display,MagickFalse); 16156 /* 16157 Restore our progress monitor and warning handlers. 16158 */ 16159 (void) SetErrorHandler(warning_handler); 16160 (void) SetWarningHandler(warning_handler); 16161 /* 16162 Change to home directory. 16163 */ 16164 directory=getcwd(working_directory,MaxTextExtent); 16165 (void) directory; 16166 { 16167 int 16168 status; 16169 16170 status=chdir(resource_info->home_directory); 16171 if (status == -1) 16172 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 16173 "UnableToOpenFile","%s",resource_info->home_directory); 16174 } 16175 *image=display_image; 16176 return(nexus); 16177} 16178#else 16179 16180/* 16181%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16182% % 16183% % 16184% % 16185+ D i s p l a y I m a g e s % 16186% % 16187% % 16188% % 16189%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16190% 16191% DisplayImages() displays an image sequence to any X window screen. It 16192% returns a value other than 0 if successful. Check the exception member 16193% of image to determine the reason for any failure. 16194% 16195% The format of the DisplayImages method is: 16196% 16197% MagickBooleanType DisplayImages(const ImageInfo *image_info, 16198% Image *images,ExceptionInfo *exception) 16199% 16200% A description of each parameter follows: 16201% 16202% o image_info: the image info. 16203% 16204% o image: the image. 16205% 16206% o exception: return any errors or warnings in this structure. 16207% 16208*/ 16209MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16210 Image *image,ExceptionInfo *exception) 16211{ 16212 assert(image_info != (const ImageInfo *) NULL); 16213 assert(image_info->signature == MagickSignature); 16214 assert(image != (Image *) NULL); 16215 assert(image->signature == MagickSignature); 16216 if (image->debug != MagickFalse) 16217 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16218 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16219 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image->filename); 16220 return(MagickFalse); 16221} 16222 16223/* 16224%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16225% % 16226% % 16227% % 16228+ R e m o t e D i s p l a y C o m m a n d % 16229% % 16230% % 16231% % 16232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16233% 16234% RemoteDisplayCommand() encourages a remote display program to display the 16235% specified image filename. 16236% 16237% The format of the RemoteDisplayCommand method is: 16238% 16239% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16240% const char *window,const char *filename,ExceptionInfo *exception) 16241% 16242% A description of each parameter follows: 16243% 16244% o image_info: the image info. 16245% 16246% o window: Specifies the name or id of an X window. 16247% 16248% o filename: the name of the image filename to display. 16249% 16250% o exception: return any errors or warnings in this structure. 16251% 16252*/ 16253MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16254 const char *window,const char *filename,ExceptionInfo *exception) 16255{ 16256 assert(image_info != (const ImageInfo *) NULL); 16257 assert(image_info->signature == MagickSignature); 16258 assert(filename != (char *) NULL); 16259 (void) window; 16260 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16261 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16262 "DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename); 16263 return(MagickFalse); 16264} 16265#endif 16266