display.c revision 9dc4c51125c7242f63ea032e209ea65fe855f82f
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% DDDD IIIII SSSSS PPPP L AAA Y Y % 7% D D I SS P P L A A Y Y % 8% D D I SSS PPPP L AAAAA Y % 9% D D I SS P L A A Y % 10% DDDD IIIII SSSSS P LLLLL A A Y % 11% % 12% % 13% MagickCore Methods to Interactively Display and Edit an Image % 14% % 15% Software Design % 16% John Cristy % 17% July 1992 % 18% % 19% % 20% Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization % 21% dedicated to making software imaging solutions freely available. % 22% % 23% You may not use this file except in compliance with the License. You may % 24% obtain a copy of the License at % 25% % 26% http://www.imagemagick.org/script/license.php % 27% % 28% Unless required by applicable law or agreed to in writing, software % 29% distributed under the License is distributed on an "AS IS" BASIS, % 30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31% See the License for the specific language governing permissions and % 32% limitations under the License. % 33% % 34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35% 36% 37*/ 38 39/* 40 Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/artifact.h" 44#include "MagickCore/attribute.h" 45#include "MagickCore/blob.h" 46#include "MagickCore/cache.h" 47#include "MagickCore/cache-private.h" 48#include "MagickCore/client.h" 49#include "MagickCore/color.h" 50#include "MagickCore/colorspace.h" 51#include "MagickCore/composite.h" 52#include "MagickCore/constitute.h" 53#include "MagickCore/decorate.h" 54#include "MagickCore/delegate.h" 55#include "MagickCore/display.h" 56#include "MagickCore/display-private.h" 57#include "MagickCore/distort.h" 58#include "MagickCore/draw.h" 59#include "MagickCore/effect.h" 60#include "MagickCore/enhance.h" 61#include "MagickCore/exception.h" 62#include "MagickCore/exception-private.h" 63#include "MagickCore/fx.h" 64#include "MagickCore/geometry.h" 65#include "MagickCore/image.h" 66#include "MagickCore/image-private.h" 67#include "MagickCore/list.h" 68#include "MagickCore/log.h" 69#include "MagickCore/magick.h" 70#include "MagickCore/memory_.h" 71#include "MagickCore/monitor.h" 72#include "MagickCore/monitor-private.h" 73#include "MagickCore/montage.h" 74#include "MagickCore/option.h" 75#include "MagickCore/paint.h" 76#include "MagickCore/pixel.h" 77#include "MagickCore/pixel-accessor.h" 78#include "MagickCore/PreRvIcccm.h" 79#include "MagickCore/property.h" 80#include "MagickCore/quantum.h" 81#include "MagickCore/quantum-private.h" 82#include "MagickCore/resize.h" 83#include "MagickCore/resource_.h" 84#include "MagickCore/shear.h" 85#include "MagickCore/segment.h" 86#include "MagickCore/statistic.h" 87#include "MagickCore/string_.h" 88#include "MagickCore/string-private.h" 89#include "MagickCore/transform.h" 90#include "MagickCore/threshold.h" 91#include "MagickCore/utility.h" 92#include "MagickCore/utility-private.h" 93#include "MagickCore/version.h" 94#include "MagickCore/widget.h" 95#include "MagickCore/widget-private.h" 96#include "MagickCore/xwindow.h" 97#include "MagickCore/xwindow-private.h" 98 99#if defined(MAGICKCORE_X11_DELEGATE) 100/* 101 Define declarations. 102*/ 103#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L) 104 105/* 106 Constant declarations. 107*/ 108static const unsigned char 109 HighlightBitmap[8] = 110 { 111 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 112 }, 113 OpaqueBitmap[8] = 114 { 115 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 116 }, 117 ShadowBitmap[8] = 118 { 119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 120 }; 121 122static const char 123 *PageSizes[] = 124 { 125 "Letter", 126 "Tabloid", 127 "Ledger", 128 "Legal", 129 "Statement", 130 "Executive", 131 "A3", 132 "A4", 133 "A5", 134 "B4", 135 "B5", 136 "Folio", 137 "Quarto", 138 "10x14", 139 (char *) NULL 140 }; 141 142/* 143 Help widget declarations. 144*/ 145static const char 146 *ImageAnnotateHelp[] = 147 { 148 "In annotate mode, the Command widget has these options:", 149 "", 150 " Font Name", 151 " fixed", 152 " variable", 153 " 5x8", 154 " 6x10", 155 " 7x13bold", 156 " 8x13bold", 157 " 9x15bold", 158 " 10x20", 159 " 12x24", 160 " Browser...", 161 " Font Color", 162 " black", 163 " blue", 164 " cyan", 165 " green", 166 " gray", 167 " red", 168 " magenta", 169 " yellow", 170 " white", 171 " transparent", 172 " Browser...", 173 " Font Color", 174 " black", 175 " blue", 176 " cyan", 177 " green", 178 " gray", 179 " red", 180 " magenta", 181 " yellow", 182 " white", 183 " transparent", 184 " Browser...", 185 " Rotate Text", 186 " -90", 187 " -45", 188 " -30", 189 " 0", 190 " 30", 191 " 45", 192 " 90", 193 " 180", 194 " Dialog...", 195 " Help", 196 " Dismiss", 197 "", 198 "Choose a font name from the Font Name sub-menu. Additional", 199 "font names can be specified with the font browser. You can", 200 "change the menu names by setting the X resources font1", 201 "through font9.", 202 "", 203 "Choose a font color from the Font Color sub-menu.", 204 "Additional font colors can be specified with the color", 205 "browser. You can change the menu colors by setting the X", 206 "resources pen1 through pen9.", 207 "", 208 "If you select the color browser and press Grab, you can", 209 "choose the font color by moving the pointer to the desired", 210 "color on the screen and press any button.", 211 "", 212 "If you choose to rotate the text, choose Rotate Text from the", 213 "menu and select an angle. Typically you will only want to", 214 "rotate one line of text at a time. Depending on the angle you", 215 "choose, subsequent lines may end up overwriting each other.", 216 "", 217 "Choosing a font and its color is optional. The default font", 218 "is fixed and the default color is black. However, you must", 219 "choose a location to begin entering text and press button 1.", 220 "An underscore character will appear at the location of the", 221 "pointer. The cursor changes to a pencil to indicate you are", 222 "in text mode. To exit immediately, press Dismiss.", 223 "", 224 "In text mode, any key presses will display the character at", 225 "the location of the underscore and advance the underscore", 226 "cursor. Enter your text and once completed press Apply to", 227 "finish your image annotation. To correct errors press BACK", 228 "SPACE. To delete an entire line of text, press DELETE. Any", 229 "text that exceeds the boundaries of the image window is", 230 "automagically continued onto the next line.", 231 "", 232 "The actual color you request for the font is saved in the", 233 "image. However, the color that appears in your image window", 234 "may be different. For example, on a monochrome screen the", 235 "text will appear black or white even if you choose the color", 236 "red as the font color. However, the image saved to a file", 237 "with -write is written with red lettering. To assure the", 238 "correct color text in the final image, any PseudoClass image", 239 "is promoted to DirectClass (see miff(5)). To force a", 240 "PseudoClass image to remain PseudoClass, use -colors.", 241 (char *) NULL, 242 }, 243 *ImageChopHelp[] = 244 { 245 "In chop mode, the Command widget has these options:", 246 "", 247 " Direction", 248 " horizontal", 249 " vertical", 250 " Help", 251 " Dismiss", 252 "", 253 "If the you choose the horizontal direction (this the", 254 "default), the area of the image between the two horizontal", 255 "endpoints of the chop line is removed. Otherwise, the area", 256 "of the image between the two vertical endpoints of the chop", 257 "line is removed.", 258 "", 259 "Select a location within the image window to begin your chop,", 260 "press and hold any button. Next, move the pointer to", 261 "another location in the image. As you move a line will", 262 "connect the initial location and the pointer. When you", 263 "release the button, the area within the image to chop is", 264 "determined by which direction you choose from the Command", 265 "widget.", 266 "", 267 "To cancel the image chopping, move the pointer back to the", 268 "starting point of the line and release the button.", 269 (char *) NULL, 270 }, 271 *ImageColorEditHelp[] = 272 { 273 "In color edit mode, the Command widget has these options:", 274 "", 275 " Method", 276 " point", 277 " replace", 278 " floodfill", 279 " filltoborder", 280 " reset", 281 " Pixel Color", 282 " black", 283 " blue", 284 " cyan", 285 " green", 286 " gray", 287 " red", 288 " magenta", 289 " yellow", 290 " white", 291 " Browser...", 292 " Border Color", 293 " black", 294 " blue", 295 " cyan", 296 " green", 297 " gray", 298 " red", 299 " magenta", 300 " yellow", 301 " white", 302 " Browser...", 303 " Fuzz", 304 " 0%", 305 " 2%", 306 " 5%", 307 " 10%", 308 " 15%", 309 " Dialog...", 310 " Undo", 311 " Help", 312 " Dismiss", 313 "", 314 "Choose a color editing method from the Method sub-menu", 315 "of the Command widget. The point method recolors any pixel", 316 "selected with the pointer until the button is released. The", 317 "replace method recolors any pixel that matches the color of", 318 "the pixel you select with a button press. Floodfill recolors", 319 "any pixel that matches the color of the pixel you select with", 320 "a button press and is a neighbor. Whereas filltoborder recolors", 321 "any neighbor pixel that is not the border color. Finally reset", 322 "changes the entire image to the designated color.", 323 "", 324 "Next, choose a pixel color from the Pixel Color sub-menu.", 325 "Additional pixel colors can be specified with the color", 326 "browser. You can change the menu colors by setting the X", 327 "resources pen1 through pen9.", 328 "", 329 "Now press button 1 to select a pixel within the image window", 330 "to change its color. Additional pixels may be recolored as", 331 "prescribed by the method you choose.", 332 "", 333 "If the Magnify widget is mapped, it can be helpful in positioning", 334 "your pointer within the image (refer to button 2).", 335 "", 336 "The actual color you request for the pixels is saved in the", 337 "image. However, the color that appears in your image window", 338 "may be different. For example, on a monochrome screen the", 339 "pixel will appear black or white even if you choose the", 340 "color red as the pixel color. However, the image saved to a", 341 "file with -write is written with red pixels. To assure the", 342 "correct color text in the final image, any PseudoClass image", 343 "is promoted to DirectClass (see miff(5)). To force a", 344 "PseudoClass image to remain PseudoClass, use -colors.", 345 (char *) NULL, 346 }, 347 *ImageCompositeHelp[] = 348 { 349 "First a widget window is displayed requesting you to enter an", 350 "image name. Press Composite, Grab or type a file name.", 351 "Press Cancel if you choose not to create a composite image.", 352 "When you choose Grab, move the pointer to the desired window", 353 "and press any button.", 354 "", 355 "If the Composite image does not have any matte information,", 356 "you are informed and the file browser is displayed again.", 357 "Enter the name of a mask image. The image is typically", 358 "grayscale and the same size as the composite image. If the", 359 "image is not grayscale, it is converted to grayscale and the", 360 "resulting intensities are used as matte information.", 361 "", 362 "A small window appears showing the location of the cursor in", 363 "the image window. You are now in composite mode. To exit", 364 "immediately, press Dismiss. In composite mode, the Command", 365 "widget has these options:", 366 "", 367 " Operators", 368 " Over", 369 " In", 370 " Out", 371 " Atop", 372 " Xor", 373 " Plus", 374 " Minus", 375 " Add", 376 " Subtract", 377 " Difference", 378 " Multiply", 379 " Bumpmap", 380 " Copy", 381 " CopyRed", 382 " CopyGreen", 383 " CopyBlue", 384 " CopyOpacity", 385 " Clear", 386 " Dissolve", 387 " Displace", 388 " Help", 389 " Dismiss", 390 "", 391 "Choose a composite operation from the Operators sub-menu of", 392 "the Command widget. How each operator behaves is described", 393 "below. Image window is the image currently displayed on", 394 "your X server and image is the image obtained with the File", 395 "Browser widget.", 396 "", 397 "Over The result is the union of the two image shapes,", 398 " with image obscuring image window in the region of", 399 " overlap.", 400 "", 401 "In The result is simply image cut by the shape of", 402 " image window. None of the image data of image", 403 " window is in the result.", 404 "", 405 "Out The resulting image is image with the shape of", 406 " image window cut out.", 407 "", 408 "Atop The result is the same shape as image image window,", 409 " with image obscuring image window where the image", 410 " shapes overlap. Note this differs from over", 411 " because the portion of image outside image window's", 412 " shape does not appear in the result.", 413 "", 414 "Xor The result is the image data from both image and", 415 " image window that is outside the overlap region.", 416 " The overlap region is blank.", 417 "", 418 "Plus The result is just the sum of the image data.", 419 " Output values are cropped to QuantumRange (no overflow).", 420 "", 421 "Minus The result of image - image window, with underflow", 422 " cropped to zero.", 423 "", 424 "Add The result of image + image window, with overflow", 425 " wrapping around (mod 256).", 426 "", 427 "Subtract The result of image - image window, with underflow", 428 " wrapping around (mod 256). The add and subtract", 429 " operators can be used to perform reversible", 430 " transformations.", 431 "", 432 "Difference", 433 " The result of abs(image - image window). This", 434 " useful for comparing two very similar images.", 435 "", 436 "Multiply", 437 " The result of image * image window. This", 438 " useful for the creation of drop-shadows.", 439 "", 440 "Bumpmap The result of surface normals from image * image", 441 " window.", 442 "", 443 "Copy The resulting image is image window replaced with", 444 " image. Here the matte information is ignored.", 445 "", 446 "CopyRed The red layer of the image window is replace with", 447 " the red layer of the image. The other layers are", 448 " untouched.", 449 "", 450 "CopyGreen", 451 " The green layer of the image window is replace with", 452 " the green layer of the image. The other layers are", 453 " untouched.", 454 "", 455 "CopyBlue The blue layer of the image window is replace with", 456 " the blue layer of the image. The other layers are", 457 " untouched.", 458 "", 459 "CopyOpacity", 460 " The matte layer of the image window is replace with", 461 " the matte layer of the image. The other layers are", 462 " untouched.", 463 "", 464 "The image compositor requires a matte, or alpha channel in", 465 "the image for some operations. This extra channel usually", 466 "defines a mask which represents a sort of a cookie-cutter", 467 "for the image. This the case when matte is opaque (full", 468 "coverage) for pixels inside the shape, zero outside, and", 469 "between 0 and QuantumRange on the boundary. If image does not", 470 "have a matte channel, it is initialized with 0 for any pixel", 471 "matching in color to pixel location (0,0), otherwise QuantumRange.", 472 "", 473 "If you choose Dissolve, the composite operator becomes Over. The", 474 "image matte channel percent transparency is initialized to factor.", 475 "The image window is initialized to (100-factor). Where factor is the", 476 "value you specify in the Dialog widget.", 477 "", 478 "Displace shifts the image pixels as defined by a displacement", 479 "map. With this option, image is used as a displacement map.", 480 "Black, within the displacement map, is a maximum positive", 481 "displacement. White is a maximum negative displacement and", 482 "middle gray is neutral. The displacement is scaled to determine", 483 "the pixel shift. By default, the displacement applies in both the", 484 "horizontal and vertical directions. However, if you specify a mask,", 485 "image is the horizontal X displacement and mask the vertical Y", 486 "displacement.", 487 "", 488 "Note that matte information for image window is not retained", 489 "for colormapped X server visuals (e.g. StaticColor,", 490 "StaticColor, GrayScale, PseudoColor). Correct compositing", 491 "behavior may require a TrueColor or DirectColor visual or a", 492 "Standard Colormap.", 493 "", 494 "Choosing a composite operator is optional. The default", 495 "operator is replace. However, you must choose a location to", 496 "composite your image and press button 1. Press and hold the", 497 "button before releasing and an outline of the image will", 498 "appear to help you identify your location.", 499 "", 500 "The actual colors of the composite image is saved. However,", 501 "the color that appears in image window may be different.", 502 "For example, on a monochrome screen image window will appear", 503 "black or white even though your composited image may have", 504 "many colors. If the image is saved to a file it is written", 505 "with the correct colors. To assure the correct colors are", 506 "saved in the final image, any PseudoClass image is promoted", 507 "to DirectClass (see miff(5)). To force a PseudoClass image", 508 "to remain PseudoClass, use -colors.", 509 (char *) NULL, 510 }, 511 *ImageCutHelp[] = 512 { 513 "In cut mode, the Command widget has these options:", 514 "", 515 " Help", 516 " Dismiss", 517 "", 518 "To define a cut region, press button 1 and drag. The", 519 "cut region is defined by a highlighted rectangle that", 520 "expands or contracts as it follows the pointer. Once you", 521 "are satisfied with the cut region, release the button.", 522 "You are now in rectify mode. In rectify mode, the Command", 523 "widget has these options:", 524 "", 525 " Cut", 526 " Help", 527 " Dismiss", 528 "", 529 "You can make adjustments by moving the pointer to one of the", 530 "cut rectangle corners, pressing a button, and dragging.", 531 "Finally, press Cut to commit your copy region. To", 532 "exit without cutting the image, press Dismiss.", 533 (char *) NULL, 534 }, 535 *ImageCopyHelp[] = 536 { 537 "In copy mode, the Command widget has these options:", 538 "", 539 " Help", 540 " Dismiss", 541 "", 542 "To define a copy region, press button 1 and drag. The", 543 "copy region is defined by a highlighted rectangle that", 544 "expands or contracts as it follows the pointer. Once you", 545 "are satisfied with the copy region, release the button.", 546 "You are now in rectify mode. In rectify mode, the Command", 547 "widget has these options:", 548 "", 549 " Copy", 550 " Help", 551 " Dismiss", 552 "", 553 "You can make adjustments by moving the pointer to one of the", 554 "copy rectangle corners, pressing a button, and dragging.", 555 "Finally, press Copy to commit your copy region. To", 556 "exit without copying the image, press Dismiss.", 557 (char *) NULL, 558 }, 559 *ImageCropHelp[] = 560 { 561 "In crop mode, the Command widget has these options:", 562 "", 563 " Help", 564 " Dismiss", 565 "", 566 "To define a cropping region, press button 1 and drag. The", 567 "cropping region is defined by a highlighted rectangle that", 568 "expands or contracts as it follows the pointer. Once you", 569 "are satisfied with the cropping region, release the button.", 570 "You are now in rectify mode. In rectify mode, the Command", 571 "widget has these options:", 572 "", 573 " Crop", 574 " Help", 575 " Dismiss", 576 "", 577 "You can make adjustments by moving the pointer to one of the", 578 "cropping rectangle corners, pressing a button, and dragging.", 579 "Finally, press Crop to commit your cropping region. To", 580 "exit without cropping the image, press Dismiss.", 581 (char *) NULL, 582 }, 583 *ImageDrawHelp[] = 584 { 585 "The cursor changes to a crosshair to indicate you are in", 586 "draw mode. To exit immediately, press Dismiss. In draw mode,", 587 "the Command widget has these options:", 588 "", 589 " Element", 590 " point", 591 " line", 592 " rectangle", 593 " fill rectangle", 594 " circle", 595 " fill circle", 596 " ellipse", 597 " fill ellipse", 598 " polygon", 599 " fill polygon", 600 " Color", 601 " black", 602 " blue", 603 " cyan", 604 " green", 605 " gray", 606 " red", 607 " magenta", 608 " yellow", 609 " white", 610 " transparent", 611 " Browser...", 612 " Stipple", 613 " Brick", 614 " Diagonal", 615 " Scales", 616 " Vertical", 617 " Wavy", 618 " Translucent", 619 " Opaque", 620 " Open...", 621 " Width", 622 " 1", 623 " 2", 624 " 4", 625 " 8", 626 " 16", 627 " Dialog...", 628 " Undo", 629 " Help", 630 " Dismiss", 631 "", 632 "Choose a drawing primitive from the Element sub-menu.", 633 "", 634 "Choose a color from the Color sub-menu. Additional", 635 "colors can be specified with the color browser.", 636 "", 637 "If you choose the color browser and press Grab, you can", 638 "select the color by moving the pointer to the desired", 639 "color on the screen and press any button. The transparent", 640 "color updates the image matte channel and is useful for", 641 "image compositing.", 642 "", 643 "Choose a stipple, if appropriate, from the Stipple sub-menu.", 644 "Additional stipples can be specified with the file browser.", 645 "Stipples obtained from the file browser must be on disk in the", 646 "X11 bitmap format.", 647 "", 648 "Choose a width, if appropriate, from the Width sub-menu. To", 649 "choose a specific width select the Dialog widget.", 650 "", 651 "Choose a point in the Image window and press button 1 and", 652 "hold. Next, move the pointer to another location in the", 653 "image. As you move, a line connects the initial location and", 654 "the pointer. When you release the button, the image is", 655 "updated with the primitive you just drew. For polygons, the", 656 "image is updated when you press and release the button without", 657 "moving the pointer.", 658 "", 659 "To cancel image drawing, move the pointer back to the", 660 "starting point of the line and release the button.", 661 (char *) NULL, 662 }, 663 *DisplayHelp[] = 664 { 665 "BUTTONS", 666 " The effects of each button press is described below. Three", 667 " buttons are required. If you have a two button mouse,", 668 " button 1 and 3 are returned. Press ALT and button 3 to", 669 " simulate button 2.", 670 "", 671 " 1 Press this button to map or unmap the Command widget.", 672 "", 673 " 2 Press and drag to define a region of the image to", 674 " magnify.", 675 "", 676 " 3 Press and drag to choose from a select set of commands.", 677 " This button behaves differently if the image being", 678 " displayed is a visual image directory. Here, choose a", 679 " particular tile of the directory and press this button and", 680 " drag to select a command from a pop-up menu. Choose from", 681 " these menu items:", 682 "", 683 " Open", 684 " Next", 685 " Former", 686 " Delete", 687 " Update", 688 "", 689 " If you choose Open, the image represented by the tile is", 690 " displayed. To return to the visual image directory, choose", 691 " Next from the Command widget. Next and Former moves to the", 692 " next or former image respectively. Choose Delete to delete", 693 " a particular image tile. Finally, choose Update to", 694 " synchronize all the image tiles with their respective", 695 " images.", 696 "", 697 "COMMAND WIDGET", 698 " The Command widget lists a number of sub-menus and commands.", 699 " They are", 700 "", 701 " File", 702 " Open...", 703 " Next", 704 " Former", 705 " Select...", 706 " Save...", 707 " Print...", 708 " Delete...", 709 " New...", 710 " Visual Directory...", 711 " Quit", 712 " Edit", 713 " Undo", 714 " Redo", 715 " Cut", 716 " Copy", 717 " Paste", 718 " View", 719 " Half Size", 720 " Original Size", 721 " Double Size", 722 " Resize...", 723 " Apply", 724 " Refresh", 725 " Restore", 726 " Transform", 727 " Crop", 728 " Chop", 729 " Flop", 730 " Flip", 731 " Rotate Right", 732 " Rotate Left", 733 " Rotate...", 734 " Shear...", 735 " Roll...", 736 " Trim Edges", 737 " Enhance", 738 " Brightness...", 739 " Saturation...", 740 " Hue...", 741 " Gamma...", 742 " Sharpen...", 743 " Dull", 744 " Contrast Stretch...", 745 " Sigmoidal Contrast...", 746 " Normalize", 747 " Equalize", 748 " Negate", 749 " Grayscale", 750 " Map...", 751 " Quantize...", 752 " Effects", 753 " Despeckle", 754 " Emboss", 755 " Reduce Noise", 756 " Add Noise", 757 " Sharpen...", 758 " Blur...", 759 " Threshold...", 760 " Edge Detect...", 761 " Spread...", 762 " Shade...", 763 " Painting...", 764 " Segment...", 765 " F/X", 766 " Solarize...", 767 " Sepia Tone...", 768 " Swirl...", 769 " Implode...", 770 " Vignette...", 771 " Wave...", 772 " Oil Painting...", 773 " Charcoal Drawing...", 774 " Image Edit", 775 " Annotate...", 776 " Draw...", 777 " Color...", 778 " Matte...", 779 " Composite...", 780 " Add Border...", 781 " Add Frame...", 782 " Comment...", 783 " Launch...", 784 " Region of Interest...", 785 " Miscellany", 786 " Image Info", 787 " Zoom Image", 788 " Show Preview...", 789 " Show Histogram", 790 " Show Matte", 791 " Background...", 792 " Slide Show", 793 " Preferences...", 794 " Help", 795 " Overview", 796 " Browse Documentation", 797 " About Display", 798 "", 799 " Menu items with a indented triangle have a sub-menu. They", 800 " are represented above as the indented items. To access a", 801 " sub-menu item, move the pointer to the appropriate menu and", 802 " press a button and drag. When you find the desired sub-menu", 803 " item, release the button and the command is executed. Move", 804 " the pointer away from the sub-menu if you decide not to", 805 " execute a particular command.", 806 "", 807 "KEYBOARD ACCELERATORS", 808 " Accelerators are one or two key presses that effect a", 809 " particular command. The keyboard accelerators that", 810 " display(1) understands is:", 811 "", 812 " Ctl+O Press to open an image from a file.", 813 "", 814 " space Press to display the next image.", 815 "", 816 " If the image is a multi-paged document such as a Postscript", 817 " document, you can skip ahead several pages by preceding", 818 " this command with a number. For example to display the", 819 " third page beyond the current page, press 3<space>.", 820 "", 821 " backspace Press to display the former image.", 822 "", 823 " If the image is a multi-paged document such as a Postscript", 824 " document, you can skip behind several pages by preceding", 825 " this command with a number. For example to display the", 826 " third page preceding the current page, press 3<backspace>.", 827 "", 828 " Ctl+S Press to write the image to a file.", 829 "", 830 " Ctl+P Press to print the image to a Postscript printer.", 831 "", 832 " Ctl+D Press to delete an image file.", 833 "", 834 " Ctl+N Press to create a blank canvas.", 835 "", 836 " Ctl+Q Press to discard all images and exit program.", 837 "", 838 " Ctl+Z Press to undo last image transformation.", 839 "", 840 " Ctl+R Press to redo last image transformation.", 841 "", 842 " Ctl+X Press to cut a region of the image.", 843 "", 844 " Ctl+C Press to copy a region of the image.", 845 "", 846 " Ctl+V Press to paste a region to the image.", 847 "", 848 " < Press to half the image size.", 849 "", 850 " - Press to return to the original image size.", 851 "", 852 " > Press to double the image size.", 853 "", 854 " % Press to resize the image to a width and height you", 855 " specify.", 856 "", 857 "Cmd-A Press to make any image transformations permanent." 858 "", 859 " By default, any image size transformations are applied", 860 " to the original image to create the image displayed on", 861 " the X server. However, the transformations are not", 862 " permanent (i.e. the original image does not change", 863 " size only the X image does). For example, if you", 864 " press > the X image will appear to double in size,", 865 " but the original image will in fact remain the same size.", 866 " To force the original image to double in size, press >", 867 " followed by Cmd-A.", 868 "", 869 " @ Press to refresh the image window.", 870 "", 871 " C Press to cut out a rectangular region of the image.", 872 "", 873 " [ Press to chop the image.", 874 "", 875 " H Press to flop image in the horizontal direction.", 876 "", 877 " V Press to flip image in the vertical direction.", 878 "", 879 " / Press to rotate the image 90 degrees clockwise.", 880 "", 881 " \\ Press to rotate the image 90 degrees counter-clockwise.", 882 "", 883 " * Press to rotate the image the number of degrees you", 884 " specify.", 885 "", 886 " S Press to shear the image the number of degrees you", 887 " specify.", 888 "", 889 " R Press to roll the image.", 890 "", 891 " T Press to trim the image edges.", 892 "", 893 " Shft-H Press to vary the image hue.", 894 "", 895 " Shft-S Press to vary the color saturation.", 896 "", 897 " Shft-L Press to vary the color brightness.", 898 "", 899 " Shft-G Press to gamma correct the image.", 900 "", 901 " Shft-C Press to sharpen the image contrast.", 902 "", 903 " Shft-Z Press to dull the image contrast.", 904 "", 905 " = Press to perform histogram equalization on the image.", 906 "", 907 " Shft-N Press to perform histogram normalization on the image.", 908 "", 909 " Shft-~ Press to negate the colors of the image.", 910 "", 911 " . Press to convert the image colors to gray.", 912 "", 913 " Shft-# Press to set the maximum number of unique colors in the", 914 " image.", 915 "", 916 " F2 Press to reduce the speckles in an image.", 917 "", 918 " F3 Press to eliminate peak noise from an image.", 919 "", 920 " F4 Press to add noise to an image.", 921 "", 922 " F5 Press to sharpen an image.", 923 "", 924 " F6 Press to delete an image file.", 925 "", 926 " F7 Press to threshold the image.", 927 "", 928 " F8 Press to detect edges within an image.", 929 "", 930 " F9 Press to emboss an image.", 931 "", 932 " F10 Press to displace pixels by a random amount.", 933 "", 934 " F11 Press to negate all pixels above the threshold level.", 935 "", 936 " F12 Press to shade the image using a distant light source.", 937 "", 938 " F13 Press to lighten or darken image edges to create a 3-D effect.", 939 "", 940 " F14 Press to segment the image by color.", 941 "", 942 " Meta-S Press to swirl image pixels about the center.", 943 "", 944 " Meta-I Press to implode image pixels about the center.", 945 "", 946 " Meta-W Press to alter an image along a sine wave.", 947 "", 948 " Meta-P Press to simulate an oil painting.", 949 "", 950 " Meta-C Press to simulate a charcoal drawing.", 951 "", 952 " Alt-A Press to annotate the image with text.", 953 "", 954 " Alt-D Press to draw on an image.", 955 "", 956 " Alt-P Press to edit an image pixel color.", 957 "", 958 " Alt-M Press to edit the image matte information.", 959 "", 960 " Alt-V Press to composite the image with another.", 961 "", 962 " Alt-B Press to add a border to the image.", 963 "", 964 " Alt-F Press to add an ornamental border to the image.", 965 "", 966 " Alt-Shft-!", 967 " Press to add an image comment.", 968 "", 969 " Ctl-A Press to apply image processing techniques to a region", 970 " of interest.", 971 "", 972 " Shft-? Press to display information about the image.", 973 "", 974 " Shft-+ Press to map the zoom image window.", 975 "", 976 " Shft-P Press to preview an image enhancement, effect, or f/x.", 977 "", 978 " F1 Press to display helpful information about display(1).", 979 "", 980 " Find Press to browse documentation about ImageMagick.", 981 "", 982 " 1-9 Press to change the level of magnification.", 983 "", 984 " Use the arrow keys to move the image one pixel up, down,", 985 " left, or right within the magnify window. Be sure to first", 986 " map the magnify window by pressing button 2.", 987 "", 988 " Press ALT and one of the arrow keys to trim off one pixel", 989 " from any side of the image.", 990 (char *) NULL, 991 }, 992 *ImageMatteEditHelp[] = 993 { 994 "Matte information within an image is useful for some", 995 "operations such as image compositing (See IMAGE", 996 "COMPOSITING). This extra channel usually defines a mask", 997 "which represents a sort of a cookie-cutter for the image.", 998 "This the case when matte is opaque (full coverage) for", 999 "pixels inside the shape, zero outside, and between 0 and", 1000 "QuantumRange on the boundary.", 1001 "", 1002 "A small window appears showing the location of the cursor in", 1003 "the image window. You are now in matte edit mode. To exit", 1004 "immediately, press Dismiss. In matte edit mode, the Command", 1005 "widget has these options:", 1006 "", 1007 " Method", 1008 " point", 1009 " replace", 1010 " floodfill", 1011 " filltoborder", 1012 " reset", 1013 " Border Color", 1014 " black", 1015 " blue", 1016 " cyan", 1017 " green", 1018 " gray", 1019 " red", 1020 " magenta", 1021 " yellow", 1022 " white", 1023 " Browser...", 1024 " Fuzz", 1025 " 0%", 1026 " 2%", 1027 " 5%", 1028 " 10%", 1029 " 15%", 1030 " Dialog...", 1031 " Matte", 1032 " Opaque", 1033 " Transparent", 1034 " Dialog...", 1035 " Undo", 1036 " Help", 1037 " Dismiss", 1038 "", 1039 "Choose a matte editing method from the Method sub-menu of", 1040 "the Command widget. The point method changes the matte value", 1041 "of any pixel selected with the pointer until the button is", 1042 "is released. The replace method changes the matte value of", 1043 "any pixel that matches the color of the pixel you select with", 1044 "a button press. Floodfill changes the matte value of any pixel", 1045 "that matches the color of the pixel you select with a button", 1046 "press and is a neighbor. Whereas filltoborder changes the matte", 1047 "value any neighbor pixel that is not the border color. Finally", 1048 "reset changes the entire image to the designated matte value.", 1049 "", 1050 "Choose Matte Value and pick Opaque or Transarent. For other values", 1051 "select the Dialog entry. Here a dialog appears requesting a matte", 1052 "value. The value you select is assigned as the opacity value of the", 1053 "selected pixel or pixels.", 1054 "", 1055 "Now, press any button to select a pixel within the image", 1056 "window to change its matte value.", 1057 "", 1058 "If the Magnify widget is mapped, it can be helpful in positioning", 1059 "your pointer within the image (refer to button 2).", 1060 "", 1061 "Matte information is only valid in a DirectClass image.", 1062 "Therefore, any PseudoClass image is promoted to DirectClass", 1063 "(see miff(5)). Note that matte information for PseudoClass", 1064 "is not retained for colormapped X server visuals (e.g.", 1065 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you", 1066 "immediately save your image to a file (refer to Write).", 1067 "Correct matte editing behavior may require a TrueColor or", 1068 "DirectColor visual or a Standard Colormap.", 1069 (char *) NULL, 1070 }, 1071 *ImagePanHelp[] = 1072 { 1073 "When an image exceeds the width or height of the X server", 1074 "screen, display maps a small panning icon. The rectangle", 1075 "within the panning icon shows the area that is currently", 1076 "displayed in the image window. To pan about the image,", 1077 "press any button and drag the pointer within the panning", 1078 "icon. The pan rectangle moves with the pointer and the", 1079 "image window is updated to reflect the location of the", 1080 "rectangle within the panning icon. When you have selected", 1081 "the area of the image you wish to view, release the button.", 1082 "", 1083 "Use the arrow keys to pan the image one pixel up, down,", 1084 "left, or right within the image window.", 1085 "", 1086 "The panning icon is withdrawn if the image becomes smaller", 1087 "than the dimensions of the X server screen.", 1088 (char *) NULL, 1089 }, 1090 *ImagePasteHelp[] = 1091 { 1092 "A small window appears showing the location of the cursor in", 1093 "the image window. You are now in paste mode. To exit", 1094 "immediately, press Dismiss. In paste mode, the Command", 1095 "widget has these options:", 1096 "", 1097 " Operators", 1098 " over", 1099 " in", 1100 " out", 1101 " atop", 1102 " xor", 1103 " plus", 1104 " minus", 1105 " add", 1106 " subtract", 1107 " difference", 1108 " replace", 1109 " Help", 1110 " Dismiss", 1111 "", 1112 "Choose a composite operation from the Operators sub-menu of", 1113 "the Command widget. How each operator behaves is described", 1114 "below. Image window is the image currently displayed on", 1115 "your X server and image is the image obtained with the File", 1116 "Browser widget.", 1117 "", 1118 "Over The result is the union of the two image shapes,", 1119 " with image obscuring image window in the region of", 1120 " overlap.", 1121 "", 1122 "In The result is simply image cut by the shape of", 1123 " image window. None of the image data of image", 1124 " window is in the result.", 1125 "", 1126 "Out The resulting image is image with the shape of", 1127 " image window cut out.", 1128 "", 1129 "Atop The result is the same shape as image image window,", 1130 " with image obscuring image window where the image", 1131 " shapes overlap. Note this differs from over", 1132 " because the portion of image outside image window's", 1133 " shape does not appear in the result.", 1134 "", 1135 "Xor The result is the image data from both image and", 1136 " image window that is outside the overlap region.", 1137 " The overlap region is blank.", 1138 "", 1139 "Plus The result is just the sum of the image data.", 1140 " Output values are cropped to QuantumRange (no overflow).", 1141 " This operation is independent of the matte", 1142 " channels.", 1143 "", 1144 "Minus The result of image - image window, with underflow", 1145 " cropped to zero.", 1146 "", 1147 "Add The result of image + image window, with overflow", 1148 " wrapping around (mod 256).", 1149 "", 1150 "Subtract The result of image - image window, with underflow", 1151 " wrapping around (mod 256). The add and subtract", 1152 " operators can be used to perform reversible", 1153 " transformations.", 1154 "", 1155 "Difference", 1156 " The result of abs(image - image window). This", 1157 " useful for comparing two very similar images.", 1158 "", 1159 "Copy The resulting image is image window replaced with", 1160 " image. Here the matte information is ignored.", 1161 "", 1162 "CopyRed The red layer of the image window is replace with", 1163 " the red layer of the image. The other layers are", 1164 " untouched.", 1165 "", 1166 "CopyGreen", 1167 " The green layer of the image window is replace with", 1168 " the green layer of the image. The other layers are", 1169 " untouched.", 1170 "", 1171 "CopyBlue The blue layer of the image window is replace with", 1172 " the blue layer of the image. The other layers are", 1173 " untouched.", 1174 "", 1175 "CopyOpacity", 1176 " The matte layer of the image window is replace with", 1177 " the matte layer of the image. The other layers are", 1178 " untouched.", 1179 "", 1180 "The image compositor requires a matte, or alpha channel in", 1181 "the image for some operations. This extra channel usually", 1182 "defines a mask which represents a sort of a cookie-cutter", 1183 "for the image. This the case when matte is opaque (full", 1184 "coverage) for pixels inside the shape, zero outside, and", 1185 "between 0 and QuantumRange on the boundary. If image does not", 1186 "have a matte channel, it is initialized with 0 for any pixel", 1187 "matching in color to pixel location (0,0), otherwise QuantumRange.", 1188 "", 1189 "Note that matte information for image window is not retained", 1190 "for colormapped X server visuals (e.g. StaticColor,", 1191 "StaticColor, GrayScale, PseudoColor). Correct compositing", 1192 "behavior may require a TrueColor or DirectColor visual or a", 1193 "Standard Colormap.", 1194 "", 1195 "Choosing a composite operator is optional. The default", 1196 "operator is replace. However, you must choose a location to", 1197 "paste your image and press button 1. Press and hold the", 1198 "button before releasing and an outline of the image will", 1199 "appear to help you identify your location.", 1200 "", 1201 "The actual colors of the pasted image is saved. However,", 1202 "the color that appears in image window may be different.", 1203 "For example, on a monochrome screen image window will appear", 1204 "black or white even though your pasted image may have", 1205 "many colors. If the image is saved to a file it is written", 1206 "with the correct colors. To assure the correct colors are", 1207 "saved in the final image, any PseudoClass image is promoted", 1208 "to DirectClass (see miff(5)). To force a PseudoClass image", 1209 "to remain PseudoClass, use -colors.", 1210 (char *) NULL, 1211 }, 1212 *ImageROIHelp[] = 1213 { 1214 "In region of interest mode, the Command widget has these", 1215 "options:", 1216 "", 1217 " Help", 1218 " Dismiss", 1219 "", 1220 "To define a region of interest, press button 1 and drag.", 1221 "The region of interest is defined by a highlighted rectangle", 1222 "that expands or contracts as it follows the pointer. Once", 1223 "you are satisfied with the region of interest, release the", 1224 "button. You are now in apply mode. In apply mode the", 1225 "Command widget has these options:", 1226 "", 1227 " File", 1228 " Save...", 1229 " Print...", 1230 " Edit", 1231 " Undo", 1232 " Redo", 1233 " Transform", 1234 " Flop", 1235 " Flip", 1236 " Rotate Right", 1237 " Rotate Left", 1238 " Enhance", 1239 " Hue...", 1240 " Saturation...", 1241 " Brightness...", 1242 " Gamma...", 1243 " Spiff", 1244 " Dull", 1245 " Contrast Stretch", 1246 " Sigmoidal Contrast...", 1247 " Normalize", 1248 " Equalize", 1249 " Negate", 1250 " Grayscale", 1251 " Map...", 1252 " Quantize...", 1253 " Effects", 1254 " Despeckle", 1255 " Emboss", 1256 " Reduce Noise", 1257 " Sharpen...", 1258 " Blur...", 1259 " Threshold...", 1260 " Edge Detect...", 1261 " Spread...", 1262 " Shade...", 1263 " Raise...", 1264 " Segment...", 1265 " F/X", 1266 " Solarize...", 1267 " Sepia Tone...", 1268 " Swirl...", 1269 " Implode...", 1270 " Vignette...", 1271 " Wave...", 1272 " Oil Painting...", 1273 " Charcoal Drawing...", 1274 " Miscellany", 1275 " Image Info", 1276 " Zoom Image", 1277 " Show Preview...", 1278 " Show Histogram", 1279 " Show Matte", 1280 " Help", 1281 " Dismiss", 1282 "", 1283 "You can make adjustments to the region of interest by moving", 1284 "the pointer to one of the rectangle corners, pressing a", 1285 "button, and dragging. Finally, choose an image processing", 1286 "technique from the Command widget. You can choose more than", 1287 "one image processing technique to apply to an area.", 1288 "Alternatively, you can move the region of interest before", 1289 "applying another image processing technique. To exit, press", 1290 "Dismiss.", 1291 (char *) NULL, 1292 }, 1293 *ImageRotateHelp[] = 1294 { 1295 "In rotate mode, the Command widget has these options:", 1296 "", 1297 " Pixel Color", 1298 " black", 1299 " blue", 1300 " cyan", 1301 " green", 1302 " gray", 1303 " red", 1304 " magenta", 1305 " yellow", 1306 " white", 1307 " Browser...", 1308 " Direction", 1309 " horizontal", 1310 " vertical", 1311 " Help", 1312 " Dismiss", 1313 "", 1314 "Choose a background color from the Pixel Color sub-menu.", 1315 "Additional background colors can be specified with the color", 1316 "browser. You can change the menu colors by setting the X", 1317 "resources pen1 through pen9.", 1318 "", 1319 "If you choose the color browser and press Grab, you can", 1320 "select the background color by moving the pointer to the", 1321 "desired color on the screen and press any button.", 1322 "", 1323 "Choose a point in the image window and press this button and", 1324 "hold. Next, move the pointer to another location in the", 1325 "image. As you move a line connects the initial location and", 1326 "the pointer. When you release the button, the degree of", 1327 "image rotation is determined by the slope of the line you", 1328 "just drew. The slope is relative to the direction you", 1329 "choose from the Direction sub-menu of the Command widget.", 1330 "", 1331 "To cancel the image rotation, move the pointer back to the", 1332 "starting point of the line and release the button.", 1333 (char *) NULL, 1334 }; 1335 1336/* 1337 Enumeration declarations. 1338*/ 1339typedef enum 1340{ 1341 CopyMode, 1342 CropMode, 1343 CutMode 1344} ClipboardMode; 1345 1346typedef enum 1347{ 1348 OpenCommand, 1349 NextCommand, 1350 FormerCommand, 1351 SelectCommand, 1352 SaveCommand, 1353 PrintCommand, 1354 DeleteCommand, 1355 NewCommand, 1356 VisualDirectoryCommand, 1357 QuitCommand, 1358 UndoCommand, 1359 RedoCommand, 1360 CutCommand, 1361 CopyCommand, 1362 PasteCommand, 1363 HalfSizeCommand, 1364 OriginalSizeCommand, 1365 DoubleSizeCommand, 1366 ResizeCommand, 1367 ApplyCommand, 1368 RefreshCommand, 1369 RestoreCommand, 1370 CropCommand, 1371 ChopCommand, 1372 FlopCommand, 1373 FlipCommand, 1374 RotateRightCommand, 1375 RotateLeftCommand, 1376 RotateCommand, 1377 ShearCommand, 1378 RollCommand, 1379 TrimCommand, 1380 HueCommand, 1381 SaturationCommand, 1382 BrightnessCommand, 1383 GammaCommand, 1384 SpiffCommand, 1385 DullCommand, 1386 ContrastStretchCommand, 1387 SigmoidalContrastCommand, 1388 NormalizeCommand, 1389 EqualizeCommand, 1390 NegateCommand, 1391 GrayscaleCommand, 1392 MapCommand, 1393 QuantizeCommand, 1394 DespeckleCommand, 1395 EmbossCommand, 1396 ReduceNoiseCommand, 1397 AddNoiseCommand, 1398 SharpenCommand, 1399 BlurCommand, 1400 ThresholdCommand, 1401 EdgeDetectCommand, 1402 SpreadCommand, 1403 ShadeCommand, 1404 RaiseCommand, 1405 SegmentCommand, 1406 SolarizeCommand, 1407 SepiaToneCommand, 1408 SwirlCommand, 1409 ImplodeCommand, 1410 VignetteCommand, 1411 WaveCommand, 1412 OilPaintCommand, 1413 CharcoalDrawCommand, 1414 AnnotateCommand, 1415 DrawCommand, 1416 ColorCommand, 1417 MatteCommand, 1418 CompositeCommand, 1419 AddBorderCommand, 1420 AddFrameCommand, 1421 CommentCommand, 1422 LaunchCommand, 1423 RegionofInterestCommand, 1424 ROIHelpCommand, 1425 ROIDismissCommand, 1426 InfoCommand, 1427 ZoomCommand, 1428 ShowPreviewCommand, 1429 ShowHistogramCommand, 1430 ShowMatteCommand, 1431 BackgroundCommand, 1432 SlideShowCommand, 1433 PreferencesCommand, 1434 HelpCommand, 1435 BrowseDocumentationCommand, 1436 VersionCommand, 1437 SaveToUndoBufferCommand, 1438 FreeBuffersCommand, 1439 NullCommand 1440} CommandType; 1441 1442typedef enum 1443{ 1444 AnnotateNameCommand, 1445 AnnotateFontColorCommand, 1446 AnnotateBackgroundColorCommand, 1447 AnnotateRotateCommand, 1448 AnnotateHelpCommand, 1449 AnnotateDismissCommand, 1450 TextHelpCommand, 1451 TextApplyCommand, 1452 ChopDirectionCommand, 1453 ChopHelpCommand, 1454 ChopDismissCommand, 1455 HorizontalChopCommand, 1456 VerticalChopCommand, 1457 ColorEditMethodCommand, 1458 ColorEditColorCommand, 1459 ColorEditBorderCommand, 1460 ColorEditFuzzCommand, 1461 ColorEditUndoCommand, 1462 ColorEditHelpCommand, 1463 ColorEditDismissCommand, 1464 CompositeOperatorsCommand, 1465 CompositeDissolveCommand, 1466 CompositeDisplaceCommand, 1467 CompositeHelpCommand, 1468 CompositeDismissCommand, 1469 CropHelpCommand, 1470 CropDismissCommand, 1471 RectifyCopyCommand, 1472 RectifyHelpCommand, 1473 RectifyDismissCommand, 1474 DrawElementCommand, 1475 DrawColorCommand, 1476 DrawStippleCommand, 1477 DrawWidthCommand, 1478 DrawUndoCommand, 1479 DrawHelpCommand, 1480 DrawDismissCommand, 1481 MatteEditMethod, 1482 MatteEditBorderCommand, 1483 MatteEditFuzzCommand, 1484 MatteEditValueCommand, 1485 MatteEditUndoCommand, 1486 MatteEditHelpCommand, 1487 MatteEditDismissCommand, 1488 PasteOperatorsCommand, 1489 PasteHelpCommand, 1490 PasteDismissCommand, 1491 RotateColorCommand, 1492 RotateDirectionCommand, 1493 RotateCropCommand, 1494 RotateSharpenCommand, 1495 RotateHelpCommand, 1496 RotateDismissCommand, 1497 HorizontalRotateCommand, 1498 VerticalRotateCommand, 1499 TileLoadCommand, 1500 TileNextCommand, 1501 TileFormerCommand, 1502 TileDeleteCommand, 1503 TileUpdateCommand 1504} ModeType; 1505 1506/* 1507 Stipples. 1508*/ 1509#define BricksWidth 20 1510#define BricksHeight 20 1511#define DiagonalWidth 16 1512#define DiagonalHeight 16 1513#define HighlightWidth 8 1514#define HighlightHeight 8 1515#define OpaqueWidth 8 1516#define OpaqueHeight 8 1517#define ScalesWidth 16 1518#define ScalesHeight 16 1519#define ShadowWidth 8 1520#define ShadowHeight 8 1521#define VerticalWidth 16 1522#define VerticalHeight 16 1523#define WavyWidth 16 1524#define WavyHeight 16 1525 1526/* 1527 Constant declaration. 1528*/ 1529static const int 1530 RoiDelta = 8; 1531 1532static const unsigned char 1533 BricksBitmap[] = 1534 { 1535 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 1536 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 1537 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 1538 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 1539 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01 1540 }, 1541 DiagonalBitmap[] = 1542 { 1543 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 1544 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 1545 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22 1546 }, 1547 ScalesBitmap[] = 1548 { 1549 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80, 1550 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 1551 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e 1552 }, 1553 VerticalBitmap[] = 1554 { 1555 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1556 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 1557 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 1558 }, 1559 WavyBitmap[] = 1560 { 1561 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff, 1562 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf, 1563 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f 1564 }; 1565 1566/* 1567 Function prototypes. 1568*/ 1569static CommandType 1570 XImageWindowCommand(Display *,XResourceInfo *,XWindows *, 1571 const MagickStatusType,KeySym,Image **,ExceptionInfo *); 1572 1573static Image 1574 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType, 1575 Image **,ExceptionInfo *), 1576 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType), 1577 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *, 1578 ExceptionInfo *), 1579 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *, 1580 ExceptionInfo *); 1581 1582static MagickBooleanType 1583 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *, 1584 ExceptionInfo *), 1585 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **, 1586 ExceptionInfo *), 1587 XChopImage(Display *,XResourceInfo *,XWindows *,Image **, 1588 ExceptionInfo *), 1589 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode, 1590 ExceptionInfo *), 1591 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1592 ExceptionInfo *), 1593 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *, 1594 ExceptionInfo *), 1595 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1596 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1597 ExceptionInfo *), 1598 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **, 1599 ExceptionInfo *), 1600 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1601 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1602 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **, 1603 ExceptionInfo *), 1604 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *), 1605 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1606 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *); 1607 1608static void 1609 XDrawPanRectangle(Display *,XWindows *), 1610 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **, 1611 ExceptionInfo *), 1612 XMagnifyImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1613 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 1614 XPanImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 1615 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType, 1616 const KeySym,ExceptionInfo *), 1617 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *), 1618 XScreenEvent(Display *,XWindows *,XEvent *,ExceptionInfo *), 1619 XTranslateImage(Display *,XWindows *,Image *,const KeySym); 1620 1621/* 1622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1623% % 1624% % 1625% % 1626% D i s p l a y I m a g e s % 1627% % 1628% % 1629% % 1630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1631% 1632% DisplayImages() displays an image sequence to any X window screen. It 1633% returns a value other than 0 if successful. Check the exception member 1634% of image to determine the reason for any failure. 1635% 1636% The format of the DisplayImages method is: 1637% 1638% MagickBooleanType DisplayImages(const ImageInfo *image_info, 1639% Image *images,ExceptionInfo *exception) 1640% 1641% A description of each parameter follows: 1642% 1643% o image_info: the image info. 1644% 1645% o image: the image. 1646% 1647% o exception: return any errors or warnings in this structure. 1648% 1649*/ 1650MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 1651 Image *images,ExceptionInfo *exception) 1652{ 1653 char 1654 *argv[1]; 1655 1656 Display 1657 *display; 1658 1659 Image 1660 *image; 1661 1662 register ssize_t 1663 i; 1664 1665 size_t 1666 state; 1667 1668 XrmDatabase 1669 resource_database; 1670 1671 XResourceInfo 1672 resource_info; 1673 1674 assert(image_info != (const ImageInfo *) NULL); 1675 assert(image_info->signature == MagickSignature); 1676 assert(images != (Image *) NULL); 1677 assert(images->signature == MagickSignature); 1678 if( IfMagickTrue(images->debug) ) 1679 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 1680 display=XOpenDisplay(image_info->server_name); 1681 if (display == (Display *) NULL) 1682 { 1683 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1684 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1685 return(MagickFalse); 1686 } 1687 if (exception->severity != UndefinedException) 1688 CatchException(exception); 1689 (void) XSetErrorHandler(XError); 1690 resource_database=XGetResourceDatabase(display,GetClientName()); 1691 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info)); 1692 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info); 1693 if (image_info->page != (char *) NULL) 1694 resource_info.image_geometry=AcquireString(image_info->page); 1695 resource_info.immutable=MagickTrue; 1696 argv[0]=AcquireString(GetClientName()); 1697 state=DefaultState; 1698 for (i=0; (state & ExitState) == 0; i++) 1699 { 1700 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations)) 1701 break; 1702 image=GetImageFromList(images,i % GetImageListLength(images)); 1703 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception); 1704 } 1705 (void) SetErrorHandler((ErrorHandler) NULL); 1706 (void) SetWarningHandler((WarningHandler) NULL); 1707 argv[0]=DestroyString(argv[0]); 1708 (void) XCloseDisplay(display); 1709 XDestroyResourceInfo(&resource_info); 1710 if (exception->severity != UndefinedException) 1711 return(MagickFalse); 1712 return(MagickTrue); 1713} 1714 1715/* 1716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1717% % 1718% % 1719% % 1720% R e m o t e D i s p l a y C o m m a n d % 1721% % 1722% % 1723% % 1724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1725% 1726% RemoteDisplayCommand() encourages a remote display program to display the 1727% specified image filename. 1728% 1729% The format of the RemoteDisplayCommand method is: 1730% 1731% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1732% const char *window,const char *filename,ExceptionInfo *exception) 1733% 1734% A description of each parameter follows: 1735% 1736% o image_info: the image info. 1737% 1738% o window: Specifies the name or id of an X window. 1739% 1740% o filename: the name of the image filename to display. 1741% 1742% o exception: return any errors or warnings in this structure. 1743% 1744*/ 1745MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 1746 const char *window,const char *filename,ExceptionInfo *exception) 1747{ 1748 Display 1749 *display; 1750 1751 MagickStatusType 1752 status; 1753 1754 assert(image_info != (const ImageInfo *) NULL); 1755 assert(image_info->signature == MagickSignature); 1756 assert(filename != (char *) NULL); 1757 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 1758 display=XOpenDisplay(image_info->server_name); 1759 if (display == (Display *) NULL) 1760 { 1761 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 1762 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 1763 return(MagickFalse); 1764 } 1765 (void) XSetErrorHandler(XError); 1766 status=XRemoteCommand(display,window,filename); 1767 (void) XCloseDisplay(display); 1768 return(IsMagickTrue(status)); 1769} 1770 1771/* 1772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1773% % 1774% % 1775% % 1776+ X A n n o t a t e E d i t I m a g e % 1777% % 1778% % 1779% % 1780%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1781% 1782% XAnnotateEditImage() annotates the image with text. 1783% 1784% The format of the XAnnotateEditImage method is: 1785% 1786% MagickBooleanType XAnnotateEditImage(Display *display, 1787% XResourceInfo *resource_info,XWindows *windows,Image *image, 1788% ExceptionInfo *exception) 1789% 1790% A description of each parameter follows: 1791% 1792% o display: Specifies a connection to an X server; returned from 1793% XOpenDisplay. 1794% 1795% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 1796% 1797% o windows: Specifies a pointer to a XWindows structure. 1798% 1799% o image: the image; returned from ReadImage. 1800% 1801*/ 1802 1803static inline ssize_t MagickMax(const ssize_t x,const ssize_t y) 1804{ 1805 if (x > y) 1806 return(x); 1807 return(y); 1808} 1809 1810static inline ssize_t MagickMin(const ssize_t x,const ssize_t y) 1811{ 1812 if (x < y) 1813 return(x); 1814 return(y); 1815} 1816 1817static MagickBooleanType XAnnotateEditImage(Display *display, 1818 XResourceInfo *resource_info,XWindows *windows,Image *image, 1819 ExceptionInfo *exception) 1820{ 1821 static const char 1822 *AnnotateMenu[] = 1823 { 1824 "Font Name", 1825 "Font Color", 1826 "Box Color", 1827 "Rotate Text", 1828 "Help", 1829 "Dismiss", 1830 (char *) NULL 1831 }, 1832 *TextMenu[] = 1833 { 1834 "Help", 1835 "Apply", 1836 (char *) NULL 1837 }; 1838 1839 static const ModeType 1840 AnnotateCommands[] = 1841 { 1842 AnnotateNameCommand, 1843 AnnotateFontColorCommand, 1844 AnnotateBackgroundColorCommand, 1845 AnnotateRotateCommand, 1846 AnnotateHelpCommand, 1847 AnnotateDismissCommand 1848 }, 1849 TextCommands[] = 1850 { 1851 TextHelpCommand, 1852 TextApplyCommand 1853 }; 1854 1855 static MagickBooleanType 1856 transparent_box = MagickTrue, 1857 transparent_pen = MagickFalse; 1858 1859 static double 1860 degrees = 0.0; 1861 1862 static unsigned int 1863 box_id = MaxNumberPens-2, 1864 font_id = 0, 1865 pen_id = 0; 1866 1867 char 1868 command[MaxTextExtent], 1869 text[MaxTextExtent]; 1870 1871 const char 1872 *ColorMenu[MaxNumberPens+1]; 1873 1874 Cursor 1875 cursor; 1876 1877 GC 1878 annotate_context; 1879 1880 int 1881 id, 1882 pen_number, 1883 status, 1884 x, 1885 y; 1886 1887 KeySym 1888 key_symbol; 1889 1890 register char 1891 *p; 1892 1893 register ssize_t 1894 i; 1895 1896 unsigned int 1897 height, 1898 width; 1899 1900 size_t 1901 state; 1902 1903 XAnnotateInfo 1904 *annotate_info, 1905 *previous_info; 1906 1907 XColor 1908 color; 1909 1910 XFontStruct 1911 *font_info; 1912 1913 XEvent 1914 event, 1915 text_event; 1916 1917 /* 1918 Map Command widget. 1919 */ 1920 (void) CloneString(&windows->command.name,"Annotate"); 1921 windows->command.data=4; 1922 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL); 1923 (void) XMapRaised(display,windows->command.id); 1924 XClientMessage(display,windows->image.id,windows->im_protocols, 1925 windows->im_update_widget,CurrentTime); 1926 /* 1927 Track pointer until button 1 is pressed. 1928 */ 1929 XQueryPosition(display,windows->image.id,&x,&y); 1930 (void) XSelectInput(display,windows->image.id, 1931 windows->image.attributes.event_mask | PointerMotionMask); 1932 cursor=XCreateFontCursor(display,XC_left_side); 1933 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1934 state=DefaultState; 1935 do 1936 { 1937 if( IfMagickTrue(windows->info.mapped) ) 1938 { 1939 /* 1940 Display pointer position. 1941 */ 1942 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 1943 x+windows->image.x,y+windows->image.y); 1944 XInfoWidget(display,windows,text); 1945 } 1946 /* 1947 Wait for next event. 1948 */ 1949 XScreenEvent(display,windows,&event,exception); 1950 if (event.xany.window == windows->command.id) 1951 { 1952 /* 1953 Select a command from the Command widget. 1954 */ 1955 id=XCommandWidget(display,windows,AnnotateMenu,&event); 1956 (void) XCheckDefineCursor(display,windows->image.id,cursor); 1957 if (id < 0) 1958 continue; 1959 switch (AnnotateCommands[id]) 1960 { 1961 case AnnotateNameCommand: 1962 { 1963 const char 1964 *FontMenu[MaxNumberFonts]; 1965 1966 int 1967 font_number; 1968 1969 /* 1970 Initialize menu selections. 1971 */ 1972 for (i=0; i < MaxNumberFonts; i++) 1973 FontMenu[i]=resource_info->font_name[i]; 1974 FontMenu[MaxNumberFonts-2]="Browser..."; 1975 FontMenu[MaxNumberFonts-1]=(const char *) NULL; 1976 /* 1977 Select a font name from the pop-up menu. 1978 */ 1979 font_number=XMenuWidget(display,windows,AnnotateMenu[id], 1980 (const char **) FontMenu,command); 1981 if (font_number < 0) 1982 break; 1983 if (font_number == (MaxNumberFonts-2)) 1984 { 1985 static char 1986 font_name[MaxTextExtent] = "fixed"; 1987 1988 /* 1989 Select a font name from a browser. 1990 */ 1991 resource_info->font_name[font_number]=font_name; 1992 XFontBrowserWidget(display,windows,"Select",font_name); 1993 if (*font_name == '\0') 1994 break; 1995 } 1996 /* 1997 Initialize font info. 1998 */ 1999 font_info=XLoadQueryFont(display,resource_info->font_name[ 2000 font_number]); 2001 if (font_info == (XFontStruct *) NULL) 2002 { 2003 XNoticeWidget(display,windows,"Unable to load font:", 2004 resource_info->font_name[font_number]); 2005 break; 2006 } 2007 font_id=(unsigned int) font_number; 2008 (void) XFreeFont(display,font_info); 2009 break; 2010 } 2011 case AnnotateFontColorCommand: 2012 { 2013 /* 2014 Initialize menu selections. 2015 */ 2016 for (i=0; i < (int) (MaxNumberPens-2); i++) 2017 ColorMenu[i]=resource_info->pen_colors[i]; 2018 ColorMenu[MaxNumberPens-2]="transparent"; 2019 ColorMenu[MaxNumberPens-1]="Browser..."; 2020 ColorMenu[MaxNumberPens]=(const char *) NULL; 2021 /* 2022 Select a pen color from the pop-up menu. 2023 */ 2024 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2025 (const char **) ColorMenu,command); 2026 if (pen_number < 0) 2027 break; 2028 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue : 2029 MagickFalse; 2030 if( IfMagickTrue(transparent_pen) ) 2031 break; 2032 if (pen_number == (MaxNumberPens-1)) 2033 { 2034 static char 2035 color_name[MaxTextExtent] = "gray"; 2036 2037 /* 2038 Select a pen color from a dialog. 2039 */ 2040 resource_info->pen_colors[pen_number]=color_name; 2041 XColorBrowserWidget(display,windows,"Select",color_name); 2042 if (*color_name == '\0') 2043 break; 2044 } 2045 /* 2046 Set pen color. 2047 */ 2048 (void) XParseColor(display,windows->map_info->colormap, 2049 resource_info->pen_colors[pen_number],&color); 2050 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2051 (unsigned int) MaxColors,&color); 2052 windows->pixel_info->pen_colors[pen_number]=color; 2053 pen_id=(unsigned int) pen_number; 2054 break; 2055 } 2056 case AnnotateBackgroundColorCommand: 2057 { 2058 /* 2059 Initialize menu selections. 2060 */ 2061 for (i=0; i < (int) (MaxNumberPens-2); i++) 2062 ColorMenu[i]=resource_info->pen_colors[i]; 2063 ColorMenu[MaxNumberPens-2]="transparent"; 2064 ColorMenu[MaxNumberPens-1]="Browser..."; 2065 ColorMenu[MaxNumberPens]=(const char *) NULL; 2066 /* 2067 Select a pen color from the pop-up menu. 2068 */ 2069 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 2070 (const char **) ColorMenu,command); 2071 if (pen_number < 0) 2072 break; 2073 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue : 2074 MagickFalse; 2075 if( IfMagickTrue(transparent_box) ) 2076 break; 2077 if (pen_number == (MaxNumberPens-1)) 2078 { 2079 static char 2080 color_name[MaxTextExtent] = "gray"; 2081 2082 /* 2083 Select a pen color from a dialog. 2084 */ 2085 resource_info->pen_colors[pen_number]=color_name; 2086 XColorBrowserWidget(display,windows,"Select",color_name); 2087 if (*color_name == '\0') 2088 break; 2089 } 2090 /* 2091 Set pen color. 2092 */ 2093 (void) XParseColor(display,windows->map_info->colormap, 2094 resource_info->pen_colors[pen_number],&color); 2095 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 2096 (unsigned int) MaxColors,&color); 2097 windows->pixel_info->pen_colors[pen_number]=color; 2098 box_id=(unsigned int) pen_number; 2099 break; 2100 } 2101 case AnnotateRotateCommand: 2102 { 2103 int 2104 entry; 2105 2106 static char 2107 angle[MaxTextExtent] = "30.0"; 2108 2109 static const char 2110 *RotateMenu[] = 2111 { 2112 "-90", 2113 "-45", 2114 "-30", 2115 "0", 2116 "30", 2117 "45", 2118 "90", 2119 "180", 2120 "Dialog...", 2121 (char *) NULL, 2122 }; 2123 2124 /* 2125 Select a command from the pop-up menu. 2126 */ 2127 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu, 2128 command); 2129 if (entry < 0) 2130 break; 2131 if (entry != 8) 2132 { 2133 degrees=StringToDouble(RotateMenu[entry],(char **) NULL); 2134 break; 2135 } 2136 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:", 2137 angle); 2138 if (*angle == '\0') 2139 break; 2140 degrees=StringToDouble(angle,(char **) NULL); 2141 break; 2142 } 2143 case AnnotateHelpCommand: 2144 { 2145 XTextViewWidget(display,resource_info,windows,MagickFalse, 2146 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2147 break; 2148 } 2149 case AnnotateDismissCommand: 2150 { 2151 /* 2152 Prematurely exit. 2153 */ 2154 state|=EscapeState; 2155 state|=ExitState; 2156 break; 2157 } 2158 default: 2159 break; 2160 } 2161 continue; 2162 } 2163 switch (event.type) 2164 { 2165 case ButtonPress: 2166 { 2167 if (event.xbutton.button != Button1) 2168 break; 2169 if (event.xbutton.window != windows->image.id) 2170 break; 2171 /* 2172 Change to text entering mode. 2173 */ 2174 x=event.xbutton.x; 2175 y=event.xbutton.y; 2176 state|=ExitState; 2177 break; 2178 } 2179 case ButtonRelease: 2180 break; 2181 case Expose: 2182 break; 2183 case KeyPress: 2184 { 2185 if (event.xkey.window != windows->image.id) 2186 break; 2187 /* 2188 Respond to a user key press. 2189 */ 2190 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2191 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2192 switch ((int) key_symbol) 2193 { 2194 case XK_Escape: 2195 case XK_F20: 2196 { 2197 /* 2198 Prematurely exit. 2199 */ 2200 state|=EscapeState; 2201 state|=ExitState; 2202 break; 2203 } 2204 case XK_F1: 2205 case XK_Help: 2206 { 2207 XTextViewWidget(display,resource_info,windows,MagickFalse, 2208 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2209 break; 2210 } 2211 default: 2212 { 2213 (void) XBell(display,0); 2214 break; 2215 } 2216 } 2217 break; 2218 } 2219 case MotionNotify: 2220 { 2221 /* 2222 Map and unmap Info widget as cursor crosses its boundaries. 2223 */ 2224 x=event.xmotion.x; 2225 y=event.xmotion.y; 2226 if( IfMagickTrue(windows->info.mapped) ) 2227 { 2228 if ((x < (int) (windows->info.x+windows->info.width)) && 2229 (y < (int) (windows->info.y+windows->info.height))) 2230 (void) XWithdrawWindow(display,windows->info.id, 2231 windows->info.screen); 2232 } 2233 else 2234 if ((x > (int) (windows->info.x+windows->info.width)) || 2235 (y > (int) (windows->info.y+windows->info.height))) 2236 (void) XMapWindow(display,windows->info.id); 2237 break; 2238 } 2239 default: 2240 break; 2241 } 2242 } while ((state & ExitState) == 0); 2243 (void) XSelectInput(display,windows->image.id, 2244 windows->image.attributes.event_mask); 2245 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 2246 if ((state & EscapeState) != 0) 2247 return(MagickTrue); 2248 /* 2249 Set font info and check boundary conditions. 2250 */ 2251 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]); 2252 if (font_info == (XFontStruct *) NULL) 2253 { 2254 XNoticeWidget(display,windows,"Unable to load font:", 2255 resource_info->font_name[font_id]); 2256 font_info=windows->font_info; 2257 } 2258 if ((x+font_info->max_bounds.width) >= (int) windows->image.width) 2259 x=(int) windows->image.width-font_info->max_bounds.width; 2260 if (y < (int) (font_info->ascent+font_info->descent)) 2261 y=(int) font_info->ascent+font_info->descent; 2262 if (((int) font_info->max_bounds.width > (int) windows->image.width) || 2263 ((font_info->ascent+font_info->descent) >= (int) windows->image.height)) 2264 return(MagickFalse); 2265 /* 2266 Initialize annotate structure. 2267 */ 2268 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info)); 2269 if (annotate_info == (XAnnotateInfo *) NULL) 2270 return(MagickFalse); 2271 XGetAnnotateInfo(annotate_info); 2272 annotate_info->x=x; 2273 annotate_info->y=y; 2274 if( IfMagickFalse(transparent_box) && IfMagickFalse(transparent_pen)) 2275 annotate_info->stencil=OpaqueStencil; 2276 else 2277 if( IfMagickFalse(transparent_box) ) 2278 annotate_info->stencil=BackgroundStencil; 2279 else 2280 annotate_info->stencil=ForegroundStencil; 2281 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent; 2282 annotate_info->degrees=degrees; 2283 annotate_info->font_info=font_info; 2284 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2285 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL, 2286 sizeof(*annotate_info->text)); 2287 if (annotate_info->text == (char *) NULL) 2288 return(MagickFalse); 2289 /* 2290 Create cursor and set graphic context. 2291 */ 2292 cursor=XCreateFontCursor(display,XC_pencil); 2293 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2294 annotate_context=windows->image.annotate_context; 2295 (void) XSetFont(display,annotate_context,font_info->fid); 2296 (void) XSetBackground(display,annotate_context, 2297 windows->pixel_info->pen_colors[box_id].pixel); 2298 (void) XSetForeground(display,annotate_context, 2299 windows->pixel_info->pen_colors[pen_id].pixel); 2300 /* 2301 Begin annotating the image with text. 2302 */ 2303 (void) CloneString(&windows->command.name,"Text"); 2304 windows->command.data=0; 2305 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL); 2306 state=DefaultState; 2307 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2308 text_event.xexpose.width=(int) font_info->max_bounds.width; 2309 text_event.xexpose.height=font_info->max_bounds.ascent+ 2310 font_info->max_bounds.descent; 2311 p=annotate_info->text; 2312 do 2313 { 2314 /* 2315 Display text cursor. 2316 */ 2317 *p='\0'; 2318 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 2319 /* 2320 Wait for next event. 2321 */ 2322 XScreenEvent(display,windows,&event,exception); 2323 if (event.xany.window == windows->command.id) 2324 { 2325 /* 2326 Select a command from the Command widget. 2327 */ 2328 (void) XSetBackground(display,annotate_context, 2329 windows->pixel_info->background_color.pixel); 2330 (void) XSetForeground(display,annotate_context, 2331 windows->pixel_info->foreground_color.pixel); 2332 id=XCommandWidget(display,windows,AnnotateMenu,&event); 2333 (void) XSetBackground(display,annotate_context, 2334 windows->pixel_info->pen_colors[box_id].pixel); 2335 (void) XSetForeground(display,annotate_context, 2336 windows->pixel_info->pen_colors[pen_id].pixel); 2337 if (id < 0) 2338 continue; 2339 switch (TextCommands[id]) 2340 { 2341 case TextHelpCommand: 2342 { 2343 XTextViewWidget(display,resource_info,windows,MagickFalse, 2344 "Help Viewer - Image Annotation",ImageAnnotateHelp); 2345 (void) XCheckDefineCursor(display,windows->image.id,cursor); 2346 break; 2347 } 2348 case TextApplyCommand: 2349 { 2350 /* 2351 Finished annotating. 2352 */ 2353 annotate_info->width=(unsigned int) XTextWidth(font_info, 2354 annotate_info->text,(int) strlen(annotate_info->text)); 2355 XRefreshWindow(display,&windows->image,&text_event); 2356 state|=ExitState; 2357 break; 2358 } 2359 default: 2360 break; 2361 } 2362 continue; 2363 } 2364 /* 2365 Erase text cursor. 2366 */ 2367 text_event.xexpose.x=x; 2368 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2369 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y, 2370 (unsigned int) text_event.xexpose.width,(unsigned int) 2371 text_event.xexpose.height,MagickFalse); 2372 XRefreshWindow(display,&windows->image,&text_event); 2373 switch (event.type) 2374 { 2375 case ButtonPress: 2376 { 2377 if (event.xbutton.window != windows->image.id) 2378 break; 2379 if (event.xbutton.button == Button2) 2380 { 2381 /* 2382 Request primary selection. 2383 */ 2384 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, 2385 windows->image.id,CurrentTime); 2386 break; 2387 } 2388 break; 2389 } 2390 case Expose: 2391 { 2392 if (event.xexpose.count == 0) 2393 { 2394 XAnnotateInfo 2395 *text_info; 2396 2397 /* 2398 Refresh Image window. 2399 */ 2400 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 2401 text_info=annotate_info; 2402 while (text_info != (XAnnotateInfo *) NULL) 2403 { 2404 if (annotate_info->stencil == ForegroundStencil) 2405 (void) XDrawString(display,windows->image.id,annotate_context, 2406 text_info->x,text_info->y,text_info->text, 2407 (int) strlen(text_info->text)); 2408 else 2409 (void) XDrawImageString(display,windows->image.id, 2410 annotate_context,text_info->x,text_info->y,text_info->text, 2411 (int) strlen(text_info->text)); 2412 text_info=text_info->previous; 2413 } 2414 (void) XDrawString(display,windows->image.id,annotate_context, 2415 x,y,"_",1); 2416 } 2417 break; 2418 } 2419 case KeyPress: 2420 { 2421 int 2422 length; 2423 2424 if (event.xkey.window != windows->image.id) 2425 break; 2426 /* 2427 Respond to a user key press. 2428 */ 2429 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 2430 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2431 *(command+length)='\0'; 2432 if (((event.xkey.state & ControlMask) != 0) || 2433 ((event.xkey.state & Mod1Mask) != 0)) 2434 state|=ModifierState; 2435 if ((state & ModifierState) != 0) 2436 switch ((int) key_symbol) 2437 { 2438 case XK_u: 2439 case XK_U: 2440 { 2441 key_symbol=DeleteCommand; 2442 break; 2443 } 2444 default: 2445 break; 2446 } 2447 switch ((int) key_symbol) 2448 { 2449 case XK_BackSpace: 2450 { 2451 /* 2452 Erase one character. 2453 */ 2454 if (p == annotate_info->text) 2455 { 2456 if (annotate_info->previous == (XAnnotateInfo *) NULL) 2457 break; 2458 else 2459 { 2460 /* 2461 Go to end of the previous line of text. 2462 */ 2463 annotate_info=annotate_info->previous; 2464 p=annotate_info->text; 2465 x=annotate_info->x+annotate_info->width; 2466 y=annotate_info->y; 2467 if (annotate_info->width != 0) 2468 p+=strlen(annotate_info->text); 2469 break; 2470 } 2471 } 2472 p--; 2473 x-=XTextWidth(font_info,p,1); 2474 text_event.xexpose.x=x; 2475 text_event.xexpose.y=y-font_info->max_bounds.ascent; 2476 XRefreshWindow(display,&windows->image,&text_event); 2477 break; 2478 } 2479 case XK_bracketleft: 2480 { 2481 key_symbol=XK_Escape; 2482 break; 2483 } 2484 case DeleteCommand: 2485 { 2486 /* 2487 Erase the entire line of text. 2488 */ 2489 while (p != annotate_info->text) 2490 { 2491 p--; 2492 x-=XTextWidth(font_info,p,1); 2493 text_event.xexpose.x=x; 2494 XRefreshWindow(display,&windows->image,&text_event); 2495 } 2496 break; 2497 } 2498 case XK_Escape: 2499 case XK_F20: 2500 { 2501 /* 2502 Finished annotating. 2503 */ 2504 annotate_info->width=(unsigned int) XTextWidth(font_info, 2505 annotate_info->text,(int) strlen(annotate_info->text)); 2506 XRefreshWindow(display,&windows->image,&text_event); 2507 state|=ExitState; 2508 break; 2509 } 2510 default: 2511 { 2512 /* 2513 Draw a single character on the Image window. 2514 */ 2515 if ((state & ModifierState) != 0) 2516 break; 2517 if (*command == '\0') 2518 break; 2519 *p=(*command); 2520 if (annotate_info->stencil == ForegroundStencil) 2521 (void) XDrawString(display,windows->image.id,annotate_context, 2522 x,y,p,1); 2523 else 2524 (void) XDrawImageString(display,windows->image.id, 2525 annotate_context,x,y,p,1); 2526 x+=XTextWidth(font_info,p,1); 2527 p++; 2528 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2529 break; 2530 } 2531 case XK_Return: 2532 case XK_KP_Enter: 2533 { 2534 /* 2535 Advance to the next line of text. 2536 */ 2537 *p='\0'; 2538 annotate_info->width=(unsigned int) XTextWidth(font_info, 2539 annotate_info->text,(int) strlen(annotate_info->text)); 2540 if (annotate_info->next != (XAnnotateInfo *) NULL) 2541 { 2542 /* 2543 Line of text already exists. 2544 */ 2545 annotate_info=annotate_info->next; 2546 x=annotate_info->x; 2547 y=annotate_info->y; 2548 p=annotate_info->text; 2549 break; 2550 } 2551 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2552 sizeof(*annotate_info->next)); 2553 if (annotate_info->next == (XAnnotateInfo *) NULL) 2554 return(MagickFalse); 2555 *annotate_info->next=(*annotate_info); 2556 annotate_info->next->previous=annotate_info; 2557 annotate_info=annotate_info->next; 2558 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2559 windows->image.width/MagickMax((ssize_t) 2560 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2561 if (annotate_info->text == (char *) NULL) 2562 return(MagickFalse); 2563 annotate_info->y+=annotate_info->height; 2564 if (annotate_info->y > (int) windows->image.height) 2565 annotate_info->y=(int) annotate_info->height; 2566 annotate_info->next=(XAnnotateInfo *) NULL; 2567 x=annotate_info->x; 2568 y=annotate_info->y; 2569 p=annotate_info->text; 2570 break; 2571 } 2572 } 2573 break; 2574 } 2575 case KeyRelease: 2576 { 2577 /* 2578 Respond to a user key release. 2579 */ 2580 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 2581 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 2582 state&=(~ModifierState); 2583 break; 2584 } 2585 case SelectionNotify: 2586 { 2587 Atom 2588 type; 2589 2590 int 2591 format; 2592 2593 unsigned char 2594 *data; 2595 2596 unsigned long 2597 after, 2598 length; 2599 2600 /* 2601 Obtain response from primary selection. 2602 */ 2603 if (event.xselection.property == (Atom) None) 2604 break; 2605 status=XGetWindowProperty(display,event.xselection.requestor, 2606 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING, 2607 &type,&format,&length,&after,&data); 2608 if ((status != Success) || (type != XA_STRING) || (format == 32) || 2609 (length == 0)) 2610 break; 2611 /* 2612 Annotate Image window with primary selection. 2613 */ 2614 for (i=0; i < (ssize_t) length; i++) 2615 { 2616 if ((char) data[i] != '\n') 2617 { 2618 /* 2619 Draw a single character on the Image window. 2620 */ 2621 *p=(char) data[i]; 2622 (void) XDrawString(display,windows->image.id,annotate_context, 2623 x,y,p,1); 2624 x+=XTextWidth(font_info,p,1); 2625 p++; 2626 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 2627 continue; 2628 } 2629 /* 2630 Advance to the next line of text. 2631 */ 2632 *p='\0'; 2633 annotate_info->width=(unsigned int) XTextWidth(font_info, 2634 annotate_info->text,(int) strlen(annotate_info->text)); 2635 if (annotate_info->next != (XAnnotateInfo *) NULL) 2636 { 2637 /* 2638 Line of text already exists. 2639 */ 2640 annotate_info=annotate_info->next; 2641 x=annotate_info->x; 2642 y=annotate_info->y; 2643 p=annotate_info->text; 2644 continue; 2645 } 2646 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 2647 sizeof(*annotate_info->next)); 2648 if (annotate_info->next == (XAnnotateInfo *) NULL) 2649 return(MagickFalse); 2650 *annotate_info->next=(*annotate_info); 2651 annotate_info->next->previous=annotate_info; 2652 annotate_info=annotate_info->next; 2653 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 2654 windows->image.width/MagickMax((ssize_t) 2655 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 2656 if (annotate_info->text == (char *) NULL) 2657 return(MagickFalse); 2658 annotate_info->y+=annotate_info->height; 2659 if (annotate_info->y > (int) windows->image.height) 2660 annotate_info->y=(int) annotate_info->height; 2661 annotate_info->next=(XAnnotateInfo *) NULL; 2662 x=annotate_info->x; 2663 y=annotate_info->y; 2664 p=annotate_info->text; 2665 } 2666 (void) XFree((void *) data); 2667 break; 2668 } 2669 default: 2670 break; 2671 } 2672 } while ((state & ExitState) == 0); 2673 (void) XFreeCursor(display,cursor); 2674 /* 2675 Annotation is relative to image configuration. 2676 */ 2677 width=(unsigned int) image->columns; 2678 height=(unsigned int) image->rows; 2679 x=0; 2680 y=0; 2681 if (windows->image.crop_geometry != (char *) NULL) 2682 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 2683 /* 2684 Initialize annotated image. 2685 */ 2686 XSetCursorState(display,windows,MagickTrue); 2687 XCheckRefreshWindows(display,windows); 2688 while (annotate_info != (XAnnotateInfo *) NULL) 2689 { 2690 if (annotate_info->width == 0) 2691 { 2692 /* 2693 No text on this line-- go to the next line of text. 2694 */ 2695 previous_info=annotate_info->previous; 2696 annotate_info->text=(char *) 2697 RelinquishMagickMemory(annotate_info->text); 2698 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2699 annotate_info=previous_info; 2700 continue; 2701 } 2702 /* 2703 Determine pixel index for box and pen color. 2704 */ 2705 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id]; 2706 if (windows->pixel_info->colors != 0) 2707 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2708 if (windows->pixel_info->pixels[i] == 2709 windows->pixel_info->pen_colors[box_id].pixel) 2710 { 2711 windows->pixel_info->box_index=(unsigned short) i; 2712 break; 2713 } 2714 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 2715 if (windows->pixel_info->colors != 0) 2716 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 2717 if (windows->pixel_info->pixels[i] == 2718 windows->pixel_info->pen_colors[pen_id].pixel) 2719 { 2720 windows->pixel_info->pen_index=(unsigned short) i; 2721 break; 2722 } 2723 /* 2724 Define the annotate geometry string. 2725 */ 2726 annotate_info->x=(int) 2727 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width; 2728 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+ 2729 windows->image.y)/windows->image.ximage->height; 2730 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent, 2731 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width, 2732 height*annotate_info->height/windows->image.ximage->height, 2733 annotate_info->x+x,annotate_info->y+y); 2734 /* 2735 Annotate image with text. 2736 */ 2737 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image, 2738 exception); 2739 if (status == 0) 2740 return(MagickFalse); 2741 /* 2742 Free up memory. 2743 */ 2744 previous_info=annotate_info->previous; 2745 annotate_info->text=DestroyString(annotate_info->text); 2746 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 2747 annotate_info=previous_info; 2748 } 2749 (void) XSetForeground(display,annotate_context, 2750 windows->pixel_info->foreground_color.pixel); 2751 (void) XSetBackground(display,annotate_context, 2752 windows->pixel_info->background_color.pixel); 2753 (void) XSetFont(display,annotate_context,windows->font_info->fid); 2754 XSetCursorState(display,windows,MagickFalse); 2755 (void) XFreeFont(display,font_info); 2756 /* 2757 Update image configuration. 2758 */ 2759 XConfigureImageColormap(display,resource_info,windows,image,exception); 2760 (void) XConfigureImage(display,resource_info,windows,image,exception); 2761 return(MagickTrue); 2762} 2763 2764/* 2765%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2766% % 2767% % 2768% % 2769+ X B a c k g r o u n d I m a g e % 2770% % 2771% % 2772% % 2773%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2774% 2775% XBackgroundImage() displays the image in the background of a window. 2776% 2777% The format of the XBackgroundImage method is: 2778% 2779% MagickBooleanType XBackgroundImage(Display *display, 2780% XResourceInfo *resource_info,XWindows *windows,Image **image, 2781% ExceptionInfo *exception) 2782% 2783% A description of each parameter follows: 2784% 2785% o display: Specifies a connection to an X server; returned from 2786% XOpenDisplay. 2787% 2788% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2789% 2790% o windows: Specifies a pointer to a XWindows structure. 2791% 2792% o image: the image. 2793% 2794% o exception: return any errors or warnings in this structure. 2795% 2796*/ 2797static MagickBooleanType XBackgroundImage(Display *display, 2798 XResourceInfo *resource_info,XWindows *windows,Image **image, 2799 ExceptionInfo *exception) 2800{ 2801#define BackgroundImageTag "Background/Image" 2802 2803 int 2804 status; 2805 2806 static char 2807 window_id[MaxTextExtent] = "root"; 2808 2809 XResourceInfo 2810 background_resources; 2811 2812 /* 2813 Put image in background. 2814 */ 2815 status=XDialogWidget(display,windows,"Background", 2816 "Enter window id (id 0x00 selects window with pointer):",window_id); 2817 if (*window_id == '\0') 2818 return(MagickFalse); 2819 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 2820 exception); 2821 XInfoWidget(display,windows,BackgroundImageTag); 2822 XSetCursorState(display,windows,MagickTrue); 2823 XCheckRefreshWindows(display,windows); 2824 background_resources=(*resource_info); 2825 background_resources.window_id=window_id; 2826 background_resources.backdrop=IsMagickTrue(status); 2827 status=XDisplayBackgroundImage(display,&background_resources,*image, 2828 exception); 2829 if (IfMagickTrue(status)) 2830 XClientMessage(display,windows->image.id,windows->im_protocols, 2831 windows->im_retain_colors,CurrentTime); 2832 XSetCursorState(display,windows,MagickFalse); 2833 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image, 2834 exception); 2835 return(MagickTrue); 2836} 2837 2838/* 2839%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2840% % 2841% % 2842% % 2843+ X C h o p I m a g e % 2844% % 2845% % 2846% % 2847%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2848% 2849% XChopImage() chops the X image. 2850% 2851% The format of the XChopImage method is: 2852% 2853% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info, 2854% XWindows *windows,Image **image,ExceptionInfo *exception) 2855% 2856% A description of each parameter follows: 2857% 2858% o display: Specifies a connection to an X server; returned from 2859% XOpenDisplay. 2860% 2861% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 2862% 2863% o windows: Specifies a pointer to a XWindows structure. 2864% 2865% o image: the image. 2866% 2867% o exception: return any errors or warnings in this structure. 2868% 2869*/ 2870static MagickBooleanType XChopImage(Display *display, 2871 XResourceInfo *resource_info,XWindows *windows,Image **image, 2872 ExceptionInfo *exception) 2873{ 2874 static const char 2875 *ChopMenu[] = 2876 { 2877 "Direction", 2878 "Help", 2879 "Dismiss", 2880 (char *) NULL 2881 }; 2882 2883 static ModeType 2884 direction = HorizontalChopCommand; 2885 2886 static const ModeType 2887 ChopCommands[] = 2888 { 2889 ChopDirectionCommand, 2890 ChopHelpCommand, 2891 ChopDismissCommand 2892 }, 2893 DirectionCommands[] = 2894 { 2895 HorizontalChopCommand, 2896 VerticalChopCommand 2897 }; 2898 2899 char 2900 text[MaxTextExtent]; 2901 2902 Image 2903 *chop_image; 2904 2905 int 2906 id, 2907 x, 2908 y; 2909 2910 double 2911 scale_factor; 2912 2913 RectangleInfo 2914 chop_info; 2915 2916 unsigned int 2917 distance, 2918 height, 2919 width; 2920 2921 size_t 2922 state; 2923 2924 XEvent 2925 event; 2926 2927 XSegment 2928 segment_info; 2929 2930 /* 2931 Map Command widget. 2932 */ 2933 (void) CloneString(&windows->command.name,"Chop"); 2934 windows->command.data=1; 2935 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL); 2936 (void) XMapRaised(display,windows->command.id); 2937 XClientMessage(display,windows->image.id,windows->im_protocols, 2938 windows->im_update_widget,CurrentTime); 2939 /* 2940 Track pointer until button 1 is pressed. 2941 */ 2942 XQueryPosition(display,windows->image.id,&x,&y); 2943 (void) XSelectInput(display,windows->image.id, 2944 windows->image.attributes.event_mask | PointerMotionMask); 2945 state=DefaultState; 2946 do 2947 { 2948 if( IfMagickTrue(windows->info.mapped) ) 2949 { 2950 /* 2951 Display pointer position. 2952 */ 2953 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 2954 x+windows->image.x,y+windows->image.y); 2955 XInfoWidget(display,windows,text); 2956 } 2957 /* 2958 Wait for next event. 2959 */ 2960 XScreenEvent(display,windows,&event,exception); 2961 if (event.xany.window == windows->command.id) 2962 { 2963 /* 2964 Select a command from the Command widget. 2965 */ 2966 id=XCommandWidget(display,windows,ChopMenu,&event); 2967 if (id < 0) 2968 continue; 2969 switch (ChopCommands[id]) 2970 { 2971 case ChopDirectionCommand: 2972 { 2973 char 2974 command[MaxTextExtent]; 2975 2976 static const char 2977 *Directions[] = 2978 { 2979 "horizontal", 2980 "vertical", 2981 (char *) NULL, 2982 }; 2983 2984 /* 2985 Select a command from the pop-up menu. 2986 */ 2987 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 2988 if (id >= 0) 2989 direction=DirectionCommands[id]; 2990 break; 2991 } 2992 case ChopHelpCommand: 2993 { 2994 XTextViewWidget(display,resource_info,windows,MagickFalse, 2995 "Help Viewer - Image Chop",ImageChopHelp); 2996 break; 2997 } 2998 case ChopDismissCommand: 2999 { 3000 /* 3001 Prematurely exit. 3002 */ 3003 state|=EscapeState; 3004 state|=ExitState; 3005 break; 3006 } 3007 default: 3008 break; 3009 } 3010 continue; 3011 } 3012 switch (event.type) 3013 { 3014 case ButtonPress: 3015 { 3016 if (event.xbutton.button != Button1) 3017 break; 3018 if (event.xbutton.window != windows->image.id) 3019 break; 3020 /* 3021 User has committed to start point of chopping line. 3022 */ 3023 segment_info.x1=(short int) event.xbutton.x; 3024 segment_info.x2=(short int) event.xbutton.x; 3025 segment_info.y1=(short int) event.xbutton.y; 3026 segment_info.y2=(short int) event.xbutton.y; 3027 state|=ExitState; 3028 break; 3029 } 3030 case ButtonRelease: 3031 break; 3032 case Expose: 3033 break; 3034 case KeyPress: 3035 { 3036 char 3037 command[MaxTextExtent]; 3038 3039 KeySym 3040 key_symbol; 3041 3042 if (event.xkey.window != windows->image.id) 3043 break; 3044 /* 3045 Respond to a user key press. 3046 */ 3047 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3048 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3049 switch ((int) key_symbol) 3050 { 3051 case XK_Escape: 3052 case XK_F20: 3053 { 3054 /* 3055 Prematurely exit. 3056 */ 3057 state|=EscapeState; 3058 state|=ExitState; 3059 break; 3060 } 3061 case XK_F1: 3062 case XK_Help: 3063 { 3064 (void) XSetFunction(display,windows->image.highlight_context, 3065 GXcopy); 3066 XTextViewWidget(display,resource_info,windows,MagickFalse, 3067 "Help Viewer - Image Chop",ImageChopHelp); 3068 (void) XSetFunction(display,windows->image.highlight_context, 3069 GXinvert); 3070 break; 3071 } 3072 default: 3073 { 3074 (void) XBell(display,0); 3075 break; 3076 } 3077 } 3078 break; 3079 } 3080 case MotionNotify: 3081 { 3082 /* 3083 Map and unmap Info widget as text cursor crosses its boundaries. 3084 */ 3085 x=event.xmotion.x; 3086 y=event.xmotion.y; 3087 if( IfMagickTrue(windows->info.mapped) ) 3088 { 3089 if ((x < (int) (windows->info.x+windows->info.width)) && 3090 (y < (int) (windows->info.y+windows->info.height))) 3091 (void) XWithdrawWindow(display,windows->info.id, 3092 windows->info.screen); 3093 } 3094 else 3095 if ((x > (int) (windows->info.x+windows->info.width)) || 3096 (y > (int) (windows->info.y+windows->info.height))) 3097 (void) XMapWindow(display,windows->info.id); 3098 } 3099 } 3100 } while ((state & ExitState) == 0); 3101 (void) XSelectInput(display,windows->image.id, 3102 windows->image.attributes.event_mask); 3103 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3104 if ((state & EscapeState) != 0) 3105 return(MagickTrue); 3106 /* 3107 Draw line as pointer moves until the mouse button is released. 3108 */ 3109 chop_info.width=0; 3110 chop_info.height=0; 3111 chop_info.x=0; 3112 chop_info.y=0; 3113 distance=0; 3114 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 3115 state=DefaultState; 3116 do 3117 { 3118 if (distance > 9) 3119 { 3120 /* 3121 Display info and draw chopping line. 3122 */ 3123 if( IfMagickFalse(windows->info.mapped) ) 3124 (void) XMapWindow(display,windows->info.id); 3125 (void) FormatLocaleString(text,MaxTextExtent, 3126 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 3127 chop_info.height,(double) chop_info.x,(double) chop_info.y); 3128 XInfoWidget(display,windows,text); 3129 XHighlightLine(display,windows->image.id, 3130 windows->image.highlight_context,&segment_info); 3131 } 3132 else 3133 if( IfMagickTrue(windows->info.mapped) ) 3134 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3135 /* 3136 Wait for next event. 3137 */ 3138 XScreenEvent(display,windows,&event,exception); 3139 if (distance > 9) 3140 XHighlightLine(display,windows->image.id, 3141 windows->image.highlight_context,&segment_info); 3142 switch (event.type) 3143 { 3144 case ButtonPress: 3145 { 3146 segment_info.x2=(short int) event.xmotion.x; 3147 segment_info.y2=(short int) event.xmotion.y; 3148 break; 3149 } 3150 case ButtonRelease: 3151 { 3152 /* 3153 User has committed to chopping line. 3154 */ 3155 segment_info.x2=(short int) event.xbutton.x; 3156 segment_info.y2=(short int) event.xbutton.y; 3157 state|=ExitState; 3158 break; 3159 } 3160 case Expose: 3161 break; 3162 case MotionNotify: 3163 { 3164 segment_info.x2=(short int) event.xmotion.x; 3165 segment_info.y2=(short int) event.xmotion.y; 3166 } 3167 default: 3168 break; 3169 } 3170 /* 3171 Check boundary conditions. 3172 */ 3173 if (segment_info.x2 < 0) 3174 segment_info.x2=0; 3175 else 3176 if (segment_info.x2 > windows->image.ximage->width) 3177 segment_info.x2=windows->image.ximage->width; 3178 if (segment_info.y2 < 0) 3179 segment_info.y2=0; 3180 else 3181 if (segment_info.y2 > windows->image.ximage->height) 3182 segment_info.y2=windows->image.ximage->height; 3183 distance=(unsigned int) 3184 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 3185 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 3186 /* 3187 Compute chopping geometry. 3188 */ 3189 if (direction == HorizontalChopCommand) 3190 { 3191 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 3192 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 3193 chop_info.height=0; 3194 chop_info.y=0; 3195 if (segment_info.x1 > (int) segment_info.x2) 3196 { 3197 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 3198 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 3199 } 3200 } 3201 else 3202 { 3203 chop_info.width=0; 3204 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 3205 chop_info.x=0; 3206 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 3207 if (segment_info.y1 > segment_info.y2) 3208 { 3209 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 3210 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 3211 } 3212 } 3213 } while ((state & ExitState) == 0); 3214 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 3215 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 3216 if (distance <= 9) 3217 return(MagickTrue); 3218 /* 3219 Image chopping is relative to image configuration. 3220 */ 3221 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 3222 exception); 3223 XSetCursorState(display,windows,MagickTrue); 3224 XCheckRefreshWindows(display,windows); 3225 windows->image.window_changes.width=windows->image.ximage->width- 3226 (unsigned int) chop_info.width; 3227 windows->image.window_changes.height=windows->image.ximage->height- 3228 (unsigned int) chop_info.height; 3229 width=(unsigned int) (*image)->columns; 3230 height=(unsigned int) (*image)->rows; 3231 x=0; 3232 y=0; 3233 if (windows->image.crop_geometry != (char *) NULL) 3234 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 3235 scale_factor=(double) width/windows->image.ximage->width; 3236 chop_info.x+=x; 3237 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 3238 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 3239 scale_factor=(double) height/windows->image.ximage->height; 3240 chop_info.y+=y; 3241 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 3242 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 3243 /* 3244 Chop image. 3245 */ 3246 chop_image=ChopImage(*image,&chop_info,exception); 3247 XSetCursorState(display,windows,MagickFalse); 3248 if (chop_image == (Image *) NULL) 3249 return(MagickFalse); 3250 *image=DestroyImage(*image); 3251 *image=chop_image; 3252 /* 3253 Update image configuration. 3254 */ 3255 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3256 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3257 return(MagickTrue); 3258} 3259 3260/* 3261%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3262% % 3263% % 3264% % 3265+ X C o l o r E d i t I m a g e % 3266% % 3267% % 3268% % 3269%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3270% 3271% XColorEditImage() allows the user to interactively change the color of one 3272% pixel for a DirectColor image or one colormap entry for a PseudoClass image. 3273% 3274% The format of the XColorEditImage method is: 3275% 3276% MagickBooleanType XColorEditImage(Display *display, 3277% XResourceInfo *resource_info,XWindows *windows,Image **image, 3278% ExceptionInfo *exception) 3279% 3280% A description of each parameter follows: 3281% 3282% o display: Specifies a connection to an X server; returned from 3283% XOpenDisplay. 3284% 3285% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3286% 3287% o windows: Specifies a pointer to a XWindows structure. 3288% 3289% o image: the image; returned from ReadImage. 3290% 3291% o exception: return any errors or warnings in this structure. 3292% 3293*/ 3294static MagickBooleanType XColorEditImage(Display *display, 3295 XResourceInfo *resource_info,XWindows *windows,Image **image, 3296 ExceptionInfo *exception) 3297{ 3298 static const char 3299 *ColorEditMenu[] = 3300 { 3301 "Method", 3302 "Pixel Color", 3303 "Border Color", 3304 "Fuzz", 3305 "Undo", 3306 "Help", 3307 "Dismiss", 3308 (char *) NULL 3309 }; 3310 3311 static const ModeType 3312 ColorEditCommands[] = 3313 { 3314 ColorEditMethodCommand, 3315 ColorEditColorCommand, 3316 ColorEditBorderCommand, 3317 ColorEditFuzzCommand, 3318 ColorEditUndoCommand, 3319 ColorEditHelpCommand, 3320 ColorEditDismissCommand 3321 }; 3322 3323 static PaintMethod 3324 method = PointMethod; 3325 3326 static unsigned int 3327 pen_id = 0; 3328 3329 static XColor 3330 border_color = { 0, 0, 0, 0, 0, 0 }; 3331 3332 char 3333 command[MaxTextExtent], 3334 text[MaxTextExtent]; 3335 3336 Cursor 3337 cursor; 3338 3339 int 3340 entry, 3341 id, 3342 x, 3343 x_offset, 3344 y, 3345 y_offset; 3346 3347 register Quantum 3348 *q; 3349 3350 register ssize_t 3351 i; 3352 3353 unsigned int 3354 height, 3355 width; 3356 3357 size_t 3358 state; 3359 3360 XColor 3361 color; 3362 3363 XEvent 3364 event; 3365 3366 /* 3367 Map Command widget. 3368 */ 3369 (void) CloneString(&windows->command.name,"Color Edit"); 3370 windows->command.data=4; 3371 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 3372 (void) XMapRaised(display,windows->command.id); 3373 XClientMessage(display,windows->image.id,windows->im_protocols, 3374 windows->im_update_widget,CurrentTime); 3375 /* 3376 Make cursor. 3377 */ 3378 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 3379 resource_info->background_color,resource_info->foreground_color); 3380 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3381 /* 3382 Track pointer until button 1 is pressed. 3383 */ 3384 XQueryPosition(display,windows->image.id,&x,&y); 3385 (void) XSelectInput(display,windows->image.id, 3386 windows->image.attributes.event_mask | PointerMotionMask); 3387 state=DefaultState; 3388 do 3389 { 3390 if( IfMagickTrue(windows->info.mapped) ) 3391 { 3392 /* 3393 Display pointer position. 3394 */ 3395 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 3396 x+windows->image.x,y+windows->image.y); 3397 XInfoWidget(display,windows,text); 3398 } 3399 /* 3400 Wait for next event. 3401 */ 3402 XScreenEvent(display,windows,&event,exception); 3403 if (event.xany.window == windows->command.id) 3404 { 3405 /* 3406 Select a command from the Command widget. 3407 */ 3408 id=XCommandWidget(display,windows,ColorEditMenu,&event); 3409 if (id < 0) 3410 { 3411 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3412 continue; 3413 } 3414 switch (ColorEditCommands[id]) 3415 { 3416 case ColorEditMethodCommand: 3417 { 3418 char 3419 **methods; 3420 3421 /* 3422 Select a method from the pop-up menu. 3423 */ 3424 methods=(char **) GetCommandOptions(MagickMethodOptions); 3425 if (methods == (char **) NULL) 3426 break; 3427 entry=XMenuWidget(display,windows,ColorEditMenu[id], 3428 (const char **) methods,command); 3429 if (entry >= 0) 3430 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 3431 MagickFalse,methods[entry]); 3432 methods=DestroyStringList(methods); 3433 break; 3434 } 3435 case ColorEditColorCommand: 3436 { 3437 const char 3438 *ColorMenu[MaxNumberPens]; 3439 3440 int 3441 pen_number; 3442 3443 /* 3444 Initialize menu selections. 3445 */ 3446 for (i=0; i < (int) (MaxNumberPens-2); i++) 3447 ColorMenu[i]=resource_info->pen_colors[i]; 3448 ColorMenu[MaxNumberPens-2]="Browser..."; 3449 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3450 /* 3451 Select a pen color from the pop-up menu. 3452 */ 3453 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3454 (const char **) ColorMenu,command); 3455 if (pen_number < 0) 3456 break; 3457 if (pen_number == (MaxNumberPens-2)) 3458 { 3459 static char 3460 color_name[MaxTextExtent] = "gray"; 3461 3462 /* 3463 Select a pen color from a dialog. 3464 */ 3465 resource_info->pen_colors[pen_number]=color_name; 3466 XColorBrowserWidget(display,windows,"Select",color_name); 3467 if (*color_name == '\0') 3468 break; 3469 } 3470 /* 3471 Set pen color. 3472 */ 3473 (void) XParseColor(display,windows->map_info->colormap, 3474 resource_info->pen_colors[pen_number],&color); 3475 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 3476 (unsigned int) MaxColors,&color); 3477 windows->pixel_info->pen_colors[pen_number]=color; 3478 pen_id=(unsigned int) pen_number; 3479 break; 3480 } 3481 case ColorEditBorderCommand: 3482 { 3483 const char 3484 *ColorMenu[MaxNumberPens]; 3485 3486 int 3487 pen_number; 3488 3489 /* 3490 Initialize menu selections. 3491 */ 3492 for (i=0; i < (int) (MaxNumberPens-2); i++) 3493 ColorMenu[i]=resource_info->pen_colors[i]; 3494 ColorMenu[MaxNumberPens-2]="Browser..."; 3495 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 3496 /* 3497 Select a pen color from the pop-up menu. 3498 */ 3499 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 3500 (const char **) ColorMenu,command); 3501 if (pen_number < 0) 3502 break; 3503 if (pen_number == (MaxNumberPens-2)) 3504 { 3505 static char 3506 color_name[MaxTextExtent] = "gray"; 3507 3508 /* 3509 Select a pen color from a dialog. 3510 */ 3511 resource_info->pen_colors[pen_number]=color_name; 3512 XColorBrowserWidget(display,windows,"Select",color_name); 3513 if (*color_name == '\0') 3514 break; 3515 } 3516 /* 3517 Set border color. 3518 */ 3519 (void) XParseColor(display,windows->map_info->colormap, 3520 resource_info->pen_colors[pen_number],&border_color); 3521 break; 3522 } 3523 case ColorEditFuzzCommand: 3524 { 3525 static char 3526 fuzz[MaxTextExtent]; 3527 3528 static const char 3529 *FuzzMenu[] = 3530 { 3531 "0%", 3532 "2%", 3533 "5%", 3534 "10%", 3535 "15%", 3536 "Dialog...", 3537 (char *) NULL, 3538 }; 3539 3540 /* 3541 Select a command from the pop-up menu. 3542 */ 3543 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 3544 command); 3545 if (entry < 0) 3546 break; 3547 if (entry != 5) 3548 { 3549 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 3550 QuantumRange+1.0); 3551 break; 3552 } 3553 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 3554 (void) XDialogWidget(display,windows,"Ok", 3555 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 3556 if (*fuzz == '\0') 3557 break; 3558 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 3559 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 3560 1.0); 3561 break; 3562 } 3563 case ColorEditUndoCommand: 3564 { 3565 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 3566 image,exception); 3567 break; 3568 } 3569 case ColorEditHelpCommand: 3570 default: 3571 { 3572 XTextViewWidget(display,resource_info,windows,MagickFalse, 3573 "Help Viewer - Image Annotation",ImageColorEditHelp); 3574 break; 3575 } 3576 case ColorEditDismissCommand: 3577 { 3578 /* 3579 Prematurely exit. 3580 */ 3581 state|=EscapeState; 3582 state|=ExitState; 3583 break; 3584 } 3585 } 3586 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3587 continue; 3588 } 3589 switch (event.type) 3590 { 3591 case ButtonPress: 3592 { 3593 if (event.xbutton.button != Button1) 3594 break; 3595 if ((event.xbutton.window != windows->image.id) && 3596 (event.xbutton.window != windows->magnify.id)) 3597 break; 3598 /* 3599 exit loop. 3600 */ 3601 x=event.xbutton.x; 3602 y=event.xbutton.y; 3603 (void) XMagickCommand(display,resource_info,windows, 3604 SaveToUndoBufferCommand,image,exception); 3605 state|=UpdateConfigurationState; 3606 break; 3607 } 3608 case ButtonRelease: 3609 { 3610 if (event.xbutton.button != Button1) 3611 break; 3612 if ((event.xbutton.window != windows->image.id) && 3613 (event.xbutton.window != windows->magnify.id)) 3614 break; 3615 /* 3616 Update colormap information. 3617 */ 3618 x=event.xbutton.x; 3619 y=event.xbutton.y; 3620 XConfigureImageColormap(display,resource_info,windows,*image,exception); 3621 (void) XConfigureImage(display,resource_info,windows,*image,exception); 3622 XInfoWidget(display,windows,text); 3623 (void) XCheckDefineCursor(display,windows->image.id,cursor); 3624 state&=(~UpdateConfigurationState); 3625 break; 3626 } 3627 case Expose: 3628 break; 3629 case KeyPress: 3630 { 3631 KeySym 3632 key_symbol; 3633 3634 if (event.xkey.window == windows->magnify.id) 3635 { 3636 Window 3637 window; 3638 3639 window=windows->magnify.id; 3640 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 3641 } 3642 if (event.xkey.window != windows->image.id) 3643 break; 3644 /* 3645 Respond to a user key press. 3646 */ 3647 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 3648 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 3649 switch ((int) key_symbol) 3650 { 3651 case XK_Escape: 3652 case XK_F20: 3653 { 3654 /* 3655 Prematurely exit. 3656 */ 3657 state|=ExitState; 3658 break; 3659 } 3660 case XK_F1: 3661 case XK_Help: 3662 { 3663 XTextViewWidget(display,resource_info,windows,MagickFalse, 3664 "Help Viewer - Image Annotation",ImageColorEditHelp); 3665 break; 3666 } 3667 default: 3668 { 3669 (void) XBell(display,0); 3670 break; 3671 } 3672 } 3673 break; 3674 } 3675 case MotionNotify: 3676 { 3677 /* 3678 Map and unmap Info widget as cursor crosses its boundaries. 3679 */ 3680 x=event.xmotion.x; 3681 y=event.xmotion.y; 3682 if( IfMagickTrue(windows->info.mapped) ) 3683 { 3684 if ((x < (int) (windows->info.x+windows->info.width)) && 3685 (y < (int) (windows->info.y+windows->info.height))) 3686 (void) XWithdrawWindow(display,windows->info.id, 3687 windows->info.screen); 3688 } 3689 else 3690 if ((x > (int) (windows->info.x+windows->info.width)) || 3691 (y > (int) (windows->info.y+windows->info.height))) 3692 (void) XMapWindow(display,windows->info.id); 3693 break; 3694 } 3695 default: 3696 break; 3697 } 3698 if (event.xany.window == windows->magnify.id) 3699 { 3700 x=windows->magnify.x-windows->image.x; 3701 y=windows->magnify.y-windows->image.y; 3702 } 3703 x_offset=x; 3704 y_offset=y; 3705 if ((state & UpdateConfigurationState) != 0) 3706 { 3707 CacheView 3708 *image_view; 3709 3710 int 3711 x, 3712 y; 3713 3714 /* 3715 Pixel edit is relative to image configuration. 3716 */ 3717 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 3718 MagickTrue); 3719 color=windows->pixel_info->pen_colors[pen_id]; 3720 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 3721 width=(unsigned int) (*image)->columns; 3722 height=(unsigned int) (*image)->rows; 3723 x=0; 3724 y=0; 3725 if (windows->image.crop_geometry != (char *) NULL) 3726 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 3727 &width,&height); 3728 x_offset=(int) 3729 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 3730 y_offset=(int) 3731 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 3732 if ((x_offset < 0) || (y_offset < 0)) 3733 continue; 3734 if ((x_offset >= (int) (*image)->columns) || 3735 (y_offset >= (int) (*image)->rows)) 3736 continue; 3737 image_view=AcquireAuthenticCacheView(*image,exception); 3738 switch (method) 3739 { 3740 case PointMethod: 3741 default: 3742 { 3743 /* 3744 Update color information using point algorithm. 3745 */ 3746 if( IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) ) 3747 return(MagickFalse); 3748 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 3749 (ssize_t) y_offset,1,1,exception); 3750 if (q == (Quantum *) NULL) 3751 break; 3752 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3753 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3754 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3755 (void) SyncCacheViewAuthenticPixels(image_view,exception); 3756 break; 3757 } 3758 case ReplaceMethod: 3759 { 3760 PixelInfo 3761 pixel, 3762 target; 3763 3764 /* 3765 Update color information using replace algorithm. 3766 */ 3767 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t) 3768 x_offset,(ssize_t) y_offset,&target,exception); 3769 if ((*image)->storage_class == DirectClass) 3770 { 3771 for (y=0; y < (int) (*image)->rows; y++) 3772 { 3773 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3774 (*image)->columns,1,exception); 3775 if (q == (Quantum *) NULL) 3776 break; 3777 for (x=0; x < (int) (*image)->columns; x++) 3778 { 3779 GetPixelInfoPixel(*image,q,&pixel); 3780 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 3781 { 3782 SetPixelRed(*image,ScaleShortToQuantum( 3783 color.red),q); 3784 SetPixelGreen(*image,ScaleShortToQuantum( 3785 color.green),q); 3786 SetPixelBlue(*image,ScaleShortToQuantum( 3787 color.blue),q); 3788 } 3789 q+=GetPixelChannels(*image); 3790 } 3791 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 3792 break; 3793 } 3794 } 3795 else 3796 { 3797 for (i=0; i < (ssize_t) (*image)->colors; i++) 3798 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target)) 3799 { 3800 (*image)->colormap[i].red=(double) ScaleShortToQuantum( 3801 color.red); 3802 (*image)->colormap[i].green=(double) ScaleShortToQuantum( 3803 color.green); 3804 (*image)->colormap[i].blue=(double) ScaleShortToQuantum( 3805 color.blue); 3806 } 3807 (void) SyncImage(*image,exception); 3808 } 3809 break; 3810 } 3811 case FloodfillMethod: 3812 case FillToBorderMethod: 3813 { 3814 DrawInfo 3815 *draw_info; 3816 3817 PixelInfo 3818 target; 3819 3820 /* 3821 Update color information using floodfill algorithm. 3822 */ 3823 (void) GetOneVirtualPixelInfo(*image, 3824 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 3825 y_offset,&target,exception); 3826 if (method == FillToBorderMethod) 3827 { 3828 target.red=(double) 3829 ScaleShortToQuantum(border_color.red); 3830 target.green=(double) 3831 ScaleShortToQuantum(border_color.green); 3832 target.blue=(double) 3833 ScaleShortToQuantum(border_color.blue); 3834 } 3835 draw_info=CloneDrawInfo(resource_info->image_info, 3836 (DrawInfo *) NULL); 3837 (void) QueryColorCompliance(resource_info->pen_colors[pen_id], 3838 AllCompliance,&draw_info->fill,exception); 3839 (void) FloodfillPaintImage(*image,draw_info,&target, 3840 (ssize_t)x_offset,(ssize_t)y_offset, 3841 IsMagickFalse(method == FloodfillMethod),exception); 3842 draw_info=DestroyDrawInfo(draw_info); 3843 break; 3844 } 3845 case ResetMethod: 3846 { 3847 /* 3848 Update color information using reset algorithm. 3849 */ 3850 if( IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) ) 3851 return(MagickFalse); 3852 for (y=0; y < (int) (*image)->rows; y++) 3853 { 3854 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 3855 (*image)->columns,1,exception); 3856 if (q == (Quantum *) NULL) 3857 break; 3858 for (x=0; x < (int) (*image)->columns; x++) 3859 { 3860 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 3861 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 3862 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 3863 q+=GetPixelChannels(*image); 3864 } 3865 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 3866 break; 3867 } 3868 break; 3869 } 3870 } 3871 image_view=DestroyCacheView(image_view); 3872 state&=(~UpdateConfigurationState); 3873 } 3874 } while ((state & ExitState) == 0); 3875 (void) XSelectInput(display,windows->image.id, 3876 windows->image.attributes.event_mask); 3877 XSetCursorState(display,windows,MagickFalse); 3878 (void) XFreeCursor(display,cursor); 3879 return(MagickTrue); 3880} 3881 3882/* 3883%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3884% % 3885% % 3886% % 3887+ X C o m p o s i t e I m a g e % 3888% % 3889% % 3890% % 3891%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3892% 3893% XCompositeImage() requests an image name from the user, reads the image and 3894% composites it with the X window image at a location the user chooses with 3895% the pointer. 3896% 3897% The format of the XCompositeImage method is: 3898% 3899% MagickBooleanType XCompositeImage(Display *display, 3900% XResourceInfo *resource_info,XWindows *windows,Image *image, 3901% ExceptionInfo *exception) 3902% 3903% A description of each parameter follows: 3904% 3905% o display: Specifies a connection to an X server; returned from 3906% XOpenDisplay. 3907% 3908% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 3909% 3910% o windows: Specifies a pointer to a XWindows structure. 3911% 3912% o image: the image; returned from ReadImage. 3913% 3914% o exception: return any errors or warnings in this structure. 3915% 3916*/ 3917static MagickBooleanType XCompositeImage(Display *display, 3918 XResourceInfo *resource_info,XWindows *windows,Image *image, 3919 ExceptionInfo *exception) 3920{ 3921 static char 3922 displacement_geometry[MaxTextExtent] = "30x30", 3923 filename[MaxTextExtent] = "\0"; 3924 3925 static const char 3926 *CompositeMenu[] = 3927 { 3928 "Operators", 3929 "Dissolve", 3930 "Displace", 3931 "Help", 3932 "Dismiss", 3933 (char *) NULL 3934 }; 3935 3936 static CompositeOperator 3937 compose = CopyCompositeOp; 3938 3939 static const ModeType 3940 CompositeCommands[] = 3941 { 3942 CompositeOperatorsCommand, 3943 CompositeDissolveCommand, 3944 CompositeDisplaceCommand, 3945 CompositeHelpCommand, 3946 CompositeDismissCommand 3947 }; 3948 3949 char 3950 text[MaxTextExtent]; 3951 3952 Cursor 3953 cursor; 3954 3955 Image 3956 *composite_image; 3957 3958 int 3959 entry, 3960 id, 3961 x, 3962 y; 3963 3964 double 3965 blend, 3966 scale_factor; 3967 3968 RectangleInfo 3969 highlight_info, 3970 composite_info; 3971 3972 unsigned int 3973 height, 3974 width; 3975 3976 size_t 3977 state; 3978 3979 XEvent 3980 event; 3981 3982 /* 3983 Request image file name from user. 3984 */ 3985 XFileBrowserWidget(display,windows,"Composite",filename); 3986 if (*filename == '\0') 3987 return(MagickTrue); 3988 /* 3989 Read image. 3990 */ 3991 XSetCursorState(display,windows,MagickTrue); 3992 XCheckRefreshWindows(display,windows); 3993 (void) CopyMagickString(resource_info->image_info->filename,filename, 3994 MaxTextExtent); 3995 composite_image=ReadImage(resource_info->image_info,exception); 3996 CatchException(exception); 3997 XSetCursorState(display,windows,MagickFalse); 3998 if (composite_image == (Image *) NULL) 3999 return(MagickFalse); 4000 /* 4001 Map Command widget. 4002 */ 4003 (void) CloneString(&windows->command.name,"Composite"); 4004 windows->command.data=1; 4005 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 4006 (void) XMapRaised(display,windows->command.id); 4007 XClientMessage(display,windows->image.id,windows->im_protocols, 4008 windows->im_update_widget,CurrentTime); 4009 /* 4010 Track pointer until button 1 is pressed. 4011 */ 4012 XQueryPosition(display,windows->image.id,&x,&y); 4013 (void) XSelectInput(display,windows->image.id, 4014 windows->image.attributes.event_mask | PointerMotionMask); 4015 composite_info.x=(ssize_t) windows->image.x+x; 4016 composite_info.y=(ssize_t) windows->image.y+y; 4017 composite_info.width=0; 4018 composite_info.height=0; 4019 cursor=XCreateFontCursor(display,XC_ul_angle); 4020 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4021 blend=0.0; 4022 state=DefaultState; 4023 do 4024 { 4025 if( IfMagickTrue(windows->info.mapped) ) 4026 { 4027 /* 4028 Display pointer position. 4029 */ 4030 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4031 (long) composite_info.x,(long) composite_info.y); 4032 XInfoWidget(display,windows,text); 4033 } 4034 highlight_info=composite_info; 4035 highlight_info.x=composite_info.x-windows->image.x; 4036 highlight_info.y=composite_info.y-windows->image.y; 4037 XHighlightRectangle(display,windows->image.id, 4038 windows->image.highlight_context,&highlight_info); 4039 /* 4040 Wait for next event. 4041 */ 4042 XScreenEvent(display,windows,&event,exception); 4043 XHighlightRectangle(display,windows->image.id, 4044 windows->image.highlight_context,&highlight_info); 4045 if (event.xany.window == windows->command.id) 4046 { 4047 /* 4048 Select a command from the Command widget. 4049 */ 4050 id=XCommandWidget(display,windows,CompositeMenu,&event); 4051 if (id < 0) 4052 continue; 4053 switch (CompositeCommands[id]) 4054 { 4055 case CompositeOperatorsCommand: 4056 { 4057 char 4058 command[MaxTextExtent], 4059 **operators; 4060 4061 /* 4062 Select a command from the pop-up menu. 4063 */ 4064 operators=GetCommandOptions(MagickComposeOptions); 4065 if (operators == (char **) NULL) 4066 break; 4067 entry=XMenuWidget(display,windows,CompositeMenu[id], 4068 (const char **) operators,command); 4069 if (entry >= 0) 4070 compose=(CompositeOperator) ParseCommandOption( 4071 MagickComposeOptions,MagickFalse,operators[entry]); 4072 operators=DestroyStringList(operators); 4073 break; 4074 } 4075 case CompositeDissolveCommand: 4076 { 4077 static char 4078 factor[MaxTextExtent] = "20.0"; 4079 4080 /* 4081 Dissolve the two images a given percent. 4082 */ 4083 (void) XSetFunction(display,windows->image.highlight_context, 4084 GXcopy); 4085 (void) XDialogWidget(display,windows,"Dissolve", 4086 "Enter the blend factor (0.0 - 99.9%):",factor); 4087 (void) XSetFunction(display,windows->image.highlight_context, 4088 GXinvert); 4089 if (*factor == '\0') 4090 break; 4091 blend=StringToDouble(factor,(char **) NULL); 4092 compose=DissolveCompositeOp; 4093 break; 4094 } 4095 case CompositeDisplaceCommand: 4096 { 4097 /* 4098 Get horizontal and vertical scale displacement geometry. 4099 */ 4100 (void) XSetFunction(display,windows->image.highlight_context, 4101 GXcopy); 4102 (void) XDialogWidget(display,windows,"Displace", 4103 "Enter the horizontal and vertical scale:",displacement_geometry); 4104 (void) XSetFunction(display,windows->image.highlight_context, 4105 GXinvert); 4106 if (*displacement_geometry == '\0') 4107 break; 4108 compose=DisplaceCompositeOp; 4109 break; 4110 } 4111 case CompositeHelpCommand: 4112 { 4113 (void) XSetFunction(display,windows->image.highlight_context, 4114 GXcopy); 4115 XTextViewWidget(display,resource_info,windows,MagickFalse, 4116 "Help Viewer - Image Composite",ImageCompositeHelp); 4117 (void) XSetFunction(display,windows->image.highlight_context, 4118 GXinvert); 4119 break; 4120 } 4121 case CompositeDismissCommand: 4122 { 4123 /* 4124 Prematurely exit. 4125 */ 4126 state|=EscapeState; 4127 state|=ExitState; 4128 break; 4129 } 4130 default: 4131 break; 4132 } 4133 continue; 4134 } 4135 switch (event.type) 4136 { 4137 case ButtonPress: 4138 { 4139 if( IfMagickTrue(image->debug) ) 4140 (void) LogMagickEvent(X11Event,GetMagickModule(), 4141 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 4142 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4143 if (event.xbutton.button != Button1) 4144 break; 4145 if (event.xbutton.window != windows->image.id) 4146 break; 4147 /* 4148 Change cursor. 4149 */ 4150 composite_info.width=composite_image->columns; 4151 composite_info.height=composite_image->rows; 4152 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4153 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4154 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4155 break; 4156 } 4157 case ButtonRelease: 4158 { 4159 if( IfMagickTrue(image->debug) ) 4160 (void) LogMagickEvent(X11Event,GetMagickModule(), 4161 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 4162 event.xbutton.button,event.xbutton.x,event.xbutton.y); 4163 if (event.xbutton.button != Button1) 4164 break; 4165 if (event.xbutton.window != windows->image.id) 4166 break; 4167 if ((composite_info.width != 0) && (composite_info.height != 0)) 4168 { 4169 /* 4170 User has selected the location of the composite image. 4171 */ 4172 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4173 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4174 state|=ExitState; 4175 } 4176 break; 4177 } 4178 case Expose: 4179 break; 4180 case KeyPress: 4181 { 4182 char 4183 command[MaxTextExtent]; 4184 4185 KeySym 4186 key_symbol; 4187 4188 int 4189 length; 4190 4191 if (event.xkey.window != windows->image.id) 4192 break; 4193 /* 4194 Respond to a user key press. 4195 */ 4196 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 4197 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4198 *(command+length)='\0'; 4199 if( IfMagickTrue(image->debug) ) 4200 (void) LogMagickEvent(X11Event,GetMagickModule(), 4201 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 4202 switch ((int) key_symbol) 4203 { 4204 case XK_Escape: 4205 case XK_F20: 4206 { 4207 /* 4208 Prematurely exit. 4209 */ 4210 composite_image=DestroyImage(composite_image); 4211 state|=EscapeState; 4212 state|=ExitState; 4213 break; 4214 } 4215 case XK_F1: 4216 case XK_Help: 4217 { 4218 (void) XSetFunction(display,windows->image.highlight_context, 4219 GXcopy); 4220 XTextViewWidget(display,resource_info,windows,MagickFalse, 4221 "Help Viewer - Image Composite",ImageCompositeHelp); 4222 (void) XSetFunction(display,windows->image.highlight_context, 4223 GXinvert); 4224 break; 4225 } 4226 default: 4227 { 4228 (void) XBell(display,0); 4229 break; 4230 } 4231 } 4232 break; 4233 } 4234 case MotionNotify: 4235 { 4236 /* 4237 Map and unmap Info widget as text cursor crosses its boundaries. 4238 */ 4239 x=event.xmotion.x; 4240 y=event.xmotion.y; 4241 if( IfMagickTrue(windows->info.mapped) ) 4242 { 4243 if ((x < (int) (windows->info.x+windows->info.width)) && 4244 (y < (int) (windows->info.y+windows->info.height))) 4245 (void) XWithdrawWindow(display,windows->info.id, 4246 windows->info.screen); 4247 } 4248 else 4249 if ((x > (int) (windows->info.x+windows->info.width)) || 4250 (y > (int) (windows->info.y+windows->info.height))) 4251 (void) XMapWindow(display,windows->info.id); 4252 composite_info.x=(ssize_t) windows->image.x+x; 4253 composite_info.y=(ssize_t) windows->image.y+y; 4254 break; 4255 } 4256 default: 4257 { 4258 if( IfMagickTrue(image->debug) ) 4259 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 4260 event.type); 4261 break; 4262 } 4263 } 4264 } while ((state & ExitState) == 0); 4265 (void) XSelectInput(display,windows->image.id, 4266 windows->image.attributes.event_mask); 4267 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 4268 XSetCursorState(display,windows,MagickFalse); 4269 (void) XFreeCursor(display,cursor); 4270 if ((state & EscapeState) != 0) 4271 return(MagickTrue); 4272 /* 4273 Image compositing is relative to image configuration. 4274 */ 4275 XSetCursorState(display,windows,MagickTrue); 4276 XCheckRefreshWindows(display,windows); 4277 width=(unsigned int) image->columns; 4278 height=(unsigned int) image->rows; 4279 x=0; 4280 y=0; 4281 if (windows->image.crop_geometry != (char *) NULL) 4282 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 4283 scale_factor=(double) width/windows->image.ximage->width; 4284 composite_info.x+=x; 4285 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 4286 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 4287 scale_factor=(double) height/windows->image.ximage->height; 4288 composite_info.y+=y; 4289 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 4290 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 4291 if ((composite_info.width != composite_image->columns) || 4292 (composite_info.height != composite_image->rows)) 4293 { 4294 Image 4295 *resize_image; 4296 4297 /* 4298 Scale composite image. 4299 */ 4300 resize_image=ResizeImage(composite_image,composite_info.width, 4301 composite_info.height,composite_image->filter,exception); 4302 composite_image=DestroyImage(composite_image); 4303 if (resize_image == (Image *) NULL) 4304 { 4305 XSetCursorState(display,windows,MagickFalse); 4306 return(MagickFalse); 4307 } 4308 composite_image=resize_image; 4309 } 4310 if (compose == DisplaceCompositeOp) 4311 (void) SetImageArtifact(composite_image,"compose:args", 4312 displacement_geometry); 4313 if (blend != 0.0) 4314 { 4315 CacheView 4316 *image_view; 4317 4318 int 4319 y; 4320 4321 Quantum 4322 opacity; 4323 4324 register int 4325 x; 4326 4327 register Quantum 4328 *q; 4329 4330 /* 4331 Create mattes for blending. 4332 */ 4333 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception); 4334 opacity=(Quantum) (ScaleQuantumToChar(QuantumRange)- 4335 ((ssize_t) ScaleQuantumToChar(QuantumRange)*blend)/100); 4336 if( IfMagickFalse(SetImageStorageClass(image,DirectClass,exception)) ) 4337 return(MagickFalse); 4338 image->alpha_trait=BlendPixelTrait; 4339 image_view=AcquireAuthenticCacheView(image,exception); 4340 for (y=0; y < (int) image->rows; y++) 4341 { 4342 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 4343 exception); 4344 if (q == (Quantum *) NULL) 4345 break; 4346 for (x=0; x < (int) image->columns; x++) 4347 { 4348 SetPixelAlpha(image,opacity,q); 4349 q+=GetPixelChannels(image); 4350 } 4351 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 4352 break; 4353 } 4354 image_view=DestroyCacheView(image_view); 4355 } 4356 /* 4357 Composite image with X Image window. 4358 */ 4359 (void) CompositeImage(image,composite_image,compose,MagickTrue, 4360 composite_info.x,composite_info.y,exception); 4361 composite_image=DestroyImage(composite_image); 4362 XSetCursorState(display,windows,MagickFalse); 4363 /* 4364 Update image configuration. 4365 */ 4366 XConfigureImageColormap(display,resource_info,windows,image,exception); 4367 (void) XConfigureImage(display,resource_info,windows,image,exception); 4368 return(MagickTrue); 4369} 4370 4371/* 4372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4373% % 4374% % 4375% % 4376+ X C o n f i g u r e I m a g e % 4377% % 4378% % 4379% % 4380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4381% 4382% XConfigureImage() creates a new X image. It also notifies the window 4383% manager of the new image size and configures the transient widows. 4384% 4385% The format of the XConfigureImage method is: 4386% 4387% MagickBooleanType XConfigureImage(Display *display, 4388% XResourceInfo *resource_info,XWindows *windows,Image *image, 4389% ExceptionInfo *exception) 4390% 4391% A description of each parameter follows: 4392% 4393% o display: Specifies a connection to an X server; returned from 4394% XOpenDisplay. 4395% 4396% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4397% 4398% o windows: Specifies a pointer to a XWindows structure. 4399% 4400% o image: the image. 4401% 4402% o exception: return any errors or warnings in this structure. 4403% 4404% o exception: return any errors or warnings in this structure. 4405% 4406*/ 4407static MagickBooleanType XConfigureImage(Display *display, 4408 XResourceInfo *resource_info,XWindows *windows,Image *image, 4409 ExceptionInfo *exception) 4410{ 4411 char 4412 geometry[MaxTextExtent]; 4413 4414 MagickStatusType 4415 status; 4416 4417 size_t 4418 mask, 4419 height, 4420 width; 4421 4422 ssize_t 4423 x, 4424 y; 4425 4426 XSizeHints 4427 *size_hints; 4428 4429 XWindowChanges 4430 window_changes; 4431 4432 /* 4433 Dismiss if window dimensions are zero. 4434 */ 4435 width=(unsigned int) windows->image.window_changes.width; 4436 height=(unsigned int) windows->image.window_changes.height; 4437 if( IfMagickTrue(image->debug) ) 4438 (void) LogMagickEvent(X11Event,GetMagickModule(), 4439 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 4440 windows->image.ximage->height,(double) width,(double) height); 4441 if ((width*height) == 0) 4442 return(MagickTrue); 4443 x=0; 4444 y=0; 4445 /* 4446 Resize image to fit Image window dimensions. 4447 */ 4448 XSetCursorState(display,windows,MagickTrue); 4449 (void) XFlush(display); 4450 if (((int) width != windows->image.ximage->width) || 4451 ((int) height != windows->image.ximage->height)) 4452 image->taint=MagickTrue; 4453 windows->magnify.x=(int) 4454 width*windows->magnify.x/windows->image.ximage->width; 4455 windows->magnify.y=(int) 4456 height*windows->magnify.y/windows->image.ximage->height; 4457 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 4458 windows->image.y=(int) 4459 (height*windows->image.y/windows->image.ximage->height); 4460 status=XMakeImage(display,resource_info,&windows->image,image, 4461 (unsigned int) width,(unsigned int) height,exception); 4462 if( IfMagickFalse(status) ) 4463 XNoticeWidget(display,windows,"Unable to configure X image:", 4464 windows->image.name); 4465 /* 4466 Notify window manager of the new configuration. 4467 */ 4468 if (resource_info->image_geometry != (char *) NULL) 4469 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!", 4470 resource_info->image_geometry); 4471 else 4472 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 4473 XDisplayWidth(display,windows->image.screen), 4474 XDisplayHeight(display,windows->image.screen)); 4475 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 4476 window_changes.width=(int) width; 4477 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 4478 window_changes.width=XDisplayWidth(display,windows->image.screen); 4479 window_changes.height=(int) height; 4480 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 4481 window_changes.height=XDisplayHeight(display,windows->image.screen); 4482 mask=(size_t) (CWWidth | CWHeight); 4483 if (resource_info->backdrop) 4484 { 4485 mask|=CWX | CWY; 4486 window_changes.x=(int) 4487 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 4488 window_changes.y=(int) 4489 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 4490 } 4491 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 4492 (unsigned int) mask,&window_changes); 4493 (void) XClearWindow(display,windows->image.id); 4494 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 4495 /* 4496 Update Magnify window configuration. 4497 */ 4498 if( IfMagickTrue(windows->magnify.mapped) ) 4499 XMakeMagnifyImage(display,windows,exception); 4500 windows->pan.crop_geometry=windows->image.crop_geometry; 4501 XBestIconSize(display,&windows->pan,image); 4502 while (((windows->pan.width << 1) < MaxIconSize) && 4503 ((windows->pan.height << 1) < MaxIconSize)) 4504 { 4505 windows->pan.width<<=1; 4506 windows->pan.height<<=1; 4507 } 4508 if (windows->pan.geometry != (char *) NULL) 4509 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 4510 &windows->pan.width,&windows->pan.height); 4511 window_changes.width=(int) windows->pan.width; 4512 window_changes.height=(int) windows->pan.height; 4513 size_hints=XAllocSizeHints(); 4514 if (size_hints != (XSizeHints *) NULL) 4515 { 4516 /* 4517 Set new size hints. 4518 */ 4519 size_hints->flags=PSize | PMinSize | PMaxSize; 4520 size_hints->width=window_changes.width; 4521 size_hints->height=window_changes.height; 4522 size_hints->min_width=size_hints->width; 4523 size_hints->min_height=size_hints->height; 4524 size_hints->max_width=size_hints->width; 4525 size_hints->max_height=size_hints->height; 4526 (void) XSetNormalHints(display,windows->pan.id,size_hints); 4527 (void) XFree((void *) size_hints); 4528 } 4529 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 4530 (unsigned int) (CWWidth | CWHeight),&window_changes); 4531 /* 4532 Update icon window configuration. 4533 */ 4534 windows->icon.crop_geometry=windows->image.crop_geometry; 4535 XBestIconSize(display,&windows->icon,image); 4536 window_changes.width=(int) windows->icon.width; 4537 window_changes.height=(int) windows->icon.height; 4538 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 4539 (unsigned int) (CWWidth | CWHeight),&window_changes); 4540 XSetCursorState(display,windows,MagickFalse); 4541 return(IsMagickTrue(status)); 4542} 4543 4544/* 4545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4546% % 4547% % 4548% % 4549+ X C r o p I m a g e % 4550% % 4551% % 4552% % 4553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4554% 4555% XCropImage() allows the user to select a region of the image and crop, copy, 4556% or cut it. For copy or cut, the image can subsequently be composited onto 4557% the image with XPasteImage. 4558% 4559% The format of the XCropImage method is: 4560% 4561% MagickBooleanType XCropImage(Display *display, 4562% XResourceInfo *resource_info,XWindows *windows,Image *image, 4563% const ClipboardMode mode,ExceptionInfo *exception) 4564% 4565% A description of each parameter follows: 4566% 4567% o display: Specifies a connection to an X server; returned from 4568% XOpenDisplay. 4569% 4570% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 4571% 4572% o windows: Specifies a pointer to a XWindows structure. 4573% 4574% o image: the image; returned from ReadImage. 4575% 4576% o mode: This unsigned value specified whether the image should be 4577% cropped, copied, or cut. 4578% 4579% o exception: return any errors or warnings in this structure. 4580% 4581*/ 4582static MagickBooleanType XCropImage(Display *display, 4583 XResourceInfo *resource_info,XWindows *windows,Image *image, 4584 const ClipboardMode mode,ExceptionInfo *exception) 4585{ 4586 static const char 4587 *CropModeMenu[] = 4588 { 4589 "Help", 4590 "Dismiss", 4591 (char *) NULL 4592 }, 4593 *RectifyModeMenu[] = 4594 { 4595 "Crop", 4596 "Help", 4597 "Dismiss", 4598 (char *) NULL 4599 }; 4600 4601 static const ModeType 4602 CropCommands[] = 4603 { 4604 CropHelpCommand, 4605 CropDismissCommand 4606 }, 4607 RectifyCommands[] = 4608 { 4609 RectifyCopyCommand, 4610 RectifyHelpCommand, 4611 RectifyDismissCommand 4612 }; 4613 4614 CacheView 4615 *image_view; 4616 4617 char 4618 command[MaxTextExtent], 4619 text[MaxTextExtent]; 4620 4621 Cursor 4622 cursor; 4623 4624 int 4625 id, 4626 x, 4627 y; 4628 4629 KeySym 4630 key_symbol; 4631 4632 Image 4633 *crop_image; 4634 4635 double 4636 scale_factor; 4637 4638 RectangleInfo 4639 crop_info, 4640 highlight_info; 4641 4642 register Quantum 4643 *q; 4644 4645 unsigned int 4646 height, 4647 width; 4648 4649 size_t 4650 state; 4651 4652 XEvent 4653 event; 4654 4655 /* 4656 Map Command widget. 4657 */ 4658 switch (mode) 4659 { 4660 case CopyMode: 4661 { 4662 (void) CloneString(&windows->command.name,"Copy"); 4663 break; 4664 } 4665 case CropMode: 4666 { 4667 (void) CloneString(&windows->command.name,"Crop"); 4668 break; 4669 } 4670 case CutMode: 4671 { 4672 (void) CloneString(&windows->command.name,"Cut"); 4673 break; 4674 } 4675 } 4676 RectifyModeMenu[0]=windows->command.name; 4677 windows->command.data=0; 4678 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 4679 (void) XMapRaised(display,windows->command.id); 4680 XClientMessage(display,windows->image.id,windows->im_protocols, 4681 windows->im_update_widget,CurrentTime); 4682 /* 4683 Track pointer until button 1 is pressed. 4684 */ 4685 XQueryPosition(display,windows->image.id,&x,&y); 4686 (void) XSelectInput(display,windows->image.id, 4687 windows->image.attributes.event_mask | PointerMotionMask); 4688 crop_info.x=(ssize_t) windows->image.x+x; 4689 crop_info.y=(ssize_t) windows->image.y+y; 4690 crop_info.width=0; 4691 crop_info.height=0; 4692 cursor=XCreateFontCursor(display,XC_fleur); 4693 state=DefaultState; 4694 do 4695 { 4696 if( IfMagickTrue(windows->info.mapped) ) 4697 { 4698 /* 4699 Display pointer position. 4700 */ 4701 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 4702 (long) crop_info.x,(long) crop_info.y); 4703 XInfoWidget(display,windows,text); 4704 } 4705 /* 4706 Wait for next event. 4707 */ 4708 XScreenEvent(display,windows,&event,exception); 4709 if (event.xany.window == windows->command.id) 4710 { 4711 /* 4712 Select a command from the Command widget. 4713 */ 4714 id=XCommandWidget(display,windows,CropModeMenu,&event); 4715 if (id < 0) 4716 continue; 4717 switch (CropCommands[id]) 4718 { 4719 case CropHelpCommand: 4720 { 4721 switch (mode) 4722 { 4723 case CopyMode: 4724 { 4725 XTextViewWidget(display,resource_info,windows,MagickFalse, 4726 "Help Viewer - Image Copy",ImageCopyHelp); 4727 break; 4728 } 4729 case CropMode: 4730 { 4731 XTextViewWidget(display,resource_info,windows,MagickFalse, 4732 "Help Viewer - Image Crop",ImageCropHelp); 4733 break; 4734 } 4735 case CutMode: 4736 { 4737 XTextViewWidget(display,resource_info,windows,MagickFalse, 4738 "Help Viewer - Image Cut",ImageCutHelp); 4739 break; 4740 } 4741 } 4742 break; 4743 } 4744 case CropDismissCommand: 4745 { 4746 /* 4747 Prematurely exit. 4748 */ 4749 state|=EscapeState; 4750 state|=ExitState; 4751 break; 4752 } 4753 default: 4754 break; 4755 } 4756 continue; 4757 } 4758 switch (event.type) 4759 { 4760 case ButtonPress: 4761 { 4762 if (event.xbutton.button != Button1) 4763 break; 4764 if (event.xbutton.window != windows->image.id) 4765 break; 4766 /* 4767 Note first corner of cropping rectangle-- exit loop. 4768 */ 4769 (void) XCheckDefineCursor(display,windows->image.id,cursor); 4770 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4771 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4772 state|=ExitState; 4773 break; 4774 } 4775 case ButtonRelease: 4776 break; 4777 case Expose: 4778 break; 4779 case KeyPress: 4780 { 4781 if (event.xkey.window != windows->image.id) 4782 break; 4783 /* 4784 Respond to a user key press. 4785 */ 4786 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 4787 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 4788 switch ((int) key_symbol) 4789 { 4790 case XK_Escape: 4791 case XK_F20: 4792 { 4793 /* 4794 Prematurely exit. 4795 */ 4796 state|=EscapeState; 4797 state|=ExitState; 4798 break; 4799 } 4800 case XK_F1: 4801 case XK_Help: 4802 { 4803 switch (mode) 4804 { 4805 case CopyMode: 4806 { 4807 XTextViewWidget(display,resource_info,windows,MagickFalse, 4808 "Help Viewer - Image Copy",ImageCopyHelp); 4809 break; 4810 } 4811 case CropMode: 4812 { 4813 XTextViewWidget(display,resource_info,windows,MagickFalse, 4814 "Help Viewer - Image Crop",ImageCropHelp); 4815 break; 4816 } 4817 case CutMode: 4818 { 4819 XTextViewWidget(display,resource_info,windows,MagickFalse, 4820 "Help Viewer - Image Cut",ImageCutHelp); 4821 break; 4822 } 4823 } 4824 break; 4825 } 4826 default: 4827 { 4828 (void) XBell(display,0); 4829 break; 4830 } 4831 } 4832 break; 4833 } 4834 case MotionNotify: 4835 { 4836 if (event.xmotion.window != windows->image.id) 4837 break; 4838 /* 4839 Map and unmap Info widget as text cursor crosses its boundaries. 4840 */ 4841 x=event.xmotion.x; 4842 y=event.xmotion.y; 4843 if( IfMagickTrue(windows->info.mapped) ) 4844 { 4845 if ((x < (int) (windows->info.x+windows->info.width)) && 4846 (y < (int) (windows->info.y+windows->info.height))) 4847 (void) XWithdrawWindow(display,windows->info.id, 4848 windows->info.screen); 4849 } 4850 else 4851 if ((x > (int) (windows->info.x+windows->info.width)) || 4852 (y > (int) (windows->info.y+windows->info.height))) 4853 (void) XMapWindow(display,windows->info.id); 4854 crop_info.x=(ssize_t) windows->image.x+x; 4855 crop_info.y=(ssize_t) windows->image.y+y; 4856 break; 4857 } 4858 default: 4859 break; 4860 } 4861 } while ((state & ExitState) == 0); 4862 (void) XSelectInput(display,windows->image.id, 4863 windows->image.attributes.event_mask); 4864 if ((state & EscapeState) != 0) 4865 { 4866 /* 4867 User want to exit without cropping. 4868 */ 4869 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4870 (void) XFreeCursor(display,cursor); 4871 return(MagickTrue); 4872 } 4873 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 4874 do 4875 { 4876 /* 4877 Size rectangle as pointer moves until the mouse button is released. 4878 */ 4879 x=(int) crop_info.x; 4880 y=(int) crop_info.y; 4881 crop_info.width=0; 4882 crop_info.height=0; 4883 state=DefaultState; 4884 do 4885 { 4886 highlight_info=crop_info; 4887 highlight_info.x=crop_info.x-windows->image.x; 4888 highlight_info.y=crop_info.y-windows->image.y; 4889 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4890 { 4891 /* 4892 Display info and draw cropping rectangle. 4893 */ 4894 if( IfMagickFalse(windows->info.mapped) ) 4895 (void) XMapWindow(display,windows->info.id); 4896 (void) FormatLocaleString(text,MaxTextExtent, 4897 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4898 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4899 XInfoWidget(display,windows,text); 4900 XHighlightRectangle(display,windows->image.id, 4901 windows->image.highlight_context,&highlight_info); 4902 } 4903 else 4904 if( IfMagickTrue(windows->info.mapped) ) 4905 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 4906 /* 4907 Wait for next event. 4908 */ 4909 XScreenEvent(display,windows,&event,exception); 4910 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 4911 XHighlightRectangle(display,windows->image.id, 4912 windows->image.highlight_context,&highlight_info); 4913 switch (event.type) 4914 { 4915 case ButtonPress: 4916 { 4917 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4918 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4919 break; 4920 } 4921 case ButtonRelease: 4922 { 4923 /* 4924 User has committed to cropping rectangle. 4925 */ 4926 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 4927 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 4928 XSetCursorState(display,windows,MagickFalse); 4929 state|=ExitState; 4930 windows->command.data=0; 4931 (void) XCommandWidget(display,windows,RectifyModeMenu, 4932 (XEvent *) NULL); 4933 break; 4934 } 4935 case Expose: 4936 break; 4937 case MotionNotify: 4938 { 4939 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 4940 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 4941 } 4942 default: 4943 break; 4944 } 4945 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 4946 ((state & ExitState) != 0)) 4947 { 4948 /* 4949 Check boundary conditions. 4950 */ 4951 if (crop_info.x < 0) 4952 crop_info.x=0; 4953 else 4954 if (crop_info.x > (ssize_t) windows->image.ximage->width) 4955 crop_info.x=(ssize_t) windows->image.ximage->width; 4956 if ((int) crop_info.x < x) 4957 crop_info.width=(unsigned int) (x-crop_info.x); 4958 else 4959 { 4960 crop_info.width=(unsigned int) (crop_info.x-x); 4961 crop_info.x=(ssize_t) x; 4962 } 4963 if (crop_info.y < 0) 4964 crop_info.y=0; 4965 else 4966 if (crop_info.y > (ssize_t) windows->image.ximage->height) 4967 crop_info.y=(ssize_t) windows->image.ximage->height; 4968 if ((int) crop_info.y < y) 4969 crop_info.height=(unsigned int) (y-crop_info.y); 4970 else 4971 { 4972 crop_info.height=(unsigned int) (crop_info.y-y); 4973 crop_info.y=(ssize_t) y; 4974 } 4975 } 4976 } while ((state & ExitState) == 0); 4977 /* 4978 Wait for user to grab a corner of the rectangle or press return. 4979 */ 4980 state=DefaultState; 4981 (void) XMapWindow(display,windows->info.id); 4982 do 4983 { 4984 if( IfMagickTrue(windows->info.mapped) ) 4985 { 4986 /* 4987 Display pointer position. 4988 */ 4989 (void) FormatLocaleString(text,MaxTextExtent, 4990 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 4991 crop_info.height,(double) crop_info.x,(double) crop_info.y); 4992 XInfoWidget(display,windows,text); 4993 } 4994 highlight_info=crop_info; 4995 highlight_info.x=crop_info.x-windows->image.x; 4996 highlight_info.y=crop_info.y-windows->image.y; 4997 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 4998 { 4999 state|=EscapeState; 5000 state|=ExitState; 5001 break; 5002 } 5003 XHighlightRectangle(display,windows->image.id, 5004 windows->image.highlight_context,&highlight_info); 5005 XScreenEvent(display,windows,&event,exception); 5006 if (event.xany.window == windows->command.id) 5007 { 5008 /* 5009 Select a command from the Command widget. 5010 */ 5011 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5012 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 5013 (void) XSetFunction(display,windows->image.highlight_context, 5014 GXinvert); 5015 XHighlightRectangle(display,windows->image.id, 5016 windows->image.highlight_context,&highlight_info); 5017 if (id >= 0) 5018 switch (RectifyCommands[id]) 5019 { 5020 case RectifyCopyCommand: 5021 { 5022 state|=ExitState; 5023 break; 5024 } 5025 case RectifyHelpCommand: 5026 { 5027 (void) XSetFunction(display,windows->image.highlight_context, 5028 GXcopy); 5029 switch (mode) 5030 { 5031 case CopyMode: 5032 { 5033 XTextViewWidget(display,resource_info,windows,MagickFalse, 5034 "Help Viewer - Image Copy",ImageCopyHelp); 5035 break; 5036 } 5037 case CropMode: 5038 { 5039 XTextViewWidget(display,resource_info,windows,MagickFalse, 5040 "Help Viewer - Image Crop",ImageCropHelp); 5041 break; 5042 } 5043 case CutMode: 5044 { 5045 XTextViewWidget(display,resource_info,windows,MagickFalse, 5046 "Help Viewer - Image Cut",ImageCutHelp); 5047 break; 5048 } 5049 } 5050 (void) XSetFunction(display,windows->image.highlight_context, 5051 GXinvert); 5052 break; 5053 } 5054 case RectifyDismissCommand: 5055 { 5056 /* 5057 Prematurely exit. 5058 */ 5059 state|=EscapeState; 5060 state|=ExitState; 5061 break; 5062 } 5063 default: 5064 break; 5065 } 5066 continue; 5067 } 5068 XHighlightRectangle(display,windows->image.id, 5069 windows->image.highlight_context,&highlight_info); 5070 switch (event.type) 5071 { 5072 case ButtonPress: 5073 { 5074 if (event.xbutton.button != Button1) 5075 break; 5076 if (event.xbutton.window != windows->image.id) 5077 break; 5078 x=windows->image.x+event.xbutton.x; 5079 y=windows->image.y+event.xbutton.y; 5080 if ((x < (int) (crop_info.x+RoiDelta)) && 5081 (x > (int) (crop_info.x-RoiDelta)) && 5082 (y < (int) (crop_info.y+RoiDelta)) && 5083 (y > (int) (crop_info.y-RoiDelta))) 5084 { 5085 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5086 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5087 state|=UpdateConfigurationState; 5088 break; 5089 } 5090 if ((x < (int) (crop_info.x+RoiDelta)) && 5091 (x > (int) (crop_info.x-RoiDelta)) && 5092 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5093 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5094 { 5095 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 5096 state|=UpdateConfigurationState; 5097 break; 5098 } 5099 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5100 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5101 (y < (int) (crop_info.y+RoiDelta)) && 5102 (y > (int) (crop_info.y-RoiDelta))) 5103 { 5104 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 5105 state|=UpdateConfigurationState; 5106 break; 5107 } 5108 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 5109 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 5110 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 5111 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 5112 { 5113 state|=UpdateConfigurationState; 5114 break; 5115 } 5116 } 5117 case ButtonRelease: 5118 { 5119 if (event.xbutton.window == windows->pan.id) 5120 if ((highlight_info.x != crop_info.x-windows->image.x) || 5121 (highlight_info.y != crop_info.y-windows->image.y)) 5122 XHighlightRectangle(display,windows->image.id, 5123 windows->image.highlight_context,&highlight_info); 5124 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5125 event.xbutton.time); 5126 break; 5127 } 5128 case Expose: 5129 { 5130 if (event.xexpose.window == windows->image.id) 5131 if (event.xexpose.count == 0) 5132 { 5133 event.xexpose.x=(int) highlight_info.x; 5134 event.xexpose.y=(int) highlight_info.y; 5135 event.xexpose.width=(int) highlight_info.width; 5136 event.xexpose.height=(int) highlight_info.height; 5137 XRefreshWindow(display,&windows->image,&event); 5138 } 5139 if (event.xexpose.window == windows->info.id) 5140 if (event.xexpose.count == 0) 5141 XInfoWidget(display,windows,text); 5142 break; 5143 } 5144 case KeyPress: 5145 { 5146 if (event.xkey.window != windows->image.id) 5147 break; 5148 /* 5149 Respond to a user key press. 5150 */ 5151 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5152 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5153 switch ((int) key_symbol) 5154 { 5155 case XK_Escape: 5156 case XK_F20: 5157 state|=EscapeState; 5158 case XK_Return: 5159 { 5160 state|=ExitState; 5161 break; 5162 } 5163 case XK_Home: 5164 case XK_KP_Home: 5165 { 5166 crop_info.x=(ssize_t) (windows->image.width/2L- 5167 crop_info.width/2L); 5168 crop_info.y=(ssize_t) (windows->image.height/2L- 5169 crop_info.height/2L); 5170 break; 5171 } 5172 case XK_Left: 5173 case XK_KP_Left: 5174 { 5175 crop_info.x--; 5176 break; 5177 } 5178 case XK_Up: 5179 case XK_KP_Up: 5180 case XK_Next: 5181 { 5182 crop_info.y--; 5183 break; 5184 } 5185 case XK_Right: 5186 case XK_KP_Right: 5187 { 5188 crop_info.x++; 5189 break; 5190 } 5191 case XK_Prior: 5192 case XK_Down: 5193 case XK_KP_Down: 5194 { 5195 crop_info.y++; 5196 break; 5197 } 5198 case XK_F1: 5199 case XK_Help: 5200 { 5201 (void) XSetFunction(display,windows->image.highlight_context, 5202 GXcopy); 5203 switch (mode) 5204 { 5205 case CopyMode: 5206 { 5207 XTextViewWidget(display,resource_info,windows,MagickFalse, 5208 "Help Viewer - Image Copy",ImageCopyHelp); 5209 break; 5210 } 5211 case CropMode: 5212 { 5213 XTextViewWidget(display,resource_info,windows,MagickFalse, 5214 "Help Viewer - Image Cropg",ImageCropHelp); 5215 break; 5216 } 5217 case CutMode: 5218 { 5219 XTextViewWidget(display,resource_info,windows,MagickFalse, 5220 "Help Viewer - Image Cutg",ImageCutHelp); 5221 break; 5222 } 5223 } 5224 (void) XSetFunction(display,windows->image.highlight_context, 5225 GXinvert); 5226 break; 5227 } 5228 default: 5229 { 5230 (void) XBell(display,0); 5231 break; 5232 } 5233 } 5234 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 5235 event.xkey.time); 5236 break; 5237 } 5238 case KeyRelease: 5239 break; 5240 case MotionNotify: 5241 { 5242 if (event.xmotion.window != windows->image.id) 5243 break; 5244 /* 5245 Map and unmap Info widget as text cursor crosses its boundaries. 5246 */ 5247 x=event.xmotion.x; 5248 y=event.xmotion.y; 5249 if( IfMagickTrue(windows->info.mapped) ) 5250 { 5251 if ((x < (int) (windows->info.x+windows->info.width)) && 5252 (y < (int) (windows->info.y+windows->info.height))) 5253 (void) XWithdrawWindow(display,windows->info.id, 5254 windows->info.screen); 5255 } 5256 else 5257 if ((x > (int) (windows->info.x+windows->info.width)) || 5258 (y > (int) (windows->info.y+windows->info.height))) 5259 (void) XMapWindow(display,windows->info.id); 5260 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 5261 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 5262 break; 5263 } 5264 case SelectionRequest: 5265 { 5266 XSelectionEvent 5267 notify; 5268 5269 XSelectionRequestEvent 5270 *request; 5271 5272 /* 5273 Set primary selection. 5274 */ 5275 (void) FormatLocaleString(text,MaxTextExtent, 5276 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 5277 crop_info.height,(double) crop_info.x,(double) crop_info.y); 5278 request=(&(event.xselectionrequest)); 5279 (void) XChangeProperty(request->display,request->requestor, 5280 request->property,request->target,8,PropModeReplace, 5281 (unsigned char *) text,(int) strlen(text)); 5282 notify.type=SelectionNotify; 5283 notify.display=request->display; 5284 notify.requestor=request->requestor; 5285 notify.selection=request->selection; 5286 notify.target=request->target; 5287 notify.time=request->time; 5288 if (request->property == None) 5289 notify.property=request->target; 5290 else 5291 notify.property=request->property; 5292 (void) XSendEvent(request->display,request->requestor,False,0, 5293 (XEvent *) ¬ify); 5294 } 5295 default: 5296 break; 5297 } 5298 if ((state & UpdateConfigurationState) != 0) 5299 { 5300 (void) XPutBackEvent(display,&event); 5301 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5302 break; 5303 } 5304 } while ((state & ExitState) == 0); 5305 } while ((state & ExitState) == 0); 5306 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 5307 XSetCursorState(display,windows,MagickFalse); 5308 if ((state & EscapeState) != 0) 5309 return(MagickTrue); 5310 if (mode == CropMode) 5311 if (((int) crop_info.width != windows->image.ximage->width) || 5312 ((int) crop_info.height != windows->image.ximage->height)) 5313 { 5314 /* 5315 Reconfigure Image window as defined by cropping rectangle. 5316 */ 5317 XSetCropGeometry(display,windows,&crop_info,image); 5318 windows->image.window_changes.width=(int) crop_info.width; 5319 windows->image.window_changes.height=(int) crop_info.height; 5320 (void) XConfigureImage(display,resource_info,windows,image,exception); 5321 return(MagickTrue); 5322 } 5323 /* 5324 Copy image before applying image transforms. 5325 */ 5326 XSetCursorState(display,windows,MagickTrue); 5327 XCheckRefreshWindows(display,windows); 5328 width=(unsigned int) image->columns; 5329 height=(unsigned int) image->rows; 5330 x=0; 5331 y=0; 5332 if (windows->image.crop_geometry != (char *) NULL) 5333 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 5334 scale_factor=(double) width/windows->image.ximage->width; 5335 crop_info.x+=x; 5336 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 5337 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 5338 scale_factor=(double) height/windows->image.ximage->height; 5339 crop_info.y+=y; 5340 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 5341 crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5); 5342 crop_image=CropImage(image,&crop_info,exception); 5343 XSetCursorState(display,windows,MagickFalse); 5344 if (crop_image == (Image *) NULL) 5345 return(MagickFalse); 5346 if (resource_info->copy_image != (Image *) NULL) 5347 resource_info->copy_image=DestroyImage(resource_info->copy_image); 5348 resource_info->copy_image=crop_image; 5349 if (mode == CopyMode) 5350 { 5351 (void) XConfigureImage(display,resource_info,windows,image,exception); 5352 return(MagickTrue); 5353 } 5354 /* 5355 Cut image. 5356 */ 5357 if( IfMagickFalse(SetImageStorageClass(image,DirectClass,exception)) ) 5358 return(MagickFalse); 5359 image->alpha_trait=BlendPixelTrait; 5360 image_view=AcquireAuthenticCacheView(image,exception); 5361 for (y=0; y < (int) crop_info.height; y++) 5362 { 5363 q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y, 5364 crop_info.width,1,exception); 5365 if (q == (Quantum *) NULL) 5366 break; 5367 for (x=0; x < (int) crop_info.width; x++) 5368 { 5369 SetPixelAlpha(image,TransparentAlpha,q); 5370 q+=GetPixelChannels(image); 5371 } 5372 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 5373 break; 5374 } 5375 image_view=DestroyCacheView(image_view); 5376 /* 5377 Update image configuration. 5378 */ 5379 XConfigureImageColormap(display,resource_info,windows,image,exception); 5380 (void) XConfigureImage(display,resource_info,windows,image,exception); 5381 return(MagickTrue); 5382} 5383 5384/* 5385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5386% % 5387% % 5388% % 5389+ X D r a w I m a g e % 5390% % 5391% % 5392% % 5393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5394% 5395% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on 5396% the image. 5397% 5398% The format of the XDrawEditImage method is: 5399% 5400% MagickBooleanType XDrawEditImage(Display *display, 5401% XResourceInfo *resource_info,XWindows *windows,Image **image, 5402% ExceptionInfo *exception) 5403% 5404% A description of each parameter follows: 5405% 5406% o display: Specifies a connection to an X server; returned from 5407% XOpenDisplay. 5408% 5409% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 5410% 5411% o windows: Specifies a pointer to a XWindows structure. 5412% 5413% o image: the image. 5414% 5415% o exception: return any errors or warnings in this structure. 5416% 5417*/ 5418static MagickBooleanType XDrawEditImage(Display *display, 5419 XResourceInfo *resource_info,XWindows *windows,Image **image, 5420 ExceptionInfo *exception) 5421{ 5422 static const char 5423 *DrawMenu[] = 5424 { 5425 "Element", 5426 "Color", 5427 "Stipple", 5428 "Width", 5429 "Undo", 5430 "Help", 5431 "Dismiss", 5432 (char *) NULL 5433 }; 5434 5435 static ElementType 5436 element = PointElement; 5437 5438 static const ModeType 5439 DrawCommands[] = 5440 { 5441 DrawElementCommand, 5442 DrawColorCommand, 5443 DrawStippleCommand, 5444 DrawWidthCommand, 5445 DrawUndoCommand, 5446 DrawHelpCommand, 5447 DrawDismissCommand 5448 }; 5449 5450 static Pixmap 5451 stipple = (Pixmap) NULL; 5452 5453 static unsigned int 5454 pen_id = 0, 5455 line_width = 1; 5456 5457 char 5458 command[MaxTextExtent], 5459 text[MaxTextExtent]; 5460 5461 Cursor 5462 cursor; 5463 5464 int 5465 entry, 5466 id, 5467 number_coordinates, 5468 x, 5469 y; 5470 5471 double 5472 degrees; 5473 5474 MagickStatusType 5475 status; 5476 5477 RectangleInfo 5478 rectangle_info; 5479 5480 register int 5481 i; 5482 5483 unsigned int 5484 distance, 5485 height, 5486 max_coordinates, 5487 width; 5488 5489 size_t 5490 state; 5491 5492 Window 5493 root_window; 5494 5495 XDrawInfo 5496 draw_info; 5497 5498 XEvent 5499 event; 5500 5501 XPoint 5502 *coordinate_info; 5503 5504 XSegment 5505 line_info; 5506 5507 /* 5508 Allocate polygon info. 5509 */ 5510 max_coordinates=2048; 5511 coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates, 5512 sizeof(*coordinate_info)); 5513 if (coordinate_info == (XPoint *) NULL) 5514 { 5515 (void) ThrowMagickException(exception,GetMagickModule(), 5516 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 5517 return(MagickFalse); 5518 } 5519 /* 5520 Map Command widget. 5521 */ 5522 (void) CloneString(&windows->command.name,"Draw"); 5523 windows->command.data=4; 5524 (void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL); 5525 (void) XMapRaised(display,windows->command.id); 5526 XClientMessage(display,windows->image.id,windows->im_protocols, 5527 windows->im_update_widget,CurrentTime); 5528 /* 5529 Wait for first button press. 5530 */ 5531 root_window=XRootWindow(display,XDefaultScreen(display)); 5532 draw_info.stencil=OpaqueStencil; 5533 status=MagickTrue; 5534 cursor=XCreateFontCursor(display,XC_tcross); 5535 for ( ; ; ) 5536 { 5537 XQueryPosition(display,windows->image.id,&x,&y); 5538 (void) XSelectInput(display,windows->image.id, 5539 windows->image.attributes.event_mask | PointerMotionMask); 5540 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5541 state=DefaultState; 5542 do 5543 { 5544 if( IfMagickTrue(windows->info.mapped) ) 5545 { 5546 /* 5547 Display pointer position. 5548 */ 5549 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 5550 x+windows->image.x,y+windows->image.y); 5551 XInfoWidget(display,windows,text); 5552 } 5553 /* 5554 Wait for next event. 5555 */ 5556 XScreenEvent(display,windows,&event,exception); 5557 if (event.xany.window == windows->command.id) 5558 { 5559 /* 5560 Select a command from the Command widget. 5561 */ 5562 id=XCommandWidget(display,windows,DrawMenu,&event); 5563 if (id < 0) 5564 continue; 5565 switch (DrawCommands[id]) 5566 { 5567 case DrawElementCommand: 5568 { 5569 static const char 5570 *Elements[] = 5571 { 5572 "point", 5573 "line", 5574 "rectangle", 5575 "fill rectangle", 5576 "circle", 5577 "fill circle", 5578 "ellipse", 5579 "fill ellipse", 5580 "polygon", 5581 "fill polygon", 5582 (char *) NULL, 5583 }; 5584 5585 /* 5586 Select a command from the pop-up menu. 5587 */ 5588 element=(ElementType) (XMenuWidget(display,windows, 5589 DrawMenu[id],Elements,command)+1); 5590 break; 5591 } 5592 case DrawColorCommand: 5593 { 5594 const char 5595 *ColorMenu[MaxNumberPens+1]; 5596 5597 int 5598 pen_number; 5599 5600 MagickBooleanType 5601 transparent; 5602 5603 XColor 5604 color; 5605 5606 /* 5607 Initialize menu selections. 5608 */ 5609 for (i=0; i < (int) (MaxNumberPens-2); i++) 5610 ColorMenu[i]=resource_info->pen_colors[i]; 5611 ColorMenu[MaxNumberPens-2]="transparent"; 5612 ColorMenu[MaxNumberPens-1]="Browser..."; 5613 ColorMenu[MaxNumberPens]=(char *) NULL; 5614 /* 5615 Select a pen color from the pop-up menu. 5616 */ 5617 pen_number=XMenuWidget(display,windows,DrawMenu[id], 5618 (const char **) ColorMenu,command); 5619 if (pen_number < 0) 5620 break; 5621 transparent=pen_number == (MaxNumberPens-2) ? MagickTrue : 5622 MagickFalse; 5623 if( IfMagickTrue(transparent) ) 5624 { 5625 draw_info.stencil=TransparentStencil; 5626 break; 5627 } 5628 if (pen_number == (MaxNumberPens-1)) 5629 { 5630 static char 5631 color_name[MaxTextExtent] = "gray"; 5632 5633 /* 5634 Select a pen color from a dialog. 5635 */ 5636 resource_info->pen_colors[pen_number]=color_name; 5637 XColorBrowserWidget(display,windows,"Select",color_name); 5638 if (*color_name == '\0') 5639 break; 5640 } 5641 /* 5642 Set pen color. 5643 */ 5644 (void) XParseColor(display,windows->map_info->colormap, 5645 resource_info->pen_colors[pen_number],&color); 5646 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 5647 (unsigned int) MaxColors,&color); 5648 windows->pixel_info->pen_colors[pen_number]=color; 5649 pen_id=(unsigned int) pen_number; 5650 draw_info.stencil=OpaqueStencil; 5651 break; 5652 } 5653 case DrawStippleCommand: 5654 { 5655 Image 5656 *stipple_image; 5657 5658 ImageInfo 5659 *image_info; 5660 5661 int 5662 status; 5663 5664 static char 5665 filename[MaxTextExtent] = "\0"; 5666 5667 static const char 5668 *StipplesMenu[] = 5669 { 5670 "Brick", 5671 "Diagonal", 5672 "Scales", 5673 "Vertical", 5674 "Wavy", 5675 "Translucent", 5676 "Opaque", 5677 (char *) NULL, 5678 (char *) NULL, 5679 }; 5680 5681 /* 5682 Select a command from the pop-up menu. 5683 */ 5684 StipplesMenu[7]="Open..."; 5685 entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu, 5686 command); 5687 if (entry < 0) 5688 break; 5689 if (stipple != (Pixmap) NULL) 5690 (void) XFreePixmap(display,stipple); 5691 stipple=(Pixmap) NULL; 5692 if (entry != 7) 5693 { 5694 switch (entry) 5695 { 5696 case 0: 5697 { 5698 stipple=XCreateBitmapFromData(display,root_window, 5699 (char *) BricksBitmap,BricksWidth,BricksHeight); 5700 break; 5701 } 5702 case 1: 5703 { 5704 stipple=XCreateBitmapFromData(display,root_window, 5705 (char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight); 5706 break; 5707 } 5708 case 2: 5709 { 5710 stipple=XCreateBitmapFromData(display,root_window, 5711 (char *) ScalesBitmap,ScalesWidth,ScalesHeight); 5712 break; 5713 } 5714 case 3: 5715 { 5716 stipple=XCreateBitmapFromData(display,root_window, 5717 (char *) VerticalBitmap,VerticalWidth,VerticalHeight); 5718 break; 5719 } 5720 case 4: 5721 { 5722 stipple=XCreateBitmapFromData(display,root_window, 5723 (char *) WavyBitmap,WavyWidth,WavyHeight); 5724 break; 5725 } 5726 case 5: 5727 { 5728 stipple=XCreateBitmapFromData(display,root_window, 5729 (char *) HighlightBitmap,HighlightWidth, 5730 HighlightHeight); 5731 break; 5732 } 5733 case 6: 5734 default: 5735 { 5736 stipple=XCreateBitmapFromData(display,root_window, 5737 (char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight); 5738 break; 5739 } 5740 } 5741 break; 5742 } 5743 XFileBrowserWidget(display,windows,"Stipple",filename); 5744 if (*filename == '\0') 5745 break; 5746 /* 5747 Read image. 5748 */ 5749 XSetCursorState(display,windows,MagickTrue); 5750 XCheckRefreshWindows(display,windows); 5751 image_info=AcquireImageInfo(); 5752 (void) CopyMagickString(image_info->filename,filename, 5753 MaxTextExtent); 5754 stipple_image=ReadImage(image_info,exception); 5755 CatchException(exception); 5756 XSetCursorState(display,windows,MagickFalse); 5757 if (stipple_image == (Image *) NULL) 5758 break; 5759 (void) AcquireUniqueFileResource(filename); 5760 (void) FormatLocaleString(stipple_image->filename,MaxTextExtent, 5761 "xbm:%s",filename); 5762 (void) WriteImage(image_info,stipple_image,exception); 5763 stipple_image=DestroyImage(stipple_image); 5764 image_info=DestroyImageInfo(image_info); 5765 status=XReadBitmapFile(display,root_window,filename,&width, 5766 &height,&stipple,&x,&y); 5767 (void) RelinquishUniqueFileResource(filename); 5768 if ((status != BitmapSuccess) != 0) 5769 XNoticeWidget(display,windows,"Unable to read X bitmap image:", 5770 filename); 5771 break; 5772 } 5773 case DrawWidthCommand: 5774 { 5775 static char 5776 width[MaxTextExtent] = "0"; 5777 5778 static const char 5779 *WidthsMenu[] = 5780 { 5781 "1", 5782 "2", 5783 "4", 5784 "8", 5785 "16", 5786 "Dialog...", 5787 (char *) NULL, 5788 }; 5789 5790 /* 5791 Select a command from the pop-up menu. 5792 */ 5793 entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu, 5794 command); 5795 if (entry < 0) 5796 break; 5797 if (entry != 5) 5798 { 5799 line_width=(unsigned int) StringToUnsignedLong( 5800 WidthsMenu[entry]); 5801 break; 5802 } 5803 (void) XDialogWidget(display,windows,"Ok","Enter line width:", 5804 width); 5805 if (*width == '\0') 5806 break; 5807 line_width=(unsigned int) StringToUnsignedLong(width); 5808 break; 5809 } 5810 case DrawUndoCommand: 5811 { 5812 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 5813 image,exception); 5814 break; 5815 } 5816 case DrawHelpCommand: 5817 { 5818 XTextViewWidget(display,resource_info,windows,MagickFalse, 5819 "Help Viewer - Image Rotation",ImageDrawHelp); 5820 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5821 break; 5822 } 5823 case DrawDismissCommand: 5824 { 5825 /* 5826 Prematurely exit. 5827 */ 5828 state|=EscapeState; 5829 state|=ExitState; 5830 break; 5831 } 5832 default: 5833 break; 5834 } 5835 (void) XCheckDefineCursor(display,windows->image.id,cursor); 5836 continue; 5837 } 5838 switch (event.type) 5839 { 5840 case ButtonPress: 5841 { 5842 if (event.xbutton.button != Button1) 5843 break; 5844 if (event.xbutton.window != windows->image.id) 5845 break; 5846 /* 5847 exit loop. 5848 */ 5849 x=event.xbutton.x; 5850 y=event.xbutton.y; 5851 state|=ExitState; 5852 break; 5853 } 5854 case ButtonRelease: 5855 break; 5856 case Expose: 5857 break; 5858 case KeyPress: 5859 { 5860 KeySym 5861 key_symbol; 5862 5863 if (event.xkey.window != windows->image.id) 5864 break; 5865 /* 5866 Respond to a user key press. 5867 */ 5868 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 5869 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 5870 switch ((int) key_symbol) 5871 { 5872 case XK_Escape: 5873 case XK_F20: 5874 { 5875 /* 5876 Prematurely exit. 5877 */ 5878 state|=EscapeState; 5879 state|=ExitState; 5880 break; 5881 } 5882 case XK_F1: 5883 case XK_Help: 5884 { 5885 XTextViewWidget(display,resource_info,windows,MagickFalse, 5886 "Help Viewer - Image Rotation",ImageDrawHelp); 5887 break; 5888 } 5889 default: 5890 { 5891 (void) XBell(display,0); 5892 break; 5893 } 5894 } 5895 break; 5896 } 5897 case MotionNotify: 5898 { 5899 /* 5900 Map and unmap Info widget as text cursor crosses its boundaries. 5901 */ 5902 x=event.xmotion.x; 5903 y=event.xmotion.y; 5904 if( IfMagickTrue(windows->info.mapped) ) 5905 { 5906 if ((x < (int) (windows->info.x+windows->info.width)) && 5907 (y < (int) (windows->info.y+windows->info.height))) 5908 (void) XWithdrawWindow(display,windows->info.id, 5909 windows->info.screen); 5910 } 5911 else 5912 if ((x > (int) (windows->info.x+windows->info.width)) || 5913 (y > (int) (windows->info.y+windows->info.height))) 5914 (void) XMapWindow(display,windows->info.id); 5915 break; 5916 } 5917 } 5918 } while ((state & ExitState) == 0); 5919 (void) XSelectInput(display,windows->image.id, 5920 windows->image.attributes.event_mask); 5921 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 5922 if ((state & EscapeState) != 0) 5923 break; 5924 /* 5925 Draw element as pointer moves until the button is released. 5926 */ 5927 distance=0; 5928 degrees=0.0; 5929 line_info.x1=x; 5930 line_info.y1=y; 5931 line_info.x2=x; 5932 line_info.y2=y; 5933 rectangle_info.x=(ssize_t) x; 5934 rectangle_info.y=(ssize_t) y; 5935 rectangle_info.width=0; 5936 rectangle_info.height=0; 5937 number_coordinates=1; 5938 coordinate_info->x=x; 5939 coordinate_info->y=y; 5940 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 5941 state=DefaultState; 5942 do 5943 { 5944 switch (element) 5945 { 5946 case PointElement: 5947 default: 5948 { 5949 if (number_coordinates > 1) 5950 { 5951 (void) XDrawLines(display,windows->image.id, 5952 windows->image.highlight_context,coordinate_info, 5953 number_coordinates,CoordModeOrigin); 5954 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d", 5955 coordinate_info[number_coordinates-1].x, 5956 coordinate_info[number_coordinates-1].y); 5957 XInfoWidget(display,windows,text); 5958 } 5959 break; 5960 } 5961 case LineElement: 5962 { 5963 if (distance > 9) 5964 { 5965 /* 5966 Display angle of the line. 5967 */ 5968 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 5969 line_info.y1),(double) (line_info.x2-line_info.x1))); 5970 (void) FormatLocaleString(text,MaxTextExtent," %g", 5971 (double) degrees); 5972 XInfoWidget(display,windows,text); 5973 XHighlightLine(display,windows->image.id, 5974 windows->image.highlight_context,&line_info); 5975 } 5976 else 5977 if( IfMagickTrue(windows->info.mapped) ) 5978 (void) XWithdrawWindow(display,windows->info.id, 5979 windows->info.screen); 5980 break; 5981 } 5982 case RectangleElement: 5983 case FillRectangleElement: 5984 { 5985 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 5986 { 5987 /* 5988 Display info and draw drawing rectangle. 5989 */ 5990 (void) FormatLocaleString(text,MaxTextExtent, 5991 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 5992 (double) rectangle_info.height,(double) rectangle_info.x, 5993 (double) rectangle_info.y); 5994 XInfoWidget(display,windows,text); 5995 XHighlightRectangle(display,windows->image.id, 5996 windows->image.highlight_context,&rectangle_info); 5997 } 5998 else 5999 if( IfMagickTrue(windows->info.mapped) ) 6000 (void) XWithdrawWindow(display,windows->info.id, 6001 windows->info.screen); 6002 break; 6003 } 6004 case CircleElement: 6005 case FillCircleElement: 6006 case EllipseElement: 6007 case FillEllipseElement: 6008 { 6009 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6010 { 6011 /* 6012 Display info and draw drawing rectangle. 6013 */ 6014 (void) FormatLocaleString(text,MaxTextExtent, 6015 " %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width, 6016 (double) rectangle_info.height,(double) rectangle_info.x, 6017 (double) rectangle_info.y); 6018 XInfoWidget(display,windows,text); 6019 XHighlightEllipse(display,windows->image.id, 6020 windows->image.highlight_context,&rectangle_info); 6021 } 6022 else 6023 if( IfMagickTrue(windows->info.mapped) ) 6024 (void) XWithdrawWindow(display,windows->info.id, 6025 windows->info.screen); 6026 break; 6027 } 6028 case PolygonElement: 6029 case FillPolygonElement: 6030 { 6031 if (number_coordinates > 1) 6032 (void) XDrawLines(display,windows->image.id, 6033 windows->image.highlight_context,coordinate_info, 6034 number_coordinates,CoordModeOrigin); 6035 if (distance > 9) 6036 { 6037 /* 6038 Display angle of the line. 6039 */ 6040 degrees=RadiansToDegrees(-atan2((double) (line_info.y2- 6041 line_info.y1),(double) (line_info.x2-line_info.x1))); 6042 (void) FormatLocaleString(text,MaxTextExtent," %g", 6043 (double) degrees); 6044 XInfoWidget(display,windows,text); 6045 XHighlightLine(display,windows->image.id, 6046 windows->image.highlight_context,&line_info); 6047 } 6048 else 6049 if( IfMagickTrue(windows->info.mapped) ) 6050 (void) XWithdrawWindow(display,windows->info.id, 6051 windows->info.screen); 6052 break; 6053 } 6054 } 6055 /* 6056 Wait for next event. 6057 */ 6058 XScreenEvent(display,windows,&event,exception); 6059 switch (element) 6060 { 6061 case PointElement: 6062 default: 6063 { 6064 if (number_coordinates > 1) 6065 (void) XDrawLines(display,windows->image.id, 6066 windows->image.highlight_context,coordinate_info, 6067 number_coordinates,CoordModeOrigin); 6068 break; 6069 } 6070 case LineElement: 6071 { 6072 if (distance > 9) 6073 XHighlightLine(display,windows->image.id, 6074 windows->image.highlight_context,&line_info); 6075 break; 6076 } 6077 case RectangleElement: 6078 case FillRectangleElement: 6079 { 6080 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6081 XHighlightRectangle(display,windows->image.id, 6082 windows->image.highlight_context,&rectangle_info); 6083 break; 6084 } 6085 case CircleElement: 6086 case FillCircleElement: 6087 case EllipseElement: 6088 case FillEllipseElement: 6089 { 6090 if ((rectangle_info.width > 3) && (rectangle_info.height > 3)) 6091 XHighlightEllipse(display,windows->image.id, 6092 windows->image.highlight_context,&rectangle_info); 6093 break; 6094 } 6095 case PolygonElement: 6096 case FillPolygonElement: 6097 { 6098 if (number_coordinates > 1) 6099 (void) XDrawLines(display,windows->image.id, 6100 windows->image.highlight_context,coordinate_info, 6101 number_coordinates,CoordModeOrigin); 6102 if (distance > 9) 6103 XHighlightLine(display,windows->image.id, 6104 windows->image.highlight_context,&line_info); 6105 break; 6106 } 6107 } 6108 switch (event.type) 6109 { 6110 case ButtonPress: 6111 break; 6112 case ButtonRelease: 6113 { 6114 /* 6115 User has committed to element. 6116 */ 6117 line_info.x2=event.xbutton.x; 6118 line_info.y2=event.xbutton.y; 6119 rectangle_info.x=(ssize_t) event.xbutton.x; 6120 rectangle_info.y=(ssize_t) event.xbutton.y; 6121 coordinate_info[number_coordinates].x=event.xbutton.x; 6122 coordinate_info[number_coordinates].y=event.xbutton.y; 6123 if (((element != PolygonElement) && 6124 (element != FillPolygonElement)) || (distance <= 9)) 6125 { 6126 state|=ExitState; 6127 break; 6128 } 6129 number_coordinates++; 6130 if (number_coordinates < (int) max_coordinates) 6131 { 6132 line_info.x1=event.xbutton.x; 6133 line_info.y1=event.xbutton.y; 6134 break; 6135 } 6136 max_coordinates<<=1; 6137 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6138 max_coordinates,sizeof(*coordinate_info)); 6139 if (coordinate_info == (XPoint *) NULL) 6140 (void) ThrowMagickException(exception,GetMagickModule(), 6141 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6142 break; 6143 } 6144 case Expose: 6145 break; 6146 case MotionNotify: 6147 { 6148 if (event.xmotion.window != windows->image.id) 6149 break; 6150 if (element != PointElement) 6151 { 6152 line_info.x2=event.xmotion.x; 6153 line_info.y2=event.xmotion.y; 6154 rectangle_info.x=(ssize_t) event.xmotion.x; 6155 rectangle_info.y=(ssize_t) event.xmotion.y; 6156 break; 6157 } 6158 coordinate_info[number_coordinates].x=event.xbutton.x; 6159 coordinate_info[number_coordinates].y=event.xbutton.y; 6160 number_coordinates++; 6161 if (number_coordinates < (int) max_coordinates) 6162 break; 6163 max_coordinates<<=1; 6164 coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info, 6165 max_coordinates,sizeof(*coordinate_info)); 6166 if (coordinate_info == (XPoint *) NULL) 6167 (void) ThrowMagickException(exception,GetMagickModule(), 6168 ResourceLimitError,"MemoryAllocationFailed","`%s'","..."); 6169 break; 6170 } 6171 default: 6172 break; 6173 } 6174 /* 6175 Check boundary conditions. 6176 */ 6177 if (line_info.x2 < 0) 6178 line_info.x2=0; 6179 else 6180 if (line_info.x2 > (int) windows->image.width) 6181 line_info.x2=(short) windows->image.width; 6182 if (line_info.y2 < 0) 6183 line_info.y2=0; 6184 else 6185 if (line_info.y2 > (int) windows->image.height) 6186 line_info.y2=(short) windows->image.height; 6187 distance=(unsigned int) 6188 (((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+ 6189 ((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1))); 6190 if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) || 6191 ((state & ExitState) != 0)) 6192 { 6193 if (rectangle_info.x < 0) 6194 rectangle_info.x=0; 6195 else 6196 if (rectangle_info.x > (ssize_t) windows->image.width) 6197 rectangle_info.x=(ssize_t) windows->image.width; 6198 if ((int) rectangle_info.x < x) 6199 rectangle_info.width=(unsigned int) (x-rectangle_info.x); 6200 else 6201 { 6202 rectangle_info.width=(unsigned int) (rectangle_info.x-x); 6203 rectangle_info.x=(ssize_t) x; 6204 } 6205 if (rectangle_info.y < 0) 6206 rectangle_info.y=0; 6207 else 6208 if (rectangle_info.y > (ssize_t) windows->image.height) 6209 rectangle_info.y=(ssize_t) windows->image.height; 6210 if ((int) rectangle_info.y < y) 6211 rectangle_info.height=(unsigned int) (y-rectangle_info.y); 6212 else 6213 { 6214 rectangle_info.height=(unsigned int) (rectangle_info.y-y); 6215 rectangle_info.y=(ssize_t) y; 6216 } 6217 } 6218 } while ((state & ExitState) == 0); 6219 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 6220 if ((element == PointElement) || (element == PolygonElement) || 6221 (element == FillPolygonElement)) 6222 { 6223 /* 6224 Determine polygon bounding box. 6225 */ 6226 rectangle_info.x=(ssize_t) coordinate_info->x; 6227 rectangle_info.y=(ssize_t) coordinate_info->y; 6228 x=coordinate_info->x; 6229 y=coordinate_info->y; 6230 for (i=1; i < number_coordinates; i++) 6231 { 6232 if (coordinate_info[i].x > x) 6233 x=coordinate_info[i].x; 6234 if (coordinate_info[i].y > y) 6235 y=coordinate_info[i].y; 6236 if ((ssize_t) coordinate_info[i].x < rectangle_info.x) 6237 rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0); 6238 if ((ssize_t) coordinate_info[i].y < rectangle_info.y) 6239 rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0); 6240 } 6241 rectangle_info.width=(size_t) (x-rectangle_info.x); 6242 rectangle_info.height=(size_t) (y-rectangle_info.y); 6243 for (i=0; i < number_coordinates; i++) 6244 { 6245 coordinate_info[i].x-=rectangle_info.x; 6246 coordinate_info[i].y-=rectangle_info.y; 6247 } 6248 } 6249 else 6250 if (distance <= 9) 6251 continue; 6252 else 6253 if ((element == RectangleElement) || 6254 (element == CircleElement) || (element == EllipseElement)) 6255 { 6256 rectangle_info.width--; 6257 rectangle_info.height--; 6258 } 6259 /* 6260 Drawing is relative to image configuration. 6261 */ 6262 draw_info.x=(int) rectangle_info.x; 6263 draw_info.y=(int) rectangle_info.y; 6264 (void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand, 6265 image,exception); 6266 width=(unsigned int) (*image)->columns; 6267 height=(unsigned int) (*image)->rows; 6268 x=0; 6269 y=0; 6270 if (windows->image.crop_geometry != (char *) NULL) 6271 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 6272 draw_info.x+=windows->image.x-(line_width/2); 6273 if (draw_info.x < 0) 6274 draw_info.x=0; 6275 draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width); 6276 draw_info.y+=windows->image.y-(line_width/2); 6277 if (draw_info.y < 0) 6278 draw_info.y=0; 6279 draw_info.y=(int) height*draw_info.y/windows->image.ximage->height; 6280 draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1); 6281 if (draw_info.width > (unsigned int) (*image)->columns) 6282 draw_info.width=(unsigned int) (*image)->columns; 6283 draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1); 6284 if (draw_info.height > (unsigned int) (*image)->rows) 6285 draw_info.height=(unsigned int) (*image)->rows; 6286 (void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d", 6287 width*draw_info.width/windows->image.ximage->width, 6288 height*draw_info.height/windows->image.ximage->height, 6289 draw_info.x+x,draw_info.y+y); 6290 /* 6291 Initialize drawing attributes. 6292 */ 6293 draw_info.degrees=0.0; 6294 draw_info.element=element; 6295 draw_info.stipple=stipple; 6296 draw_info.line_width=line_width; 6297 draw_info.line_info=line_info; 6298 if (line_info.x1 > (int) (line_width/2)) 6299 draw_info.line_info.x1=(short) line_width/2; 6300 if (line_info.y1 > (int) (line_width/2)) 6301 draw_info.line_info.y1=(short) line_width/2; 6302 draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2)); 6303 draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2)); 6304 if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0)) 6305 { 6306 draw_info.line_info.x2=(-draw_info.line_info.x2); 6307 draw_info.line_info.y2=(-draw_info.line_info.y2); 6308 } 6309 if (draw_info.line_info.x2 < 0) 6310 { 6311 draw_info.line_info.x2=(-draw_info.line_info.x2); 6312 Swap(draw_info.line_info.x1,draw_info.line_info.x2); 6313 } 6314 if (draw_info.line_info.y2 < 0) 6315 { 6316 draw_info.line_info.y2=(-draw_info.line_info.y2); 6317 Swap(draw_info.line_info.y1,draw_info.line_info.y2); 6318 } 6319 draw_info.rectangle_info=rectangle_info; 6320 if (draw_info.rectangle_info.x > (ssize_t) (line_width/2)) 6321 draw_info.rectangle_info.x=(ssize_t) line_width/2; 6322 if (draw_info.rectangle_info.y > (ssize_t) (line_width/2)) 6323 draw_info.rectangle_info.y=(ssize_t) line_width/2; 6324 draw_info.number_coordinates=(unsigned int) number_coordinates; 6325 draw_info.coordinate_info=coordinate_info; 6326 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 6327 /* 6328 Draw element on image. 6329 */ 6330 XSetCursorState(display,windows,MagickTrue); 6331 XCheckRefreshWindows(display,windows); 6332 status=XDrawImage(display,windows->pixel_info,&draw_info,*image,exception); 6333 XSetCursorState(display,windows,MagickFalse); 6334 /* 6335 Update image colormap and return to image drawing. 6336 */ 6337 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6338 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6339 } 6340 XSetCursorState(display,windows,MagickFalse); 6341 coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info); 6342 return(IsMagickTrue(status)); 6343} 6344 6345/* 6346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6347% % 6348% % 6349% % 6350+ X D r a w P a n R e c t a n g l e % 6351% % 6352% % 6353% % 6354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6355% 6356% XDrawPanRectangle() draws a rectangle in the pan window. The pan window 6357% displays a zoom image and the rectangle shows which portion of the image is 6358% displayed in the Image window. 6359% 6360% The format of the XDrawPanRectangle method is: 6361% 6362% XDrawPanRectangle(Display *display,XWindows *windows) 6363% 6364% A description of each parameter follows: 6365% 6366% o display: Specifies a connection to an X server; returned from 6367% XOpenDisplay. 6368% 6369% o windows: Specifies a pointer to a XWindows structure. 6370% 6371*/ 6372static void XDrawPanRectangle(Display *display,XWindows *windows) 6373{ 6374 double 6375 scale_factor; 6376 6377 RectangleInfo 6378 highlight_info; 6379 6380 /* 6381 Determine dimensions of the panning rectangle. 6382 */ 6383 scale_factor=(double) windows->pan.width/windows->image.ximage->width; 6384 highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5); 6385 highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5); 6386 scale_factor=(double) 6387 windows->pan.height/windows->image.ximage->height; 6388 highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5); 6389 highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5); 6390 /* 6391 Display the panning rectangle. 6392 */ 6393 (void) XClearWindow(display,windows->pan.id); 6394 XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context, 6395 &highlight_info); 6396} 6397 6398/* 6399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6400% % 6401% % 6402% % 6403+ X I m a g e C a c h e % 6404% % 6405% % 6406% % 6407%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6408% 6409% XImageCache() handles the creation, manipulation, and destruction of the 6410% image cache (undo and redo buffers). 6411% 6412% The format of the XImageCache method is: 6413% 6414% void XImageCache(Display *display,XResourceInfo *resource_info, 6415% XWindows *windows,const CommandType command,Image **image, 6416% ExceptionInfo *exception) 6417% 6418% A description of each parameter follows: 6419% 6420% o display: Specifies a connection to an X server; returned from 6421% XOpenDisplay. 6422% 6423% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6424% 6425% o windows: Specifies a pointer to a XWindows structure. 6426% 6427% o command: Specifies a command to perform. 6428% 6429% o image: the image; XImageCache may transform the image and return a new 6430% image pointer. 6431% 6432% o exception: return any errors or warnings in this structure. 6433% 6434*/ 6435static void XImageCache(Display *display,XResourceInfo *resource_info, 6436 XWindows *windows,const CommandType command,Image **image, 6437 ExceptionInfo *exception) 6438{ 6439 Image 6440 *cache_image; 6441 6442 static Image 6443 *redo_image = (Image *) NULL, 6444 *undo_image = (Image *) NULL; 6445 6446 switch (command) 6447 { 6448 case FreeBuffersCommand: 6449 { 6450 /* 6451 Free memory from the undo and redo cache. 6452 */ 6453 while (undo_image != (Image *) NULL) 6454 { 6455 cache_image=undo_image; 6456 undo_image=GetPreviousImageInList(undo_image); 6457 cache_image->list=DestroyImage(cache_image->list); 6458 cache_image=DestroyImage(cache_image); 6459 } 6460 undo_image=NewImageList(); 6461 if (redo_image != (Image *) NULL) 6462 redo_image=DestroyImage(redo_image); 6463 redo_image=NewImageList(); 6464 return; 6465 } 6466 case UndoCommand: 6467 { 6468 char 6469 image_geometry[MaxTextExtent]; 6470 6471 /* 6472 Undo the last image transformation. 6473 */ 6474 if (undo_image == (Image *) NULL) 6475 { 6476 (void) XBell(display,0); 6477 return; 6478 } 6479 cache_image=undo_image; 6480 undo_image=GetPreviousImageInList(undo_image); 6481 windows->image.window_changes.width=(int) cache_image->columns; 6482 windows->image.window_changes.height=(int) cache_image->rows; 6483 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 6484 windows->image.ximage->width,windows->image.ximage->height); 6485 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 6486 exception); 6487 if (windows->image.crop_geometry != (char *) NULL) 6488 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 6489 windows->image.crop_geometry); 6490 windows->image.crop_geometry=cache_image->geometry; 6491 if (redo_image != (Image *) NULL) 6492 redo_image=DestroyImage(redo_image); 6493 redo_image=(*image); 6494 *image=cache_image->list; 6495 cache_image=DestroyImage(cache_image); 6496 if( IfMagickTrue(windows->image.orphan) ) 6497 return; 6498 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6499 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6500 return; 6501 } 6502 case CutCommand: 6503 case PasteCommand: 6504 case ApplyCommand: 6505 case HalfSizeCommand: 6506 case OriginalSizeCommand: 6507 case DoubleSizeCommand: 6508 case ResizeCommand: 6509 case TrimCommand: 6510 case CropCommand: 6511 case ChopCommand: 6512 case FlipCommand: 6513 case FlopCommand: 6514 case RotateRightCommand: 6515 case RotateLeftCommand: 6516 case RotateCommand: 6517 case ShearCommand: 6518 case RollCommand: 6519 case NegateCommand: 6520 case ContrastStretchCommand: 6521 case SigmoidalContrastCommand: 6522 case NormalizeCommand: 6523 case EqualizeCommand: 6524 case HueCommand: 6525 case SaturationCommand: 6526 case BrightnessCommand: 6527 case GammaCommand: 6528 case SpiffCommand: 6529 case DullCommand: 6530 case GrayscaleCommand: 6531 case MapCommand: 6532 case QuantizeCommand: 6533 case DespeckleCommand: 6534 case EmbossCommand: 6535 case ReduceNoiseCommand: 6536 case AddNoiseCommand: 6537 case SharpenCommand: 6538 case BlurCommand: 6539 case ThresholdCommand: 6540 case EdgeDetectCommand: 6541 case SpreadCommand: 6542 case ShadeCommand: 6543 case RaiseCommand: 6544 case SegmentCommand: 6545 case SolarizeCommand: 6546 case SepiaToneCommand: 6547 case SwirlCommand: 6548 case ImplodeCommand: 6549 case VignetteCommand: 6550 case WaveCommand: 6551 case OilPaintCommand: 6552 case CharcoalDrawCommand: 6553 case AnnotateCommand: 6554 case AddBorderCommand: 6555 case AddFrameCommand: 6556 case CompositeCommand: 6557 case CommentCommand: 6558 case LaunchCommand: 6559 case RegionofInterestCommand: 6560 case SaveToUndoBufferCommand: 6561 case RedoCommand: 6562 { 6563 Image 6564 *previous_image; 6565 6566 ssize_t 6567 bytes; 6568 6569 bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelInfo)); 6570 if (undo_image != (Image *) NULL) 6571 { 6572 /* 6573 Ensure the undo cache has enough memory available. 6574 */ 6575 previous_image=undo_image; 6576 while (previous_image != (Image *) NULL) 6577 { 6578 bytes+=previous_image->list->columns*previous_image->list->rows* 6579 sizeof(PixelInfo); 6580 if (bytes <= (ssize_t) (resource_info->undo_cache << 20)) 6581 { 6582 previous_image=GetPreviousImageInList(previous_image); 6583 continue; 6584 } 6585 bytes-=previous_image->list->columns*previous_image->list->rows* 6586 sizeof(PixelInfo); 6587 if (previous_image == undo_image) 6588 undo_image=NewImageList(); 6589 else 6590 previous_image->next->previous=NewImageList(); 6591 break; 6592 } 6593 while (previous_image != (Image *) NULL) 6594 { 6595 /* 6596 Delete any excess memory from undo cache. 6597 */ 6598 cache_image=previous_image; 6599 previous_image=GetPreviousImageInList(previous_image); 6600 cache_image->list=DestroyImage(cache_image->list); 6601 cache_image=DestroyImage(cache_image); 6602 } 6603 } 6604 if (bytes > (ssize_t) (resource_info->undo_cache << 20)) 6605 break; 6606 /* 6607 Save image before transformations are applied. 6608 */ 6609 cache_image=AcquireImage((ImageInfo *) NULL,exception); 6610 if (cache_image == (Image *) NULL) 6611 break; 6612 XSetCursorState(display,windows,MagickTrue); 6613 XCheckRefreshWindows(display,windows); 6614 cache_image->list=CloneImage(*image,0,0,MagickTrue,exception); 6615 XSetCursorState(display,windows,MagickFalse); 6616 if (cache_image->list == (Image *) NULL) 6617 { 6618 cache_image=DestroyImage(cache_image); 6619 break; 6620 } 6621 cache_image->columns=(size_t) windows->image.ximage->width; 6622 cache_image->rows=(size_t) windows->image.ximage->height; 6623 cache_image->geometry=windows->image.crop_geometry; 6624 if (windows->image.crop_geometry != (char *) NULL) 6625 { 6626 cache_image->geometry=AcquireString((char *) NULL); 6627 (void) CopyMagickString(cache_image->geometry, 6628 windows->image.crop_geometry,MaxTextExtent); 6629 } 6630 if (undo_image == (Image *) NULL) 6631 { 6632 undo_image=cache_image; 6633 break; 6634 } 6635 undo_image->next=cache_image; 6636 undo_image->next->previous=undo_image; 6637 undo_image=undo_image->next; 6638 break; 6639 } 6640 default: 6641 break; 6642 } 6643 if (command == RedoCommand) 6644 { 6645 /* 6646 Redo the last image transformation. 6647 */ 6648 if (redo_image == (Image *) NULL) 6649 { 6650 (void) XBell(display,0); 6651 return; 6652 } 6653 windows->image.window_changes.width=(int) redo_image->columns; 6654 windows->image.window_changes.height=(int) redo_image->rows; 6655 if (windows->image.crop_geometry != (char *) NULL) 6656 windows->image.crop_geometry=(char *) 6657 RelinquishMagickMemory(windows->image.crop_geometry); 6658 windows->image.crop_geometry=redo_image->geometry; 6659 *image=DestroyImage(*image); 6660 *image=redo_image; 6661 redo_image=NewImageList(); 6662 if( IfMagickTrue(windows->image.orphan) ) 6663 return; 6664 XConfigureImageColormap(display,resource_info,windows,*image,exception); 6665 (void) XConfigureImage(display,resource_info,windows,*image,exception); 6666 return; 6667 } 6668 if (command != InfoCommand) 6669 return; 6670 /* 6671 Display image info. 6672 */ 6673 XSetCursorState(display,windows,MagickTrue); 6674 XCheckRefreshWindows(display,windows); 6675 XDisplayImageInfo(display,resource_info,windows,undo_image,*image,exception); 6676 XSetCursorState(display,windows,MagickFalse); 6677} 6678 6679/* 6680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6681% % 6682% % 6683% % 6684+ X I m a g e W i n d o w C o m m a n d % 6685% % 6686% % 6687% % 6688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6689% 6690% XImageWindowCommand() makes a transform to the image or Image window as 6691% specified by a user menu button or keyboard command. 6692% 6693% The format of the XImageWindowCommand method is: 6694% 6695% CommandType XImageWindowCommand(Display *display, 6696% XResourceInfo *resource_info,XWindows *windows, 6697% const MagickStatusType state,KeySym key_symbol,Image **image, 6698% ExceptionInfo *exception) 6699% 6700% A description of each parameter follows: 6701% 6702% o nexus: Method XImageWindowCommand returns an image when the 6703% user chooses 'Open Image' from the command menu. Otherwise a null 6704% image is returned. 6705% 6706% o display: Specifies a connection to an X server; returned from 6707% XOpenDisplay. 6708% 6709% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 6710% 6711% o windows: Specifies a pointer to a XWindows structure. 6712% 6713% o state: key mask. 6714% 6715% o key_symbol: Specifies a command to perform. 6716% 6717% o image: the image; XImageWIndowCommand may transform the image and 6718% return a new image pointer. 6719% 6720% o exception: return any errors or warnings in this structure. 6721% 6722*/ 6723static CommandType XImageWindowCommand(Display *display, 6724 XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state, 6725 KeySym key_symbol,Image **image,ExceptionInfo *exception) 6726{ 6727 static char 6728 delta[MaxTextExtent] = ""; 6729 6730 static const char 6731 Digits[] = "01234567890"; 6732 6733 static KeySym 6734 last_symbol = XK_0; 6735 6736 if ((key_symbol >= XK_0) && (key_symbol <= XK_9)) 6737 { 6738 if (((last_symbol < XK_0) || (last_symbol > XK_9))) 6739 { 6740 *delta='\0'; 6741 resource_info->quantum=1; 6742 } 6743 last_symbol=key_symbol; 6744 delta[strlen(delta)+1]='\0'; 6745 delta[strlen(delta)]=Digits[key_symbol-XK_0]; 6746 resource_info->quantum=StringToLong(delta); 6747 return(NullCommand); 6748 } 6749 last_symbol=key_symbol; 6750 if (resource_info->immutable) 6751 { 6752 /* 6753 Virtual image window has a restricted command set. 6754 */ 6755 switch (key_symbol) 6756 { 6757 case XK_question: 6758 return(InfoCommand); 6759 case XK_p: 6760 case XK_Print: 6761 return(PrintCommand); 6762 case XK_space: 6763 return(NextCommand); 6764 case XK_q: 6765 case XK_Escape: 6766 return(QuitCommand); 6767 default: 6768 break; 6769 } 6770 return(NullCommand); 6771 } 6772 switch ((int) key_symbol) 6773 { 6774 case XK_o: 6775 { 6776 if ((state & ControlMask) == 0) 6777 break; 6778 return(OpenCommand); 6779 } 6780 case XK_space: 6781 return(NextCommand); 6782 case XK_BackSpace: 6783 return(FormerCommand); 6784 case XK_s: 6785 { 6786 if ((state & Mod1Mask) != 0) 6787 return(SwirlCommand); 6788 if ((state & ControlMask) == 0) 6789 return(ShearCommand); 6790 return(SaveCommand); 6791 } 6792 case XK_p: 6793 case XK_Print: 6794 { 6795 if ((state & Mod1Mask) != 0) 6796 return(OilPaintCommand); 6797 if ((state & Mod4Mask) != 0) 6798 return(ColorCommand); 6799 if ((state & ControlMask) == 0) 6800 return(NullCommand); 6801 return(PrintCommand); 6802 } 6803 case XK_d: 6804 { 6805 if ((state & Mod4Mask) != 0) 6806 return(DrawCommand); 6807 if ((state & ControlMask) == 0) 6808 return(NullCommand); 6809 return(DeleteCommand); 6810 } 6811 case XK_Select: 6812 { 6813 if ((state & ControlMask) == 0) 6814 return(NullCommand); 6815 return(SelectCommand); 6816 } 6817 case XK_n: 6818 { 6819 if ((state & ControlMask) == 0) 6820 return(NullCommand); 6821 return(NewCommand); 6822 } 6823 case XK_q: 6824 case XK_Escape: 6825 return(QuitCommand); 6826 case XK_z: 6827 case XK_Undo: 6828 { 6829 if ((state & ControlMask) == 0) 6830 return(NullCommand); 6831 return(UndoCommand); 6832 } 6833 case XK_r: 6834 case XK_Redo: 6835 { 6836 if ((state & ControlMask) == 0) 6837 return(RollCommand); 6838 return(RedoCommand); 6839 } 6840 case XK_x: 6841 { 6842 if ((state & ControlMask) == 0) 6843 return(NullCommand); 6844 return(CutCommand); 6845 } 6846 case XK_c: 6847 { 6848 if ((state & Mod1Mask) != 0) 6849 return(CharcoalDrawCommand); 6850 if ((state & ControlMask) == 0) 6851 return(CropCommand); 6852 return(CopyCommand); 6853 } 6854 case XK_v: 6855 case XK_Insert: 6856 { 6857 if ((state & Mod4Mask) != 0) 6858 return(CompositeCommand); 6859 if ((state & ControlMask) == 0) 6860 return(FlipCommand); 6861 return(PasteCommand); 6862 } 6863 case XK_less: 6864 return(HalfSizeCommand); 6865 case XK_minus: 6866 return(OriginalSizeCommand); 6867 case XK_greater: 6868 return(DoubleSizeCommand); 6869 case XK_percent: 6870 return(ResizeCommand); 6871 case XK_at: 6872 return(RefreshCommand); 6873 case XK_bracketleft: 6874 return(ChopCommand); 6875 case XK_h: 6876 return(FlopCommand); 6877 case XK_slash: 6878 return(RotateRightCommand); 6879 case XK_backslash: 6880 return(RotateLeftCommand); 6881 case XK_asterisk: 6882 return(RotateCommand); 6883 case XK_t: 6884 return(TrimCommand); 6885 case XK_H: 6886 return(HueCommand); 6887 case XK_S: 6888 return(SaturationCommand); 6889 case XK_L: 6890 return(BrightnessCommand); 6891 case XK_G: 6892 return(GammaCommand); 6893 case XK_C: 6894 return(SpiffCommand); 6895 case XK_Z: 6896 return(DullCommand); 6897 case XK_N: 6898 return(NormalizeCommand); 6899 case XK_equal: 6900 return(EqualizeCommand); 6901 case XK_asciitilde: 6902 return(NegateCommand); 6903 case XK_period: 6904 return(GrayscaleCommand); 6905 case XK_numbersign: 6906 return(QuantizeCommand); 6907 case XK_F2: 6908 return(DespeckleCommand); 6909 case XK_F3: 6910 return(EmbossCommand); 6911 case XK_F4: 6912 return(ReduceNoiseCommand); 6913 case XK_F5: 6914 return(AddNoiseCommand); 6915 case XK_F6: 6916 return(SharpenCommand); 6917 case XK_F7: 6918 return(BlurCommand); 6919 case XK_F8: 6920 return(ThresholdCommand); 6921 case XK_F9: 6922 return(EdgeDetectCommand); 6923 case XK_F10: 6924 return(SpreadCommand); 6925 case XK_F11: 6926 return(ShadeCommand); 6927 case XK_F12: 6928 return(RaiseCommand); 6929 case XK_F13: 6930 return(SegmentCommand); 6931 case XK_i: 6932 { 6933 if ((state & Mod1Mask) == 0) 6934 return(NullCommand); 6935 return(ImplodeCommand); 6936 } 6937 case XK_w: 6938 { 6939 if ((state & Mod1Mask) == 0) 6940 return(NullCommand); 6941 return(WaveCommand); 6942 } 6943 case XK_m: 6944 { 6945 if ((state & Mod4Mask) == 0) 6946 return(NullCommand); 6947 return(MatteCommand); 6948 } 6949 case XK_b: 6950 { 6951 if ((state & Mod4Mask) == 0) 6952 return(NullCommand); 6953 return(AddBorderCommand); 6954 } 6955 case XK_f: 6956 { 6957 if ((state & Mod4Mask) == 0) 6958 return(NullCommand); 6959 return(AddFrameCommand); 6960 } 6961 case XK_exclam: 6962 { 6963 if ((state & Mod4Mask) == 0) 6964 return(NullCommand); 6965 return(CommentCommand); 6966 } 6967 case XK_a: 6968 { 6969 if ((state & Mod1Mask) != 0) 6970 return(ApplyCommand); 6971 if ((state & Mod4Mask) != 0) 6972 return(AnnotateCommand); 6973 if ((state & ControlMask) == 0) 6974 return(NullCommand); 6975 return(RegionofInterestCommand); 6976 } 6977 case XK_question: 6978 return(InfoCommand); 6979 case XK_plus: 6980 return(ZoomCommand); 6981 case XK_P: 6982 { 6983 if ((state & ShiftMask) == 0) 6984 return(NullCommand); 6985 return(ShowPreviewCommand); 6986 } 6987 case XK_Execute: 6988 return(LaunchCommand); 6989 case XK_F1: 6990 return(HelpCommand); 6991 case XK_Find: 6992 return(BrowseDocumentationCommand); 6993 case XK_Menu: 6994 { 6995 (void) XMapRaised(display,windows->command.id); 6996 return(NullCommand); 6997 } 6998 case XK_Next: 6999 case XK_Prior: 7000 case XK_Home: 7001 case XK_KP_Home: 7002 { 7003 XTranslateImage(display,windows,*image,key_symbol); 7004 return(NullCommand); 7005 } 7006 case XK_Up: 7007 case XK_KP_Up: 7008 case XK_Down: 7009 case XK_KP_Down: 7010 case XK_Left: 7011 case XK_KP_Left: 7012 case XK_Right: 7013 case XK_KP_Right: 7014 { 7015 if ((state & Mod1Mask) != 0) 7016 { 7017 RectangleInfo 7018 crop_info; 7019 7020 /* 7021 Trim one pixel from edge of image. 7022 */ 7023 crop_info.x=0; 7024 crop_info.y=0; 7025 crop_info.width=(size_t) windows->image.ximage->width; 7026 crop_info.height=(size_t) windows->image.ximage->height; 7027 if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up)) 7028 { 7029 if (resource_info->quantum >= (int) crop_info.height) 7030 resource_info->quantum=(int) crop_info.height-1; 7031 crop_info.height-=resource_info->quantum; 7032 } 7033 if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down)) 7034 { 7035 if (resource_info->quantum >= (int) (crop_info.height-crop_info.y)) 7036 resource_info->quantum=(int) (crop_info.height-crop_info.y-1); 7037 crop_info.y+=resource_info->quantum; 7038 crop_info.height-=resource_info->quantum; 7039 } 7040 if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left)) 7041 { 7042 if (resource_info->quantum >= (int) crop_info.width) 7043 resource_info->quantum=(int) crop_info.width-1; 7044 crop_info.width-=resource_info->quantum; 7045 } 7046 if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right)) 7047 { 7048 if (resource_info->quantum >= (int) (crop_info.width-crop_info.x)) 7049 resource_info->quantum=(int) (crop_info.width-crop_info.x-1); 7050 crop_info.x+=resource_info->quantum; 7051 crop_info.width-=resource_info->quantum; 7052 } 7053 if ((int) (windows->image.x+windows->image.width) > 7054 (int) crop_info.width) 7055 windows->image.x=(int) (crop_info.width-windows->image.width); 7056 if ((int) (windows->image.y+windows->image.height) > 7057 (int) crop_info.height) 7058 windows->image.y=(int) (crop_info.height-windows->image.height); 7059 XSetCropGeometry(display,windows,&crop_info,*image); 7060 windows->image.window_changes.width=(int) crop_info.width; 7061 windows->image.window_changes.height=(int) crop_info.height; 7062 (void) XSetWindowBackgroundPixmap(display,windows->image.id,None); 7063 (void) XConfigureImage(display,resource_info,windows,*image, 7064 exception); 7065 return(NullCommand); 7066 } 7067 XTranslateImage(display,windows,*image,key_symbol); 7068 return(NullCommand); 7069 } 7070 default: 7071 return(NullCommand); 7072 } 7073 return(NullCommand); 7074} 7075 7076/* 7077%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7078% % 7079% % 7080% % 7081+ X M a g i c k C o m m a n d % 7082% % 7083% % 7084% % 7085%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7086% 7087% XMagickCommand() makes a transform to the image or Image window as 7088% specified by a user menu button or keyboard command. 7089% 7090% The format of the XMagickCommand method is: 7091% 7092% Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7093% XWindows *windows,const CommandType command,Image **image, 7094% ExceptionInfo *exception) 7095% 7096% A description of each parameter follows: 7097% 7098% o display: Specifies a connection to an X server; returned from 7099% XOpenDisplay. 7100% 7101% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 7102% 7103% o windows: Specifies a pointer to a XWindows structure. 7104% 7105% o command: Specifies a command to perform. 7106% 7107% o image: the image; XMagickCommand may transform the image and return a 7108% new image pointer. 7109% 7110% o exception: return any errors or warnings in this structure. 7111% 7112*/ 7113static Image *XMagickCommand(Display *display,XResourceInfo *resource_info, 7114 XWindows *windows,const CommandType command,Image **image, 7115 ExceptionInfo *exception) 7116{ 7117 char 7118 filename[MaxTextExtent], 7119 geometry[MaxTextExtent], 7120 modulate_factors[MaxTextExtent]; 7121 7122 GeometryInfo 7123 geometry_info; 7124 7125 Image 7126 *nexus; 7127 7128 ImageInfo 7129 *image_info; 7130 7131 int 7132 x, 7133 y; 7134 7135 MagickStatusType 7136 flags, 7137 status; 7138 7139 QuantizeInfo 7140 quantize_info; 7141 7142 RectangleInfo 7143 page_geometry; 7144 7145 register int 7146 i; 7147 7148 static char 7149 color[MaxTextExtent] = "gray"; 7150 7151 unsigned int 7152 height, 7153 width; 7154 7155 /* 7156 Process user command. 7157 */ 7158 XCheckRefreshWindows(display,windows); 7159 XImageCache(display,resource_info,windows,command,image,exception); 7160 nexus=NewImageList(); 7161 windows->image.window_changes.width=windows->image.ximage->width; 7162 windows->image.window_changes.height=windows->image.ximage->height; 7163 image_info=CloneImageInfo(resource_info->image_info); 7164 SetGeometryInfo(&geometry_info); 7165 GetQuantizeInfo(&quantize_info); 7166 switch (command) 7167 { 7168 case OpenCommand: 7169 { 7170 /* 7171 Load image. 7172 */ 7173 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 7174 break; 7175 } 7176 case NextCommand: 7177 { 7178 /* 7179 Display next image. 7180 */ 7181 for (i=0; i < resource_info->quantum; i++) 7182 XClientMessage(display,windows->image.id,windows->im_protocols, 7183 windows->im_next_image,CurrentTime); 7184 break; 7185 } 7186 case FormerCommand: 7187 { 7188 /* 7189 Display former image. 7190 */ 7191 for (i=0; i < resource_info->quantum; i++) 7192 XClientMessage(display,windows->image.id,windows->im_protocols, 7193 windows->im_former_image,CurrentTime); 7194 break; 7195 } 7196 case SelectCommand: 7197 { 7198 int 7199 status; 7200 7201 /* 7202 Select image. 7203 */ 7204 if (*resource_info->home_directory == '\0') 7205 (void) CopyMagickString(resource_info->home_directory,".", 7206 MaxTextExtent); 7207 status=chdir(resource_info->home_directory); 7208 if (status == -1) 7209 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 7210 "UnableToOpenFile","%s",resource_info->home_directory); 7211 nexus=XOpenImage(display,resource_info,windows,MagickTrue); 7212 break; 7213 } 7214 case SaveCommand: 7215 { 7216 /* 7217 Save image. 7218 */ 7219 status=XSaveImage(display,resource_info,windows,*image,exception); 7220 if( IfMagickFalse(status) ) 7221 { 7222 char 7223 message[MaxTextExtent]; 7224 7225 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7226 exception->reason != (char *) NULL ? exception->reason : "", 7227 exception->description != (char *) NULL ? exception->description : 7228 ""); 7229 XNoticeWidget(display,windows,"Unable to save file:",message); 7230 break; 7231 } 7232 break; 7233 } 7234 case PrintCommand: 7235 { 7236 /* 7237 Print image. 7238 */ 7239 status=XPrintImage(display,resource_info,windows,*image,exception); 7240 if( IfMagickFalse(status) ) 7241 { 7242 char 7243 message[MaxTextExtent]; 7244 7245 (void) FormatLocaleString(message,MaxTextExtent,"%s:%s", 7246 exception->reason != (char *) NULL ? exception->reason : "", 7247 exception->description != (char *) NULL ? exception->description : 7248 ""); 7249 XNoticeWidget(display,windows,"Unable to print file:",message); 7250 break; 7251 } 7252 break; 7253 } 7254 case DeleteCommand: 7255 { 7256 static char 7257 filename[MaxTextExtent] = "\0"; 7258 7259 /* 7260 Delete image file. 7261 */ 7262 XFileBrowserWidget(display,windows,"Delete",filename); 7263 if (*filename == '\0') 7264 break; 7265 status=IsMagickTrue(remove_utf8(filename)); 7266 if( IfMagickTrue(status) ) 7267 XNoticeWidget(display,windows,"Unable to delete image file:",filename); 7268 break; 7269 } 7270 case NewCommand: 7271 { 7272 int 7273 status; 7274 7275 static char 7276 color[MaxTextExtent] = "gray", 7277 geometry[MaxTextExtent] = "640x480"; 7278 7279 static const char 7280 *format = "gradient"; 7281 7282 /* 7283 Query user for canvas geometry. 7284 */ 7285 status=XDialogWidget(display,windows,"New","Enter image geometry:", 7286 geometry); 7287 if (*geometry == '\0') 7288 break; 7289 if (status == 0) 7290 format="xc"; 7291 XColorBrowserWidget(display,windows,"Select",color); 7292 if (*color == '\0') 7293 break; 7294 /* 7295 Create canvas. 7296 */ 7297 (void) FormatLocaleString(image_info->filename,MaxTextExtent, 7298 "%s:%s",format,color); 7299 (void) CloneString(&image_info->size,geometry); 7300 nexus=ReadImage(image_info,exception); 7301 CatchException(exception); 7302 XClientMessage(display,windows->image.id,windows->im_protocols, 7303 windows->im_next_image,CurrentTime); 7304 break; 7305 } 7306 case VisualDirectoryCommand: 7307 { 7308 /* 7309 Visual Image directory. 7310 */ 7311 nexus=XVisualDirectoryImage(display,resource_info,windows,exception); 7312 break; 7313 } 7314 case QuitCommand: 7315 { 7316 /* 7317 exit program. 7318 */ 7319 if( IfMagickFalse(resource_info->confirm_exit) ) 7320 XClientMessage(display,windows->image.id,windows->im_protocols, 7321 windows->im_exit,CurrentTime); 7322 else 7323 { 7324 int 7325 status; 7326 7327 /* 7328 Confirm program exit. 7329 */ 7330 status=XConfirmWidget(display,windows,"Do you really want to exit", 7331 resource_info->client_name); 7332 if (status > 0) 7333 XClientMessage(display,windows->image.id,windows->im_protocols, 7334 windows->im_exit,CurrentTime); 7335 } 7336 break; 7337 } 7338 case CutCommand: 7339 { 7340 /* 7341 Cut image. 7342 */ 7343 (void) XCropImage(display,resource_info,windows,*image,CutMode,exception); 7344 break; 7345 } 7346 case CopyCommand: 7347 { 7348 /* 7349 Copy image. 7350 */ 7351 (void) XCropImage(display,resource_info,windows,*image,CopyMode, 7352 exception); 7353 break; 7354 } 7355 case PasteCommand: 7356 { 7357 /* 7358 Paste image. 7359 */ 7360 status=XPasteImage(display,resource_info,windows,*image,exception); 7361 if( IfMagickFalse(status) ) 7362 { 7363 XNoticeWidget(display,windows,"Unable to paste X image", 7364 (*image)->filename); 7365 break; 7366 } 7367 break; 7368 } 7369 case HalfSizeCommand: 7370 { 7371 /* 7372 Half image size. 7373 */ 7374 windows->image.window_changes.width=windows->image.ximage->width/2; 7375 windows->image.window_changes.height=windows->image.ximage->height/2; 7376 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7377 break; 7378 } 7379 case OriginalSizeCommand: 7380 { 7381 /* 7382 Original image size. 7383 */ 7384 windows->image.window_changes.width=(int) (*image)->columns; 7385 windows->image.window_changes.height=(int) (*image)->rows; 7386 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7387 break; 7388 } 7389 case DoubleSizeCommand: 7390 { 7391 /* 7392 Double the image size. 7393 */ 7394 windows->image.window_changes.width=windows->image.ximage->width << 1; 7395 windows->image.window_changes.height=windows->image.ximage->height << 1; 7396 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7397 break; 7398 } 7399 case ResizeCommand: 7400 { 7401 int 7402 status; 7403 7404 size_t 7405 height, 7406 width; 7407 7408 ssize_t 7409 x, 7410 y; 7411 7412 /* 7413 Resize image. 7414 */ 7415 width=(size_t) windows->image.ximage->width; 7416 height=(size_t) windows->image.ximage->height; 7417 x=0; 7418 y=0; 7419 (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0", 7420 (double) width,(double) height); 7421 status=XDialogWidget(display,windows,"Resize", 7422 "Enter resize geometry (e.g. 640x480, 200%):",geometry); 7423 if (*geometry == '\0') 7424 break; 7425 if (status == 0) 7426 (void) ConcatenateMagickString(geometry,"!",MaxTextExtent); 7427 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 7428 windows->image.window_changes.width=(int) width; 7429 windows->image.window_changes.height=(int) height; 7430 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7431 break; 7432 } 7433 case ApplyCommand: 7434 { 7435 char 7436 image_geometry[MaxTextExtent]; 7437 7438 if ((windows->image.crop_geometry == (char *) NULL) && 7439 ((int) (*image)->columns == windows->image.ximage->width) && 7440 ((int) (*image)->rows == windows->image.ximage->height)) 7441 break; 7442 /* 7443 Apply size transforms to image. 7444 */ 7445 XSetCursorState(display,windows,MagickTrue); 7446 XCheckRefreshWindows(display,windows); 7447 /* 7448 Crop and/or scale displayed image. 7449 */ 7450 (void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!", 7451 windows->image.ximage->width,windows->image.ximage->height); 7452 (void) TransformImage(image,windows->image.crop_geometry,image_geometry, 7453 exception); 7454 if (windows->image.crop_geometry != (char *) NULL) 7455 windows->image.crop_geometry=(char *) RelinquishMagickMemory( 7456 windows->image.crop_geometry); 7457 windows->image.x=0; 7458 windows->image.y=0; 7459 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7460 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7461 break; 7462 } 7463 case RefreshCommand: 7464 { 7465 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7466 break; 7467 } 7468 case RestoreCommand: 7469 { 7470 /* 7471 Restore Image window to its original size. 7472 */ 7473 if ((windows->image.width == (unsigned int) (*image)->columns) && 7474 (windows->image.height == (unsigned int) (*image)->rows) && 7475 (windows->image.crop_geometry == (char *) NULL)) 7476 { 7477 (void) XBell(display,0); 7478 break; 7479 } 7480 windows->image.window_changes.width=(int) (*image)->columns; 7481 windows->image.window_changes.height=(int) (*image)->rows; 7482 if (windows->image.crop_geometry != (char *) NULL) 7483 { 7484 windows->image.crop_geometry=(char *) 7485 RelinquishMagickMemory(windows->image.crop_geometry); 7486 windows->image.crop_geometry=(char *) NULL; 7487 windows->image.x=0; 7488 windows->image.y=0; 7489 } 7490 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7491 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7492 break; 7493 } 7494 case CropCommand: 7495 { 7496 /* 7497 Crop image. 7498 */ 7499 (void) XCropImage(display,resource_info,windows,*image,CropMode, 7500 exception); 7501 break; 7502 } 7503 case ChopCommand: 7504 { 7505 /* 7506 Chop image. 7507 */ 7508 status=XChopImage(display,resource_info,windows,image,exception); 7509 if( IfMagickFalse(status) ) 7510 { 7511 XNoticeWidget(display,windows,"Unable to cut X image", 7512 (*image)->filename); 7513 break; 7514 } 7515 break; 7516 } 7517 case FlopCommand: 7518 { 7519 Image 7520 *flop_image; 7521 7522 /* 7523 Flop image scanlines. 7524 */ 7525 XSetCursorState(display,windows,MagickTrue); 7526 XCheckRefreshWindows(display,windows); 7527 flop_image=FlopImage(*image,exception); 7528 if (flop_image != (Image *) NULL) 7529 { 7530 *image=DestroyImage(*image); 7531 *image=flop_image; 7532 } 7533 CatchException(exception); 7534 XSetCursorState(display,windows,MagickFalse); 7535 if (windows->image.crop_geometry != (char *) NULL) 7536 { 7537 /* 7538 Flop crop geometry. 7539 */ 7540 width=(unsigned int) (*image)->columns; 7541 height=(unsigned int) (*image)->rows; 7542 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7543 &width,&height); 7544 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7545 "%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y); 7546 } 7547 if( IfMagickTrue(windows->image.orphan) ) 7548 break; 7549 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7550 break; 7551 } 7552 case FlipCommand: 7553 { 7554 Image 7555 *flip_image; 7556 7557 /* 7558 Flip image scanlines. 7559 */ 7560 XSetCursorState(display,windows,MagickTrue); 7561 XCheckRefreshWindows(display,windows); 7562 flip_image=FlipImage(*image,exception); 7563 if (flip_image != (Image *) NULL) 7564 { 7565 *image=DestroyImage(*image); 7566 *image=flip_image; 7567 } 7568 CatchException(exception); 7569 XSetCursorState(display,windows,MagickFalse); 7570 if (windows->image.crop_geometry != (char *) NULL) 7571 { 7572 /* 7573 Flip crop geometry. 7574 */ 7575 width=(unsigned int) (*image)->columns; 7576 height=(unsigned int) (*image)->rows; 7577 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 7578 &width,&height); 7579 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 7580 "%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y); 7581 } 7582 if( IfMagickTrue(windows->image.orphan) ) 7583 break; 7584 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7585 break; 7586 } 7587 case RotateRightCommand: 7588 { 7589 /* 7590 Rotate image 90 degrees clockwise. 7591 */ 7592 status=XRotateImage(display,resource_info,windows,90.0,image,exception); 7593 if( IfMagickFalse(status) ) 7594 { 7595 XNoticeWidget(display,windows,"Unable to rotate X image", 7596 (*image)->filename); 7597 break; 7598 } 7599 break; 7600 } 7601 case RotateLeftCommand: 7602 { 7603 /* 7604 Rotate image 90 degrees counter-clockwise. 7605 */ 7606 status=XRotateImage(display,resource_info,windows,-90.0,image,exception); 7607 if( IfMagickFalse(status) ) 7608 { 7609 XNoticeWidget(display,windows,"Unable to rotate X image", 7610 (*image)->filename); 7611 break; 7612 } 7613 break; 7614 } 7615 case RotateCommand: 7616 { 7617 /* 7618 Rotate image. 7619 */ 7620 status=XRotateImage(display,resource_info,windows,0.0,image,exception); 7621 if( IfMagickFalse(status) ) 7622 { 7623 XNoticeWidget(display,windows,"Unable to rotate X image", 7624 (*image)->filename); 7625 break; 7626 } 7627 break; 7628 } 7629 case ShearCommand: 7630 { 7631 Image 7632 *shear_image; 7633 7634 static char 7635 geometry[MaxTextExtent] = "45.0x45.0"; 7636 7637 /* 7638 Query user for shear color and geometry. 7639 */ 7640 XColorBrowserWidget(display,windows,"Select",color); 7641 if (*color == '\0') 7642 break; 7643 (void) XDialogWidget(display,windows,"Shear","Enter shear geometry:", 7644 geometry); 7645 if (*geometry == '\0') 7646 break; 7647 /* 7648 Shear image. 7649 */ 7650 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7651 exception); 7652 XSetCursorState(display,windows,MagickTrue); 7653 XCheckRefreshWindows(display,windows); 7654 (void) QueryColorCompliance(color,AllCompliance, 7655 &(*image)->background_color,exception); 7656 flags=ParseGeometry(geometry,&geometry_info); 7657 if ((flags & SigmaValue) == 0) 7658 geometry_info.sigma=geometry_info.rho; 7659 shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma, 7660 exception); 7661 if (shear_image != (Image *) NULL) 7662 { 7663 *image=DestroyImage(*image); 7664 *image=shear_image; 7665 } 7666 CatchException(exception); 7667 XSetCursorState(display,windows,MagickFalse); 7668 if( IfMagickTrue(windows->image.orphan) ) 7669 break; 7670 windows->image.window_changes.width=(int) (*image)->columns; 7671 windows->image.window_changes.height=(int) (*image)->rows; 7672 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7673 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7674 break; 7675 } 7676 case RollCommand: 7677 { 7678 Image 7679 *roll_image; 7680 7681 static char 7682 geometry[MaxTextExtent] = "+2+2"; 7683 7684 /* 7685 Query user for the roll geometry. 7686 */ 7687 (void) XDialogWidget(display,windows,"Roll","Enter roll geometry:", 7688 geometry); 7689 if (*geometry == '\0') 7690 break; 7691 /* 7692 Roll image. 7693 */ 7694 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 7695 exception); 7696 XSetCursorState(display,windows,MagickTrue); 7697 XCheckRefreshWindows(display,windows); 7698 (void) ParsePageGeometry(*image,geometry,&page_geometry, 7699 exception); 7700 roll_image=RollImage(*image,page_geometry.x,page_geometry.y, 7701 exception); 7702 if (roll_image != (Image *) NULL) 7703 { 7704 *image=DestroyImage(*image); 7705 *image=roll_image; 7706 } 7707 CatchException(exception); 7708 XSetCursorState(display,windows,MagickFalse); 7709 if( IfMagickTrue(windows->image.orphan) ) 7710 break; 7711 windows->image.window_changes.width=(int) (*image)->columns; 7712 windows->image.window_changes.height=(int) (*image)->rows; 7713 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7714 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7715 break; 7716 } 7717 case TrimCommand: 7718 { 7719 static char 7720 fuzz[MaxTextExtent]; 7721 7722 /* 7723 Query user for the fuzz factor. 7724 */ 7725 (void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0* 7726 (*image)->fuzz/(QuantumRange+1.0)); 7727 (void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz); 7728 if (*fuzz == '\0') 7729 break; 7730 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0); 7731 /* 7732 Trim image. 7733 */ 7734 status=XTrimImage(display,resource_info,windows,*image,exception); 7735 if( IfMagickFalse(status) ) 7736 { 7737 XNoticeWidget(display,windows,"Unable to trim X image", 7738 (*image)->filename); 7739 break; 7740 } 7741 break; 7742 } 7743 case HueCommand: 7744 { 7745 static char 7746 hue_percent[MaxTextExtent] = "110"; 7747 7748 /* 7749 Query user for percent hue change. 7750 */ 7751 (void) XDialogWidget(display,windows,"Apply", 7752 "Enter percent change in image hue (0-200):",hue_percent); 7753 if (*hue_percent == '\0') 7754 break; 7755 /* 7756 Vary the image hue. 7757 */ 7758 XSetCursorState(display,windows,MagickTrue); 7759 XCheckRefreshWindows(display,windows); 7760 (void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent); 7761 (void) ConcatenateMagickString(modulate_factors,hue_percent, 7762 MaxTextExtent); 7763 (void) ModulateImage(*image,modulate_factors,exception); 7764 XSetCursorState(display,windows,MagickFalse); 7765 if( IfMagickTrue(windows->image.orphan) ) 7766 break; 7767 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7768 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7769 break; 7770 } 7771 case SaturationCommand: 7772 { 7773 static char 7774 saturation_percent[MaxTextExtent] = "110"; 7775 7776 /* 7777 Query user for percent saturation change. 7778 */ 7779 (void) XDialogWidget(display,windows,"Apply", 7780 "Enter percent change in color saturation (0-200):",saturation_percent); 7781 if (*saturation_percent == '\0') 7782 break; 7783 /* 7784 Vary color saturation. 7785 */ 7786 XSetCursorState(display,windows,MagickTrue); 7787 XCheckRefreshWindows(display,windows); 7788 (void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent); 7789 (void) ConcatenateMagickString(modulate_factors,saturation_percent, 7790 MaxTextExtent); 7791 (void) ModulateImage(*image,modulate_factors,exception); 7792 XSetCursorState(display,windows,MagickFalse); 7793 if( IfMagickTrue(windows->image.orphan) ) 7794 break; 7795 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7796 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7797 break; 7798 } 7799 case BrightnessCommand: 7800 { 7801 static char 7802 brightness_percent[MaxTextExtent] = "110"; 7803 7804 /* 7805 Query user for percent brightness change. 7806 */ 7807 (void) XDialogWidget(display,windows,"Apply", 7808 "Enter percent change in color brightness (0-200):",brightness_percent); 7809 if (*brightness_percent == '\0') 7810 break; 7811 /* 7812 Vary the color brightness. 7813 */ 7814 XSetCursorState(display,windows,MagickTrue); 7815 XCheckRefreshWindows(display,windows); 7816 (void) CopyMagickString(modulate_factors,brightness_percent, 7817 MaxTextExtent); 7818 (void) ModulateImage(*image,modulate_factors,exception); 7819 XSetCursorState(display,windows,MagickFalse); 7820 if( IfMagickTrue(windows->image.orphan) ) 7821 break; 7822 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7823 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7824 break; 7825 } 7826 case GammaCommand: 7827 { 7828 static char 7829 factor[MaxTextExtent] = "1.6"; 7830 7831 /* 7832 Query user for gamma value. 7833 */ 7834 (void) XDialogWidget(display,windows,"Gamma", 7835 "Enter gamma value (e.g. 1.2):",factor); 7836 if (*factor == '\0') 7837 break; 7838 /* 7839 Gamma correct image. 7840 */ 7841 XSetCursorState(display,windows,MagickTrue); 7842 XCheckRefreshWindows(display,windows); 7843 (void) GammaImage(*image,atof(factor),exception); 7844 XSetCursorState(display,windows,MagickFalse); 7845 if( IfMagickTrue(windows->image.orphan) ) 7846 break; 7847 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7848 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7849 break; 7850 } 7851 case SpiffCommand: 7852 { 7853 /* 7854 Sharpen the image contrast. 7855 */ 7856 XSetCursorState(display,windows,MagickTrue); 7857 XCheckRefreshWindows(display,windows); 7858 (void) ContrastImage(*image,MagickTrue,exception); 7859 XSetCursorState(display,windows,MagickFalse); 7860 if( IfMagickTrue(windows->image.orphan) ) 7861 break; 7862 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7863 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7864 break; 7865 } 7866 case DullCommand: 7867 { 7868 /* 7869 Dull the image contrast. 7870 */ 7871 XSetCursorState(display,windows,MagickTrue); 7872 XCheckRefreshWindows(display,windows); 7873 (void) ContrastImage(*image,MagickFalse,exception); 7874 XSetCursorState(display,windows,MagickFalse); 7875 if( IfMagickTrue(windows->image.orphan) ) 7876 break; 7877 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7878 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7879 break; 7880 } 7881 case ContrastStretchCommand: 7882 { 7883 double 7884 black_point, 7885 white_point; 7886 7887 static char 7888 levels[MaxTextExtent] = "1%"; 7889 7890 /* 7891 Query user for gamma value. 7892 */ 7893 (void) XDialogWidget(display,windows,"Contrast Stretch", 7894 "Enter black and white points:",levels); 7895 if (*levels == '\0') 7896 break; 7897 /* 7898 Contrast stretch image. 7899 */ 7900 XSetCursorState(display,windows,MagickTrue); 7901 XCheckRefreshWindows(display,windows); 7902 flags=ParseGeometry(levels,&geometry_info); 7903 black_point=geometry_info.rho; 7904 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point; 7905 if ((flags & PercentValue) != 0) 7906 { 7907 black_point*=(double) (*image)->columns*(*image)->rows/100.0; 7908 white_point*=(double) (*image)->columns*(*image)->rows/100.0; 7909 } 7910 white_point=(double) (*image)->columns*(*image)->rows-white_point; 7911 (void) ContrastStretchImage(*image,black_point,white_point, 7912 exception); 7913 XSetCursorState(display,windows,MagickFalse); 7914 if( IfMagickTrue(windows->image.orphan) ) 7915 break; 7916 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7917 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7918 break; 7919 } 7920 case SigmoidalContrastCommand: 7921 { 7922 GeometryInfo 7923 geometry_info; 7924 7925 MagickStatusType 7926 flags; 7927 7928 static char 7929 levels[MaxTextExtent] = "3x50%"; 7930 7931 /* 7932 Query user for gamma value. 7933 */ 7934 (void) XDialogWidget(display,windows,"Sigmoidal Contrast", 7935 "Enter contrast and midpoint:",levels); 7936 if (*levels == '\0') 7937 break; 7938 /* 7939 Contrast stretch image. 7940 */ 7941 XSetCursorState(display,windows,MagickTrue); 7942 XCheckRefreshWindows(display,windows); 7943 flags=ParseGeometry(levels,&geometry_info); 7944 if ((flags & SigmaValue) == 0) 7945 geometry_info.sigma=1.0*QuantumRange/2.0; 7946 if ((flags & PercentValue) != 0) 7947 geometry_info.sigma=1.0*QuantumRange*geometry_info.sigma/100.0; 7948 (void) SigmoidalContrastImage(*image,MagickTrue,geometry_info.rho, 7949 geometry_info.sigma,exception); 7950 XSetCursorState(display,windows,MagickFalse); 7951 if( IfMagickTrue(windows->image.orphan) ) 7952 break; 7953 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7954 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7955 break; 7956 } 7957 case NormalizeCommand: 7958 { 7959 /* 7960 Perform histogram normalization on the image. 7961 */ 7962 XSetCursorState(display,windows,MagickTrue); 7963 XCheckRefreshWindows(display,windows); 7964 (void) NormalizeImage(*image,exception); 7965 XSetCursorState(display,windows,MagickFalse); 7966 if( IfMagickTrue(windows->image.orphan) ) 7967 break; 7968 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7969 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7970 break; 7971 } 7972 case EqualizeCommand: 7973 { 7974 /* 7975 Perform histogram equalization on the image. 7976 */ 7977 XSetCursorState(display,windows,MagickTrue); 7978 XCheckRefreshWindows(display,windows); 7979 (void) EqualizeImage(*image,exception); 7980 XSetCursorState(display,windows,MagickFalse); 7981 if( IfMagickTrue(windows->image.orphan) ) 7982 break; 7983 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7984 (void) XConfigureImage(display,resource_info,windows,*image,exception); 7985 break; 7986 } 7987 case NegateCommand: 7988 { 7989 /* 7990 Negate colors in image. 7991 */ 7992 XSetCursorState(display,windows,MagickTrue); 7993 XCheckRefreshWindows(display,windows); 7994 (void) NegateImage(*image,MagickFalse,exception); 7995 XSetCursorState(display,windows,MagickFalse); 7996 if( IfMagickTrue(windows->image.orphan) ) 7997 break; 7998 XConfigureImageColormap(display,resource_info,windows,*image,exception); 7999 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8000 break; 8001 } 8002 case GrayscaleCommand: 8003 { 8004 /* 8005 Convert image to grayscale. 8006 */ 8007 XSetCursorState(display,windows,MagickTrue); 8008 XCheckRefreshWindows(display,windows); 8009 (void) SetImageType(*image,(*image)->alpha_trait != BlendPixelTrait ? 8010 GrayscaleType : GrayscaleMatteType,exception); 8011 XSetCursorState(display,windows,MagickFalse); 8012 if( IfMagickTrue(windows->image.orphan) ) 8013 break; 8014 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8015 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8016 break; 8017 } 8018 case MapCommand: 8019 { 8020 Image 8021 *affinity_image; 8022 8023 static char 8024 filename[MaxTextExtent] = "\0"; 8025 8026 /* 8027 Request image file name from user. 8028 */ 8029 XFileBrowserWidget(display,windows,"Map",filename); 8030 if (*filename == '\0') 8031 break; 8032 /* 8033 Map image. 8034 */ 8035 XSetCursorState(display,windows,MagickTrue); 8036 XCheckRefreshWindows(display,windows); 8037 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 8038 affinity_image=ReadImage(image_info,exception); 8039 if (affinity_image != (Image *) NULL) 8040 { 8041 (void) RemapImage(&quantize_info,*image,affinity_image,exception); 8042 affinity_image=DestroyImage(affinity_image); 8043 } 8044 CatchException(exception); 8045 XSetCursorState(display,windows,MagickFalse); 8046 if( IfMagickTrue(windows->image.orphan) ) 8047 break; 8048 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8049 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8050 break; 8051 } 8052 case QuantizeCommand: 8053 { 8054 int 8055 status; 8056 8057 static char 8058 colors[MaxTextExtent] = "256"; 8059 8060 /* 8061 Query user for maximum number of colors. 8062 */ 8063 status=XDialogWidget(display,windows,"Quantize", 8064 "Maximum number of colors:",colors); 8065 if (*colors == '\0') 8066 break; 8067 /* 8068 Color reduce the image. 8069 */ 8070 XSetCursorState(display,windows,MagickTrue); 8071 XCheckRefreshWindows(display,windows); 8072 quantize_info.number_colors=StringToUnsignedLong(colors); 8073 quantize_info.dither_method=status != 0 ? RiemersmaDitherMethod : 8074 NoDitherMethod; 8075 (void) QuantizeImage(&quantize_info,*image,exception); 8076 XSetCursorState(display,windows,MagickFalse); 8077 if( IfMagickTrue(windows->image.orphan) ) 8078 break; 8079 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8080 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8081 break; 8082 } 8083 case DespeckleCommand: 8084 { 8085 Image 8086 *despeckle_image; 8087 8088 /* 8089 Despeckle image. 8090 */ 8091 XSetCursorState(display,windows,MagickTrue); 8092 XCheckRefreshWindows(display,windows); 8093 despeckle_image=DespeckleImage(*image,exception); 8094 if (despeckle_image != (Image *) NULL) 8095 { 8096 *image=DestroyImage(*image); 8097 *image=despeckle_image; 8098 } 8099 CatchException(exception); 8100 XSetCursorState(display,windows,MagickFalse); 8101 if( IfMagickTrue(windows->image.orphan) ) 8102 break; 8103 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8104 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8105 break; 8106 } 8107 case EmbossCommand: 8108 { 8109 Image 8110 *emboss_image; 8111 8112 static char 8113 radius[MaxTextExtent] = "0.0x1.0"; 8114 8115 /* 8116 Query user for emboss radius. 8117 */ 8118 (void) XDialogWidget(display,windows,"Emboss", 8119 "Enter the emboss radius and standard deviation:",radius); 8120 if (*radius == '\0') 8121 break; 8122 /* 8123 Reduce noise in the image. 8124 */ 8125 XSetCursorState(display,windows,MagickTrue); 8126 XCheckRefreshWindows(display,windows); 8127 flags=ParseGeometry(radius,&geometry_info); 8128 if ((flags & SigmaValue) == 0) 8129 geometry_info.sigma=1.0; 8130 emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma, 8131 exception); 8132 if (emboss_image != (Image *) NULL) 8133 { 8134 *image=DestroyImage(*image); 8135 *image=emboss_image; 8136 } 8137 CatchException(exception); 8138 XSetCursorState(display,windows,MagickFalse); 8139 if( IfMagickTrue(windows->image.orphan) ) 8140 break; 8141 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8142 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8143 break; 8144 } 8145 case ReduceNoiseCommand: 8146 { 8147 Image 8148 *noise_image; 8149 8150 static char 8151 radius[MaxTextExtent] = "0"; 8152 8153 /* 8154 Query user for noise radius. 8155 */ 8156 (void) XDialogWidget(display,windows,"Reduce Noise", 8157 "Enter the noise radius:",radius); 8158 if (*radius == '\0') 8159 break; 8160 /* 8161 Reduce noise in the image. 8162 */ 8163 XSetCursorState(display,windows,MagickTrue); 8164 XCheckRefreshWindows(display,windows); 8165 flags=ParseGeometry(radius,&geometry_info); 8166 noise_image=StatisticImage(*image,NonpeakStatistic,(size_t) 8167 geometry_info.rho,(size_t) geometry_info.rho,exception); 8168 if (noise_image != (Image *) NULL) 8169 { 8170 *image=DestroyImage(*image); 8171 *image=noise_image; 8172 } 8173 CatchException(exception); 8174 XSetCursorState(display,windows,MagickFalse); 8175 if( IfMagickTrue(windows->image.orphan) ) 8176 break; 8177 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8178 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8179 break; 8180 } 8181 case AddNoiseCommand: 8182 { 8183 char 8184 **noises; 8185 8186 Image 8187 *noise_image; 8188 8189 static char 8190 noise_type[MaxTextExtent] = "Gaussian"; 8191 8192 /* 8193 Add noise to the image. 8194 */ 8195 noises=GetCommandOptions(MagickNoiseOptions); 8196 if (noises == (char **) NULL) 8197 break; 8198 XListBrowserWidget(display,windows,&windows->widget, 8199 (const char **) noises,"Add Noise", 8200 "Select a type of noise to add to your image:",noise_type); 8201 noises=DestroyStringList(noises); 8202 if (*noise_type == '\0') 8203 break; 8204 XSetCursorState(display,windows,MagickTrue); 8205 XCheckRefreshWindows(display,windows); 8206 noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption( 8207 MagickNoiseOptions,MagickFalse,noise_type),1.0,exception); 8208 if (noise_image != (Image *) NULL) 8209 { 8210 *image=DestroyImage(*image); 8211 *image=noise_image; 8212 } 8213 CatchException(exception); 8214 XSetCursorState(display,windows,MagickFalse); 8215 if( IfMagickTrue(windows->image.orphan) ) 8216 break; 8217 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8218 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8219 break; 8220 } 8221 case SharpenCommand: 8222 { 8223 Image 8224 *sharp_image; 8225 8226 static char 8227 radius[MaxTextExtent] = "0.0x1.0"; 8228 8229 /* 8230 Query user for sharpen radius. 8231 */ 8232 (void) XDialogWidget(display,windows,"Sharpen", 8233 "Enter the sharpen radius and standard deviation:",radius); 8234 if (*radius == '\0') 8235 break; 8236 /* 8237 Sharpen image scanlines. 8238 */ 8239 XSetCursorState(display,windows,MagickTrue); 8240 XCheckRefreshWindows(display,windows); 8241 flags=ParseGeometry(radius,&geometry_info); 8242 sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma, 8243 exception); 8244 if (sharp_image != (Image *) NULL) 8245 { 8246 *image=DestroyImage(*image); 8247 *image=sharp_image; 8248 } 8249 CatchException(exception); 8250 XSetCursorState(display,windows,MagickFalse); 8251 if( IfMagickTrue(windows->image.orphan) ) 8252 break; 8253 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8254 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8255 break; 8256 } 8257 case BlurCommand: 8258 { 8259 Image 8260 *blur_image; 8261 8262 static char 8263 radius[MaxTextExtent] = "0.0x1.0"; 8264 8265 /* 8266 Query user for blur radius. 8267 */ 8268 (void) XDialogWidget(display,windows,"Blur", 8269 "Enter the blur radius and standard deviation:",radius); 8270 if (*radius == '\0') 8271 break; 8272 /* 8273 Blur an image. 8274 */ 8275 XSetCursorState(display,windows,MagickTrue); 8276 XCheckRefreshWindows(display,windows); 8277 flags=ParseGeometry(radius,&geometry_info); 8278 blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma, 8279 exception); 8280 if (blur_image != (Image *) NULL) 8281 { 8282 *image=DestroyImage(*image); 8283 *image=blur_image; 8284 } 8285 CatchException(exception); 8286 XSetCursorState(display,windows,MagickFalse); 8287 if( IfMagickTrue(windows->image.orphan) ) 8288 break; 8289 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8290 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8291 break; 8292 } 8293 case ThresholdCommand: 8294 { 8295 double 8296 threshold; 8297 8298 static char 8299 factor[MaxTextExtent] = "128"; 8300 8301 /* 8302 Query user for threshold value. 8303 */ 8304 (void) XDialogWidget(display,windows,"Threshold", 8305 "Enter threshold value:",factor); 8306 if (*factor == '\0') 8307 break; 8308 /* 8309 Gamma correct image. 8310 */ 8311 XSetCursorState(display,windows,MagickTrue); 8312 XCheckRefreshWindows(display,windows); 8313 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8314 (void) BilevelImage(*image,threshold,exception); 8315 XSetCursorState(display,windows,MagickFalse); 8316 if( IfMagickTrue(windows->image.orphan) ) 8317 break; 8318 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8319 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8320 break; 8321 } 8322 case EdgeDetectCommand: 8323 { 8324 Image 8325 *edge_image; 8326 8327 static char 8328 radius[MaxTextExtent] = "0"; 8329 8330 /* 8331 Query user for edge factor. 8332 */ 8333 (void) XDialogWidget(display,windows,"Detect Edges", 8334 "Enter the edge detect radius:",radius); 8335 if (*radius == '\0') 8336 break; 8337 /* 8338 Detect edge in image. 8339 */ 8340 XSetCursorState(display,windows,MagickTrue); 8341 XCheckRefreshWindows(display,windows); 8342 flags=ParseGeometry(radius,&geometry_info); 8343 edge_image=EdgeImage(*image,geometry_info.rho,exception); 8344 if (edge_image != (Image *) NULL) 8345 { 8346 *image=DestroyImage(*image); 8347 *image=edge_image; 8348 } 8349 CatchException(exception); 8350 XSetCursorState(display,windows,MagickFalse); 8351 if( IfMagickTrue(windows->image.orphan) ) 8352 break; 8353 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8354 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8355 break; 8356 } 8357 case SpreadCommand: 8358 { 8359 Image 8360 *spread_image; 8361 8362 static char 8363 amount[MaxTextExtent] = "2"; 8364 8365 /* 8366 Query user for spread amount. 8367 */ 8368 (void) XDialogWidget(display,windows,"Spread", 8369 "Enter the displacement amount:",amount); 8370 if (*amount == '\0') 8371 break; 8372 /* 8373 Displace image pixels by a random amount. 8374 */ 8375 XSetCursorState(display,windows,MagickTrue); 8376 XCheckRefreshWindows(display,windows); 8377 flags=ParseGeometry(amount,&geometry_info); 8378 spread_image=EdgeImage(*image,geometry_info.rho,exception); 8379 if (spread_image != (Image *) NULL) 8380 { 8381 *image=DestroyImage(*image); 8382 *image=spread_image; 8383 } 8384 CatchException(exception); 8385 XSetCursorState(display,windows,MagickFalse); 8386 if( IfMagickTrue(windows->image.orphan) ) 8387 break; 8388 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8389 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8390 break; 8391 } 8392 case ShadeCommand: 8393 { 8394 Image 8395 *shade_image; 8396 8397 int 8398 status; 8399 8400 static char 8401 geometry[MaxTextExtent] = "30x30"; 8402 8403 /* 8404 Query user for the shade geometry. 8405 */ 8406 status=XDialogWidget(display,windows,"Shade", 8407 "Enter the azimuth and elevation of the light source:",geometry); 8408 if (*geometry == '\0') 8409 break; 8410 /* 8411 Shade image pixels. 8412 */ 8413 XSetCursorState(display,windows,MagickTrue); 8414 XCheckRefreshWindows(display,windows); 8415 flags=ParseGeometry(geometry,&geometry_info); 8416 if ((flags & SigmaValue) == 0) 8417 geometry_info.sigma=1.0; 8418 shade_image=ShadeImage(*image,IsMagickTrue(status), 8419 geometry_info.rho,geometry_info.sigma,exception); 8420 if (shade_image != (Image *) NULL) 8421 { 8422 *image=DestroyImage(*image); 8423 *image=shade_image; 8424 } 8425 CatchException(exception); 8426 XSetCursorState(display,windows,MagickFalse); 8427 if( IfMagickTrue(windows->image.orphan) ) 8428 break; 8429 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8430 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8431 break; 8432 } 8433 case RaiseCommand: 8434 { 8435 static char 8436 bevel_width[MaxTextExtent] = "10"; 8437 8438 /* 8439 Query user for bevel width. 8440 */ 8441 (void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width); 8442 if (*bevel_width == '\0') 8443 break; 8444 /* 8445 Raise an image. 8446 */ 8447 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8448 exception); 8449 XSetCursorState(display,windows,MagickTrue); 8450 XCheckRefreshWindows(display,windows); 8451 (void) ParsePageGeometry(*image,bevel_width,&page_geometry, 8452 exception); 8453 (void) RaiseImage(*image,&page_geometry,MagickTrue,exception); 8454 XSetCursorState(display,windows,MagickFalse); 8455 if( IfMagickTrue(windows->image.orphan) ) 8456 break; 8457 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8458 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8459 break; 8460 } 8461 case SegmentCommand: 8462 { 8463 static char 8464 threshold[MaxTextExtent] = "1.0x1.5"; 8465 8466 /* 8467 Query user for smoothing threshold. 8468 */ 8469 (void) XDialogWidget(display,windows,"Segment","Smooth threshold:", 8470 threshold); 8471 if (*threshold == '\0') 8472 break; 8473 /* 8474 Segment an image. 8475 */ 8476 XSetCursorState(display,windows,MagickTrue); 8477 XCheckRefreshWindows(display,windows); 8478 flags=ParseGeometry(threshold,&geometry_info); 8479 if ((flags & SigmaValue) == 0) 8480 geometry_info.sigma=1.0; 8481 (void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho, 8482 geometry_info.sigma,exception); 8483 XSetCursorState(display,windows,MagickFalse); 8484 if( IfMagickTrue(windows->image.orphan) ) 8485 break; 8486 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8487 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8488 break; 8489 } 8490 case SepiaToneCommand: 8491 { 8492 double 8493 threshold; 8494 8495 Image 8496 *sepia_image; 8497 8498 static char 8499 factor[MaxTextExtent] = "80%"; 8500 8501 /* 8502 Query user for sepia-tone factor. 8503 */ 8504 (void) XDialogWidget(display,windows,"Sepia Tone", 8505 "Enter the sepia tone factor (0 - 99.9%):",factor); 8506 if (*factor == '\0') 8507 break; 8508 /* 8509 Sepia tone image pixels. 8510 */ 8511 XSetCursorState(display,windows,MagickTrue); 8512 XCheckRefreshWindows(display,windows); 8513 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8514 sepia_image=SepiaToneImage(*image,threshold,exception); 8515 if (sepia_image != (Image *) NULL) 8516 { 8517 *image=DestroyImage(*image); 8518 *image=sepia_image; 8519 } 8520 CatchException(exception); 8521 XSetCursorState(display,windows,MagickFalse); 8522 if( IfMagickTrue(windows->image.orphan) ) 8523 break; 8524 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8525 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8526 break; 8527 } 8528 case SolarizeCommand: 8529 { 8530 double 8531 threshold; 8532 8533 static char 8534 factor[MaxTextExtent] = "60%"; 8535 8536 /* 8537 Query user for solarize factor. 8538 */ 8539 (void) XDialogWidget(display,windows,"Solarize", 8540 "Enter the solarize factor (0 - 99.9%):",factor); 8541 if (*factor == '\0') 8542 break; 8543 /* 8544 Solarize image pixels. 8545 */ 8546 XSetCursorState(display,windows,MagickTrue); 8547 XCheckRefreshWindows(display,windows); 8548 threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0); 8549 (void) SolarizeImage(*image,threshold,exception); 8550 XSetCursorState(display,windows,MagickFalse); 8551 if( IfMagickTrue(windows->image.orphan) ) 8552 break; 8553 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8554 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8555 break; 8556 } 8557 case SwirlCommand: 8558 { 8559 Image 8560 *swirl_image; 8561 8562 static char 8563 degrees[MaxTextExtent] = "60"; 8564 8565 /* 8566 Query user for swirl angle. 8567 */ 8568 (void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:", 8569 degrees); 8570 if (*degrees == '\0') 8571 break; 8572 /* 8573 Swirl image pixels about the center. 8574 */ 8575 XSetCursorState(display,windows,MagickTrue); 8576 XCheckRefreshWindows(display,windows); 8577 flags=ParseGeometry(degrees,&geometry_info); 8578 swirl_image=SwirlImage(*image,geometry_info.rho,(*image)->interpolate, 8579 exception); 8580 if (swirl_image != (Image *) NULL) 8581 { 8582 *image=DestroyImage(*image); 8583 *image=swirl_image; 8584 } 8585 CatchException(exception); 8586 XSetCursorState(display,windows,MagickFalse); 8587 if( IfMagickTrue(windows->image.orphan) ) 8588 break; 8589 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8590 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8591 break; 8592 } 8593 case ImplodeCommand: 8594 { 8595 Image 8596 *implode_image; 8597 8598 static char 8599 factor[MaxTextExtent] = "0.3"; 8600 8601 /* 8602 Query user for implode factor. 8603 */ 8604 (void) XDialogWidget(display,windows,"Implode", 8605 "Enter the implosion/explosion factor (-1.0 - 1.0):",factor); 8606 if (*factor == '\0') 8607 break; 8608 /* 8609 Implode image pixels about the center. 8610 */ 8611 XSetCursorState(display,windows,MagickTrue); 8612 XCheckRefreshWindows(display,windows); 8613 flags=ParseGeometry(factor,&geometry_info); 8614 implode_image=ImplodeImage(*image,geometry_info.rho,(*image)->interpolate, 8615 exception); 8616 if (implode_image != (Image *) NULL) 8617 { 8618 *image=DestroyImage(*image); 8619 *image=implode_image; 8620 } 8621 CatchException(exception); 8622 XSetCursorState(display,windows,MagickFalse); 8623 if( IfMagickTrue(windows->image.orphan) ) 8624 break; 8625 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8626 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8627 break; 8628 } 8629 case VignetteCommand: 8630 { 8631 Image 8632 *vignette_image; 8633 8634 static char 8635 geometry[MaxTextExtent] = "0x20"; 8636 8637 /* 8638 Query user for the vignette geometry. 8639 */ 8640 (void) XDialogWidget(display,windows,"Vignette", 8641 "Enter the radius, sigma, and x and y offsets:",geometry); 8642 if (*geometry == '\0') 8643 break; 8644 /* 8645 Soften the edges of the image in vignette style 8646 */ 8647 XSetCursorState(display,windows,MagickTrue); 8648 XCheckRefreshWindows(display,windows); 8649 flags=ParseGeometry(geometry,&geometry_info); 8650 if ((flags & SigmaValue) == 0) 8651 geometry_info.sigma=1.0; 8652 if ((flags & XiValue) == 0) 8653 geometry_info.xi=0.1*(*image)->columns; 8654 if ((flags & PsiValue) == 0) 8655 geometry_info.psi=0.1*(*image)->rows; 8656 vignette_image=VignetteImage(*image,geometry_info.rho,0.0,(ssize_t) 8657 ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5), 8658 exception); 8659 if (vignette_image != (Image *) NULL) 8660 { 8661 *image=DestroyImage(*image); 8662 *image=vignette_image; 8663 } 8664 CatchException(exception); 8665 XSetCursorState(display,windows,MagickFalse); 8666 if( IfMagickTrue(windows->image.orphan) ) 8667 break; 8668 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8669 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8670 break; 8671 } 8672 case WaveCommand: 8673 { 8674 Image 8675 *wave_image; 8676 8677 static char 8678 geometry[MaxTextExtent] = "25x150"; 8679 8680 /* 8681 Query user for the wave geometry. 8682 */ 8683 (void) XDialogWidget(display,windows,"Wave", 8684 "Enter the amplitude and length of the wave:",geometry); 8685 if (*geometry == '\0') 8686 break; 8687 /* 8688 Alter an image along a sine wave. 8689 */ 8690 XSetCursorState(display,windows,MagickTrue); 8691 XCheckRefreshWindows(display,windows); 8692 flags=ParseGeometry(geometry,&geometry_info); 8693 if ((flags & SigmaValue) == 0) 8694 geometry_info.sigma=1.0; 8695 wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma, 8696 (*image)->interpolate,exception); 8697 if (wave_image != (Image *) NULL) 8698 { 8699 *image=DestroyImage(*image); 8700 *image=wave_image; 8701 } 8702 CatchException(exception); 8703 XSetCursorState(display,windows,MagickFalse); 8704 if( IfMagickTrue(windows->image.orphan) ) 8705 break; 8706 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8707 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8708 break; 8709 } 8710 case OilPaintCommand: 8711 { 8712 Image 8713 *paint_image; 8714 8715 static char 8716 radius[MaxTextExtent] = "0"; 8717 8718 /* 8719 Query user for circular neighborhood radius. 8720 */ 8721 (void) XDialogWidget(display,windows,"Oil Paint", 8722 "Enter the mask radius:",radius); 8723 if (*radius == '\0') 8724 break; 8725 /* 8726 OilPaint image scanlines. 8727 */ 8728 XSetCursorState(display,windows,MagickTrue); 8729 XCheckRefreshWindows(display,windows); 8730 flags=ParseGeometry(radius,&geometry_info); 8731 paint_image=OilPaintImage(*image,geometry_info.rho,geometry_info.sigma, 8732 exception); 8733 if (paint_image != (Image *) NULL) 8734 { 8735 *image=DestroyImage(*image); 8736 *image=paint_image; 8737 } 8738 CatchException(exception); 8739 XSetCursorState(display,windows,MagickFalse); 8740 if( IfMagickTrue(windows->image.orphan) ) 8741 break; 8742 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8743 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8744 break; 8745 } 8746 case CharcoalDrawCommand: 8747 { 8748 Image 8749 *charcoal_image; 8750 8751 static char 8752 radius[MaxTextExtent] = "0x1"; 8753 8754 /* 8755 Query user for charcoal radius. 8756 */ 8757 (void) XDialogWidget(display,windows,"Charcoal Draw", 8758 "Enter the charcoal radius and sigma:",radius); 8759 if (*radius == '\0') 8760 break; 8761 /* 8762 Charcoal the image. 8763 */ 8764 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8765 exception); 8766 XSetCursorState(display,windows,MagickTrue); 8767 XCheckRefreshWindows(display,windows); 8768 flags=ParseGeometry(radius,&geometry_info); 8769 if ((flags & SigmaValue) == 0) 8770 geometry_info.sigma=geometry_info.rho; 8771 charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma, 8772 exception); 8773 if (charcoal_image != (Image *) NULL) 8774 { 8775 *image=DestroyImage(*image); 8776 *image=charcoal_image; 8777 } 8778 CatchException(exception); 8779 XSetCursorState(display,windows,MagickFalse); 8780 if( IfMagickTrue(windows->image.orphan) ) 8781 break; 8782 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8783 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8784 break; 8785 } 8786 case AnnotateCommand: 8787 { 8788 /* 8789 Annotate the image with text. 8790 */ 8791 status=XAnnotateEditImage(display,resource_info,windows,*image,exception); 8792 if( IfMagickFalse(status) ) 8793 { 8794 XNoticeWidget(display,windows,"Unable to annotate X image", 8795 (*image)->filename); 8796 break; 8797 } 8798 break; 8799 } 8800 case DrawCommand: 8801 { 8802 /* 8803 Draw image. 8804 */ 8805 status=XDrawEditImage(display,resource_info,windows,image,exception); 8806 if( IfMagickFalse(status) ) 8807 { 8808 XNoticeWidget(display,windows,"Unable to draw on the X image", 8809 (*image)->filename); 8810 break; 8811 } 8812 break; 8813 } 8814 case ColorCommand: 8815 { 8816 /* 8817 Color edit. 8818 */ 8819 status=XColorEditImage(display,resource_info,windows,image,exception); 8820 if( IfMagickFalse(status) ) 8821 { 8822 XNoticeWidget(display,windows,"Unable to pixel edit X image", 8823 (*image)->filename); 8824 break; 8825 } 8826 break; 8827 } 8828 case MatteCommand: 8829 { 8830 /* 8831 Matte edit. 8832 */ 8833 status=XMatteEditImage(display,resource_info,windows,image,exception); 8834 if( IfMagickFalse(status) ) 8835 { 8836 XNoticeWidget(display,windows,"Unable to matte edit X image", 8837 (*image)->filename); 8838 break; 8839 } 8840 break; 8841 } 8842 case CompositeCommand: 8843 { 8844 /* 8845 Composite image. 8846 */ 8847 status=XCompositeImage(display,resource_info,windows,*image, 8848 exception); 8849 if( IfMagickFalse(status) ) 8850 { 8851 XNoticeWidget(display,windows,"Unable to composite X image", 8852 (*image)->filename); 8853 break; 8854 } 8855 break; 8856 } 8857 case AddBorderCommand: 8858 { 8859 Image 8860 *border_image; 8861 8862 static char 8863 geometry[MaxTextExtent] = "6x6"; 8864 8865 /* 8866 Query user for border color and geometry. 8867 */ 8868 XColorBrowserWidget(display,windows,"Select",color); 8869 if (*color == '\0') 8870 break; 8871 (void) XDialogWidget(display,windows,"Add Border", 8872 "Enter border geometry:",geometry); 8873 if (*geometry == '\0') 8874 break; 8875 /* 8876 Add a border to the image. 8877 */ 8878 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8879 exception); 8880 XSetCursorState(display,windows,MagickTrue); 8881 XCheckRefreshWindows(display,windows); 8882 (void) QueryColorCompliance(color,AllCompliance,&(*image)->border_color, 8883 exception); 8884 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8885 exception); 8886 border_image=BorderImage(*image,&page_geometry,(*image)->compose, 8887 exception); 8888 if (border_image != (Image *) NULL) 8889 { 8890 *image=DestroyImage(*image); 8891 *image=border_image; 8892 } 8893 CatchException(exception); 8894 XSetCursorState(display,windows,MagickFalse); 8895 if( IfMagickTrue(windows->image.orphan) ) 8896 break; 8897 windows->image.window_changes.width=(int) (*image)->columns; 8898 windows->image.window_changes.height=(int) (*image)->rows; 8899 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8900 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8901 break; 8902 } 8903 case AddFrameCommand: 8904 { 8905 FrameInfo 8906 frame_info; 8907 8908 Image 8909 *frame_image; 8910 8911 static char 8912 geometry[MaxTextExtent] = "6x6"; 8913 8914 /* 8915 Query user for frame color and geometry. 8916 */ 8917 XColorBrowserWidget(display,windows,"Select",color); 8918 if (*color == '\0') 8919 break; 8920 (void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:", 8921 geometry); 8922 if (*geometry == '\0') 8923 break; 8924 /* 8925 Surround image with an ornamental border. 8926 */ 8927 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 8928 exception); 8929 XSetCursorState(display,windows,MagickTrue); 8930 XCheckRefreshWindows(display,windows); 8931 (void) QueryColorCompliance(color,AllCompliance,&(*image)->matte_color, 8932 exception); 8933 (void) ParsePageGeometry(*image,geometry,&page_geometry, 8934 exception); 8935 frame_info.width=page_geometry.width; 8936 frame_info.height=page_geometry.height; 8937 frame_info.outer_bevel=page_geometry.x; 8938 frame_info.inner_bevel=page_geometry.y; 8939 frame_info.x=(ssize_t) frame_info.width; 8940 frame_info.y=(ssize_t) frame_info.height; 8941 frame_info.width=(*image)->columns+2*frame_info.width; 8942 frame_info.height=(*image)->rows+2*frame_info.height; 8943 frame_image=FrameImage(*image,&frame_info,(*image)->compose,exception); 8944 if (frame_image != (Image *) NULL) 8945 { 8946 *image=DestroyImage(*image); 8947 *image=frame_image; 8948 } 8949 CatchException(exception); 8950 XSetCursorState(display,windows,MagickFalse); 8951 if( IfMagickTrue(windows->image.orphan) ) 8952 break; 8953 windows->image.window_changes.width=(int) (*image)->columns; 8954 windows->image.window_changes.height=(int) (*image)->rows; 8955 XConfigureImageColormap(display,resource_info,windows,*image,exception); 8956 (void) XConfigureImage(display,resource_info,windows,*image,exception); 8957 break; 8958 } 8959 case CommentCommand: 8960 { 8961 const char 8962 *value; 8963 8964 FILE 8965 *file; 8966 8967 int 8968 unique_file; 8969 8970 /* 8971 Edit image comment. 8972 */ 8973 unique_file=AcquireUniqueFileResource(image_info->filename); 8974 if (unique_file == -1) 8975 XNoticeWidget(display,windows,"Unable to edit image comment", 8976 image_info->filename); 8977 value=GetImageProperty(*image,"comment",exception); 8978 if (value == (char *) NULL) 8979 unique_file=close(unique_file)-1; 8980 else 8981 { 8982 register const char 8983 *p; 8984 8985 file=fdopen(unique_file,"w"); 8986 if (file == (FILE *) NULL) 8987 { 8988 XNoticeWidget(display,windows,"Unable to edit image comment", 8989 image_info->filename); 8990 break; 8991 } 8992 for (p=value; *p != '\0'; p++) 8993 (void) fputc((int) *p,file); 8994 (void) fputc('\n',file); 8995 (void) fclose(file); 8996 } 8997 XSetCursorState(display,windows,MagickTrue); 8998 XCheckRefreshWindows(display,windows); 8999 status=InvokeDelegate(image_info,*image,"edit",(char *) NULL, 9000 exception); 9001 if( IfMagickFalse(status) ) 9002 XNoticeWidget(display,windows,"Unable to edit image comment", 9003 (char *) NULL); 9004 else 9005 { 9006 char 9007 *comment; 9008 9009 comment=FileToString(image_info->filename,~0UL,exception); 9010 if (comment != (char *) NULL) 9011 { 9012 (void) SetImageProperty(*image,"comment",comment,exception); 9013 (*image)->taint=MagickTrue; 9014 } 9015 } 9016 (void) RelinquishUniqueFileResource(image_info->filename); 9017 XSetCursorState(display,windows,MagickFalse); 9018 break; 9019 } 9020 case LaunchCommand: 9021 { 9022 /* 9023 Launch program. 9024 */ 9025 XSetCursorState(display,windows,MagickTrue); 9026 XCheckRefreshWindows(display,windows); 9027 (void) AcquireUniqueFilename(filename); 9028 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s", 9029 filename); 9030 status=WriteImage(image_info,*image,exception); 9031 if( IfMagickFalse(status) ) 9032 XNoticeWidget(display,windows,"Unable to launch image editor", 9033 (char *) NULL); 9034 else 9035 { 9036 nexus=ReadImage(resource_info->image_info,exception); 9037 CatchException(exception); 9038 XClientMessage(display,windows->image.id,windows->im_protocols, 9039 windows->im_next_image,CurrentTime); 9040 } 9041 (void) RelinquishUniqueFileResource(filename); 9042 XSetCursorState(display,windows,MagickFalse); 9043 break; 9044 } 9045 case RegionofInterestCommand: 9046 { 9047 /* 9048 Apply an image processing technique to a region of interest. 9049 */ 9050 (void) XROIImage(display,resource_info,windows,image,exception); 9051 break; 9052 } 9053 case InfoCommand: 9054 break; 9055 case ZoomCommand: 9056 { 9057 /* 9058 Zoom image. 9059 */ 9060 if( IfMagickTrue(windows->magnify.mapped) ) 9061 (void) XRaiseWindow(display,windows->magnify.id); 9062 else 9063 { 9064 /* 9065 Make magnify image. 9066 */ 9067 XSetCursorState(display,windows,MagickTrue); 9068 (void) XMapRaised(display,windows->magnify.id); 9069 XSetCursorState(display,windows,MagickFalse); 9070 } 9071 break; 9072 } 9073 case ShowPreviewCommand: 9074 { 9075 char 9076 **previews; 9077 9078 Image 9079 *preview_image; 9080 9081 static char 9082 preview_type[MaxTextExtent] = "Gamma"; 9083 9084 /* 9085 Select preview type from menu. 9086 */ 9087 previews=GetCommandOptions(MagickPreviewOptions); 9088 if (previews == (char **) NULL) 9089 break; 9090 XListBrowserWidget(display,windows,&windows->widget, 9091 (const char **) previews,"Preview", 9092 "Select an enhancement, effect, or F/X:",preview_type); 9093 previews=DestroyStringList(previews); 9094 if (*preview_type == '\0') 9095 break; 9096 /* 9097 Show image preview. 9098 */ 9099 XSetCursorState(display,windows,MagickTrue); 9100 XCheckRefreshWindows(display,windows); 9101 image_info->preview_type=(PreviewType) 9102 ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type); 9103 image_info->group=(ssize_t) windows->image.id; 9104 (void) DeleteImageProperty(*image,"label"); 9105 (void) SetImageProperty(*image,"label","Preview",exception); 9106 (void) AcquireUniqueFilename(filename); 9107 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s", 9108 filename); 9109 status=WriteImage(image_info,*image,exception); 9110 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9111 preview_image=ReadImage(image_info,exception); 9112 (void) RelinquishUniqueFileResource(filename); 9113 if (preview_image == (Image *) NULL) 9114 break; 9115 (void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s", 9116 filename); 9117 status=WriteImage(image_info,preview_image,exception); 9118 preview_image=DestroyImage(preview_image); 9119 if( IfMagickFalse(status) ) 9120 XNoticeWidget(display,windows,"Unable to show image preview", 9121 (*image)->filename); 9122 XDelay(display,1500); 9123 XSetCursorState(display,windows,MagickFalse); 9124 break; 9125 } 9126 case ShowHistogramCommand: 9127 { 9128 Image 9129 *histogram_image; 9130 9131 /* 9132 Show image histogram. 9133 */ 9134 XSetCursorState(display,windows,MagickTrue); 9135 XCheckRefreshWindows(display,windows); 9136 image_info->group=(ssize_t) windows->image.id; 9137 (void) DeleteImageProperty(*image,"label"); 9138 (void) SetImageProperty(*image,"label","Histogram",exception); 9139 (void) AcquireUniqueFilename(filename); 9140 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s", 9141 filename); 9142 status=WriteImage(image_info,*image,exception); 9143 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9144 histogram_image=ReadImage(image_info,exception); 9145 (void) RelinquishUniqueFileResource(filename); 9146 if (histogram_image == (Image *) NULL) 9147 break; 9148 (void) FormatLocaleString(histogram_image->filename,MaxTextExtent, 9149 "show:%s",filename); 9150 status=WriteImage(image_info,histogram_image,exception); 9151 histogram_image=DestroyImage(histogram_image); 9152 if( IfMagickFalse(status) ) 9153 XNoticeWidget(display,windows,"Unable to show histogram", 9154 (*image)->filename); 9155 XDelay(display,1500); 9156 XSetCursorState(display,windows,MagickFalse); 9157 break; 9158 } 9159 case ShowMatteCommand: 9160 { 9161 Image 9162 *matte_image; 9163 9164 if ((*image)->alpha_trait != BlendPixelTrait) 9165 { 9166 XNoticeWidget(display,windows, 9167 "Image does not have any matte information",(*image)->filename); 9168 break; 9169 } 9170 /* 9171 Show image matte. 9172 */ 9173 XSetCursorState(display,windows,MagickTrue); 9174 XCheckRefreshWindows(display,windows); 9175 image_info->group=(ssize_t) windows->image.id; 9176 (void) DeleteImageProperty(*image,"label"); 9177 (void) SetImageProperty(*image,"label","Matte",exception); 9178 (void) AcquireUniqueFilename(filename); 9179 (void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s", 9180 filename); 9181 status=WriteImage(image_info,*image,exception); 9182 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 9183 matte_image=ReadImage(image_info,exception); 9184 (void) RelinquishUniqueFileResource(filename); 9185 if (matte_image == (Image *) NULL) 9186 break; 9187 (void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s", 9188 filename); 9189 status=WriteImage(image_info,matte_image,exception); 9190 matte_image=DestroyImage(matte_image); 9191 if( IfMagickFalse(status) ) 9192 XNoticeWidget(display,windows,"Unable to show matte", 9193 (*image)->filename); 9194 XDelay(display,1500); 9195 XSetCursorState(display,windows,MagickFalse); 9196 break; 9197 } 9198 case BackgroundCommand: 9199 { 9200 /* 9201 Background image. 9202 */ 9203 status=XBackgroundImage(display,resource_info,windows,image,exception); 9204 if( IfMagickFalse(status) ) 9205 break; 9206 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9207 if (nexus != (Image *) NULL) 9208 XClientMessage(display,windows->image.id,windows->im_protocols, 9209 windows->im_next_image,CurrentTime); 9210 break; 9211 } 9212 case SlideShowCommand: 9213 { 9214 static char 9215 delay[MaxTextExtent] = "5"; 9216 9217 /* 9218 Display next image after pausing. 9219 */ 9220 (void) XDialogWidget(display,windows,"Slide Show", 9221 "Pause how many 1/100ths of a second between images:",delay); 9222 if (*delay == '\0') 9223 break; 9224 resource_info->delay=StringToUnsignedLong(delay); 9225 XClientMessage(display,windows->image.id,windows->im_protocols, 9226 windows->im_next_image,CurrentTime); 9227 break; 9228 } 9229 case PreferencesCommand: 9230 { 9231 /* 9232 Set user preferences. 9233 */ 9234 status=XPreferencesWidget(display,resource_info,windows); 9235 if( IfMagickFalse(status) ) 9236 break; 9237 nexus=CloneImage(*image,0,0,MagickTrue,exception); 9238 if (nexus != (Image *) NULL) 9239 XClientMessage(display,windows->image.id,windows->im_protocols, 9240 windows->im_next_image,CurrentTime); 9241 break; 9242 } 9243 case HelpCommand: 9244 { 9245 /* 9246 User requested help. 9247 */ 9248 XTextViewWidget(display,resource_info,windows,MagickFalse, 9249 "Help Viewer - Display",DisplayHelp); 9250 break; 9251 } 9252 case BrowseDocumentationCommand: 9253 { 9254 Atom 9255 mozilla_atom; 9256 9257 Window 9258 mozilla_window, 9259 root_window; 9260 9261 /* 9262 Browse the ImageMagick documentation. 9263 */ 9264 root_window=XRootWindow(display,XDefaultScreen(display)); 9265 mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse); 9266 mozilla_window=XWindowByProperty(display,root_window,mozilla_atom); 9267 if (mozilla_window != (Window) NULL) 9268 { 9269 char 9270 command[MaxTextExtent], 9271 *url; 9272 9273 /* 9274 Display documentation using Netscape remote control. 9275 */ 9276 url=GetMagickHomeURL(); 9277 (void) FormatLocaleString(command,MaxTextExtent, 9278 "openurl(%s,new-tab)",url); 9279 url=DestroyString(url); 9280 mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse); 9281 (void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING, 9282 8,PropModeReplace,(unsigned char *) command,(int) strlen(command)); 9283 XSetCursorState(display,windows,MagickFalse); 9284 break; 9285 } 9286 XSetCursorState(display,windows,MagickTrue); 9287 XCheckRefreshWindows(display,windows); 9288 status=InvokeDelegate(image_info,*image,"browse",(char *) NULL, 9289 exception); 9290 if( IfMagickFalse(status) ) 9291 XNoticeWidget(display,windows,"Unable to browse documentation", 9292 (char *) NULL); 9293 XDelay(display,1500); 9294 XSetCursorState(display,windows,MagickFalse); 9295 break; 9296 } 9297 case VersionCommand: 9298 { 9299 XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL), 9300 GetMagickCopyright()); 9301 break; 9302 } 9303 case SaveToUndoBufferCommand: 9304 break; 9305 default: 9306 { 9307 (void) XBell(display,0); 9308 break; 9309 } 9310 } 9311 image_info=DestroyImageInfo(image_info); 9312 return(nexus); 9313} 9314 9315/* 9316%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9317% % 9318% % 9319% % 9320+ X M a g n i f y I m a g e % 9321% % 9322% % 9323% % 9324%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9325% 9326% XMagnifyImage() magnifies portions of the image as indicated by the pointer. 9327% The magnified portion is displayed in a separate window. 9328% 9329% The format of the XMagnifyImage method is: 9330% 9331% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9332% ExceptionInfo *exception) 9333% 9334% A description of each parameter follows: 9335% 9336% o display: Specifies a connection to an X server; returned from 9337% XOpenDisplay. 9338% 9339% o windows: Specifies a pointer to a XWindows structure. 9340% 9341% o event: Specifies a pointer to a XEvent structure. If it is NULL, 9342% the entire image is refreshed. 9343% 9344% o exception: return any errors or warnings in this structure. 9345% 9346*/ 9347static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event, 9348 ExceptionInfo *exception) 9349{ 9350 char 9351 text[MaxTextExtent]; 9352 9353 register int 9354 x, 9355 y; 9356 9357 size_t 9358 state; 9359 9360 /* 9361 Update magnified image until the mouse button is released. 9362 */ 9363 (void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor); 9364 state=DefaultState; 9365 x=event->xbutton.x; 9366 y=event->xbutton.y; 9367 windows->magnify.x=(int) windows->image.x+x; 9368 windows->magnify.y=(int) windows->image.y+y; 9369 do 9370 { 9371 /* 9372 Map and unmap Info widget as text cursor crosses its boundaries. 9373 */ 9374 if( IfMagickTrue(windows->info.mapped) ) 9375 { 9376 if ((x < (int) (windows->info.x+windows->info.width)) && 9377 (y < (int) (windows->info.y+windows->info.height))) 9378 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 9379 } 9380 else 9381 if ((x > (int) (windows->info.x+windows->info.width)) || 9382 (y > (int) (windows->info.y+windows->info.height))) 9383 (void) XMapWindow(display,windows->info.id); 9384 if( IfMagickTrue(windows->info.mapped) ) 9385 { 9386 /* 9387 Display pointer position. 9388 */ 9389 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9390 windows->magnify.x,windows->magnify.y); 9391 XInfoWidget(display,windows,text); 9392 } 9393 /* 9394 Wait for next event. 9395 */ 9396 XScreenEvent(display,windows,event,exception); 9397 switch (event->type) 9398 { 9399 case ButtonPress: 9400 break; 9401 case ButtonRelease: 9402 { 9403 /* 9404 User has finished magnifying image. 9405 */ 9406 x=event->xbutton.x; 9407 y=event->xbutton.y; 9408 state|=ExitState; 9409 break; 9410 } 9411 case Expose: 9412 break; 9413 case MotionNotify: 9414 { 9415 x=event->xmotion.x; 9416 y=event->xmotion.y; 9417 break; 9418 } 9419 default: 9420 break; 9421 } 9422 /* 9423 Check boundary conditions. 9424 */ 9425 if (x < 0) 9426 x=0; 9427 else 9428 if (x >= (int) windows->image.width) 9429 x=(int) windows->image.width-1; 9430 if (y < 0) 9431 y=0; 9432 else 9433 if (y >= (int) windows->image.height) 9434 y=(int) windows->image.height-1; 9435 } while ((state & ExitState) == 0); 9436 /* 9437 Display magnified image. 9438 */ 9439 XSetCursorState(display,windows,MagickFalse); 9440} 9441 9442/* 9443%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9444% % 9445% % 9446% % 9447+ X M a g n i f y W i n d o w C o m m a n d % 9448% % 9449% % 9450% % 9451%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9452% 9453% XMagnifyWindowCommand() moves the image within an Magnify window by one 9454% pixel as specified by the key symbol. 9455% 9456% The format of the XMagnifyWindowCommand method is: 9457% 9458% void XMagnifyWindowCommand(Display *display,XWindows *windows, 9459% const MagickStatusType state,const KeySym key_symbol, 9460% ExceptionInfo *exception) 9461% 9462% A description of each parameter follows: 9463% 9464% o display: Specifies a connection to an X server; returned from 9465% XOpenDisplay. 9466% 9467% o windows: Specifies a pointer to a XWindows structure. 9468% 9469% o state: key mask. 9470% 9471% o key_symbol: Specifies a KeySym which indicates which side of the image 9472% to trim. 9473% 9474% o exception: return any errors or warnings in this structure. 9475% 9476*/ 9477static void XMagnifyWindowCommand(Display *display,XWindows *windows, 9478 const MagickStatusType state,const KeySym key_symbol,ExceptionInfo *exception) 9479{ 9480 unsigned int 9481 quantum; 9482 9483 /* 9484 User specified a magnify factor or position. 9485 */ 9486 quantum=1; 9487 if ((state & Mod1Mask) != 0) 9488 quantum=10; 9489 switch ((int) key_symbol) 9490 { 9491 case QuitCommand: 9492 { 9493 (void) XWithdrawWindow(display,windows->magnify.id, 9494 windows->magnify.screen); 9495 break; 9496 } 9497 case XK_Home: 9498 case XK_KP_Home: 9499 { 9500 windows->magnify.x=(int) windows->image.width/2; 9501 windows->magnify.y=(int) windows->image.height/2; 9502 break; 9503 } 9504 case XK_Left: 9505 case XK_KP_Left: 9506 { 9507 if (windows->magnify.x > 0) 9508 windows->magnify.x-=quantum; 9509 break; 9510 } 9511 case XK_Up: 9512 case XK_KP_Up: 9513 { 9514 if (windows->magnify.y > 0) 9515 windows->magnify.y-=quantum; 9516 break; 9517 } 9518 case XK_Right: 9519 case XK_KP_Right: 9520 { 9521 if (windows->magnify.x < (int) (windows->image.ximage->width-1)) 9522 windows->magnify.x+=quantum; 9523 break; 9524 } 9525 case XK_Down: 9526 case XK_KP_Down: 9527 { 9528 if (windows->magnify.y < (int) (windows->image.ximage->height-1)) 9529 windows->magnify.y+=quantum; 9530 break; 9531 } 9532 case XK_0: 9533 case XK_1: 9534 case XK_2: 9535 case XK_3: 9536 case XK_4: 9537 case XK_5: 9538 case XK_6: 9539 case XK_7: 9540 case XK_8: 9541 case XK_9: 9542 { 9543 windows->magnify.data=(key_symbol-XK_0); 9544 break; 9545 } 9546 case XK_KP_0: 9547 case XK_KP_1: 9548 case XK_KP_2: 9549 case XK_KP_3: 9550 case XK_KP_4: 9551 case XK_KP_5: 9552 case XK_KP_6: 9553 case XK_KP_7: 9554 case XK_KP_8: 9555 case XK_KP_9: 9556 { 9557 windows->magnify.data=(key_symbol-XK_KP_0); 9558 break; 9559 } 9560 default: 9561 break; 9562 } 9563 XMakeMagnifyImage(display,windows,exception); 9564} 9565 9566/* 9567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9568% % 9569% % 9570% % 9571+ X M a k e P a n I m a g e % 9572% % 9573% % 9574% % 9575%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9576% 9577% XMakePanImage() creates a thumbnail of the image and displays it in the Pan 9578% icon window. 9579% 9580% The format of the XMakePanImage method is: 9581% 9582% void XMakePanImage(Display *display,XResourceInfo *resource_info, 9583% XWindows *windows,Image *image,ExceptionInfo *exception) 9584% 9585% A description of each parameter follows: 9586% 9587% o display: Specifies a connection to an X server; returned from 9588% XOpenDisplay. 9589% 9590% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9591% 9592% o windows: Specifies a pointer to a XWindows structure. 9593% 9594% o image: the image. 9595% 9596% o exception: return any errors or warnings in this structure. 9597% 9598*/ 9599static void XMakePanImage(Display *display,XResourceInfo *resource_info, 9600 XWindows *windows,Image *image,ExceptionInfo *exception) 9601{ 9602 MagickStatusType 9603 status; 9604 9605 /* 9606 Create and display image for panning icon. 9607 */ 9608 XSetCursorState(display,windows,MagickTrue); 9609 XCheckRefreshWindows(display,windows); 9610 windows->pan.x=(int) windows->image.x; 9611 windows->pan.y=(int) windows->image.y; 9612 status=XMakeImage(display,resource_info,&windows->pan,image, 9613 windows->pan.width,windows->pan.height,exception); 9614 if( IfMagickFalse(status) ) 9615 ThrowXWindowFatalException(ResourceLimitError, 9616 "MemoryAllocationFailed",image->filename); 9617 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 9618 windows->pan.pixmap); 9619 (void) XClearWindow(display,windows->pan.id); 9620 XDrawPanRectangle(display,windows); 9621 XSetCursorState(display,windows,MagickFalse); 9622} 9623 9624/* 9625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9626% % 9627% % 9628% % 9629+ X M a t t a E d i t I m a g e % 9630% % 9631% % 9632% % 9633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 9634% 9635% XMatteEditImage() allows the user to interactively change the Matte channel 9636% of an image. If the image is PseudoClass it is promoted to DirectClass 9637% before the matte information is stored. 9638% 9639% The format of the XMatteEditImage method is: 9640% 9641% MagickBooleanType XMatteEditImage(Display *display, 9642% XResourceInfo *resource_info,XWindows *windows,Image **image, 9643% ExceptionInfo *exception) 9644% 9645% A description of each parameter follows: 9646% 9647% o display: Specifies a connection to an X server; returned from 9648% XOpenDisplay. 9649% 9650% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 9651% 9652% o windows: Specifies a pointer to a XWindows structure. 9653% 9654% o image: the image; returned from ReadImage. 9655% 9656% o exception: return any errors or warnings in this structure. 9657% 9658*/ 9659static MagickBooleanType XMatteEditImage(Display *display, 9660 XResourceInfo *resource_info,XWindows *windows,Image **image, 9661 ExceptionInfo *exception) 9662{ 9663 static char 9664 matte[MaxTextExtent] = "0"; 9665 9666 static const char 9667 *MatteEditMenu[] = 9668 { 9669 "Method", 9670 "Border Color", 9671 "Fuzz", 9672 "Matte Value", 9673 "Undo", 9674 "Help", 9675 "Dismiss", 9676 (char *) NULL 9677 }; 9678 9679 static const ModeType 9680 MatteEditCommands[] = 9681 { 9682 MatteEditMethod, 9683 MatteEditBorderCommand, 9684 MatteEditFuzzCommand, 9685 MatteEditValueCommand, 9686 MatteEditUndoCommand, 9687 MatteEditHelpCommand, 9688 MatteEditDismissCommand 9689 }; 9690 9691 static PaintMethod 9692 method = PointMethod; 9693 9694 static XColor 9695 border_color = { 0, 0, 0, 0, 0, 0 }; 9696 9697 char 9698 command[MaxTextExtent], 9699 text[MaxTextExtent]; 9700 9701 Cursor 9702 cursor; 9703 9704 int 9705 entry, 9706 id, 9707 x, 9708 x_offset, 9709 y, 9710 y_offset; 9711 9712 register int 9713 i; 9714 9715 register Quantum 9716 *q; 9717 9718 unsigned int 9719 height, 9720 width; 9721 9722 size_t 9723 state; 9724 9725 XEvent 9726 event; 9727 9728 /* 9729 Map Command widget. 9730 */ 9731 (void) CloneString(&windows->command.name,"Matte Edit"); 9732 windows->command.data=4; 9733 (void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL); 9734 (void) XMapRaised(display,windows->command.id); 9735 XClientMessage(display,windows->image.id,windows->im_protocols, 9736 windows->im_update_widget,CurrentTime); 9737 /* 9738 Make cursor. 9739 */ 9740 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 9741 resource_info->background_color,resource_info->foreground_color); 9742 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9743 /* 9744 Track pointer until button 1 is pressed. 9745 */ 9746 XQueryPosition(display,windows->image.id,&x,&y); 9747 (void) XSelectInput(display,windows->image.id, 9748 windows->image.attributes.event_mask | PointerMotionMask); 9749 state=DefaultState; 9750 do 9751 { 9752 if( IfMagickTrue(windows->info.mapped) ) 9753 { 9754 /* 9755 Display pointer position. 9756 */ 9757 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 9758 x+windows->image.x,y+windows->image.y); 9759 XInfoWidget(display,windows,text); 9760 } 9761 /* 9762 Wait for next event. 9763 */ 9764 XScreenEvent(display,windows,&event,exception); 9765 if (event.xany.window == windows->command.id) 9766 { 9767 /* 9768 Select a command from the Command widget. 9769 */ 9770 id=XCommandWidget(display,windows,MatteEditMenu,&event); 9771 if (id < 0) 9772 { 9773 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9774 continue; 9775 } 9776 switch (MatteEditCommands[id]) 9777 { 9778 case MatteEditMethod: 9779 { 9780 char 9781 **methods; 9782 9783 /* 9784 Select a method from the pop-up menu. 9785 */ 9786 methods=GetCommandOptions(MagickMethodOptions); 9787 if (methods == (char **) NULL) 9788 break; 9789 entry=XMenuWidget(display,windows,MatteEditMenu[id], 9790 (const char **) methods,command); 9791 if (entry >= 0) 9792 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 9793 MagickFalse,methods[entry]); 9794 methods=DestroyStringList(methods); 9795 break; 9796 } 9797 case MatteEditBorderCommand: 9798 { 9799 const char 9800 *ColorMenu[MaxNumberPens]; 9801 9802 int 9803 pen_number; 9804 9805 /* 9806 Initialize menu selections. 9807 */ 9808 for (i=0; i < (int) (MaxNumberPens-2); i++) 9809 ColorMenu[i]=resource_info->pen_colors[i]; 9810 ColorMenu[MaxNumberPens-2]="Browser..."; 9811 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 9812 /* 9813 Select a pen color from the pop-up menu. 9814 */ 9815 pen_number=XMenuWidget(display,windows,MatteEditMenu[id], 9816 (const char **) ColorMenu,command); 9817 if (pen_number < 0) 9818 break; 9819 if (pen_number == (MaxNumberPens-2)) 9820 { 9821 static char 9822 color_name[MaxTextExtent] = "gray"; 9823 9824 /* 9825 Select a pen color from a dialog. 9826 */ 9827 resource_info->pen_colors[pen_number]=color_name; 9828 XColorBrowserWidget(display,windows,"Select",color_name); 9829 if (*color_name == '\0') 9830 break; 9831 } 9832 /* 9833 Set border color. 9834 */ 9835 (void) XParseColor(display,windows->map_info->colormap, 9836 resource_info->pen_colors[pen_number],&border_color); 9837 break; 9838 } 9839 case MatteEditFuzzCommand: 9840 { 9841 static char 9842 fuzz[MaxTextExtent]; 9843 9844 static const char 9845 *FuzzMenu[] = 9846 { 9847 "0%", 9848 "2%", 9849 "5%", 9850 "10%", 9851 "15%", 9852 "Dialog...", 9853 (char *) NULL, 9854 }; 9855 9856 /* 9857 Select a command from the pop-up menu. 9858 */ 9859 entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu, 9860 command); 9861 if (entry < 0) 9862 break; 9863 if (entry != 5) 9864 { 9865 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 9866 QuantumRange+1.0); 9867 break; 9868 } 9869 (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 9870 (void) XDialogWidget(display,windows,"Ok", 9871 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 9872 if (*fuzz == '\0') 9873 break; 9874 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 9875 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 9876 1.0); 9877 break; 9878 } 9879 case MatteEditValueCommand: 9880 { 9881 static char 9882 message[MaxTextExtent]; 9883 9884 static const char 9885 *MatteMenu[] = 9886 { 9887 "Opaque", 9888 "Transparent", 9889 "Dialog...", 9890 (char *) NULL, 9891 }; 9892 9893 /* 9894 Select a command from the pop-up menu. 9895 */ 9896 entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu, 9897 command); 9898 if (entry < 0) 9899 break; 9900 if (entry != 2) 9901 { 9902 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9903 OpaqueAlpha); 9904 if (LocaleCompare(MatteMenu[entry],"Transparent") == 0) 9905 (void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat, 9906 (Quantum) TransparentAlpha); 9907 break; 9908 } 9909 (void) FormatLocaleString(message,MaxTextExtent, 9910 "Enter matte value (0 - " QuantumFormat "):",(Quantum) 9911 QuantumRange); 9912 (void) XDialogWidget(display,windows,"Matte",message,matte); 9913 if (*matte == '\0') 9914 break; 9915 break; 9916 } 9917 case MatteEditUndoCommand: 9918 { 9919 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 9920 image,exception); 9921 break; 9922 } 9923 case MatteEditHelpCommand: 9924 { 9925 XTextViewWidget(display,resource_info,windows,MagickFalse, 9926 "Help Viewer - Matte Edit",ImageMatteEditHelp); 9927 break; 9928 } 9929 case MatteEditDismissCommand: 9930 { 9931 /* 9932 Prematurely exit. 9933 */ 9934 state|=EscapeState; 9935 state|=ExitState; 9936 break; 9937 } 9938 default: 9939 break; 9940 } 9941 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9942 continue; 9943 } 9944 switch (event.type) 9945 { 9946 case ButtonPress: 9947 { 9948 if (event.xbutton.button != Button1) 9949 break; 9950 if ((event.xbutton.window != windows->image.id) && 9951 (event.xbutton.window != windows->magnify.id)) 9952 break; 9953 /* 9954 Update matte data. 9955 */ 9956 x=event.xbutton.x; 9957 y=event.xbutton.y; 9958 (void) XMagickCommand(display,resource_info,windows, 9959 SaveToUndoBufferCommand,image,exception); 9960 state|=UpdateConfigurationState; 9961 break; 9962 } 9963 case ButtonRelease: 9964 { 9965 if (event.xbutton.button != Button1) 9966 break; 9967 if ((event.xbutton.window != windows->image.id) && 9968 (event.xbutton.window != windows->magnify.id)) 9969 break; 9970 /* 9971 Update colormap information. 9972 */ 9973 x=event.xbutton.x; 9974 y=event.xbutton.y; 9975 XConfigureImageColormap(display,resource_info,windows,*image,exception); 9976 (void) XConfigureImage(display,resource_info,windows,*image,exception); 9977 XInfoWidget(display,windows,text); 9978 (void) XCheckDefineCursor(display,windows->image.id,cursor); 9979 state&=(~UpdateConfigurationState); 9980 break; 9981 } 9982 case Expose: 9983 break; 9984 case KeyPress: 9985 { 9986 char 9987 command[MaxTextExtent]; 9988 9989 KeySym 9990 key_symbol; 9991 9992 if (event.xkey.window == windows->magnify.id) 9993 { 9994 Window 9995 window; 9996 9997 window=windows->magnify.id; 9998 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 9999 } 10000 if (event.xkey.window != windows->image.id) 10001 break; 10002 /* 10003 Respond to a user key press. 10004 */ 10005 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 10006 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10007 switch ((int) key_symbol) 10008 { 10009 case XK_Escape: 10010 case XK_F20: 10011 { 10012 /* 10013 Prematurely exit. 10014 */ 10015 state|=ExitState; 10016 break; 10017 } 10018 case XK_F1: 10019 case XK_Help: 10020 { 10021 XTextViewWidget(display,resource_info,windows,MagickFalse, 10022 "Help Viewer - Matte Edit",ImageMatteEditHelp); 10023 break; 10024 } 10025 default: 10026 { 10027 (void) XBell(display,0); 10028 break; 10029 } 10030 } 10031 break; 10032 } 10033 case MotionNotify: 10034 { 10035 /* 10036 Map and unmap Info widget as cursor crosses its boundaries. 10037 */ 10038 x=event.xmotion.x; 10039 y=event.xmotion.y; 10040 if( IfMagickTrue(windows->info.mapped) ) 10041 { 10042 if ((x < (int) (windows->info.x+windows->info.width)) && 10043 (y < (int) (windows->info.y+windows->info.height))) 10044 (void) XWithdrawWindow(display,windows->info.id, 10045 windows->info.screen); 10046 } 10047 else 10048 if ((x > (int) (windows->info.x+windows->info.width)) || 10049 (y > (int) (windows->info.y+windows->info.height))) 10050 (void) XMapWindow(display,windows->info.id); 10051 break; 10052 } 10053 default: 10054 break; 10055 } 10056 if (event.xany.window == windows->magnify.id) 10057 { 10058 x=windows->magnify.x-windows->image.x; 10059 y=windows->magnify.y-windows->image.y; 10060 } 10061 x_offset=x; 10062 y_offset=y; 10063 if ((state & UpdateConfigurationState) != 0) 10064 { 10065 CacheView 10066 *image_view; 10067 10068 int 10069 x, 10070 y; 10071 10072 /* 10073 Matte edit is relative to image configuration. 10074 */ 10075 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 10076 MagickTrue); 10077 XPutPixel(windows->image.ximage,x_offset,y_offset, 10078 windows->pixel_info->background_color.pixel); 10079 width=(unsigned int) (*image)->columns; 10080 height=(unsigned int) (*image)->rows; 10081 x=0; 10082 y=0; 10083 if (windows->image.crop_geometry != (char *) NULL) 10084 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width, 10085 &height); 10086 x_offset=(int) (width*(windows->image.x+x_offset)/ 10087 windows->image.ximage->width+x); 10088 y_offset=(int) (height*(windows->image.y+y_offset)/ 10089 windows->image.ximage->height+y); 10090 if ((x_offset < 0) || (y_offset < 0)) 10091 continue; 10092 if ((x_offset >= (int) (*image)->columns) || 10093 (y_offset >= (int) (*image)->rows)) 10094 continue; 10095 if( IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) ) 10096 return(MagickFalse); 10097 if ((*image)->alpha_trait != BlendPixelTrait) 10098 (void) SetImageAlphaChannel(*image,OpaqueAlphaChannel,exception); 10099 image_view=AcquireAuthenticCacheView(*image,exception); 10100 switch (method) 10101 { 10102 case PointMethod: 10103 default: 10104 { 10105 /* 10106 Update matte information using point algorithm. 10107 */ 10108 q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset, 10109 (ssize_t) y_offset,1,1,exception); 10110 if (q == (Quantum *) NULL) 10111 break; 10112 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10113 (void) SyncCacheViewAuthenticPixels(image_view,exception); 10114 break; 10115 } 10116 case ReplaceMethod: 10117 { 10118 PixelInfo 10119 pixel, 10120 target; 10121 10122 /* 10123 Update matte information using replace algorithm. 10124 */ 10125 (void) GetOneCacheViewVirtualPixelInfo(image_view,(ssize_t) 10126 x_offset,(ssize_t) y_offset,&target,exception); 10127 for (y=0; y < (int) (*image)->rows; y++) 10128 { 10129 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10130 (*image)->columns,1,exception); 10131 if (q == (Quantum *) NULL) 10132 break; 10133 for (x=0; x < (int) (*image)->columns; x++) 10134 { 10135 GetPixelInfoPixel(*image,q,&pixel); 10136 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 10137 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10138 q+=GetPixelChannels(*image); 10139 } 10140 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 10141 break; 10142 } 10143 break; 10144 } 10145 case FloodfillMethod: 10146 case FillToBorderMethod: 10147 { 10148 ChannelType 10149 channel_mask; 10150 10151 DrawInfo 10152 *draw_info; 10153 10154 PixelInfo 10155 target; 10156 10157 /* 10158 Update matte information using floodfill algorithm. 10159 */ 10160 (void) GetOneVirtualPixelInfo(*image, 10161 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 10162 y_offset,&target,exception); 10163 if (method == FillToBorderMethod) 10164 { 10165 target.red=(double) ScaleShortToQuantum( 10166 border_color.red); 10167 target.green=(double) ScaleShortToQuantum( 10168 border_color.green); 10169 target.blue=(double) ScaleShortToQuantum( 10170 border_color.blue); 10171 } 10172 draw_info=CloneDrawInfo(resource_info->image_info, 10173 (DrawInfo *) NULL); 10174 draw_info->fill.alpha=(double) ClampToQuantum( 10175 StringToDouble(matte,(char **) NULL)); 10176 channel_mask=SetImageChannelMask(*image,AlphaChannel); 10177 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 10178 x_offset,(ssize_t) y_offset, 10179 IsMagickFalse(method == FloodfillMethod),exception); 10180 (void) SetPixelChannelMask(*image,channel_mask); 10181 draw_info=DestroyDrawInfo(draw_info); 10182 break; 10183 } 10184 case ResetMethod: 10185 { 10186 /* 10187 Update matte information using reset algorithm. 10188 */ 10189 if( IfMagickFalse(SetImageStorageClass(*image,DirectClass,exception)) ) 10190 return(MagickFalse); 10191 for (y=0; y < (int) (*image)->rows; y++) 10192 { 10193 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 10194 (*image)->columns,1,exception); 10195 if (q == (Quantum *) NULL) 10196 break; 10197 for (x=0; x < (int) (*image)->columns; x++) 10198 { 10199 SetPixelAlpha(*image,(Quantum) StringToLong(matte),q); 10200 q+=GetPixelChannels(*image); 10201 } 10202 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 10203 break; 10204 } 10205 if (StringToLong(matte) == (long) OpaqueAlpha) 10206 (*image)->alpha_trait=UndefinedPixelTrait; 10207 break; 10208 } 10209 } 10210 image_view=DestroyCacheView(image_view); 10211 state&=(~UpdateConfigurationState); 10212 } 10213 } while ((state & ExitState) == 0); 10214 (void) XSelectInput(display,windows->image.id, 10215 windows->image.attributes.event_mask); 10216 XSetCursorState(display,windows,MagickFalse); 10217 (void) XFreeCursor(display,cursor); 10218 return(MagickTrue); 10219} 10220 10221/* 10222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10223% % 10224% % 10225% % 10226+ X O p e n I m a g e % 10227% % 10228% % 10229% % 10230%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10231% 10232% XOpenImage() loads an image from a file. 10233% 10234% The format of the XOpenImage method is: 10235% 10236% Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10237% XWindows *windows,const unsigned int command) 10238% 10239% A description of each parameter follows: 10240% 10241% o display: Specifies a connection to an X server; returned from 10242% XOpenDisplay. 10243% 10244% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10245% 10246% o windows: Specifies a pointer to a XWindows structure. 10247% 10248% o command: A value other than zero indicates that the file is selected 10249% from the command line argument list. 10250% 10251*/ 10252static Image *XOpenImage(Display *display,XResourceInfo *resource_info, 10253 XWindows *windows,const MagickBooleanType command) 10254{ 10255 const MagickInfo 10256 *magick_info; 10257 10258 ExceptionInfo 10259 *exception; 10260 10261 Image 10262 *nexus; 10263 10264 ImageInfo 10265 *image_info; 10266 10267 static char 10268 filename[MaxTextExtent] = "\0"; 10269 10270 /* 10271 Request file name from user. 10272 */ 10273 if( IfMagickFalse(command) ) 10274 XFileBrowserWidget(display,windows,"Open",filename); 10275 else 10276 { 10277 char 10278 **filelist, 10279 **files; 10280 10281 int 10282 count, 10283 status; 10284 10285 register int 10286 i, 10287 j; 10288 10289 /* 10290 Select next image from the command line. 10291 */ 10292 status=XGetCommand(display,windows->image.id,&files,&count); 10293 if (status == 0) 10294 { 10295 ThrowXWindowFatalException(XServerError,"UnableToGetProperty","..."); 10296 return((Image *) NULL); 10297 } 10298 filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist)); 10299 if (filelist == (char **) NULL) 10300 { 10301 ThrowXWindowFatalException(ResourceLimitError, 10302 "MemoryAllocationFailed","..."); 10303 (void) XFreeStringList(files); 10304 return((Image *) NULL); 10305 } 10306 j=0; 10307 for (i=1; i < count; i++) 10308 if (*files[i] != '-') 10309 filelist[j++]=files[i]; 10310 filelist[j]=(char *) NULL; 10311 XListBrowserWidget(display,windows,&windows->widget, 10312 (const char **) filelist,"Load","Select Image to Load:",filename); 10313 filelist=(char **) RelinquishMagickMemory(filelist); 10314 (void) XFreeStringList(files); 10315 } 10316 if (*filename == '\0') 10317 return((Image *) NULL); 10318 image_info=CloneImageInfo(resource_info->image_info); 10319 (void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL, 10320 (void *) NULL); 10321 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10322 exception=AcquireExceptionInfo(); 10323 (void) SetImageInfo(image_info,0,exception); 10324 if (LocaleCompare(image_info->magick,"X") == 0) 10325 { 10326 char 10327 seconds[MaxTextExtent]; 10328 10329 /* 10330 User may want to delay the X server screen grab. 10331 */ 10332 (void) CopyMagickString(seconds,"0",MaxTextExtent); 10333 (void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:", 10334 seconds); 10335 if (*seconds == '\0') 10336 return((Image *) NULL); 10337 XDelay(display,(size_t) (1000*StringToLong(seconds))); 10338 } 10339 magick_info=GetMagickInfo(image_info->magick,exception); 10340 if ((magick_info != (const MagickInfo *) NULL) && 10341 IfMagickTrue(magick_info->raw)) 10342 { 10343 char 10344 geometry[MaxTextExtent]; 10345 10346 /* 10347 Request image size from the user. 10348 */ 10349 (void) CopyMagickString(geometry,"512x512",MaxTextExtent); 10350 if (image_info->size != (char *) NULL) 10351 (void) CopyMagickString(geometry,image_info->size,MaxTextExtent); 10352 (void) XDialogWidget(display,windows,"Load","Enter the image geometry:", 10353 geometry); 10354 (void) CloneString(&image_info->size,geometry); 10355 } 10356 /* 10357 Load the image. 10358 */ 10359 XSetCursorState(display,windows,MagickTrue); 10360 XCheckRefreshWindows(display,windows); 10361 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 10362 nexus=ReadImage(image_info,exception); 10363 CatchException(exception); 10364 XSetCursorState(display,windows,MagickFalse); 10365 if (nexus != (Image *) NULL) 10366 XClientMessage(display,windows->image.id,windows->im_protocols, 10367 windows->im_next_image,CurrentTime); 10368 else 10369 { 10370 char 10371 *text, 10372 **textlist; 10373 10374 /* 10375 Unknown image format. 10376 */ 10377 text=FileToString(filename,~0,exception); 10378 if (text == (char *) NULL) 10379 return((Image *) NULL); 10380 textlist=StringToList(text); 10381 if (textlist != (char **) NULL) 10382 { 10383 char 10384 title[MaxTextExtent]; 10385 10386 register int 10387 i; 10388 10389 (void) FormatLocaleString(title,MaxTextExtent, 10390 "Unknown format: %s",filename); 10391 XTextViewWidget(display,resource_info,windows,MagickTrue,title, 10392 (const char **) textlist); 10393 for (i=0; textlist[i] != (char *) NULL; i++) 10394 textlist[i]=DestroyString(textlist[i]); 10395 textlist=(char **) RelinquishMagickMemory(textlist); 10396 } 10397 text=DestroyString(text); 10398 } 10399 exception=DestroyExceptionInfo(exception); 10400 image_info=DestroyImageInfo(image_info); 10401 return(nexus); 10402} 10403 10404/* 10405%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10406% % 10407% % 10408% % 10409+ X P a n I m a g e % 10410% % 10411% % 10412% % 10413%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10414% 10415% XPanImage() pans the image until the mouse button is released. 10416% 10417% The format of the XPanImage method is: 10418% 10419% void XPanImage(Display *display,XWindows *windows,XEvent *event, 10420% ExceptionInfo *exception) 10421% 10422% A description of each parameter follows: 10423% 10424% o display: Specifies a connection to an X server; returned from 10425% XOpenDisplay. 10426% 10427% o windows: Specifies a pointer to a XWindows structure. 10428% 10429% o event: Specifies a pointer to a XEvent structure. If it is NULL, 10430% the entire image is refreshed. 10431% 10432% o exception: return any errors or warnings in this structure. 10433% 10434*/ 10435static void XPanImage(Display *display,XWindows *windows,XEvent *event, 10436 ExceptionInfo *exception) 10437{ 10438 char 10439 text[MaxTextExtent]; 10440 10441 Cursor 10442 cursor; 10443 10444 double 10445 x_factor, 10446 y_factor; 10447 10448 RectangleInfo 10449 pan_info; 10450 10451 size_t 10452 state; 10453 10454 /* 10455 Define cursor. 10456 */ 10457 if ((windows->image.ximage->width > (int) windows->image.width) && 10458 (windows->image.ximage->height > (int) windows->image.height)) 10459 cursor=XCreateFontCursor(display,XC_fleur); 10460 else 10461 if (windows->image.ximage->width > (int) windows->image.width) 10462 cursor=XCreateFontCursor(display,XC_sb_h_double_arrow); 10463 else 10464 if (windows->image.ximage->height > (int) windows->image.height) 10465 cursor=XCreateFontCursor(display,XC_sb_v_double_arrow); 10466 else 10467 cursor=XCreateFontCursor(display,XC_arrow); 10468 (void) XCheckDefineCursor(display,windows->pan.id,cursor); 10469 /* 10470 Pan image as pointer moves until the mouse button is released. 10471 */ 10472 x_factor=(double) windows->image.ximage->width/windows->pan.width; 10473 y_factor=(double) windows->image.ximage->height/windows->pan.height; 10474 pan_info.width=windows->pan.width*windows->image.width/ 10475 windows->image.ximage->width; 10476 pan_info.height=windows->pan.height*windows->image.height/ 10477 windows->image.ximage->height; 10478 pan_info.x=0; 10479 pan_info.y=0; 10480 state=UpdateConfigurationState; 10481 do 10482 { 10483 switch (event->type) 10484 { 10485 case ButtonPress: 10486 { 10487 /* 10488 User choose an initial pan location. 10489 */ 10490 pan_info.x=(ssize_t) event->xbutton.x; 10491 pan_info.y=(ssize_t) event->xbutton.y; 10492 state|=UpdateConfigurationState; 10493 break; 10494 } 10495 case ButtonRelease: 10496 { 10497 /* 10498 User has finished panning the image. 10499 */ 10500 pan_info.x=(ssize_t) event->xbutton.x; 10501 pan_info.y=(ssize_t) event->xbutton.y; 10502 state|=UpdateConfigurationState | ExitState; 10503 break; 10504 } 10505 case MotionNotify: 10506 { 10507 pan_info.x=(ssize_t) event->xmotion.x; 10508 pan_info.y=(ssize_t) event->xmotion.y; 10509 state|=UpdateConfigurationState; 10510 } 10511 default: 10512 break; 10513 } 10514 if ((state & UpdateConfigurationState) != 0) 10515 { 10516 /* 10517 Check boundary conditions. 10518 */ 10519 if (pan_info.x < (ssize_t) (pan_info.width/2)) 10520 pan_info.x=0; 10521 else 10522 pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2))); 10523 if (pan_info.x < 0) 10524 pan_info.x=0; 10525 else 10526 if ((int) (pan_info.x+windows->image.width) > 10527 windows->image.ximage->width) 10528 pan_info.x=(ssize_t) 10529 (windows->image.ximage->width-windows->image.width); 10530 if (pan_info.y < (ssize_t) (pan_info.height/2)) 10531 pan_info.y=0; 10532 else 10533 pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2))); 10534 if (pan_info.y < 0) 10535 pan_info.y=0; 10536 else 10537 if ((int) (pan_info.y+windows->image.height) > 10538 windows->image.ximage->height) 10539 pan_info.y=(ssize_t) 10540 (windows->image.ximage->height-windows->image.height); 10541 if ((windows->image.x != (int) pan_info.x) || 10542 (windows->image.y != (int) pan_info.y)) 10543 { 10544 /* 10545 Display image pan offset. 10546 */ 10547 windows->image.x=(int) pan_info.x; 10548 windows->image.y=(int) pan_info.y; 10549 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 10550 windows->image.width,windows->image.height,windows->image.x, 10551 windows->image.y); 10552 XInfoWidget(display,windows,text); 10553 /* 10554 Refresh Image window. 10555 */ 10556 XDrawPanRectangle(display,windows); 10557 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 10558 } 10559 state&=(~UpdateConfigurationState); 10560 } 10561 /* 10562 Wait for next event. 10563 */ 10564 if ((state & ExitState) == 0) 10565 XScreenEvent(display,windows,event,exception); 10566 } while ((state & ExitState) == 0); 10567 /* 10568 Restore cursor. 10569 */ 10570 (void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor); 10571 (void) XFreeCursor(display,cursor); 10572 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 10573} 10574 10575/* 10576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10577% % 10578% % 10579% % 10580+ X P a s t e I m a g e % 10581% % 10582% % 10583% % 10584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10585% 10586% XPasteImage() pastes an image previously saved with XCropImage in the X 10587% window image at a location the user chooses with the pointer. 10588% 10589% The format of the XPasteImage method is: 10590% 10591% MagickBooleanType XPasteImage(Display *display, 10592% XResourceInfo *resource_info,XWindows *windows,Image *image, 10593% ExceptionInfo *exception) 10594% 10595% A description of each parameter follows: 10596% 10597% o display: Specifies a connection to an X server; returned from 10598% XOpenDisplay. 10599% 10600% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10601% 10602% o windows: Specifies a pointer to a XWindows structure. 10603% 10604% o image: the image; returned from ReadImage. 10605% 10606% o exception: return any errors or warnings in this structure. 10607% 10608*/ 10609static MagickBooleanType XPasteImage(Display *display, 10610 XResourceInfo *resource_info,XWindows *windows,Image *image, 10611 ExceptionInfo *exception) 10612{ 10613 static const char 10614 *PasteMenu[] = 10615 { 10616 "Operator", 10617 "Help", 10618 "Dismiss", 10619 (char *) NULL 10620 }; 10621 10622 static const ModeType 10623 PasteCommands[] = 10624 { 10625 PasteOperatorsCommand, 10626 PasteHelpCommand, 10627 PasteDismissCommand 10628 }; 10629 10630 static CompositeOperator 10631 compose = CopyCompositeOp; 10632 10633 char 10634 text[MaxTextExtent]; 10635 10636 Cursor 10637 cursor; 10638 10639 Image 10640 *paste_image; 10641 10642 int 10643 entry, 10644 id, 10645 x, 10646 y; 10647 10648 double 10649 scale_factor; 10650 10651 RectangleInfo 10652 highlight_info, 10653 paste_info; 10654 10655 unsigned int 10656 height, 10657 width; 10658 10659 size_t 10660 state; 10661 10662 XEvent 10663 event; 10664 10665 /* 10666 Copy image. 10667 */ 10668 if (resource_info->copy_image == (Image *) NULL) 10669 return(MagickFalse); 10670 paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,exception); 10671 /* 10672 Map Command widget. 10673 */ 10674 (void) CloneString(&windows->command.name,"Paste"); 10675 windows->command.data=1; 10676 (void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL); 10677 (void) XMapRaised(display,windows->command.id); 10678 XClientMessage(display,windows->image.id,windows->im_protocols, 10679 windows->im_update_widget,CurrentTime); 10680 /* 10681 Track pointer until button 1 is pressed. 10682 */ 10683 XSetCursorState(display,windows,MagickFalse); 10684 XQueryPosition(display,windows->image.id,&x,&y); 10685 (void) XSelectInput(display,windows->image.id, 10686 windows->image.attributes.event_mask | PointerMotionMask); 10687 paste_info.x=(ssize_t) windows->image.x+x; 10688 paste_info.y=(ssize_t) windows->image.y+y; 10689 paste_info.width=0; 10690 paste_info.height=0; 10691 cursor=XCreateFontCursor(display,XC_ul_angle); 10692 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 10693 state=DefaultState; 10694 do 10695 { 10696 if( IfMagickTrue(windows->info.mapped) ) 10697 { 10698 /* 10699 Display pointer position. 10700 */ 10701 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 10702 (long) paste_info.x,(long) paste_info.y); 10703 XInfoWidget(display,windows,text); 10704 } 10705 highlight_info=paste_info; 10706 highlight_info.x=paste_info.x-windows->image.x; 10707 highlight_info.y=paste_info.y-windows->image.y; 10708 XHighlightRectangle(display,windows->image.id, 10709 windows->image.highlight_context,&highlight_info); 10710 /* 10711 Wait for next event. 10712 */ 10713 XScreenEvent(display,windows,&event,exception); 10714 XHighlightRectangle(display,windows->image.id, 10715 windows->image.highlight_context,&highlight_info); 10716 if (event.xany.window == windows->command.id) 10717 { 10718 /* 10719 Select a command from the Command widget. 10720 */ 10721 id=XCommandWidget(display,windows,PasteMenu,&event); 10722 if (id < 0) 10723 continue; 10724 switch (PasteCommands[id]) 10725 { 10726 case PasteOperatorsCommand: 10727 { 10728 char 10729 command[MaxTextExtent], 10730 **operators; 10731 10732 /* 10733 Select a command from the pop-up menu. 10734 */ 10735 operators=GetCommandOptions(MagickComposeOptions); 10736 if (operators == (char **) NULL) 10737 break; 10738 entry=XMenuWidget(display,windows,PasteMenu[id], 10739 (const char **) operators,command); 10740 if (entry >= 0) 10741 compose=(CompositeOperator) ParseCommandOption( 10742 MagickComposeOptions,MagickFalse,operators[entry]); 10743 operators=DestroyStringList(operators); 10744 break; 10745 } 10746 case PasteHelpCommand: 10747 { 10748 XTextViewWidget(display,resource_info,windows,MagickFalse, 10749 "Help Viewer - Image Composite",ImagePasteHelp); 10750 break; 10751 } 10752 case PasteDismissCommand: 10753 { 10754 /* 10755 Prematurely exit. 10756 */ 10757 state|=EscapeState; 10758 state|=ExitState; 10759 break; 10760 } 10761 default: 10762 break; 10763 } 10764 continue; 10765 } 10766 switch (event.type) 10767 { 10768 case ButtonPress: 10769 { 10770 if( IfMagickTrue(image->debug) ) 10771 (void) LogMagickEvent(X11Event,GetMagickModule(), 10772 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 10773 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10774 if (event.xbutton.button != Button1) 10775 break; 10776 if (event.xbutton.window != windows->image.id) 10777 break; 10778 /* 10779 Paste rectangle is relative to image configuration. 10780 */ 10781 width=(unsigned int) image->columns; 10782 height=(unsigned int) image->rows; 10783 x=0; 10784 y=0; 10785 if (windows->image.crop_geometry != (char *) NULL) 10786 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 10787 &width,&height); 10788 scale_factor=(double) windows->image.ximage->width/width; 10789 paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5); 10790 scale_factor=(double) windows->image.ximage->height/height; 10791 paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5); 10792 (void) XCheckDefineCursor(display,windows->image.id,cursor); 10793 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10794 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10795 break; 10796 } 10797 case ButtonRelease: 10798 { 10799 if( IfMagickTrue(image->debug) ) 10800 (void) LogMagickEvent(X11Event,GetMagickModule(), 10801 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 10802 event.xbutton.button,event.xbutton.x,event.xbutton.y); 10803 if (event.xbutton.button != Button1) 10804 break; 10805 if (event.xbutton.window != windows->image.id) 10806 break; 10807 if ((paste_info.width != 0) && (paste_info.height != 0)) 10808 { 10809 /* 10810 User has selected the location of the paste image. 10811 */ 10812 paste_info.x=(ssize_t) windows->image.x+event.xbutton.x; 10813 paste_info.y=(ssize_t) windows->image.y+event.xbutton.y; 10814 state|=ExitState; 10815 } 10816 break; 10817 } 10818 case Expose: 10819 break; 10820 case KeyPress: 10821 { 10822 char 10823 command[MaxTextExtent]; 10824 10825 KeySym 10826 key_symbol; 10827 10828 int 10829 length; 10830 10831 if (event.xkey.window != windows->image.id) 10832 break; 10833 /* 10834 Respond to a user key press. 10835 */ 10836 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 10837 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 10838 *(command+length)='\0'; 10839 if( IfMagickTrue(image->debug) ) 10840 (void) LogMagickEvent(X11Event,GetMagickModule(), 10841 "Key press: 0x%lx (%s)",(long) key_symbol,command); 10842 switch ((int) key_symbol) 10843 { 10844 case XK_Escape: 10845 case XK_F20: 10846 { 10847 /* 10848 Prematurely exit. 10849 */ 10850 paste_image=DestroyImage(paste_image); 10851 state|=EscapeState; 10852 state|=ExitState; 10853 break; 10854 } 10855 case XK_F1: 10856 case XK_Help: 10857 { 10858 (void) XSetFunction(display,windows->image.highlight_context, 10859 GXcopy); 10860 XTextViewWidget(display,resource_info,windows,MagickFalse, 10861 "Help Viewer - Image Composite",ImagePasteHelp); 10862 (void) XSetFunction(display,windows->image.highlight_context, 10863 GXinvert); 10864 break; 10865 } 10866 default: 10867 { 10868 (void) XBell(display,0); 10869 break; 10870 } 10871 } 10872 break; 10873 } 10874 case MotionNotify: 10875 { 10876 /* 10877 Map and unmap Info widget as text cursor crosses its boundaries. 10878 */ 10879 x=event.xmotion.x; 10880 y=event.xmotion.y; 10881 if( IfMagickTrue(windows->info.mapped) ) 10882 { 10883 if ((x < (int) (windows->info.x+windows->info.width)) && 10884 (y < (int) (windows->info.y+windows->info.height))) 10885 (void) XWithdrawWindow(display,windows->info.id, 10886 windows->info.screen); 10887 } 10888 else 10889 if ((x > (int) (windows->info.x+windows->info.width)) || 10890 (y > (int) (windows->info.y+windows->info.height))) 10891 (void) XMapWindow(display,windows->info.id); 10892 paste_info.x=(ssize_t) windows->image.x+x; 10893 paste_info.y=(ssize_t) windows->image.y+y; 10894 break; 10895 } 10896 default: 10897 { 10898 if( IfMagickTrue(image->debug) ) 10899 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 10900 event.type); 10901 break; 10902 } 10903 } 10904 } while ((state & ExitState) == 0); 10905 (void) XSelectInput(display,windows->image.id, 10906 windows->image.attributes.event_mask); 10907 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 10908 XSetCursorState(display,windows,MagickFalse); 10909 (void) XFreeCursor(display,cursor); 10910 if ((state & EscapeState) != 0) 10911 return(MagickTrue); 10912 /* 10913 Image pasting is relative to image configuration. 10914 */ 10915 XSetCursorState(display,windows,MagickTrue); 10916 XCheckRefreshWindows(display,windows); 10917 width=(unsigned int) image->columns; 10918 height=(unsigned int) image->rows; 10919 x=0; 10920 y=0; 10921 if (windows->image.crop_geometry != (char *) NULL) 10922 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 10923 scale_factor=(double) width/windows->image.ximage->width; 10924 paste_info.x+=x; 10925 paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5); 10926 paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5); 10927 scale_factor=(double) height/windows->image.ximage->height; 10928 paste_info.y+=y; 10929 paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5); 10930 paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5); 10931 /* 10932 Paste image with X Image window. 10933 */ 10934 (void) CompositeImage(image,paste_image,compose,MagickTrue,paste_info.x, 10935 paste_info.y,exception); 10936 paste_image=DestroyImage(paste_image); 10937 XSetCursorState(display,windows,MagickFalse); 10938 /* 10939 Update image colormap. 10940 */ 10941 XConfigureImageColormap(display,resource_info,windows,image,exception); 10942 (void) XConfigureImage(display,resource_info,windows,image,exception); 10943 return(MagickTrue); 10944} 10945 10946/* 10947%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10948% % 10949% % 10950% % 10951+ X P r i n t I m a g e % 10952% % 10953% % 10954% % 10955%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 10956% 10957% XPrintImage() prints an image to a Postscript printer. 10958% 10959% The format of the XPrintImage method is: 10960% 10961% MagickBooleanType XPrintImage(Display *display, 10962% XResourceInfo *resource_info,XWindows *windows,Image *image, 10963% ExceptionInfo *exception) 10964% 10965% A description of each parameter follows: 10966% 10967% o display: Specifies a connection to an X server; returned from 10968% XOpenDisplay. 10969% 10970% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 10971% 10972% o windows: Specifies a pointer to a XWindows structure. 10973% 10974% o image: the image. 10975% 10976% o exception: return any errors or warnings in this structure. 10977% 10978*/ 10979static MagickBooleanType XPrintImage(Display *display, 10980 XResourceInfo *resource_info,XWindows *windows,Image *image, 10981 ExceptionInfo *exception) 10982{ 10983 char 10984 filename[MaxTextExtent], 10985 geometry[MaxTextExtent]; 10986 10987 Image 10988 *print_image; 10989 10990 ImageInfo 10991 *image_info; 10992 10993 MagickStatusType 10994 status; 10995 10996 /* 10997 Request Postscript page geometry from user. 10998 */ 10999 image_info=CloneImageInfo(resource_info->image_info); 11000 (void) FormatLocaleString(geometry,MaxTextExtent,"Letter"); 11001 if (image_info->page != (char *) NULL) 11002 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 11003 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 11004 "Select Postscript Page Geometry:",geometry); 11005 if (*geometry == '\0') 11006 return(MagickTrue); 11007 image_info->page=GetPageGeometry(geometry); 11008 /* 11009 Apply image transforms. 11010 */ 11011 XSetCursorState(display,windows,MagickTrue); 11012 XCheckRefreshWindows(display,windows); 11013 print_image=CloneImage(image,0,0,MagickTrue,exception); 11014 if (print_image == (Image *) NULL) 11015 return(MagickFalse); 11016 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 11017 windows->image.ximage->width,windows->image.ximage->height); 11018 (void) TransformImage(&print_image,windows->image.crop_geometry,geometry, 11019 exception); 11020 /* 11021 Print image. 11022 */ 11023 (void) AcquireUniqueFilename(filename); 11024 (void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s", 11025 filename); 11026 status=WriteImage(image_info,print_image,exception); 11027 (void) RelinquishUniqueFileResource(filename); 11028 print_image=DestroyImage(print_image); 11029 image_info=DestroyImageInfo(image_info); 11030 XSetCursorState(display,windows,MagickFalse); 11031 return(IsMagickTrue(status)); 11032} 11033 11034/* 11035%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11036% % 11037% % 11038% % 11039+ X R O I I m a g e % 11040% % 11041% % 11042% % 11043%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11044% 11045% XROIImage() applies an image processing technique to a region of interest. 11046% 11047% The format of the XROIImage method is: 11048% 11049% MagickBooleanType XROIImage(Display *display, 11050% XResourceInfo *resource_info,XWindows *windows,Image **image, 11051% ExceptionInfo *exception) 11052% 11053% A description of each parameter follows: 11054% 11055% o display: Specifies a connection to an X server; returned from 11056% XOpenDisplay. 11057% 11058% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 11059% 11060% o windows: Specifies a pointer to a XWindows structure. 11061% 11062% o image: the image; returned from ReadImage. 11063% 11064% o exception: return any errors or warnings in this structure. 11065% 11066*/ 11067static MagickBooleanType XROIImage(Display *display, 11068 XResourceInfo *resource_info,XWindows *windows,Image **image, 11069 ExceptionInfo *exception) 11070{ 11071#define ApplyMenus 7 11072 11073 static const char 11074 *ROIMenu[] = 11075 { 11076 "Help", 11077 "Dismiss", 11078 (char *) NULL 11079 }, 11080 *ApplyMenu[] = 11081 { 11082 "File", 11083 "Edit", 11084 "Transform", 11085 "Enhance", 11086 "Effects", 11087 "F/X", 11088 "Miscellany", 11089 "Help", 11090 "Dismiss", 11091 (char *) NULL 11092 }, 11093 *FileMenu[] = 11094 { 11095 "Save...", 11096 "Print...", 11097 (char *) NULL 11098 }, 11099 *EditMenu[] = 11100 { 11101 "Undo", 11102 "Redo", 11103 (char *) NULL 11104 }, 11105 *TransformMenu[] = 11106 { 11107 "Flop", 11108 "Flip", 11109 "Rotate Right", 11110 "Rotate Left", 11111 (char *) NULL 11112 }, 11113 *EnhanceMenu[] = 11114 { 11115 "Hue...", 11116 "Saturation...", 11117 "Brightness...", 11118 "Gamma...", 11119 "Spiff", 11120 "Dull", 11121 "Contrast Stretch...", 11122 "Sigmoidal Contrast...", 11123 "Normalize", 11124 "Equalize", 11125 "Negate", 11126 "Grayscale", 11127 "Map...", 11128 "Quantize...", 11129 (char *) NULL 11130 }, 11131 *EffectsMenu[] = 11132 { 11133 "Despeckle", 11134 "Emboss", 11135 "Reduce Noise", 11136 "Add Noise", 11137 "Sharpen...", 11138 "Blur...", 11139 "Threshold...", 11140 "Edge Detect...", 11141 "Spread...", 11142 "Shade...", 11143 "Raise...", 11144 "Segment...", 11145 (char *) NULL 11146 }, 11147 *FXMenu[] = 11148 { 11149 "Solarize...", 11150 "Sepia Tone...", 11151 "Swirl...", 11152 "Implode...", 11153 "Vignette...", 11154 "Wave...", 11155 "Oil Paint...", 11156 "Charcoal Draw...", 11157 (char *) NULL 11158 }, 11159 *MiscellanyMenu[] = 11160 { 11161 "Image Info", 11162 "Zoom Image", 11163 "Show Preview...", 11164 "Show Histogram", 11165 "Show Matte", 11166 (char *) NULL 11167 }; 11168 11169 static const char 11170 **Menus[ApplyMenus] = 11171 { 11172 FileMenu, 11173 EditMenu, 11174 TransformMenu, 11175 EnhanceMenu, 11176 EffectsMenu, 11177 FXMenu, 11178 MiscellanyMenu 11179 }; 11180 11181 static const CommandType 11182 ApplyCommands[] = 11183 { 11184 NullCommand, 11185 NullCommand, 11186 NullCommand, 11187 NullCommand, 11188 NullCommand, 11189 NullCommand, 11190 NullCommand, 11191 HelpCommand, 11192 QuitCommand 11193 }, 11194 FileCommands[] = 11195 { 11196 SaveCommand, 11197 PrintCommand 11198 }, 11199 EditCommands[] = 11200 { 11201 UndoCommand, 11202 RedoCommand 11203 }, 11204 TransformCommands[] = 11205 { 11206 FlopCommand, 11207 FlipCommand, 11208 RotateRightCommand, 11209 RotateLeftCommand 11210 }, 11211 EnhanceCommands[] = 11212 { 11213 HueCommand, 11214 SaturationCommand, 11215 BrightnessCommand, 11216 GammaCommand, 11217 SpiffCommand, 11218 DullCommand, 11219 ContrastStretchCommand, 11220 SigmoidalContrastCommand, 11221 NormalizeCommand, 11222 EqualizeCommand, 11223 NegateCommand, 11224 GrayscaleCommand, 11225 MapCommand, 11226 QuantizeCommand 11227 }, 11228 EffectsCommands[] = 11229 { 11230 DespeckleCommand, 11231 EmbossCommand, 11232 ReduceNoiseCommand, 11233 AddNoiseCommand, 11234 SharpenCommand, 11235 BlurCommand, 11236 EdgeDetectCommand, 11237 SpreadCommand, 11238 ShadeCommand, 11239 RaiseCommand, 11240 SegmentCommand 11241 }, 11242 FXCommands[] = 11243 { 11244 SolarizeCommand, 11245 SepiaToneCommand, 11246 SwirlCommand, 11247 ImplodeCommand, 11248 VignetteCommand, 11249 WaveCommand, 11250 OilPaintCommand, 11251 CharcoalDrawCommand 11252 }, 11253 MiscellanyCommands[] = 11254 { 11255 InfoCommand, 11256 ZoomCommand, 11257 ShowPreviewCommand, 11258 ShowHistogramCommand, 11259 ShowMatteCommand 11260 }, 11261 ROICommands[] = 11262 { 11263 ROIHelpCommand, 11264 ROIDismissCommand 11265 }; 11266 11267 static const CommandType 11268 *Commands[ApplyMenus] = 11269 { 11270 FileCommands, 11271 EditCommands, 11272 TransformCommands, 11273 EnhanceCommands, 11274 EffectsCommands, 11275 FXCommands, 11276 MiscellanyCommands 11277 }; 11278 11279 char 11280 command[MaxTextExtent], 11281 text[MaxTextExtent]; 11282 11283 CommandType 11284 command_type; 11285 11286 Cursor 11287 cursor; 11288 11289 Image 11290 *roi_image; 11291 11292 int 11293 entry, 11294 id, 11295 x, 11296 y; 11297 11298 double 11299 scale_factor; 11300 11301 MagickProgressMonitor 11302 progress_monitor; 11303 11304 RectangleInfo 11305 crop_info, 11306 highlight_info, 11307 roi_info; 11308 11309 unsigned int 11310 height, 11311 width; 11312 11313 size_t 11314 state; 11315 11316 XEvent 11317 event; 11318 11319 /* 11320 Map Command widget. 11321 */ 11322 (void) CloneString(&windows->command.name,"ROI"); 11323 windows->command.data=0; 11324 (void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL); 11325 (void) XMapRaised(display,windows->command.id); 11326 XClientMessage(display,windows->image.id,windows->im_protocols, 11327 windows->im_update_widget,CurrentTime); 11328 /* 11329 Track pointer until button 1 is pressed. 11330 */ 11331 XQueryPosition(display,windows->image.id,&x,&y); 11332 (void) XSelectInput(display,windows->image.id, 11333 windows->image.attributes.event_mask | PointerMotionMask); 11334 roi_info.x=(ssize_t) windows->image.x+x; 11335 roi_info.y=(ssize_t) windows->image.y+y; 11336 roi_info.width=0; 11337 roi_info.height=0; 11338 cursor=XCreateFontCursor(display,XC_fleur); 11339 state=DefaultState; 11340 do 11341 { 11342 if( IfMagickTrue(windows->info.mapped) ) 11343 { 11344 /* 11345 Display pointer position. 11346 */ 11347 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 11348 (long) roi_info.x,(long) roi_info.y); 11349 XInfoWidget(display,windows,text); 11350 } 11351 /* 11352 Wait for next event. 11353 */ 11354 XScreenEvent(display,windows,&event,exception); 11355 if (event.xany.window == windows->command.id) 11356 { 11357 /* 11358 Select a command from the Command widget. 11359 */ 11360 id=XCommandWidget(display,windows,ROIMenu,&event); 11361 if (id < 0) 11362 continue; 11363 switch (ROICommands[id]) 11364 { 11365 case ROIHelpCommand: 11366 { 11367 XTextViewWidget(display,resource_info,windows,MagickFalse, 11368 "Help Viewer - Region of Interest",ImageROIHelp); 11369 break; 11370 } 11371 case ROIDismissCommand: 11372 { 11373 /* 11374 Prematurely exit. 11375 */ 11376 state|=EscapeState; 11377 state|=ExitState; 11378 break; 11379 } 11380 default: 11381 break; 11382 } 11383 continue; 11384 } 11385 switch (event.type) 11386 { 11387 case ButtonPress: 11388 { 11389 if (event.xbutton.button != Button1) 11390 break; 11391 if (event.xbutton.window != windows->image.id) 11392 break; 11393 /* 11394 Note first corner of region of interest rectangle-- exit loop. 11395 */ 11396 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11397 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11398 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11399 state|=ExitState; 11400 break; 11401 } 11402 case ButtonRelease: 11403 break; 11404 case Expose: 11405 break; 11406 case KeyPress: 11407 { 11408 KeySym 11409 key_symbol; 11410 11411 if (event.xkey.window != windows->image.id) 11412 break; 11413 /* 11414 Respond to a user key press. 11415 */ 11416 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11417 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11418 switch ((int) key_symbol) 11419 { 11420 case XK_Escape: 11421 case XK_F20: 11422 { 11423 /* 11424 Prematurely exit. 11425 */ 11426 state|=EscapeState; 11427 state|=ExitState; 11428 break; 11429 } 11430 case XK_F1: 11431 case XK_Help: 11432 { 11433 XTextViewWidget(display,resource_info,windows,MagickFalse, 11434 "Help Viewer - Region of Interest",ImageROIHelp); 11435 break; 11436 } 11437 default: 11438 { 11439 (void) XBell(display,0); 11440 break; 11441 } 11442 } 11443 break; 11444 } 11445 case MotionNotify: 11446 { 11447 /* 11448 Map and unmap Info widget as text cursor crosses its boundaries. 11449 */ 11450 x=event.xmotion.x; 11451 y=event.xmotion.y; 11452 if( IfMagickTrue(windows->info.mapped) ) 11453 { 11454 if ((x < (int) (windows->info.x+windows->info.width)) && 11455 (y < (int) (windows->info.y+windows->info.height))) 11456 (void) XWithdrawWindow(display,windows->info.id, 11457 windows->info.screen); 11458 } 11459 else 11460 if ((x > (int) (windows->info.x+windows->info.width)) || 11461 (y > (int) (windows->info.y+windows->info.height))) 11462 (void) XMapWindow(display,windows->info.id); 11463 roi_info.x=(ssize_t) windows->image.x+x; 11464 roi_info.y=(ssize_t) windows->image.y+y; 11465 break; 11466 } 11467 default: 11468 break; 11469 } 11470 } while ((state & ExitState) == 0); 11471 (void) XSelectInput(display,windows->image.id, 11472 windows->image.attributes.event_mask); 11473 if ((state & EscapeState) != 0) 11474 { 11475 /* 11476 User want to exit without region of interest. 11477 */ 11478 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11479 (void) XFreeCursor(display,cursor); 11480 return(MagickTrue); 11481 } 11482 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 11483 do 11484 { 11485 /* 11486 Size rectangle as pointer moves until the mouse button is released. 11487 */ 11488 x=(int) roi_info.x; 11489 y=(int) roi_info.y; 11490 roi_info.width=0; 11491 roi_info.height=0; 11492 state=DefaultState; 11493 do 11494 { 11495 highlight_info=roi_info; 11496 highlight_info.x=roi_info.x-windows->image.x; 11497 highlight_info.y=roi_info.y-windows->image.y; 11498 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11499 { 11500 /* 11501 Display info and draw region of interest rectangle. 11502 */ 11503 if( IfMagickFalse(windows->info.mapped) ) 11504 (void) XMapWindow(display,windows->info.id); 11505 (void) FormatLocaleString(text,MaxTextExtent, 11506 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11507 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11508 XInfoWidget(display,windows,text); 11509 XHighlightRectangle(display,windows->image.id, 11510 windows->image.highlight_context,&highlight_info); 11511 } 11512 else 11513 if( IfMagickTrue(windows->info.mapped) ) 11514 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 11515 /* 11516 Wait for next event. 11517 */ 11518 XScreenEvent(display,windows,&event,exception); 11519 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 11520 XHighlightRectangle(display,windows->image.id, 11521 windows->image.highlight_context,&highlight_info); 11522 switch (event.type) 11523 { 11524 case ButtonPress: 11525 { 11526 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11527 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11528 break; 11529 } 11530 case ButtonRelease: 11531 { 11532 /* 11533 User has committed to region of interest rectangle. 11534 */ 11535 roi_info.x=(ssize_t) windows->image.x+event.xbutton.x; 11536 roi_info.y=(ssize_t) windows->image.y+event.xbutton.y; 11537 XSetCursorState(display,windows,MagickFalse); 11538 state|=ExitState; 11539 if (LocaleCompare(windows->command.name,"Apply") == 0) 11540 break; 11541 (void) CloneString(&windows->command.name,"Apply"); 11542 windows->command.data=ApplyMenus; 11543 (void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL); 11544 break; 11545 } 11546 case Expose: 11547 break; 11548 case MotionNotify: 11549 { 11550 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11551 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11552 } 11553 default: 11554 break; 11555 } 11556 if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) || 11557 ((state & ExitState) != 0)) 11558 { 11559 /* 11560 Check boundary conditions. 11561 */ 11562 if (roi_info.x < 0) 11563 roi_info.x=0; 11564 else 11565 if (roi_info.x > (ssize_t) windows->image.ximage->width) 11566 roi_info.x=(ssize_t) windows->image.ximage->width; 11567 if ((int) roi_info.x < x) 11568 roi_info.width=(unsigned int) (x-roi_info.x); 11569 else 11570 { 11571 roi_info.width=(unsigned int) (roi_info.x-x); 11572 roi_info.x=(ssize_t) x; 11573 } 11574 if (roi_info.y < 0) 11575 roi_info.y=0; 11576 else 11577 if (roi_info.y > (ssize_t) windows->image.ximage->height) 11578 roi_info.y=(ssize_t) windows->image.ximage->height; 11579 if ((int) roi_info.y < y) 11580 roi_info.height=(unsigned int) (y-roi_info.y); 11581 else 11582 { 11583 roi_info.height=(unsigned int) (roi_info.y-y); 11584 roi_info.y=(ssize_t) y; 11585 } 11586 } 11587 } while ((state & ExitState) == 0); 11588 /* 11589 Wait for user to grab a corner of the rectangle or press return. 11590 */ 11591 state=DefaultState; 11592 command_type=NullCommand; 11593 (void) XMapWindow(display,windows->info.id); 11594 do 11595 { 11596 if( IfMagickTrue(windows->info.mapped) ) 11597 { 11598 /* 11599 Display pointer position. 11600 */ 11601 (void) FormatLocaleString(text,MaxTextExtent, 11602 " %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11603 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11604 XInfoWidget(display,windows,text); 11605 } 11606 highlight_info=roi_info; 11607 highlight_info.x=roi_info.x-windows->image.x; 11608 highlight_info.y=roi_info.y-windows->image.y; 11609 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 11610 { 11611 state|=EscapeState; 11612 state|=ExitState; 11613 break; 11614 } 11615 if ((state & UpdateRegionState) != 0) 11616 { 11617 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11618 switch (command_type) 11619 { 11620 case UndoCommand: 11621 case RedoCommand: 11622 { 11623 (void) XMagickCommand(display,resource_info,windows,command_type, 11624 image,exception); 11625 break; 11626 } 11627 default: 11628 { 11629 /* 11630 Region of interest is relative to image configuration. 11631 */ 11632 progress_monitor=SetImageProgressMonitor(*image, 11633 (MagickProgressMonitor) NULL,(*image)->client_data); 11634 crop_info=roi_info; 11635 width=(unsigned int) (*image)->columns; 11636 height=(unsigned int) (*image)->rows; 11637 x=0; 11638 y=0; 11639 if (windows->image.crop_geometry != (char *) NULL) 11640 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 11641 &width,&height); 11642 scale_factor=(double) width/windows->image.ximage->width; 11643 crop_info.x+=x; 11644 crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5); 11645 crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5); 11646 scale_factor=(double) 11647 height/windows->image.ximage->height; 11648 crop_info.y+=y; 11649 crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5); 11650 crop_info.height=(unsigned int) 11651 (scale_factor*crop_info.height+0.5); 11652 roi_image=CropImage(*image,&crop_info,exception); 11653 (void) SetImageProgressMonitor(*image,progress_monitor, 11654 (*image)->client_data); 11655 if (roi_image == (Image *) NULL) 11656 continue; 11657 /* 11658 Apply image processing technique to the region of interest. 11659 */ 11660 windows->image.orphan=MagickTrue; 11661 (void) XMagickCommand(display,resource_info,windows,command_type, 11662 &roi_image,exception); 11663 progress_monitor=SetImageProgressMonitor(*image, 11664 (MagickProgressMonitor) NULL,(*image)->client_data); 11665 (void) XMagickCommand(display,resource_info,windows, 11666 SaveToUndoBufferCommand,image,exception); 11667 windows->image.orphan=MagickFalse; 11668 (void) CompositeImage(*image,roi_image,CopyCompositeOp, 11669 MagickTrue,crop_info.x,crop_info.y,exception); 11670 roi_image=DestroyImage(roi_image); 11671 (void) SetImageProgressMonitor(*image,progress_monitor, 11672 (*image)->client_data); 11673 break; 11674 } 11675 } 11676 if (command_type != InfoCommand) 11677 { 11678 XConfigureImageColormap(display,resource_info,windows,*image, 11679 exception); 11680 (void) XConfigureImage(display,resource_info,windows,*image, 11681 exception); 11682 } 11683 XCheckRefreshWindows(display,windows); 11684 XInfoWidget(display,windows,text); 11685 (void) XSetFunction(display,windows->image.highlight_context, 11686 GXinvert); 11687 state&=(~UpdateRegionState); 11688 } 11689 XHighlightRectangle(display,windows->image.id, 11690 windows->image.highlight_context,&highlight_info); 11691 XScreenEvent(display,windows,&event,exception); 11692 if (event.xany.window == windows->command.id) 11693 { 11694 /* 11695 Select a command from the Command widget. 11696 */ 11697 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11698 command_type=NullCommand; 11699 id=XCommandWidget(display,windows,ApplyMenu,&event); 11700 if (id >= 0) 11701 { 11702 (void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent); 11703 command_type=ApplyCommands[id]; 11704 if (id < ApplyMenus) 11705 { 11706 /* 11707 Select a command from a pop-up menu. 11708 */ 11709 entry=XMenuWidget(display,windows,ApplyMenu[id], 11710 (const char **) Menus[id],command); 11711 if (entry >= 0) 11712 { 11713 (void) CopyMagickString(command,Menus[id][entry], 11714 MaxTextExtent); 11715 command_type=Commands[id][entry]; 11716 } 11717 } 11718 } 11719 (void) XSetFunction(display,windows->image.highlight_context, 11720 GXinvert); 11721 XHighlightRectangle(display,windows->image.id, 11722 windows->image.highlight_context,&highlight_info); 11723 if (command_type == HelpCommand) 11724 { 11725 (void) XSetFunction(display,windows->image.highlight_context, 11726 GXcopy); 11727 XTextViewWidget(display,resource_info,windows,MagickFalse, 11728 "Help Viewer - Region of Interest",ImageROIHelp); 11729 (void) XSetFunction(display,windows->image.highlight_context, 11730 GXinvert); 11731 continue; 11732 } 11733 if (command_type == QuitCommand) 11734 { 11735 /* 11736 exit. 11737 */ 11738 state|=EscapeState; 11739 state|=ExitState; 11740 continue; 11741 } 11742 if (command_type != NullCommand) 11743 state|=UpdateRegionState; 11744 continue; 11745 } 11746 XHighlightRectangle(display,windows->image.id, 11747 windows->image.highlight_context,&highlight_info); 11748 switch (event.type) 11749 { 11750 case ButtonPress: 11751 { 11752 x=windows->image.x; 11753 y=windows->image.y; 11754 if (event.xbutton.button != Button1) 11755 break; 11756 if (event.xbutton.window != windows->image.id) 11757 break; 11758 x=windows->image.x+event.xbutton.x; 11759 y=windows->image.y+event.xbutton.y; 11760 if ((x < (int) (roi_info.x+RoiDelta)) && 11761 (x > (int) (roi_info.x-RoiDelta)) && 11762 (y < (int) (roi_info.y+RoiDelta)) && 11763 (y > (int) (roi_info.y-RoiDelta))) 11764 { 11765 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11766 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11767 state|=UpdateConfigurationState; 11768 break; 11769 } 11770 if ((x < (int) (roi_info.x+RoiDelta)) && 11771 (x > (int) (roi_info.x-RoiDelta)) && 11772 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11773 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11774 { 11775 roi_info.x=(ssize_t) (roi_info.x+roi_info.width); 11776 state|=UpdateConfigurationState; 11777 break; 11778 } 11779 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11780 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11781 (y < (int) (roi_info.y+RoiDelta)) && 11782 (y > (int) (roi_info.y-RoiDelta))) 11783 { 11784 roi_info.y=(ssize_t) (roi_info.y+roi_info.height); 11785 state|=UpdateConfigurationState; 11786 break; 11787 } 11788 if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) && 11789 (x > (int) (roi_info.x+roi_info.width-RoiDelta)) && 11790 (y < (int) (roi_info.y+roi_info.height+RoiDelta)) && 11791 (y > (int) (roi_info.y+roi_info.height-RoiDelta))) 11792 { 11793 state|=UpdateConfigurationState; 11794 break; 11795 } 11796 } 11797 case ButtonRelease: 11798 { 11799 if (event.xbutton.window == windows->pan.id) 11800 if ((highlight_info.x != crop_info.x-windows->image.x) || 11801 (highlight_info.y != crop_info.y-windows->image.y)) 11802 XHighlightRectangle(display,windows->image.id, 11803 windows->image.highlight_context,&highlight_info); 11804 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11805 event.xbutton.time); 11806 break; 11807 } 11808 case Expose: 11809 { 11810 if (event.xexpose.window == windows->image.id) 11811 if (event.xexpose.count == 0) 11812 { 11813 event.xexpose.x=(int) highlight_info.x; 11814 event.xexpose.y=(int) highlight_info.y; 11815 event.xexpose.width=(int) highlight_info.width; 11816 event.xexpose.height=(int) highlight_info.height; 11817 XRefreshWindow(display,&windows->image,&event); 11818 } 11819 if (event.xexpose.window == windows->info.id) 11820 if (event.xexpose.count == 0) 11821 XInfoWidget(display,windows,text); 11822 break; 11823 } 11824 case KeyPress: 11825 { 11826 KeySym 11827 key_symbol; 11828 11829 if (event.xkey.window != windows->image.id) 11830 break; 11831 /* 11832 Respond to a user key press. 11833 */ 11834 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 11835 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 11836 switch ((int) key_symbol) 11837 { 11838 case XK_Shift_L: 11839 case XK_Shift_R: 11840 break; 11841 case XK_Escape: 11842 case XK_F20: 11843 state|=EscapeState; 11844 case XK_Return: 11845 { 11846 state|=ExitState; 11847 break; 11848 } 11849 case XK_Home: 11850 case XK_KP_Home: 11851 { 11852 roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L); 11853 roi_info.y=(ssize_t) (windows->image.height/2L- 11854 roi_info.height/2L); 11855 break; 11856 } 11857 case XK_Left: 11858 case XK_KP_Left: 11859 { 11860 roi_info.x--; 11861 break; 11862 } 11863 case XK_Up: 11864 case XK_KP_Up: 11865 case XK_Next: 11866 { 11867 roi_info.y--; 11868 break; 11869 } 11870 case XK_Right: 11871 case XK_KP_Right: 11872 { 11873 roi_info.x++; 11874 break; 11875 } 11876 case XK_Prior: 11877 case XK_Down: 11878 case XK_KP_Down: 11879 { 11880 roi_info.y++; 11881 break; 11882 } 11883 case XK_F1: 11884 case XK_Help: 11885 { 11886 (void) XSetFunction(display,windows->image.highlight_context, 11887 GXcopy); 11888 XTextViewWidget(display,resource_info,windows,MagickFalse, 11889 "Help Viewer - Region of Interest",ImageROIHelp); 11890 (void) XSetFunction(display,windows->image.highlight_context, 11891 GXinvert); 11892 break; 11893 } 11894 default: 11895 { 11896 command_type=XImageWindowCommand(display,resource_info,windows, 11897 event.xkey.state,key_symbol,image,exception); 11898 if (command_type != NullCommand) 11899 state|=UpdateRegionState; 11900 break; 11901 } 11902 } 11903 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 11904 event.xkey.time); 11905 break; 11906 } 11907 case KeyRelease: 11908 break; 11909 case MotionNotify: 11910 { 11911 if (event.xbutton.window != windows->image.id) 11912 break; 11913 /* 11914 Map and unmap Info widget as text cursor crosses its boundaries. 11915 */ 11916 x=event.xmotion.x; 11917 y=event.xmotion.y; 11918 if( IfMagickTrue(windows->info.mapped) ) 11919 { 11920 if ((x < (int) (windows->info.x+windows->info.width)) && 11921 (y < (int) (windows->info.y+windows->info.height))) 11922 (void) XWithdrawWindow(display,windows->info.id, 11923 windows->info.screen); 11924 } 11925 else 11926 if ((x > (int) (windows->info.x+windows->info.width)) || 11927 (y > (int) (windows->info.y+windows->info.height))) 11928 (void) XMapWindow(display,windows->info.id); 11929 roi_info.x=(ssize_t) windows->image.x+event.xmotion.x; 11930 roi_info.y=(ssize_t) windows->image.y+event.xmotion.y; 11931 break; 11932 } 11933 case SelectionRequest: 11934 { 11935 XSelectionEvent 11936 notify; 11937 11938 XSelectionRequestEvent 11939 *request; 11940 11941 /* 11942 Set primary selection. 11943 */ 11944 (void) FormatLocaleString(text,MaxTextExtent, 11945 "%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double) 11946 roi_info.height,(double) roi_info.x,(double) roi_info.y); 11947 request=(&(event.xselectionrequest)); 11948 (void) XChangeProperty(request->display,request->requestor, 11949 request->property,request->target,8,PropModeReplace, 11950 (unsigned char *) text,(int) strlen(text)); 11951 notify.type=SelectionNotify; 11952 notify.display=request->display; 11953 notify.requestor=request->requestor; 11954 notify.selection=request->selection; 11955 notify.target=request->target; 11956 notify.time=request->time; 11957 if (request->property == None) 11958 notify.property=request->target; 11959 else 11960 notify.property=request->property; 11961 (void) XSendEvent(request->display,request->requestor,False,0, 11962 (XEvent *) ¬ify); 11963 } 11964 default: 11965 break; 11966 } 11967 if ((state & UpdateConfigurationState) != 0) 11968 { 11969 (void) XPutBackEvent(display,&event); 11970 (void) XCheckDefineCursor(display,windows->image.id,cursor); 11971 break; 11972 } 11973 } while ((state & ExitState) == 0); 11974 } while ((state & ExitState) == 0); 11975 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 11976 XSetCursorState(display,windows,MagickFalse); 11977 if ((state & EscapeState) != 0) 11978 return(MagickTrue); 11979 return(MagickTrue); 11980} 11981 11982/* 11983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11984% % 11985% % 11986% % 11987+ X R o t a t e I m a g e % 11988% % 11989% % 11990% % 11991%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11992% 11993% XRotateImage() rotates the X image. If the degrees parameter if zero, the 11994% rotation angle is computed from the slope of a line drawn by the user. 11995% 11996% The format of the XRotateImage method is: 11997% 11998% MagickBooleanType XRotateImage(Display *display, 11999% XResourceInfo *resource_info,XWindows *windows,double degrees, 12000% Image **image,ExceptionInfo *exception) 12001% 12002% A description of each parameter follows: 12003% 12004% o display: Specifies a connection to an X server; returned from 12005% XOpenDisplay. 12006% 12007% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12008% 12009% o windows: Specifies a pointer to a XWindows structure. 12010% 12011% o degrees: Specifies the number of degrees to rotate the image. 12012% 12013% o image: the image. 12014% 12015% o exception: return any errors or warnings in this structure. 12016% 12017*/ 12018static MagickBooleanType XRotateImage(Display *display, 12019 XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image, 12020 ExceptionInfo *exception) 12021{ 12022 static const char 12023 *RotateMenu[] = 12024 { 12025 "Pixel Color", 12026 "Direction", 12027 "Help", 12028 "Dismiss", 12029 (char *) NULL 12030 }; 12031 12032 static ModeType 12033 direction = HorizontalRotateCommand; 12034 12035 static const ModeType 12036 DirectionCommands[] = 12037 { 12038 HorizontalRotateCommand, 12039 VerticalRotateCommand 12040 }, 12041 RotateCommands[] = 12042 { 12043 RotateColorCommand, 12044 RotateDirectionCommand, 12045 RotateHelpCommand, 12046 RotateDismissCommand 12047 }; 12048 12049 static unsigned int 12050 pen_id = 0; 12051 12052 char 12053 command[MaxTextExtent], 12054 text[MaxTextExtent]; 12055 12056 Image 12057 *rotate_image; 12058 12059 int 12060 id, 12061 x, 12062 y; 12063 12064 double 12065 normalized_degrees; 12066 12067 register int 12068 i; 12069 12070 unsigned int 12071 height, 12072 rotations, 12073 width; 12074 12075 if (degrees == 0.0) 12076 { 12077 unsigned int 12078 distance; 12079 12080 size_t 12081 state; 12082 12083 XEvent 12084 event; 12085 12086 XSegment 12087 rotate_info; 12088 12089 /* 12090 Map Command widget. 12091 */ 12092 (void) CloneString(&windows->command.name,"Rotate"); 12093 windows->command.data=2; 12094 (void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL); 12095 (void) XMapRaised(display,windows->command.id); 12096 XClientMessage(display,windows->image.id,windows->im_protocols, 12097 windows->im_update_widget,CurrentTime); 12098 /* 12099 Wait for first button press. 12100 */ 12101 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12102 XQueryPosition(display,windows->image.id,&x,&y); 12103 rotate_info.x1=x; 12104 rotate_info.y1=y; 12105 rotate_info.x2=x; 12106 rotate_info.y2=y; 12107 state=DefaultState; 12108 do 12109 { 12110 XHighlightLine(display,windows->image.id, 12111 windows->image.highlight_context,&rotate_info); 12112 /* 12113 Wait for next event. 12114 */ 12115 XScreenEvent(display,windows,&event,exception); 12116 XHighlightLine(display,windows->image.id, 12117 windows->image.highlight_context,&rotate_info); 12118 if (event.xany.window == windows->command.id) 12119 { 12120 /* 12121 Select a command from the Command widget. 12122 */ 12123 id=XCommandWidget(display,windows,RotateMenu,&event); 12124 if (id < 0) 12125 continue; 12126 (void) XSetFunction(display,windows->image.highlight_context, 12127 GXcopy); 12128 switch (RotateCommands[id]) 12129 { 12130 case RotateColorCommand: 12131 { 12132 const char 12133 *ColorMenu[MaxNumberPens]; 12134 12135 int 12136 pen_number; 12137 12138 XColor 12139 color; 12140 12141 /* 12142 Initialize menu selections. 12143 */ 12144 for (i=0; i < (int) (MaxNumberPens-2); i++) 12145 ColorMenu[i]=resource_info->pen_colors[i]; 12146 ColorMenu[MaxNumberPens-2]="Browser..."; 12147 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 12148 /* 12149 Select a pen color from the pop-up menu. 12150 */ 12151 pen_number=XMenuWidget(display,windows,RotateMenu[id], 12152 (const char **) ColorMenu,command); 12153 if (pen_number < 0) 12154 break; 12155 if (pen_number == (MaxNumberPens-2)) 12156 { 12157 static char 12158 color_name[MaxTextExtent] = "gray"; 12159 12160 /* 12161 Select a pen color from a dialog. 12162 */ 12163 resource_info->pen_colors[pen_number]=color_name; 12164 XColorBrowserWidget(display,windows,"Select",color_name); 12165 if (*color_name == '\0') 12166 break; 12167 } 12168 /* 12169 Set pen color. 12170 */ 12171 (void) XParseColor(display,windows->map_info->colormap, 12172 resource_info->pen_colors[pen_number],&color); 12173 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 12174 (unsigned int) MaxColors,&color); 12175 windows->pixel_info->pen_colors[pen_number]=color; 12176 pen_id=(unsigned int) pen_number; 12177 break; 12178 } 12179 case RotateDirectionCommand: 12180 { 12181 static const char 12182 *Directions[] = 12183 { 12184 "horizontal", 12185 "vertical", 12186 (char *) NULL, 12187 }; 12188 12189 /* 12190 Select a command from the pop-up menu. 12191 */ 12192 id=XMenuWidget(display,windows,RotateMenu[id], 12193 Directions,command); 12194 if (id >= 0) 12195 direction=DirectionCommands[id]; 12196 break; 12197 } 12198 case RotateHelpCommand: 12199 { 12200 XTextViewWidget(display,resource_info,windows,MagickFalse, 12201 "Help Viewer - Image Rotation",ImageRotateHelp); 12202 break; 12203 } 12204 case RotateDismissCommand: 12205 { 12206 /* 12207 Prematurely exit. 12208 */ 12209 state|=EscapeState; 12210 state|=ExitState; 12211 break; 12212 } 12213 default: 12214 break; 12215 } 12216 (void) XSetFunction(display,windows->image.highlight_context, 12217 GXinvert); 12218 continue; 12219 } 12220 switch (event.type) 12221 { 12222 case ButtonPress: 12223 { 12224 if (event.xbutton.button != Button1) 12225 break; 12226 if (event.xbutton.window != windows->image.id) 12227 break; 12228 /* 12229 exit loop. 12230 */ 12231 (void) XSetFunction(display,windows->image.highlight_context, 12232 GXcopy); 12233 rotate_info.x1=event.xbutton.x; 12234 rotate_info.y1=event.xbutton.y; 12235 state|=ExitState; 12236 break; 12237 } 12238 case ButtonRelease: 12239 break; 12240 case Expose: 12241 break; 12242 case KeyPress: 12243 { 12244 char 12245 command[MaxTextExtent]; 12246 12247 KeySym 12248 key_symbol; 12249 12250 if (event.xkey.window != windows->image.id) 12251 break; 12252 /* 12253 Respond to a user key press. 12254 */ 12255 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 12256 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12257 switch ((int) key_symbol) 12258 { 12259 case XK_Escape: 12260 case XK_F20: 12261 { 12262 /* 12263 Prematurely exit. 12264 */ 12265 state|=EscapeState; 12266 state|=ExitState; 12267 break; 12268 } 12269 case XK_F1: 12270 case XK_Help: 12271 { 12272 (void) XSetFunction(display,windows->image.highlight_context, 12273 GXcopy); 12274 XTextViewWidget(display,resource_info,windows,MagickFalse, 12275 "Help Viewer - Image Rotation",ImageRotateHelp); 12276 (void) XSetFunction(display,windows->image.highlight_context, 12277 GXinvert); 12278 break; 12279 } 12280 default: 12281 { 12282 (void) XBell(display,0); 12283 break; 12284 } 12285 } 12286 break; 12287 } 12288 case MotionNotify: 12289 { 12290 rotate_info.x1=event.xmotion.x; 12291 rotate_info.y1=event.xmotion.y; 12292 } 12293 } 12294 rotate_info.x2=rotate_info.x1; 12295 rotate_info.y2=rotate_info.y1; 12296 if (direction == HorizontalRotateCommand) 12297 rotate_info.x2+=32; 12298 else 12299 rotate_info.y2-=32; 12300 } while ((state & ExitState) == 0); 12301 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12302 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12303 if ((state & EscapeState) != 0) 12304 return(MagickTrue); 12305 /* 12306 Draw line as pointer moves until the mouse button is released. 12307 */ 12308 distance=0; 12309 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 12310 state=DefaultState; 12311 do 12312 { 12313 if (distance > 9) 12314 { 12315 /* 12316 Display info and draw rotation line. 12317 */ 12318 if( IfMagickFalse(windows->info.mapped) ) 12319 (void) XMapWindow(display,windows->info.id); 12320 (void) FormatLocaleString(text,MaxTextExtent," %g", 12321 direction == VerticalRotateCommand ? degrees-90.0 : degrees); 12322 XInfoWidget(display,windows,text); 12323 XHighlightLine(display,windows->image.id, 12324 windows->image.highlight_context,&rotate_info); 12325 } 12326 else 12327 if( IfMagickTrue(windows->info.mapped) ) 12328 (void) XWithdrawWindow(display,windows->info.id, 12329 windows->info.screen); 12330 /* 12331 Wait for next event. 12332 */ 12333 XScreenEvent(display,windows,&event,exception); 12334 if (distance > 9) 12335 XHighlightLine(display,windows->image.id, 12336 windows->image.highlight_context,&rotate_info); 12337 switch (event.type) 12338 { 12339 case ButtonPress: 12340 break; 12341 case ButtonRelease: 12342 { 12343 /* 12344 User has committed to rotation line. 12345 */ 12346 rotate_info.x2=event.xbutton.x; 12347 rotate_info.y2=event.xbutton.y; 12348 state|=ExitState; 12349 break; 12350 } 12351 case Expose: 12352 break; 12353 case MotionNotify: 12354 { 12355 rotate_info.x2=event.xmotion.x; 12356 rotate_info.y2=event.xmotion.y; 12357 } 12358 default: 12359 break; 12360 } 12361 /* 12362 Check boundary conditions. 12363 */ 12364 if (rotate_info.x2 < 0) 12365 rotate_info.x2=0; 12366 else 12367 if (rotate_info.x2 > (int) windows->image.width) 12368 rotate_info.x2=(short) windows->image.width; 12369 if (rotate_info.y2 < 0) 12370 rotate_info.y2=0; 12371 else 12372 if (rotate_info.y2 > (int) windows->image.height) 12373 rotate_info.y2=(short) windows->image.height; 12374 /* 12375 Compute rotation angle from the slope of the line. 12376 */ 12377 degrees=0.0; 12378 distance=(unsigned int) 12379 ((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+ 12380 ((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1)); 12381 if (distance > 9) 12382 degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2- 12383 rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1))); 12384 } while ((state & ExitState) == 0); 12385 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 12386 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12387 if (distance <= 9) 12388 return(MagickTrue); 12389 } 12390 if (direction == VerticalRotateCommand) 12391 degrees-=90.0; 12392 if (degrees == 0.0) 12393 return(MagickTrue); 12394 /* 12395 Rotate image. 12396 */ 12397 normalized_degrees=degrees; 12398 while (normalized_degrees < -45.0) 12399 normalized_degrees+=360.0; 12400 for (rotations=0; normalized_degrees > 45.0; rotations++) 12401 normalized_degrees-=90.0; 12402 if (normalized_degrees != 0.0) 12403 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 12404 exception); 12405 XSetCursorState(display,windows,MagickTrue); 12406 XCheckRefreshWindows(display,windows); 12407 (*image)->background_color.red=(double) ScaleShortToQuantum( 12408 windows->pixel_info->pen_colors[pen_id].red); 12409 (*image)->background_color.green=(double) ScaleShortToQuantum( 12410 windows->pixel_info->pen_colors[pen_id].green); 12411 (*image)->background_color.blue=(double) ScaleShortToQuantum( 12412 windows->pixel_info->pen_colors[pen_id].blue); 12413 rotate_image=RotateImage(*image,degrees,exception); 12414 XSetCursorState(display,windows,MagickFalse); 12415 if (rotate_image == (Image *) NULL) 12416 return(MagickFalse); 12417 *image=DestroyImage(*image); 12418 *image=rotate_image; 12419 if (windows->image.crop_geometry != (char *) NULL) 12420 { 12421 /* 12422 Rotate crop geometry. 12423 */ 12424 width=(unsigned int) (*image)->columns; 12425 height=(unsigned int) (*image)->rows; 12426 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12427 switch (rotations % 4) 12428 { 12429 default: 12430 case 0: 12431 break; 12432 case 1: 12433 { 12434 /* 12435 Rotate 90 degrees. 12436 */ 12437 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12438 "%ux%u%+d%+d",height,width,(int) (*image)->columns- 12439 (int) height-y,x); 12440 break; 12441 } 12442 case 2: 12443 { 12444 /* 12445 Rotate 180 degrees. 12446 */ 12447 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12448 "%ux%u%+d%+d",width,height,(int) width-x,(int) height-y); 12449 break; 12450 } 12451 case 3: 12452 { 12453 /* 12454 Rotate 270 degrees. 12455 */ 12456 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 12457 "%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x); 12458 break; 12459 } 12460 } 12461 } 12462 if( IfMagickTrue(windows->image.orphan) ) 12463 return(MagickTrue); 12464 if (normalized_degrees != 0.0) 12465 { 12466 /* 12467 Update image colormap. 12468 */ 12469 windows->image.window_changes.width=(int) (*image)->columns; 12470 windows->image.window_changes.height=(int) (*image)->rows; 12471 if (windows->image.crop_geometry != (char *) NULL) 12472 { 12473 /* 12474 Obtain dimensions of image from crop geometry. 12475 */ 12476 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 12477 &width,&height); 12478 windows->image.window_changes.width=(int) width; 12479 windows->image.window_changes.height=(int) height; 12480 } 12481 XConfigureImageColormap(display,resource_info,windows,*image,exception); 12482 } 12483 else 12484 if (((rotations % 4) == 1) || ((rotations % 4) == 3)) 12485 { 12486 windows->image.window_changes.width=windows->image.ximage->height; 12487 windows->image.window_changes.height=windows->image.ximage->width; 12488 } 12489 /* 12490 Update image configuration. 12491 */ 12492 (void) XConfigureImage(display,resource_info,windows,*image,exception); 12493 return(MagickTrue); 12494} 12495 12496/* 12497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12498% % 12499% % 12500% % 12501+ X S a v e I m a g e % 12502% % 12503% % 12504% % 12505%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12506% 12507% XSaveImage() saves an image to a file. 12508% 12509% The format of the XSaveImage method is: 12510% 12511% MagickBooleanType XSaveImage(Display *display, 12512% XResourceInfo *resource_info,XWindows *windows,Image *image, 12513% ExceptionInfo *exception) 12514% 12515% A description of each parameter follows: 12516% 12517% o display: Specifies a connection to an X server; returned from 12518% XOpenDisplay. 12519% 12520% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 12521% 12522% o windows: Specifies a pointer to a XWindows structure. 12523% 12524% o image: the image. 12525% 12526% o exception: return any errors or warnings in this structure. 12527% 12528*/ 12529static MagickBooleanType XSaveImage(Display *display, 12530 XResourceInfo *resource_info,XWindows *windows,Image *image, 12531 ExceptionInfo *exception) 12532{ 12533 char 12534 filename[MaxTextExtent], 12535 geometry[MaxTextExtent]; 12536 12537 Image 12538 *save_image; 12539 12540 ImageInfo 12541 *image_info; 12542 12543 MagickStatusType 12544 status; 12545 12546 /* 12547 Request file name from user. 12548 */ 12549 if (resource_info->write_filename != (char *) NULL) 12550 (void) CopyMagickString(filename,resource_info->write_filename, 12551 MaxTextExtent); 12552 else 12553 { 12554 char 12555 path[MaxTextExtent]; 12556 12557 int 12558 status; 12559 12560 GetPathComponent(image->filename,HeadPath,path); 12561 GetPathComponent(image->filename,TailPath,filename); 12562 if (*path != '\0') 12563 { 12564 status=chdir(path); 12565 if (status == -1) 12566 (void) ThrowMagickException(exception,GetMagickModule(), 12567 FileOpenError,"UnableToOpenFile","%s",path); 12568 } 12569 } 12570 XFileBrowserWidget(display,windows,"Save",filename); 12571 if (*filename == '\0') 12572 return(MagickTrue); 12573 if( IfMagickTrue(IsPathAccessible(filename)) ) 12574 { 12575 int 12576 status; 12577 12578 /* 12579 File exists-- seek user's permission before overwriting. 12580 */ 12581 status=XConfirmWidget(display,windows,"Overwrite",filename); 12582 if (status <= 0) 12583 return(MagickTrue); 12584 } 12585 image_info=CloneImageInfo(resource_info->image_info); 12586 (void) CopyMagickString(image_info->filename,filename,MaxTextExtent); 12587 (void) SetImageInfo(image_info,1,exception); 12588 if ((LocaleCompare(image_info->magick,"JPEG") == 0) || 12589 (LocaleCompare(image_info->magick,"JPG") == 0)) 12590 { 12591 char 12592 quality[MaxTextExtent]; 12593 12594 int 12595 status; 12596 12597 /* 12598 Request JPEG quality from user. 12599 */ 12600 (void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double) 12601 image->quality); 12602 status=XDialogWidget(display,windows,"Save","Enter JPEG quality:", 12603 quality); 12604 if (*quality == '\0') 12605 return(MagickTrue); 12606 image->quality=StringToUnsignedLong(quality); 12607 image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace; 12608 } 12609 if ((LocaleCompare(image_info->magick,"EPS") == 0) || 12610 (LocaleCompare(image_info->magick,"PDF") == 0) || 12611 (LocaleCompare(image_info->magick,"PS") == 0) || 12612 (LocaleCompare(image_info->magick,"PS2") == 0)) 12613 { 12614 char 12615 geometry[MaxTextExtent]; 12616 12617 /* 12618 Request page geometry from user. 12619 */ 12620 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12621 if (LocaleCompare(image_info->magick,"PDF") == 0) 12622 (void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent); 12623 if (image_info->page != (char *) NULL) 12624 (void) CopyMagickString(geometry,image_info->page,MaxTextExtent); 12625 XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select", 12626 "Select page geometry:",geometry); 12627 if (*geometry != '\0') 12628 image_info->page=GetPageGeometry(geometry); 12629 } 12630 /* 12631 Apply image transforms. 12632 */ 12633 XSetCursorState(display,windows,MagickTrue); 12634 XCheckRefreshWindows(display,windows); 12635 save_image=CloneImage(image,0,0,MagickTrue,exception); 12636 if (save_image == (Image *) NULL) 12637 return(MagickFalse); 12638 (void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!", 12639 windows->image.ximage->width,windows->image.ximage->height); 12640 (void) TransformImage(&save_image,windows->image.crop_geometry,geometry, 12641 exception); 12642 /* 12643 Write image. 12644 */ 12645 (void) CopyMagickString(save_image->filename,filename,MaxTextExtent); 12646 status=WriteImage(image_info,save_image,exception); 12647 if( IfMagickTrue(status) ) 12648 image->taint=MagickFalse; 12649 save_image=DestroyImage(save_image); 12650 image_info=DestroyImageInfo(image_info); 12651 XSetCursorState(display,windows,MagickFalse); 12652 return(IsMagickTrue(status)); 12653} 12654 12655/* 12656%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12657% % 12658% % 12659% % 12660+ X S c r e e n E v e n t % 12661% % 12662% % 12663% % 12664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12665% 12666% XScreenEvent() handles global events associated with the Pan and Magnify 12667% windows. 12668% 12669% The format of the XScreenEvent function is: 12670% 12671% void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12672% ExceptionInfo *exception) 12673% 12674% A description of each parameter follows: 12675% 12676% o display: Specifies a pointer to the Display structure; returned from 12677% XOpenDisplay. 12678% 12679% o windows: Specifies a pointer to a XWindows structure. 12680% 12681% o event: Specifies a pointer to a X11 XEvent structure. 12682% 12683% o exception: return any errors or warnings in this structure. 12684% 12685*/ 12686 12687#if defined(__cplusplus) || defined(c_plusplus) 12688extern "C" { 12689#endif 12690 12691static int XPredicate(Display *magick_unused(display),XEvent *event,char *data) 12692{ 12693 register XWindows 12694 *windows; 12695 12696 windows=(XWindows *) data; 12697 if ((event->type == ClientMessage) && 12698 (event->xclient.window == windows->image.id)) 12699 return(MagickFalse); 12700 return(MagickTrue); 12701} 12702 12703#if defined(__cplusplus) || defined(c_plusplus) 12704} 12705#endif 12706 12707static void XScreenEvent(Display *display,XWindows *windows,XEvent *event, 12708 ExceptionInfo *exception) 12709{ 12710 register int 12711 x, 12712 y; 12713 12714 (void) XIfEvent(display,event,XPredicate,(char *) windows); 12715 if (event->xany.window == windows->command.id) 12716 return; 12717 switch (event->type) 12718 { 12719 case ButtonPress: 12720 case ButtonRelease: 12721 { 12722 if ((event->xbutton.button == Button3) && 12723 (event->xbutton.state & Mod1Mask)) 12724 { 12725 /* 12726 Convert Alt-Button3 to Button2. 12727 */ 12728 event->xbutton.button=Button2; 12729 event->xbutton.state&=(~Mod1Mask); 12730 } 12731 if (event->xbutton.window == windows->backdrop.id) 12732 { 12733 (void) XSetInputFocus(display,event->xbutton.window,RevertToParent, 12734 event->xbutton.time); 12735 break; 12736 } 12737 if (event->xbutton.window == windows->pan.id) 12738 { 12739 XPanImage(display,windows,event,exception); 12740 break; 12741 } 12742 if (event->xbutton.window == windows->image.id) 12743 if (event->xbutton.button == Button2) 12744 { 12745 /* 12746 Update magnified image. 12747 */ 12748 x=event->xbutton.x; 12749 y=event->xbutton.y; 12750 if (x < 0) 12751 x=0; 12752 else 12753 if (x >= (int) windows->image.width) 12754 x=(int) (windows->image.width-1); 12755 windows->magnify.x=(int) windows->image.x+x; 12756 if (y < 0) 12757 y=0; 12758 else 12759 if (y >= (int) windows->image.height) 12760 y=(int) (windows->image.height-1); 12761 windows->magnify.y=windows->image.y+y; 12762 if( IfMagickFalse(windows->magnify.mapped) ) 12763 (void) XMapRaised(display,windows->magnify.id); 12764 XMakeMagnifyImage(display,windows,exception); 12765 if (event->type == ButtonRelease) 12766 (void) XWithdrawWindow(display,windows->info.id, 12767 windows->info.screen); 12768 break; 12769 } 12770 break; 12771 } 12772 case ClientMessage: 12773 { 12774 /* 12775 If client window delete message, exit. 12776 */ 12777 if (event->xclient.message_type != windows->wm_protocols) 12778 break; 12779 if (*event->xclient.data.l != (long) windows->wm_delete_window) 12780 break; 12781 if (event->xclient.window == windows->magnify.id) 12782 { 12783 (void) XWithdrawWindow(display,windows->magnify.id, 12784 windows->magnify.screen); 12785 break; 12786 } 12787 break; 12788 } 12789 case ConfigureNotify: 12790 { 12791 if (event->xconfigure.window == windows->magnify.id) 12792 { 12793 unsigned int 12794 magnify; 12795 12796 /* 12797 Magnify window has a new configuration. 12798 */ 12799 windows->magnify.width=(unsigned int) event->xconfigure.width; 12800 windows->magnify.height=(unsigned int) event->xconfigure.height; 12801 if( IfMagickFalse(windows->magnify.mapped) ) 12802 break; 12803 magnify=1; 12804 while ((int) magnify <= event->xconfigure.width) 12805 magnify<<=1; 12806 while ((int) magnify <= event->xconfigure.height) 12807 magnify<<=1; 12808 magnify>>=1; 12809 if (((int) magnify != event->xconfigure.width) || 12810 ((int) magnify != event->xconfigure.height)) 12811 { 12812 XWindowChanges 12813 window_changes; 12814 12815 window_changes.width=(int) magnify; 12816 window_changes.height=(int) magnify; 12817 (void) XReconfigureWMWindow(display,windows->magnify.id, 12818 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 12819 &window_changes); 12820 break; 12821 } 12822 XMakeMagnifyImage(display,windows,exception); 12823 break; 12824 } 12825 break; 12826 } 12827 case Expose: 12828 { 12829 if (event->xexpose.window == windows->image.id) 12830 { 12831 XRefreshWindow(display,&windows->image,event); 12832 break; 12833 } 12834 if (event->xexpose.window == windows->pan.id) 12835 if (event->xexpose.count == 0) 12836 { 12837 XDrawPanRectangle(display,windows); 12838 break; 12839 } 12840 if (event->xexpose.window == windows->magnify.id) 12841 if (event->xexpose.count == 0) 12842 { 12843 XMakeMagnifyImage(display,windows,exception); 12844 break; 12845 } 12846 break; 12847 } 12848 case KeyPress: 12849 { 12850 char 12851 command[MaxTextExtent]; 12852 12853 KeySym 12854 key_symbol; 12855 12856 if (event->xkey.window != windows->magnify.id) 12857 break; 12858 /* 12859 Respond to a user key press. 12860 */ 12861 (void) XLookupString((XKeyEvent *) &event->xkey,command,(int) 12862 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 12863 XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol, 12864 exception); 12865 break; 12866 } 12867 case MapNotify: 12868 { 12869 if (event->xmap.window == windows->magnify.id) 12870 { 12871 windows->magnify.mapped=MagickTrue; 12872 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 12873 break; 12874 } 12875 if (event->xmap.window == windows->info.id) 12876 { 12877 windows->info.mapped=MagickTrue; 12878 break; 12879 } 12880 break; 12881 } 12882 case MotionNotify: 12883 { 12884 while (XCheckMaskEvent(display,ButtonMotionMask,event)) ; 12885 if (event->xmotion.window == windows->image.id) 12886 if( IfMagickTrue(windows->magnify.mapped) ) 12887 { 12888 /* 12889 Update magnified image. 12890 */ 12891 x=event->xmotion.x; 12892 y=event->xmotion.y; 12893 if (x < 0) 12894 x=0; 12895 else 12896 if (x >= (int) windows->image.width) 12897 x=(int) (windows->image.width-1); 12898 windows->magnify.x=(int) windows->image.x+x; 12899 if (y < 0) 12900 y=0; 12901 else 12902 if (y >= (int) windows->image.height) 12903 y=(int) (windows->image.height-1); 12904 windows->magnify.y=windows->image.y+y; 12905 XMakeMagnifyImage(display,windows,exception); 12906 } 12907 break; 12908 } 12909 case UnmapNotify: 12910 { 12911 if (event->xunmap.window == windows->magnify.id) 12912 { 12913 windows->magnify.mapped=MagickFalse; 12914 break; 12915 } 12916 if (event->xunmap.window == windows->info.id) 12917 { 12918 windows->info.mapped=MagickFalse; 12919 break; 12920 } 12921 break; 12922 } 12923 default: 12924 break; 12925 } 12926} 12927 12928/* 12929%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12930% % 12931% % 12932% % 12933+ X S e t C r o p G e o m e t r y % 12934% % 12935% % 12936% % 12937%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 12938% 12939% XSetCropGeometry() accepts a cropping geometry relative to the Image window 12940% and translates it to a cropping geometry relative to the image. 12941% 12942% The format of the XSetCropGeometry method is: 12943% 12944% void XSetCropGeometry(Display *display,XWindows *windows, 12945% RectangleInfo *crop_info,Image *image) 12946% 12947% A description of each parameter follows: 12948% 12949% o display: Specifies a connection to an X server; returned from 12950% XOpenDisplay. 12951% 12952% o windows: Specifies a pointer to a XWindows structure. 12953% 12954% o crop_info: A pointer to a RectangleInfo that defines a region of the 12955% Image window to crop. 12956% 12957% o image: the image. 12958% 12959*/ 12960static void XSetCropGeometry(Display *display,XWindows *windows, 12961 RectangleInfo *crop_info,Image *image) 12962{ 12963 char 12964 text[MaxTextExtent]; 12965 12966 int 12967 x, 12968 y; 12969 12970 double 12971 scale_factor; 12972 12973 unsigned int 12974 height, 12975 width; 12976 12977 if( IfMagickTrue(windows->info.mapped) ) 12978 { 12979 /* 12980 Display info on cropping rectangle. 12981 */ 12982 (void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g", 12983 (double) crop_info->width,(double) crop_info->height,(double) 12984 crop_info->x,(double) crop_info->y); 12985 XInfoWidget(display,windows,text); 12986 } 12987 /* 12988 Cropping geometry is relative to any previous crop geometry. 12989 */ 12990 x=0; 12991 y=0; 12992 width=(unsigned int) image->columns; 12993 height=(unsigned int) image->rows; 12994 if (windows->image.crop_geometry != (char *) NULL) 12995 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 12996 else 12997 windows->image.crop_geometry=AcquireString((char *) NULL); 12998 /* 12999 Define the crop geometry string from the cropping rectangle. 13000 */ 13001 scale_factor=(double) width/windows->image.ximage->width; 13002 if (crop_info->x > 0) 13003 x+=(int) (scale_factor*crop_info->x+0.5); 13004 width=(unsigned int) (scale_factor*crop_info->width+0.5); 13005 if (width == 0) 13006 width=1; 13007 scale_factor=(double) height/windows->image.ximage->height; 13008 if (crop_info->y > 0) 13009 y+=(int) (scale_factor*crop_info->y+0.5); 13010 height=(unsigned int) (scale_factor*crop_info->height+0.5); 13011 if (height == 0) 13012 height=1; 13013 (void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent, 13014 "%ux%u%+d%+d",width,height,x,y); 13015} 13016 13017/* 13018%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13019% % 13020% % 13021% % 13022+ X T i l e I m a g e % 13023% % 13024% % 13025% % 13026%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13027% 13028% XTileImage() loads or deletes a selected tile from a visual image directory. 13029% The load or delete command is chosen from a menu. 13030% 13031% The format of the XTileImage method is: 13032% 13033% Image *XTileImage(Display *display,XResourceInfo *resource_info, 13034% XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13035% 13036% A description of each parameter follows: 13037% 13038% o tile_image: XTileImage reads or deletes the tile image 13039% and returns it. A null image is returned if an error occurs. 13040% 13041% o display: Specifies a connection to an X server; returned from 13042% XOpenDisplay. 13043% 13044% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13045% 13046% o windows: Specifies a pointer to a XWindows structure. 13047% 13048% o image: the image; returned from ReadImage. 13049% 13050% o event: Specifies a pointer to a XEvent structure. If it is NULL, 13051% the entire image is refreshed. 13052% 13053% o exception: return any errors or warnings in this structure. 13054% 13055*/ 13056static Image *XTileImage(Display *display,XResourceInfo *resource_info, 13057 XWindows *windows,Image *image,XEvent *event,ExceptionInfo *exception) 13058{ 13059 static const char 13060 *VerbMenu[] = 13061 { 13062 "Load", 13063 "Next", 13064 "Former", 13065 "Delete", 13066 "Update", 13067 (char *) NULL, 13068 }; 13069 13070 static const ModeType 13071 TileCommands[] = 13072 { 13073 TileLoadCommand, 13074 TileNextCommand, 13075 TileFormerCommand, 13076 TileDeleteCommand, 13077 TileUpdateCommand 13078 }; 13079 13080 char 13081 command[MaxTextExtent], 13082 filename[MaxTextExtent]; 13083 13084 Image 13085 *tile_image; 13086 13087 int 13088 id, 13089 status, 13090 tile, 13091 x, 13092 y; 13093 13094 double 13095 scale_factor; 13096 13097 register char 13098 *p, 13099 *q; 13100 13101 register int 13102 i; 13103 13104 unsigned int 13105 height, 13106 width; 13107 13108 /* 13109 Tile image is relative to montage image configuration. 13110 */ 13111 x=0; 13112 y=0; 13113 width=(unsigned int) image->columns; 13114 height=(unsigned int) image->rows; 13115 if (windows->image.crop_geometry != (char *) NULL) 13116 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 13117 scale_factor=(double) width/windows->image.ximage->width; 13118 event->xbutton.x+=windows->image.x; 13119 event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5); 13120 scale_factor=(double) height/windows->image.ximage->height; 13121 event->xbutton.y+=windows->image.y; 13122 event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5); 13123 /* 13124 Determine size and location of each tile in the visual image directory. 13125 */ 13126 width=(unsigned int) image->columns; 13127 height=(unsigned int) image->rows; 13128 x=0; 13129 y=0; 13130 (void) XParseGeometry(image->montage,&x,&y,&width,&height); 13131 tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+ 13132 (event->xbutton.x-x)/width; 13133 if (tile < 0) 13134 { 13135 /* 13136 Button press is outside any tile. 13137 */ 13138 (void) XBell(display,0); 13139 return((Image *) NULL); 13140 } 13141 /* 13142 Determine file name from the tile directory. 13143 */ 13144 p=image->directory; 13145 for (i=tile; (i != 0) && (*p != '\0'); ) 13146 { 13147 if (*p == '\n') 13148 i--; 13149 p++; 13150 } 13151 if (*p == '\0') 13152 { 13153 /* 13154 Button press is outside any tile. 13155 */ 13156 (void) XBell(display,0); 13157 return((Image *) NULL); 13158 } 13159 /* 13160 Select a command from the pop-up menu. 13161 */ 13162 id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command); 13163 if (id < 0) 13164 return((Image *) NULL); 13165 q=p; 13166 while ((*q != '\n') && (*q != '\0')) 13167 q++; 13168 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13169 /* 13170 Perform command for the selected tile. 13171 */ 13172 XSetCursorState(display,windows,MagickTrue); 13173 XCheckRefreshWindows(display,windows); 13174 tile_image=NewImageList(); 13175 switch (TileCommands[id]) 13176 { 13177 case TileLoadCommand: 13178 { 13179 /* 13180 Load tile image. 13181 */ 13182 XCheckRefreshWindows(display,windows); 13183 (void) CopyMagickString(resource_info->image_info->magick,"MIFF", 13184 MaxTextExtent); 13185 (void) CopyMagickString(resource_info->image_info->filename,filename, 13186 MaxTextExtent); 13187 tile_image=ReadImage(resource_info->image_info,exception); 13188 CatchException(exception); 13189 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13190 break; 13191 } 13192 case TileNextCommand: 13193 { 13194 /* 13195 Display next image. 13196 */ 13197 XClientMessage(display,windows->image.id,windows->im_protocols, 13198 windows->im_next_image,CurrentTime); 13199 break; 13200 } 13201 case TileFormerCommand: 13202 { 13203 /* 13204 Display former image. 13205 */ 13206 XClientMessage(display,windows->image.id,windows->im_protocols, 13207 windows->im_former_image,CurrentTime); 13208 break; 13209 } 13210 case TileDeleteCommand: 13211 { 13212 /* 13213 Delete tile image. 13214 */ 13215 if( IfMagickFalse(IsPathAccessible(filename)) ) 13216 { 13217 XNoticeWidget(display,windows,"Image file does not exist:",filename); 13218 break; 13219 } 13220 status=XConfirmWidget(display,windows,"Really delete tile",filename); 13221 if (status <= 0) 13222 break; 13223 status=IsMagickTrue(remove_utf8(filename)); 13224 if( IfMagickTrue(status) ) 13225 { 13226 XNoticeWidget(display,windows,"Unable to delete image file:", 13227 filename); 13228 break; 13229 } 13230 } 13231 case TileUpdateCommand: 13232 { 13233 int 13234 x_offset, 13235 y_offset; 13236 13237 PixelInfo 13238 pixel; 13239 13240 register int 13241 j; 13242 13243 register Quantum 13244 *s; 13245 13246 /* 13247 Ensure all the images exist. 13248 */ 13249 tile=0; 13250 GetPixelInfo(image,&pixel); 13251 for (p=image->directory; *p != '\0'; p++) 13252 { 13253 CacheView 13254 *image_view; 13255 13256 q=p; 13257 while ((*q != '\n') && (*q != '\0')) 13258 q++; 13259 (void) CopyMagickString(filename,p,(size_t) (q-p+1)); 13260 p=q; 13261 if( IfMagickTrue(IsPathAccessible(filename)) ) 13262 { 13263 tile++; 13264 continue; 13265 } 13266 /* 13267 Overwrite tile with background color. 13268 */ 13269 x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x); 13270 y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y); 13271 image_view=AcquireAuthenticCacheView(image,exception); 13272 (void) GetOneCacheViewVirtualPixelInfo(image_view,0,0,&pixel,exception); 13273 for (i=0; i < (int) height; i++) 13274 { 13275 s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t) 13276 y_offset+i,width,1,exception); 13277 if (s == (Quantum *) NULL) 13278 break; 13279 for (j=0; j < (int) width; j++) 13280 { 13281 SetPixelInfoPixel(image,&pixel,s); 13282 s+=GetPixelChannels(image); 13283 } 13284 if( IfMagickFalse(SyncCacheViewAuthenticPixels(image_view,exception)) ) 13285 break; 13286 } 13287 image_view=DestroyCacheView(image_view); 13288 tile++; 13289 } 13290 windows->image.window_changes.width=(int) image->columns; 13291 windows->image.window_changes.height=(int) image->rows; 13292 XConfigureImageColormap(display,resource_info,windows,image,exception); 13293 (void) XConfigureImage(display,resource_info,windows,image,exception); 13294 break; 13295 } 13296 default: 13297 break; 13298 } 13299 XSetCursorState(display,windows,MagickFalse); 13300 return(tile_image); 13301} 13302 13303/* 13304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13305% % 13306% % 13307% % 13308+ X T r a n s l a t e I m a g e % 13309% % 13310% % 13311% % 13312%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13313% 13314% XTranslateImage() translates the image within an Image window by one pixel 13315% as specified by the key symbol. If the image has a montage string the 13316% translation is respect to the width and height contained within the string. 13317% 13318% The format of the XTranslateImage method is: 13319% 13320% void XTranslateImage(Display *display,XWindows *windows, 13321% Image *image,const KeySym key_symbol) 13322% 13323% A description of each parameter follows: 13324% 13325% o display: Specifies a connection to an X server; returned from 13326% XOpenDisplay. 13327% 13328% o windows: Specifies a pointer to a XWindows structure. 13329% 13330% o image: the image. 13331% 13332% o key_symbol: Specifies a KeySym which indicates which side of the image 13333% to trim. 13334% 13335*/ 13336static void XTranslateImage(Display *display,XWindows *windows, 13337 Image *image,const KeySym key_symbol) 13338{ 13339 char 13340 text[MaxTextExtent]; 13341 13342 int 13343 x, 13344 y; 13345 13346 unsigned int 13347 x_offset, 13348 y_offset; 13349 13350 /* 13351 User specified a pan position offset. 13352 */ 13353 x_offset=windows->image.width; 13354 y_offset=windows->image.height; 13355 if (image->montage != (char *) NULL) 13356 (void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset); 13357 switch ((int) key_symbol) 13358 { 13359 case XK_Home: 13360 case XK_KP_Home: 13361 { 13362 windows->image.x=(int) windows->image.width/2; 13363 windows->image.y=(int) windows->image.height/2; 13364 break; 13365 } 13366 case XK_Left: 13367 case XK_KP_Left: 13368 { 13369 windows->image.x-=x_offset; 13370 break; 13371 } 13372 case XK_Next: 13373 case XK_Up: 13374 case XK_KP_Up: 13375 { 13376 windows->image.y-=y_offset; 13377 break; 13378 } 13379 case XK_Right: 13380 case XK_KP_Right: 13381 { 13382 windows->image.x+=x_offset; 13383 break; 13384 } 13385 case XK_Prior: 13386 case XK_Down: 13387 case XK_KP_Down: 13388 { 13389 windows->image.y+=y_offset; 13390 break; 13391 } 13392 default: 13393 return; 13394 } 13395 /* 13396 Check boundary conditions. 13397 */ 13398 if (windows->image.x < 0) 13399 windows->image.x=0; 13400 else 13401 if ((int) (windows->image.x+windows->image.width) > 13402 windows->image.ximage->width) 13403 windows->image.x=(int) windows->image.ximage->width-windows->image.width; 13404 if (windows->image.y < 0) 13405 windows->image.y=0; 13406 else 13407 if ((int) (windows->image.y+windows->image.height) > 13408 windows->image.ximage->height) 13409 windows->image.y=(int) windows->image.ximage->height-windows->image.height; 13410 /* 13411 Refresh Image window. 13412 */ 13413 (void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ", 13414 windows->image.width,windows->image.height,windows->image.x, 13415 windows->image.y); 13416 XInfoWidget(display,windows,text); 13417 XCheckRefreshWindows(display,windows); 13418 XDrawPanRectangle(display,windows); 13419 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 13420 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 13421} 13422 13423/* 13424%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13425% % 13426% % 13427% % 13428+ X T r i m I m a g e % 13429% % 13430% % 13431% % 13432%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13433% 13434% XTrimImage() trims the edges from the Image window. 13435% 13436% The format of the XTrimImage method is: 13437% 13438% MagickBooleanType XTrimImage(Display *display, 13439% XResourceInfo *resource_info,XWindows *windows,Image *image, 13440% ExceptionInfo *exception) 13441% 13442% A description of each parameter follows: 13443% 13444% o display: Specifies a connection to an X server; returned from 13445% XOpenDisplay. 13446% 13447% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13448% 13449% o windows: Specifies a pointer to a XWindows structure. 13450% 13451% o image: the image. 13452% 13453% o exception: return any errors or warnings in this structure. 13454% 13455*/ 13456static MagickBooleanType XTrimImage(Display *display, 13457 XResourceInfo *resource_info,XWindows *windows,Image *image, 13458 ExceptionInfo *exception) 13459{ 13460 RectangleInfo 13461 trim_info; 13462 13463 register int 13464 x, 13465 y; 13466 13467 size_t 13468 background, 13469 pixel; 13470 13471 /* 13472 Trim edges from image. 13473 */ 13474 XSetCursorState(display,windows,MagickTrue); 13475 XCheckRefreshWindows(display,windows); 13476 /* 13477 Crop the left edge. 13478 */ 13479 background=XGetPixel(windows->image.ximage,0,0); 13480 trim_info.width=(size_t) windows->image.ximage->width; 13481 for (x=0; x < windows->image.ximage->width; x++) 13482 { 13483 for (y=0; y < windows->image.ximage->height; y++) 13484 { 13485 pixel=XGetPixel(windows->image.ximage,x,y); 13486 if (pixel != background) 13487 break; 13488 } 13489 if (y < windows->image.ximage->height) 13490 break; 13491 } 13492 trim_info.x=(ssize_t) x; 13493 if (trim_info.x == (ssize_t) windows->image.ximage->width) 13494 { 13495 XSetCursorState(display,windows,MagickFalse); 13496 return(MagickFalse); 13497 } 13498 /* 13499 Crop the right edge. 13500 */ 13501 background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0); 13502 for (x=windows->image.ximage->width-1; x != 0; x--) 13503 { 13504 for (y=0; y < windows->image.ximage->height; y++) 13505 { 13506 pixel=XGetPixel(windows->image.ximage,x,y); 13507 if (pixel != background) 13508 break; 13509 } 13510 if (y < windows->image.ximage->height) 13511 break; 13512 } 13513 trim_info.width=(size_t) (x-trim_info.x+1); 13514 /* 13515 Crop the top edge. 13516 */ 13517 background=XGetPixel(windows->image.ximage,0,0); 13518 trim_info.height=(size_t) windows->image.ximage->height; 13519 for (y=0; y < windows->image.ximage->height; y++) 13520 { 13521 for (x=0; x < windows->image.ximage->width; x++) 13522 { 13523 pixel=XGetPixel(windows->image.ximage,x,y); 13524 if (pixel != background) 13525 break; 13526 } 13527 if (x < windows->image.ximage->width) 13528 break; 13529 } 13530 trim_info.y=(ssize_t) y; 13531 /* 13532 Crop the bottom edge. 13533 */ 13534 background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1); 13535 for (y=windows->image.ximage->height-1; y != 0; y--) 13536 { 13537 for (x=0; x < windows->image.ximage->width; x++) 13538 { 13539 pixel=XGetPixel(windows->image.ximage,x,y); 13540 if (pixel != background) 13541 break; 13542 } 13543 if (x < windows->image.ximage->width) 13544 break; 13545 } 13546 trim_info.height=(size_t) y-trim_info.y+1; 13547 if (((unsigned int) trim_info.width != windows->image.width) || 13548 ((unsigned int) trim_info.height != windows->image.height)) 13549 { 13550 /* 13551 Reconfigure Image window as defined by the trimming rectangle. 13552 */ 13553 XSetCropGeometry(display,windows,&trim_info,image); 13554 windows->image.window_changes.width=(int) trim_info.width; 13555 windows->image.window_changes.height=(int) trim_info.height; 13556 (void) XConfigureImage(display,resource_info,windows,image,exception); 13557 } 13558 XSetCursorState(display,windows,MagickFalse); 13559 return(MagickTrue); 13560} 13561 13562/* 13563%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13564% % 13565% % 13566% % 13567+ X V i s u a l D i r e c t o r y I m a g e % 13568% % 13569% % 13570% % 13571%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13572% 13573% XVisualDirectoryImage() creates a Visual Image Directory. 13574% 13575% The format of the XVisualDirectoryImage method is: 13576% 13577% Image *XVisualDirectoryImage(Display *display, 13578% XResourceInfo *resource_info,XWindows *windows, 13579% ExceptionInfo *exception) 13580% 13581% A description of each parameter follows: 13582% 13583% o display: Specifies a connection to an X server; returned from 13584% XOpenDisplay. 13585% 13586% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13587% 13588% o windows: Specifies a pointer to a XWindows structure. 13589% 13590% o exception: return any errors or warnings in this structure. 13591% 13592*/ 13593static Image *XVisualDirectoryImage(Display *display, 13594 XResourceInfo *resource_info,XWindows *windows,ExceptionInfo *exception) 13595{ 13596#define TileImageTag "Scale/Image" 13597#define XClientName "montage" 13598 13599 char 13600 **filelist; 13601 13602 Image 13603 *images, 13604 *montage_image, 13605 *next_image, 13606 *thumbnail_image; 13607 13608 ImageInfo 13609 *read_info; 13610 13611 int 13612 number_files; 13613 13614 MagickBooleanType 13615 backdrop; 13616 13617 MagickStatusType 13618 status; 13619 13620 MontageInfo 13621 *montage_info; 13622 13623 RectangleInfo 13624 geometry; 13625 13626 register int 13627 i; 13628 13629 static char 13630 filename[MaxTextExtent] = "\0", 13631 filenames[MaxTextExtent] = "*"; 13632 13633 XResourceInfo 13634 background_resources; 13635 13636 /* 13637 Request file name from user. 13638 */ 13639 XFileBrowserWidget(display,windows,"Directory",filenames); 13640 if (*filenames == '\0') 13641 return((Image *) NULL); 13642 /* 13643 Expand the filenames. 13644 */ 13645 filelist=(char **) AcquireMagickMemory(sizeof(*filelist)); 13646 if (filelist == (char **) NULL) 13647 { 13648 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13649 filenames); 13650 return((Image *) NULL); 13651 } 13652 number_files=1; 13653 filelist[0]=filenames; 13654 status=ExpandFilenames(&number_files,&filelist); 13655 if( IfMagickFalse(status) || (number_files == 0)) 13656 { 13657 if (number_files == 0) 13658 ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames) 13659 else 13660 ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed", 13661 filenames); 13662 return((Image *) NULL); 13663 } 13664 /* 13665 Set image background resources. 13666 */ 13667 background_resources=(*resource_info); 13668 background_resources.window_id=AcquireString(""); 13669 (void) FormatLocaleString(background_resources.window_id,MaxTextExtent, 13670 "0x%lx",windows->image.id); 13671 background_resources.backdrop=MagickTrue; 13672 /* 13673 Read each image and convert them to a tile. 13674 */ 13675 backdrop=IsMagickTrue( (windows->visual_info->klass == TrueColor) || 13676 (windows->visual_info->klass == DirectColor) ); 13677 read_info=CloneImageInfo(resource_info->image_info); 13678 (void) SetImageOption(read_info,"jpeg:size","120x120"); 13679 (void) CloneString(&read_info->size,DefaultTileGeometry); 13680 (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL, 13681 (void *) NULL); 13682 images=NewImageList(); 13683 XSetCursorState(display,windows,MagickTrue); 13684 XCheckRefreshWindows(display,windows); 13685 for (i=0; i < (int) number_files; i++) 13686 { 13687 (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent); 13688 filelist[i]=DestroyString(filelist[i]); 13689 *read_info->magick='\0'; 13690 next_image=ReadImage(read_info,exception); 13691 CatchException(exception); 13692 if (next_image != (Image *) NULL) 13693 { 13694 (void) DeleteImageProperty(next_image,"label"); 13695 (void) SetImageProperty(next_image,"label",InterpretImageProperties( 13696 read_info,next_image,DefaultTileLabel,exception),exception); 13697 (void) ParseRegionGeometry(next_image,read_info->size,&geometry, 13698 exception); 13699 thumbnail_image=ThumbnailImage(next_image,geometry.width, 13700 geometry.height,exception); 13701 if (thumbnail_image != (Image *) NULL) 13702 { 13703 next_image=DestroyImage(next_image); 13704 next_image=thumbnail_image; 13705 } 13706 if (backdrop) 13707 { 13708 (void) XDisplayBackgroundImage(display,&background_resources, 13709 next_image,exception); 13710 XSetCursorState(display,windows,MagickTrue); 13711 } 13712 AppendImageToList(&images,next_image); 13713 if (images->progress_monitor != (MagickProgressMonitor) NULL) 13714 { 13715 MagickBooleanType 13716 proceed; 13717 13718 proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i, 13719 (MagickSizeType) number_files); 13720 if( IfMagickFalse(proceed) ) 13721 break; 13722 } 13723 } 13724 } 13725 filelist=(char **) RelinquishMagickMemory(filelist); 13726 if (images == (Image *) NULL) 13727 { 13728 read_info=DestroyImageInfo(read_info); 13729 XSetCursorState(display,windows,MagickFalse); 13730 ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames); 13731 return((Image *) NULL); 13732 } 13733 /* 13734 Create the Visual Image Directory. 13735 */ 13736 montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL); 13737 montage_info->pointsize=10; 13738 if (resource_info->font != (char *) NULL) 13739 (void) CloneString(&montage_info->font,resource_info->font); 13740 (void) CopyMagickString(montage_info->filename,filename,MaxTextExtent); 13741 montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList( 13742 images),exception); 13743 images=DestroyImageList(images); 13744 montage_info=DestroyMontageInfo(montage_info); 13745 read_info=DestroyImageInfo(read_info); 13746 XSetCursorState(display,windows,MagickFalse); 13747 if (montage_image == (Image *) NULL) 13748 return(montage_image); 13749 XClientMessage(display,windows->image.id,windows->im_protocols, 13750 windows->im_next_image,CurrentTime); 13751 return(montage_image); 13752} 13753 13754/* 13755%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13756% % 13757% % 13758% % 13759% X D i s p l a y B a c k g r o u n d I m a g e % 13760% % 13761% % 13762% % 13763%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13764% 13765% XDisplayBackgroundImage() displays an image in the background of a window. 13766% 13767% The format of the XDisplayBackgroundImage method is: 13768% 13769% MagickBooleanType XDisplayBackgroundImage(Display *display, 13770% XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13771% 13772% A description of each parameter follows: 13773% 13774% o display: Specifies a connection to an X server; returned from 13775% XOpenDisplay. 13776% 13777% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 13778% 13779% o image: the image. 13780% 13781% o exception: return any errors or warnings in this structure. 13782% 13783*/ 13784MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display, 13785 XResourceInfo *resource_info,Image *image,ExceptionInfo *exception) 13786{ 13787 char 13788 geometry[MaxTextExtent], 13789 visual_type[MaxTextExtent]; 13790 13791 int 13792 height, 13793 status, 13794 width; 13795 13796 RectangleInfo 13797 geometry_info; 13798 13799 static XPixelInfo 13800 pixel; 13801 13802 static XStandardColormap 13803 *map_info; 13804 13805 static XVisualInfo 13806 *visual_info = (XVisualInfo *) NULL; 13807 13808 static XWindowInfo 13809 window_info; 13810 13811 size_t 13812 delay; 13813 13814 Window 13815 root_window; 13816 13817 XGCValues 13818 context_values; 13819 13820 XResourceInfo 13821 resources; 13822 13823 XWindowAttributes 13824 window_attributes; 13825 13826 /* 13827 Determine target window. 13828 */ 13829 assert(image != (Image *) NULL); 13830 assert(image->signature == MagickSignature); 13831 if( IfMagickTrue(image->debug) ) 13832 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 13833 resources=(*resource_info); 13834 window_info.id=(Window) NULL; 13835 root_window=XRootWindow(display,XDefaultScreen(display)); 13836 if (LocaleCompare(resources.window_id,"root") == 0) 13837 window_info.id=root_window; 13838 else 13839 { 13840 if (isdigit((unsigned char) *resources.window_id) != 0) 13841 window_info.id=XWindowByID(display,root_window, 13842 (Window) strtol((char *) resources.window_id,(char **) NULL,0)); 13843 if (window_info.id == (Window) NULL) 13844 window_info.id=XWindowByName(display,root_window,resources.window_id); 13845 } 13846 if (window_info.id == (Window) NULL) 13847 { 13848 ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists", 13849 resources.window_id); 13850 return(MagickFalse); 13851 } 13852 /* 13853 Determine window visual id. 13854 */ 13855 window_attributes.width=XDisplayWidth(display,XDefaultScreen(display)); 13856 window_attributes.height=XDisplayHeight(display,XDefaultScreen(display)); 13857 (void) CopyMagickString(visual_type,"default",MaxTextExtent); 13858 status=XGetWindowAttributes(display,window_info.id,&window_attributes); 13859 if (status != 0) 13860 (void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx", 13861 XVisualIDFromVisual(window_attributes.visual)); 13862 if (visual_info == (XVisualInfo *) NULL) 13863 { 13864 /* 13865 Allocate standard colormap. 13866 */ 13867 map_info=XAllocStandardColormap(); 13868 if (map_info == (XStandardColormap *) NULL) 13869 ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed", 13870 image->filename); 13871 map_info->colormap=(Colormap) NULL; 13872 pixel.pixels=(unsigned long *) NULL; 13873 /* 13874 Initialize visual info. 13875 */ 13876 resources.map_type=(char *) NULL; 13877 resources.visual_type=visual_type; 13878 visual_info=XBestVisualInfo(display,map_info,&resources); 13879 if (visual_info == (XVisualInfo *) NULL) 13880 ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual", 13881 resources.visual_type); 13882 /* 13883 Initialize window info. 13884 */ 13885 window_info.ximage=(XImage *) NULL; 13886 window_info.matte_image=(XImage *) NULL; 13887 window_info.pixmap=(Pixmap) NULL; 13888 window_info.matte_pixmap=(Pixmap) NULL; 13889 } 13890 /* 13891 Free previous root colors. 13892 */ 13893 if (window_info.id == root_window) 13894 (void) XDestroyWindowColors(display,root_window); 13895 /* 13896 Initialize Standard Colormap. 13897 */ 13898 resources.colormap=SharedColormap; 13899 XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel, 13900 exception); 13901 /* 13902 Graphic context superclass. 13903 */ 13904 context_values.background=pixel.background_color.pixel; 13905 context_values.foreground=pixel.foreground_color.pixel; 13906 pixel.annotate_context=XCreateGC(display,window_info.id, 13907 (size_t) (GCBackground | GCForeground),&context_values); 13908 if (pixel.annotate_context == (GC) NULL) 13909 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 13910 image->filename); 13911 /* 13912 Initialize Image window attributes. 13913 */ 13914 window_info.name=AcquireString("\0"); 13915 window_info.icon_name=AcquireString("\0"); 13916 XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL, 13917 &resources,&window_info); 13918 /* 13919 Create the X image. 13920 */ 13921 window_info.width=(unsigned int) image->columns; 13922 window_info.height=(unsigned int) image->rows; 13923 if ((image->columns != window_info.width) || 13924 (image->rows != window_info.height)) 13925 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13926 image->filename); 13927 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>", 13928 window_attributes.width,window_attributes.height); 13929 geometry_info.width=window_info.width; 13930 geometry_info.height=window_info.height; 13931 geometry_info.x=(ssize_t) window_info.x; 13932 geometry_info.y=(ssize_t) window_info.y; 13933 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 13934 &geometry_info.width,&geometry_info.height); 13935 window_info.width=(unsigned int) geometry_info.width; 13936 window_info.height=(unsigned int) geometry_info.height; 13937 window_info.x=(int) geometry_info.x; 13938 window_info.y=(int) geometry_info.y; 13939 status=XMakeImage(display,&resources,&window_info,image,window_info.width, 13940 window_info.height,exception); 13941 if( IfMagickFalse(status) ) 13942 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 13943 image->filename); 13944 window_info.x=0; 13945 window_info.y=0; 13946 if( IfMagickTrue(image->debug) ) 13947 { 13948 (void) LogMagickEvent(X11Event,GetMagickModule(), 13949 "Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene, 13950 (double) image->columns,(double) image->rows); 13951 if (image->colors != 0) 13952 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 13953 image->colors); 13954 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick); 13955 } 13956 /* 13957 Adjust image dimensions as specified by backdrop or geometry options. 13958 */ 13959 width=(int) window_info.width; 13960 height=(int) window_info.height; 13961 if( IfMagickTrue(resources.backdrop) ) 13962 { 13963 /* 13964 Center image on window. 13965 */ 13966 window_info.x=(window_attributes.width/2)- 13967 (window_info.ximage->width/2); 13968 window_info.y=(window_attributes.height/2)- 13969 (window_info.ximage->height/2); 13970 width=window_attributes.width; 13971 height=window_attributes.height; 13972 } 13973 if ((resources.image_geometry != (char *) NULL) && 13974 (*resources.image_geometry != '\0')) 13975 { 13976 char 13977 default_geometry[MaxTextExtent]; 13978 13979 int 13980 flags, 13981 gravity; 13982 13983 XSizeHints 13984 *size_hints; 13985 13986 /* 13987 User specified geometry. 13988 */ 13989 size_hints=XAllocSizeHints(); 13990 if (size_hints == (XSizeHints *) NULL) 13991 ThrowXWindowFatalException(ResourceLimitFatalError, 13992 "MemoryAllocationFailed",image->filename); 13993 size_hints->flags=0L; 13994 (void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d", 13995 width,height); 13996 flags=XWMGeometry(display,visual_info->screen,resources.image_geometry, 13997 default_geometry,window_info.border_width,size_hints,&window_info.x, 13998 &window_info.y,&width,&height,&gravity); 13999 if (flags & (XValue | YValue)) 14000 { 14001 width=window_attributes.width; 14002 height=window_attributes.height; 14003 } 14004 (void) XFree((void *) size_hints); 14005 } 14006 /* 14007 Create the X pixmap. 14008 */ 14009 window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width, 14010 (unsigned int) height,window_info.depth); 14011 if (window_info.pixmap == (Pixmap) NULL) 14012 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap", 14013 image->filename); 14014 /* 14015 Display pixmap on the window. 14016 */ 14017 if (((unsigned int) width > window_info.width) || 14018 ((unsigned int) height > window_info.height)) 14019 (void) XFillRectangle(display,window_info.pixmap, 14020 window_info.annotate_context,0,0,(unsigned int) width, 14021 (unsigned int) height); 14022 (void) XPutImage(display,window_info.pixmap,window_info.annotate_context, 14023 window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int) 14024 window_info.width,(unsigned int) window_info.height); 14025 (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap); 14026 (void) XClearWindow(display,window_info.id); 14027 delay=1000*image->delay/MagickMax(image->ticks_per_second,1L); 14028 XDelay(display,delay == 0UL ? 10UL : delay); 14029 (void) XSync(display,MagickFalse); 14030 return(IsMagickTrue(window_info.id == root_window)); 14031} 14032 14033/* 14034%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14035% % 14036% % 14037% % 14038+ X D i s p l a y I m a g e % 14039% % 14040% % 14041% % 14042%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14043% 14044% XDisplayImage() displays an image via X11. A new image is created and 14045% returned if the user interactively transforms the displayed image. 14046% 14047% The format of the XDisplayImage method is: 14048% 14049% Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14050% char **argv,int argc,Image **image,size_t *state, 14051% ExceptionInfo *exception) 14052% 14053% A description of each parameter follows: 14054% 14055% o nexus: Method XDisplayImage returns an image when the 14056% user chooses 'Open Image' from the command menu or picks a tile 14057% from the image directory. Otherwise a null image is returned. 14058% 14059% o display: Specifies a connection to an X server; returned from 14060% XOpenDisplay. 14061% 14062% o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 14063% 14064% o argv: Specifies the application's argument list. 14065% 14066% o argc: Specifies the number of arguments. 14067% 14068% o image: Specifies an address to an address of an Image structure; 14069% 14070% o exception: return any errors or warnings in this structure. 14071% 14072*/ 14073MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info, 14074 char **argv,int argc,Image **image,size_t *state,ExceptionInfo *exception) 14075{ 14076#define MagnifySize 256 /* must be a power of 2 */ 14077#define MagickMenus 10 14078#define MagickTitle "Commands" 14079 14080 static const char 14081 *CommandMenu[] = 14082 { 14083 "File", 14084 "Edit", 14085 "View", 14086 "Transform", 14087 "Enhance", 14088 "Effects", 14089 "F/X", 14090 "Image Edit", 14091 "Miscellany", 14092 "Help", 14093 (char *) NULL 14094 }, 14095 *FileMenu[] = 14096 { 14097 "Open...", 14098 "Next", 14099 "Former", 14100 "Select...", 14101 "Save...", 14102 "Print...", 14103 "Delete...", 14104 "New...", 14105 "Visual Directory...", 14106 "Quit", 14107 (char *) NULL 14108 }, 14109 *EditMenu[] = 14110 { 14111 "Undo", 14112 "Redo", 14113 "Cut", 14114 "Copy", 14115 "Paste", 14116 (char *) NULL 14117 }, 14118 *ViewMenu[] = 14119 { 14120 "Half Size", 14121 "Original Size", 14122 "Double Size", 14123 "Resize...", 14124 "Apply", 14125 "Refresh", 14126 "Restore", 14127 (char *) NULL 14128 }, 14129 *TransformMenu[] = 14130 { 14131 "Crop", 14132 "Chop", 14133 "Flop", 14134 "Flip", 14135 "Rotate Right", 14136 "Rotate Left", 14137 "Rotate...", 14138 "Shear...", 14139 "Roll...", 14140 "Trim Edges", 14141 (char *) NULL 14142 }, 14143 *EnhanceMenu[] = 14144 { 14145 "Hue...", 14146 "Saturation...", 14147 "Brightness...", 14148 "Gamma...", 14149 "Spiff", 14150 "Dull", 14151 "Contrast Stretch...", 14152 "Sigmoidal Contrast...", 14153 "Normalize", 14154 "Equalize", 14155 "Negate", 14156 "Grayscale", 14157 "Map...", 14158 "Quantize...", 14159 (char *) NULL 14160 }, 14161 *EffectsMenu[] = 14162 { 14163 "Despeckle", 14164 "Emboss", 14165 "Reduce Noise", 14166 "Add Noise...", 14167 "Sharpen...", 14168 "Blur...", 14169 "Threshold...", 14170 "Edge Detect...", 14171 "Spread...", 14172 "Shade...", 14173 "Raise...", 14174 "Segment...", 14175 (char *) NULL 14176 }, 14177 *FXMenu[] = 14178 { 14179 "Solarize...", 14180 "Sepia Tone...", 14181 "Swirl...", 14182 "Implode...", 14183 "Vignette...", 14184 "Wave...", 14185 "Oil Paint...", 14186 "Charcoal Draw...", 14187 (char *) NULL 14188 }, 14189 *ImageEditMenu[] = 14190 { 14191 "Annotate...", 14192 "Draw...", 14193 "Color...", 14194 "Matte...", 14195 "Composite...", 14196 "Add Border...", 14197 "Add Frame...", 14198 "Comment...", 14199 "Launch...", 14200 "Region of Interest...", 14201 (char *) NULL 14202 }, 14203 *MiscellanyMenu[] = 14204 { 14205 "Image Info", 14206 "Zoom Image", 14207 "Show Preview...", 14208 "Show Histogram", 14209 "Show Matte", 14210 "Background...", 14211 "Slide Show...", 14212 "Preferences...", 14213 (char *) NULL 14214 }, 14215 *HelpMenu[] = 14216 { 14217 "Overview", 14218 "Browse Documentation", 14219 "About Display", 14220 (char *) NULL 14221 }, 14222 *ShortCutsMenu[] = 14223 { 14224 "Next", 14225 "Former", 14226 "Open...", 14227 "Save...", 14228 "Print...", 14229 "Undo", 14230 "Restore", 14231 "Image Info", 14232 "Quit", 14233 (char *) NULL 14234 }, 14235 *VirtualMenu[] = 14236 { 14237 "Image Info", 14238 "Print", 14239 "Next", 14240 "Quit", 14241 (char *) NULL 14242 }; 14243 14244 static const char 14245 **Menus[MagickMenus] = 14246 { 14247 FileMenu, 14248 EditMenu, 14249 ViewMenu, 14250 TransformMenu, 14251 EnhanceMenu, 14252 EffectsMenu, 14253 FXMenu, 14254 ImageEditMenu, 14255 MiscellanyMenu, 14256 HelpMenu 14257 }; 14258 14259 static CommandType 14260 CommandMenus[] = 14261 { 14262 NullCommand, 14263 NullCommand, 14264 NullCommand, 14265 NullCommand, 14266 NullCommand, 14267 NullCommand, 14268 NullCommand, 14269 NullCommand, 14270 NullCommand, 14271 NullCommand, 14272 }, 14273 FileCommands[] = 14274 { 14275 OpenCommand, 14276 NextCommand, 14277 FormerCommand, 14278 SelectCommand, 14279 SaveCommand, 14280 PrintCommand, 14281 DeleteCommand, 14282 NewCommand, 14283 VisualDirectoryCommand, 14284 QuitCommand 14285 }, 14286 EditCommands[] = 14287 { 14288 UndoCommand, 14289 RedoCommand, 14290 CutCommand, 14291 CopyCommand, 14292 PasteCommand 14293 }, 14294 ViewCommands[] = 14295 { 14296 HalfSizeCommand, 14297 OriginalSizeCommand, 14298 DoubleSizeCommand, 14299 ResizeCommand, 14300 ApplyCommand, 14301 RefreshCommand, 14302 RestoreCommand 14303 }, 14304 TransformCommands[] = 14305 { 14306 CropCommand, 14307 ChopCommand, 14308 FlopCommand, 14309 FlipCommand, 14310 RotateRightCommand, 14311 RotateLeftCommand, 14312 RotateCommand, 14313 ShearCommand, 14314 RollCommand, 14315 TrimCommand 14316 }, 14317 EnhanceCommands[] = 14318 { 14319 HueCommand, 14320 SaturationCommand, 14321 BrightnessCommand, 14322 GammaCommand, 14323 SpiffCommand, 14324 DullCommand, 14325 ContrastStretchCommand, 14326 SigmoidalContrastCommand, 14327 NormalizeCommand, 14328 EqualizeCommand, 14329 NegateCommand, 14330 GrayscaleCommand, 14331 MapCommand, 14332 QuantizeCommand 14333 }, 14334 EffectsCommands[] = 14335 { 14336 DespeckleCommand, 14337 EmbossCommand, 14338 ReduceNoiseCommand, 14339 AddNoiseCommand, 14340 SharpenCommand, 14341 BlurCommand, 14342 ThresholdCommand, 14343 EdgeDetectCommand, 14344 SpreadCommand, 14345 ShadeCommand, 14346 RaiseCommand, 14347 SegmentCommand 14348 }, 14349 FXCommands[] = 14350 { 14351 SolarizeCommand, 14352 SepiaToneCommand, 14353 SwirlCommand, 14354 ImplodeCommand, 14355 VignetteCommand, 14356 WaveCommand, 14357 OilPaintCommand, 14358 CharcoalDrawCommand 14359 }, 14360 ImageEditCommands[] = 14361 { 14362 AnnotateCommand, 14363 DrawCommand, 14364 ColorCommand, 14365 MatteCommand, 14366 CompositeCommand, 14367 AddBorderCommand, 14368 AddFrameCommand, 14369 CommentCommand, 14370 LaunchCommand, 14371 RegionofInterestCommand 14372 }, 14373 MiscellanyCommands[] = 14374 { 14375 InfoCommand, 14376 ZoomCommand, 14377 ShowPreviewCommand, 14378 ShowHistogramCommand, 14379 ShowMatteCommand, 14380 BackgroundCommand, 14381 SlideShowCommand, 14382 PreferencesCommand 14383 }, 14384 HelpCommands[] = 14385 { 14386 HelpCommand, 14387 BrowseDocumentationCommand, 14388 VersionCommand 14389 }, 14390 ShortCutsCommands[] = 14391 { 14392 NextCommand, 14393 FormerCommand, 14394 OpenCommand, 14395 SaveCommand, 14396 PrintCommand, 14397 UndoCommand, 14398 RestoreCommand, 14399 InfoCommand, 14400 QuitCommand 14401 }, 14402 VirtualCommands[] = 14403 { 14404 InfoCommand, 14405 PrintCommand, 14406 NextCommand, 14407 QuitCommand 14408 }; 14409 14410 static CommandType 14411 *Commands[MagickMenus] = 14412 { 14413 FileCommands, 14414 EditCommands, 14415 ViewCommands, 14416 TransformCommands, 14417 EnhanceCommands, 14418 EffectsCommands, 14419 FXCommands, 14420 ImageEditCommands, 14421 MiscellanyCommands, 14422 HelpCommands 14423 }; 14424 14425 char 14426 command[MaxTextExtent], 14427 *directory, 14428 geometry[MaxTextExtent], 14429 resource_name[MaxTextExtent]; 14430 14431 CommandType 14432 command_type; 14433 14434 Image 14435 *display_image, 14436 *nexus; 14437 14438 int 14439 entry, 14440 id; 14441 14442 KeySym 14443 key_symbol; 14444 14445 MagickStatusType 14446 context_mask, 14447 status; 14448 14449 RectangleInfo 14450 geometry_info; 14451 14452 register int 14453 i; 14454 14455 static char 14456 working_directory[MaxTextExtent]; 14457 14458 static XPoint 14459 vid_info; 14460 14461 static XWindowInfo 14462 *magick_windows[MaxXWindows]; 14463 14464 static unsigned int 14465 number_windows; 14466 14467 struct stat 14468 attributes; 14469 14470 time_t 14471 timer, 14472 timestamp, 14473 update_time; 14474 14475 unsigned int 14476 height, 14477 width; 14478 14479 size_t 14480 delay; 14481 14482 WarningHandler 14483 warning_handler; 14484 14485 Window 14486 root_window; 14487 14488 XClassHint 14489 *class_hints; 14490 14491 XEvent 14492 event; 14493 14494 XFontStruct 14495 *font_info; 14496 14497 XGCValues 14498 context_values; 14499 14500 XPixelInfo 14501 *icon_pixel, 14502 *pixel; 14503 14504 XResourceInfo 14505 *icon_resources; 14506 14507 XStandardColormap 14508 *icon_map, 14509 *map_info; 14510 14511 XVisualInfo 14512 *icon_visual, 14513 *visual_info; 14514 14515 XWindowChanges 14516 window_changes; 14517 14518 XWindows 14519 *windows; 14520 14521 XWMHints 14522 *manager_hints; 14523 14524 assert(image != (Image **) NULL); 14525 assert((*image)->signature == MagickSignature); 14526 if( IfMagickTrue((*image)->debug) ) 14527 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename); 14528 display_image=(*image); 14529 warning_handler=(WarningHandler) NULL; 14530 windows=XSetWindows((XWindows *) ~0); 14531 if (windows != (XWindows *) NULL) 14532 { 14533 int 14534 status; 14535 14536 if (*working_directory == '\0') 14537 (void) CopyMagickString(working_directory,".",MaxTextExtent); 14538 status=chdir(working_directory); 14539 if (status == -1) 14540 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 14541 "UnableToOpenFile","%s",working_directory); 14542 warning_handler=resource_info->display_warnings ? 14543 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 14544 warning_handler=resource_info->display_warnings ? 14545 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 14546 } 14547 else 14548 { 14549 /* 14550 Allocate windows structure. 14551 */ 14552 resource_info->colors=display_image->colors; 14553 windows=XSetWindows(XInitializeWindows(display,resource_info)); 14554 if (windows == (XWindows *) NULL) 14555 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow", 14556 (*image)->filename); 14557 /* 14558 Initialize window id's. 14559 */ 14560 number_windows=0; 14561 magick_windows[number_windows++]=(&windows->icon); 14562 magick_windows[number_windows++]=(&windows->backdrop); 14563 magick_windows[number_windows++]=(&windows->image); 14564 magick_windows[number_windows++]=(&windows->info); 14565 magick_windows[number_windows++]=(&windows->command); 14566 magick_windows[number_windows++]=(&windows->widget); 14567 magick_windows[number_windows++]=(&windows->popup); 14568 magick_windows[number_windows++]=(&windows->magnify); 14569 magick_windows[number_windows++]=(&windows->pan); 14570 for (i=0; i < (int) number_windows; i++) 14571 magick_windows[i]->id=(Window) NULL; 14572 vid_info.x=0; 14573 vid_info.y=0; 14574 } 14575 /* 14576 Initialize font info. 14577 */ 14578 if (windows->font_info != (XFontStruct *) NULL) 14579 (void) XFreeFont(display,windows->font_info); 14580 windows->font_info=XBestFont(display,resource_info,MagickFalse); 14581 if (windows->font_info == (XFontStruct *) NULL) 14582 ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont", 14583 resource_info->font); 14584 /* 14585 Initialize Standard Colormap. 14586 */ 14587 map_info=windows->map_info; 14588 icon_map=windows->icon_map; 14589 visual_info=windows->visual_info; 14590 icon_visual=windows->icon_visual; 14591 pixel=windows->pixel_info; 14592 icon_pixel=windows->icon_pixel; 14593 font_info=windows->font_info; 14594 icon_resources=windows->icon_resources; 14595 class_hints=windows->class_hints; 14596 manager_hints=windows->manager_hints; 14597 root_window=XRootWindow(display,visual_info->screen); 14598 nexus=NewImageList(); 14599 if( IfMagickTrue(display_image->debug) ) 14600 { 14601 (void) LogMagickEvent(X11Event,GetMagickModule(), 14602 "Image: %s[%.20g] %.20gx%.20g ",display_image->filename, 14603 (double) display_image->scene,(double) display_image->columns, 14604 (double) display_image->rows); 14605 if (display_image->colors != 0) 14606 (void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double) 14607 display_image->colors); 14608 (void) LogMagickEvent(X11Event,GetMagickModule(),"%s", 14609 display_image->magick); 14610 } 14611 XMakeStandardColormap(display,visual_info,resource_info,display_image, 14612 map_info,pixel,exception); 14613 display_image->taint=MagickFalse; 14614 /* 14615 Initialize graphic context. 14616 */ 14617 windows->context.id=(Window) NULL; 14618 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14619 resource_info,&windows->context); 14620 (void) CloneString(&class_hints->res_name,resource_info->client_name); 14621 (void) CloneString(&class_hints->res_class,resource_info->client_name); 14622 class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]); 14623 manager_hints->flags=InputHint | StateHint; 14624 manager_hints->input=MagickFalse; 14625 manager_hints->initial_state=WithdrawnState; 14626 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14627 &windows->context); 14628 if( IfMagickTrue(display_image->debug) ) 14629 (void) LogMagickEvent(X11Event,GetMagickModule(), 14630 "Window id: 0x%lx (context)",windows->context.id); 14631 context_values.background=pixel->background_color.pixel; 14632 context_values.font=font_info->fid; 14633 context_values.foreground=pixel->foreground_color.pixel; 14634 context_values.graphics_exposures=MagickFalse; 14635 context_mask=(MagickStatusType) 14636 (GCBackground | GCFont | GCForeground | GCGraphicsExposures); 14637 if (pixel->annotate_context != (GC) NULL) 14638 (void) XFreeGC(display,pixel->annotate_context); 14639 pixel->annotate_context=XCreateGC(display,windows->context.id, 14640 context_mask,&context_values); 14641 if (pixel->annotate_context == (GC) NULL) 14642 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14643 display_image->filename); 14644 context_values.background=pixel->depth_color.pixel; 14645 if (pixel->widget_context != (GC) NULL) 14646 (void) XFreeGC(display,pixel->widget_context); 14647 pixel->widget_context=XCreateGC(display,windows->context.id,context_mask, 14648 &context_values); 14649 if (pixel->widget_context == (GC) NULL) 14650 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14651 display_image->filename); 14652 context_values.background=pixel->foreground_color.pixel; 14653 context_values.foreground=pixel->background_color.pixel; 14654 context_values.plane_mask=context_values.background ^ 14655 context_values.foreground; 14656 if (pixel->highlight_context != (GC) NULL) 14657 (void) XFreeGC(display,pixel->highlight_context); 14658 pixel->highlight_context=XCreateGC(display,windows->context.id, 14659 (size_t) (context_mask | GCPlaneMask),&context_values); 14660 if (pixel->highlight_context == (GC) NULL) 14661 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14662 display_image->filename); 14663 (void) XDestroyWindow(display,windows->context.id); 14664 /* 14665 Initialize icon window. 14666 */ 14667 XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL, 14668 icon_resources,&windows->icon); 14669 windows->icon.geometry=resource_info->icon_geometry; 14670 XBestIconSize(display,&windows->icon,display_image); 14671 windows->icon.attributes.colormap=XDefaultColormap(display, 14672 icon_visual->screen); 14673 windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask; 14674 manager_hints->flags=InputHint | StateHint; 14675 manager_hints->input=MagickFalse; 14676 manager_hints->initial_state=IconicState; 14677 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14678 &windows->icon); 14679 if( IfMagickTrue(display_image->debug) ) 14680 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)", 14681 windows->icon.id); 14682 /* 14683 Initialize graphic context for icon window. 14684 */ 14685 if (icon_pixel->annotate_context != (GC) NULL) 14686 (void) XFreeGC(display,icon_pixel->annotate_context); 14687 context_values.background=icon_pixel->background_color.pixel; 14688 context_values.foreground=icon_pixel->foreground_color.pixel; 14689 icon_pixel->annotate_context=XCreateGC(display,windows->icon.id, 14690 (size_t) (GCBackground | GCForeground),&context_values); 14691 if (icon_pixel->annotate_context == (GC) NULL) 14692 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext", 14693 display_image->filename); 14694 windows->icon.annotate_context=icon_pixel->annotate_context; 14695 /* 14696 Initialize Image window. 14697 */ 14698 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14699 &windows->image); 14700 windows->image.shape=MagickTrue; /* non-rectangular shape hint */ 14701 if( IfMagickFalse(resource_info->use_shared_memory) ) 14702 windows->image.shared_memory=MagickFalse; 14703 if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState)) 14704 { 14705 char 14706 *title; 14707 14708 title=InterpretImageProperties(resource_info->image_info,display_image, 14709 resource_info->title,exception); 14710 (void) CopyMagickString(windows->image.name,title,MaxTextExtent); 14711 (void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent); 14712 title=DestroyString(title); 14713 } 14714 else 14715 { 14716 char 14717 filename[MaxTextExtent]; 14718 14719 /* 14720 Window name is the base of the filename. 14721 */ 14722 GetPathComponent(display_image->magick_filename,TailPath,filename); 14723 if (display_image->scene == 0) 14724 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14725 "%s: %s",MagickPackageName,filename); 14726 else 14727 (void) FormatLocaleString(windows->image.name,MaxTextExtent, 14728 "%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename, 14729 (double) display_image->scene,(double) GetImageListLength( 14730 display_image)); 14731 (void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent); 14732 } 14733 if (resource_info->immutable) 14734 windows->image.immutable=MagickTrue; 14735 windows->image.use_pixmap=resource_info->use_pixmap; 14736 windows->image.geometry=resource_info->image_geometry; 14737 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 14738 XDisplayWidth(display,visual_info->screen), 14739 XDisplayHeight(display,visual_info->screen)); 14740 geometry_info.width=display_image->columns; 14741 geometry_info.height=display_image->rows; 14742 geometry_info.x=0; 14743 geometry_info.y=0; 14744 (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y, 14745 &geometry_info.width,&geometry_info.height); 14746 windows->image.width=(unsigned int) geometry_info.width; 14747 windows->image.height=(unsigned int) geometry_info.height; 14748 windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14749 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14750 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14751 PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask; 14752 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14753 resource_info,&windows->backdrop); 14754 if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL)) 14755 { 14756 /* 14757 Initialize backdrop window. 14758 */ 14759 windows->backdrop.x=0; 14760 windows->backdrop.y=0; 14761 (void) CloneString(&windows->backdrop.name,"Backdrop"); 14762 windows->backdrop.flags=(size_t) (USSize | USPosition); 14763 windows->backdrop.width=(unsigned int) 14764 XDisplayWidth(display,visual_info->screen); 14765 windows->backdrop.height=(unsigned int) 14766 XDisplayHeight(display,visual_info->screen); 14767 windows->backdrop.border_width=0; 14768 windows->backdrop.immutable=MagickTrue; 14769 windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask | 14770 ButtonReleaseMask; 14771 windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask | 14772 StructureNotifyMask; 14773 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14774 manager_hints->icon_window=windows->icon.id; 14775 manager_hints->input=MagickTrue; 14776 manager_hints->initial_state=resource_info->iconic ? IconicState : 14777 NormalState; 14778 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14779 &windows->backdrop); 14780 if( IfMagickTrue(display_image->debug) ) 14781 (void) LogMagickEvent(X11Event,GetMagickModule(), 14782 "Window id: 0x%lx (backdrop)",windows->backdrop.id); 14783 (void) XMapWindow(display,windows->backdrop.id); 14784 (void) XClearWindow(display,windows->backdrop.id); 14785 if (windows->image.id != (Window) NULL) 14786 { 14787 (void) XDestroyWindow(display,windows->image.id); 14788 windows->image.id=(Window) NULL; 14789 } 14790 /* 14791 Position image in the center the backdrop. 14792 */ 14793 windows->image.flags|=USPosition; 14794 windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)- 14795 (windows->image.width/2); 14796 windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)- 14797 (windows->image.height/2); 14798 } 14799 manager_hints->flags=IconWindowHint | InputHint | StateHint; 14800 manager_hints->icon_window=windows->icon.id; 14801 manager_hints->input=MagickTrue; 14802 manager_hints->initial_state=resource_info->iconic ? IconicState : 14803 NormalState; 14804 if (windows->group_leader.id != (Window) NULL) 14805 { 14806 /* 14807 Follow the leader. 14808 */ 14809 manager_hints->flags|=WindowGroupHint; 14810 manager_hints->window_group=windows->group_leader.id; 14811 (void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask); 14812 if( IfMagickTrue(display_image->debug) ) 14813 (void) LogMagickEvent(X11Event,GetMagickModule(), 14814 "Window id: 0x%lx (group leader)",windows->group_leader.id); 14815 } 14816 XMakeWindow(display, 14817 (Window) (resource_info->backdrop ? windows->backdrop.id : root_window), 14818 argv,argc,class_hints,manager_hints,&windows->image); 14819 (void) XChangeProperty(display,windows->image.id,windows->im_protocols, 14820 XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0); 14821 if (windows->group_leader.id != (Window) NULL) 14822 (void) XSetTransientForHint(display,windows->image.id, 14823 windows->group_leader.id); 14824 if( IfMagickTrue(display_image->debug) ) 14825 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)", 14826 windows->image.id); 14827 /* 14828 Initialize Info widget. 14829 */ 14830 XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info, 14831 &windows->info); 14832 (void) CloneString(&windows->info.name,"Info"); 14833 (void) CloneString(&windows->info.icon_name,"Info"); 14834 windows->info.border_width=1; 14835 windows->info.x=2; 14836 windows->info.y=2; 14837 windows->info.flags|=PPosition; 14838 windows->info.attributes.win_gravity=UnmapGravity; 14839 windows->info.attributes.event_mask=ButtonPressMask | ExposureMask | 14840 StructureNotifyMask; 14841 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14842 manager_hints->input=MagickFalse; 14843 manager_hints->initial_state=NormalState; 14844 manager_hints->window_group=windows->image.id; 14845 XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints, 14846 &windows->info); 14847 windows->info.highlight_stipple=XCreateBitmapFromData(display, 14848 windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14849 windows->info.shadow_stipple=XCreateBitmapFromData(display, 14850 windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14851 (void) XSetTransientForHint(display,windows->info.id,windows->image.id); 14852 if( IfMagickTrue(windows->image.mapped) ) 14853 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 14854 if( IfMagickTrue(display_image->debug) ) 14855 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)", 14856 windows->info.id); 14857 /* 14858 Initialize Command widget. 14859 */ 14860 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14861 resource_info,&windows->command); 14862 windows->command.data=MagickMenus; 14863 (void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL); 14864 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command", 14865 resource_info->client_name); 14866 windows->command.geometry=XGetResourceClass(resource_info->resource_database, 14867 resource_name,"geometry",(char *) NULL); 14868 (void) CloneString(&windows->command.name,MagickTitle); 14869 windows->command.border_width=0; 14870 windows->command.flags|=PPosition; 14871 windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14872 ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask | 14873 OwnerGrabButtonMask | StructureNotifyMask; 14874 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14875 manager_hints->input=MagickTrue; 14876 manager_hints->initial_state=NormalState; 14877 manager_hints->window_group=windows->image.id; 14878 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14879 &windows->command); 14880 windows->command.highlight_stipple=XCreateBitmapFromData(display, 14881 windows->command.id,(char *) HighlightBitmap,HighlightWidth, 14882 HighlightHeight); 14883 windows->command.shadow_stipple=XCreateBitmapFromData(display, 14884 windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14885 (void) XSetTransientForHint(display,windows->command.id,windows->image.id); 14886 if( IfMagickTrue(windows->command.mapped) ) 14887 (void) XMapRaised(display,windows->command.id); 14888 if( IfMagickTrue(display_image->debug) ) 14889 (void) LogMagickEvent(X11Event,GetMagickModule(), 14890 "Window id: 0x%lx (command)",windows->command.id); 14891 /* 14892 Initialize Widget window. 14893 */ 14894 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14895 resource_info,&windows->widget); 14896 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget", 14897 resource_info->client_name); 14898 windows->widget.geometry=XGetResourceClass(resource_info->resource_database, 14899 resource_name,"geometry",(char *) NULL); 14900 windows->widget.border_width=0; 14901 windows->widget.flags|=PPosition; 14902 windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14903 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14904 KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask | 14905 StructureNotifyMask; 14906 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14907 manager_hints->input=MagickTrue; 14908 manager_hints->initial_state=NormalState; 14909 manager_hints->window_group=windows->image.id; 14910 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14911 &windows->widget); 14912 windows->widget.highlight_stipple=XCreateBitmapFromData(display, 14913 windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14914 windows->widget.shadow_stipple=XCreateBitmapFromData(display, 14915 windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14916 (void) XSetTransientForHint(display,windows->widget.id,windows->image.id); 14917 if( IfMagickTrue(display_image->debug) ) 14918 (void) LogMagickEvent(X11Event,GetMagickModule(), 14919 "Window id: 0x%lx (widget)",windows->widget.id); 14920 /* 14921 Initialize popup window. 14922 */ 14923 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14924 resource_info,&windows->popup); 14925 windows->popup.border_width=0; 14926 windows->popup.flags|=PPosition; 14927 windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 14928 ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask | 14929 KeyReleaseMask | LeaveWindowMask | StructureNotifyMask; 14930 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14931 manager_hints->input=MagickTrue; 14932 manager_hints->initial_state=NormalState; 14933 manager_hints->window_group=windows->image.id; 14934 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14935 &windows->popup); 14936 windows->popup.highlight_stipple=XCreateBitmapFromData(display, 14937 windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight); 14938 windows->popup.shadow_stipple=XCreateBitmapFromData(display, 14939 windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight); 14940 (void) XSetTransientForHint(display,windows->popup.id,windows->image.id); 14941 if( IfMagickTrue(display_image->debug) ) 14942 (void) LogMagickEvent(X11Event,GetMagickModule(), 14943 "Window id: 0x%lx (pop up)",windows->popup.id); 14944 /* 14945 Initialize Magnify window and cursor. 14946 */ 14947 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14948 resource_info,&windows->magnify); 14949 if( IfMagickFalse(resource_info->use_shared_memory) ) 14950 windows->magnify.shared_memory=MagickFalse; 14951 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify", 14952 resource_info->client_name); 14953 windows->magnify.geometry=XGetResourceClass(resource_info->resource_database, 14954 resource_name,"geometry",(char *) NULL); 14955 (void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX", 14956 resource_info->magnify); 14957 if (windows->magnify.cursor != (Cursor) NULL) 14958 (void) XFreeCursor(display,windows->magnify.cursor); 14959 windows->magnify.cursor=XMakeCursor(display,windows->image.id, 14960 map_info->colormap,resource_info->background_color, 14961 resource_info->foreground_color); 14962 if (windows->magnify.cursor == (Cursor) NULL) 14963 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor", 14964 display_image->filename); 14965 windows->magnify.width=MagnifySize; 14966 windows->magnify.height=MagnifySize; 14967 windows->magnify.flags|=PPosition; 14968 windows->magnify.min_width=MagnifySize; 14969 windows->magnify.min_height=MagnifySize; 14970 windows->magnify.width_inc=MagnifySize; 14971 windows->magnify.height_inc=MagnifySize; 14972 windows->magnify.data=resource_info->magnify; 14973 windows->magnify.attributes.cursor=windows->magnify.cursor; 14974 windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask | 14975 ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask | 14976 StructureNotifyMask; 14977 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 14978 manager_hints->input=MagickTrue; 14979 manager_hints->initial_state=NormalState; 14980 manager_hints->window_group=windows->image.id; 14981 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 14982 &windows->magnify); 14983 if( IfMagickTrue(display_image->debug) ) 14984 (void) LogMagickEvent(X11Event,GetMagickModule(), 14985 "Window id: 0x%lx (magnify)",windows->magnify.id); 14986 (void) XSetTransientForHint(display,windows->magnify.id,windows->image.id); 14987 /* 14988 Initialize panning window. 14989 */ 14990 XGetWindowInfo(display,visual_info,map_info,pixel,font_info, 14991 resource_info,&windows->pan); 14992 (void) CloneString(&windows->pan.name,"Pan Icon"); 14993 windows->pan.width=windows->icon.width; 14994 windows->pan.height=windows->icon.height; 14995 (void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan", 14996 resource_info->client_name); 14997 windows->pan.geometry=XGetResourceClass(resource_info->resource_database, 14998 resource_name,"geometry",(char *) NULL); 14999 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 15000 &windows->pan.width,&windows->pan.height); 15001 windows->pan.flags|=PPosition; 15002 windows->pan.immutable=MagickTrue; 15003 windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask | 15004 ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask | 15005 StructureNotifyMask; 15006 manager_hints->flags=InputHint | StateHint | WindowGroupHint; 15007 manager_hints->input=MagickFalse; 15008 manager_hints->initial_state=NormalState; 15009 manager_hints->window_group=windows->image.id; 15010 XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints, 15011 &windows->pan); 15012 if( IfMagickTrue(display_image->debug) ) 15013 (void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)", 15014 windows->pan.id); 15015 (void) XSetTransientForHint(display,windows->pan.id,windows->image.id); 15016 if( IfMagickTrue(windows->info.mapped) ) 15017 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15018 if( IfMagickFalse(windows->image.mapped) || 15019 (windows->backdrop.id != (Window) NULL)) 15020 (void) XMapWindow(display,windows->image.id); 15021 /* 15022 Set our progress monitor and warning handlers. 15023 */ 15024 if (warning_handler == (WarningHandler) NULL) 15025 { 15026 warning_handler=resource_info->display_warnings ? 15027 SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL); 15028 warning_handler=resource_info->display_warnings ? 15029 SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL); 15030 } 15031 /* 15032 Initialize Image and Magnify X images. 15033 */ 15034 windows->image.x=0; 15035 windows->image.y=0; 15036 windows->magnify.shape=MagickFalse; 15037 width=(unsigned int) display_image->columns; 15038 height=(unsigned int) display_image->rows; 15039 if ((display_image->columns != width) || (display_image->rows != height)) 15040 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15041 display_image->filename); 15042 status=XMakeImage(display,resource_info,&windows->image,display_image, 15043 width,height,exception); 15044 if( IfMagickFalse(status) ) 15045 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15046 display_image->filename); 15047 status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL, 15048 windows->magnify.width,windows->magnify.height,exception); 15049 if( IfMagickFalse(status) ) 15050 ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage", 15051 display_image->filename); 15052 if( IfMagickTrue(windows->magnify.mapped) ) 15053 (void) XMapRaised(display,windows->magnify.id); 15054 if( IfMagickTrue(windows->pan.mapped) ) 15055 (void) XMapRaised(display,windows->pan.id); 15056 windows->image.window_changes.width=(int) display_image->columns; 15057 windows->image.window_changes.height=(int) display_image->rows; 15058 (void) XConfigureImage(display,resource_info,windows,display_image,exception); 15059 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 15060 (void) XSync(display,MagickFalse); 15061 /* 15062 Respond to events. 15063 */ 15064 delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L); 15065 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15066 update_time=0; 15067 if( IfMagickTrue(resource_info->update) ) 15068 { 15069 MagickBooleanType 15070 status; 15071 15072 /* 15073 Determine when file data was last modified. 15074 */ 15075 status=GetPathAttributes(display_image->filename,&attributes); 15076 if( IfMagickTrue(status) ) 15077 update_time=attributes.st_mtime; 15078 } 15079 *state&=(~FormerImageState); 15080 *state&=(~MontageImageState); 15081 *state&=(~NextImageState); 15082 do 15083 { 15084 /* 15085 Handle a window event. 15086 */ 15087 if( IfMagickTrue(windows->image.mapped) ) 15088 if ((display_image->delay != 0) || (resource_info->update != 0)) 15089 { 15090 if (timer < time((time_t *) NULL)) 15091 { 15092 if( IfMagickFalse(resource_info->update) ) 15093 *state|=NextImageState | ExitState; 15094 else 15095 { 15096 MagickBooleanType 15097 status; 15098 15099 /* 15100 Determine if image file was modified. 15101 */ 15102 status=GetPathAttributes(display_image->filename,&attributes); 15103 if( IfMagickTrue(status) ) 15104 if (update_time != attributes.st_mtime) 15105 { 15106 /* 15107 Redisplay image. 15108 */ 15109 (void) FormatLocaleString( 15110 resource_info->image_info->filename,MaxTextExtent, 15111 "%s:%s",display_image->magick, 15112 display_image->filename); 15113 nexus=ReadImage(resource_info->image_info,exception); 15114 if (nexus != (Image *) NULL) 15115 { 15116 nexus=DestroyImage(nexus); 15117 *state|=NextImageState | ExitState; 15118 } 15119 } 15120 delay=display_image->delay/MagickMax( 15121 display_image->ticks_per_second,1L); 15122 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15123 } 15124 } 15125 if (XEventsQueued(display,QueuedAfterFlush) == 0) 15126 { 15127 /* 15128 Do not block if delay > 0. 15129 */ 15130 XDelay(display,SuspendTime << 2); 15131 continue; 15132 } 15133 } 15134 timestamp=time((time_t *) NULL); 15135 (void) XNextEvent(display,&event); 15136 if( IfMagickFalse(windows->image.stasis) ) 15137 windows->image.stasis=IsMagickTrue((time((time_t *) NULL)-timestamp) > 0); 15138 if( IfMagickFalse(windows->magnify.stasis) ) 15139 windows->magnify.stasis=IsMagickTrue((time((time_t *) NULL)-timestamp) > 0); 15140 if (event.xany.window == windows->command.id) 15141 { 15142 /* 15143 Select a command from the Command widget. 15144 */ 15145 id=XCommandWidget(display,windows,CommandMenu,&event); 15146 if (id < 0) 15147 continue; 15148 (void) CopyMagickString(command,CommandMenu[id],MaxTextExtent); 15149 command_type=CommandMenus[id]; 15150 if (id < MagickMenus) 15151 { 15152 /* 15153 Select a command from a pop-up menu. 15154 */ 15155 entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id], 15156 command); 15157 if (entry < 0) 15158 continue; 15159 (void) CopyMagickString(command,Menus[id][entry],MaxTextExtent); 15160 command_type=Commands[id][entry]; 15161 } 15162 if (command_type != NullCommand) 15163 nexus=XMagickCommand(display,resource_info,windows,command_type, 15164 &display_image,exception); 15165 continue; 15166 } 15167 switch (event.type) 15168 { 15169 case ButtonPress: 15170 { 15171 if( IfMagickTrue(display_image->debug) ) 15172 (void) LogMagickEvent(X11Event,GetMagickModule(), 15173 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 15174 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15175 if ((event.xbutton.button == Button3) && 15176 (event.xbutton.state & Mod1Mask)) 15177 { 15178 /* 15179 Convert Alt-Button3 to Button2. 15180 */ 15181 event.xbutton.button=Button2; 15182 event.xbutton.state&=(~Mod1Mask); 15183 } 15184 if (event.xbutton.window == windows->backdrop.id) 15185 { 15186 (void) XSetInputFocus(display,event.xbutton.window,RevertToParent, 15187 event.xbutton.time); 15188 break; 15189 } 15190 if (event.xbutton.window == windows->image.id) 15191 { 15192 switch (event.xbutton.button) 15193 { 15194 case Button1: 15195 { 15196 if (resource_info->immutable) 15197 { 15198 /* 15199 Select a command from the Virtual menu. 15200 */ 15201 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15202 command); 15203 if (entry >= 0) 15204 nexus=XMagickCommand(display,resource_info,windows, 15205 VirtualCommands[entry],&display_image,exception); 15206 break; 15207 } 15208 /* 15209 Map/unmap Command widget. 15210 */ 15211 if( IfMagickTrue(windows->command.mapped) ) 15212 (void) XWithdrawWindow(display,windows->command.id, 15213 windows->command.screen); 15214 else 15215 { 15216 (void) XCommandWidget(display,windows,CommandMenu, 15217 (XEvent *) NULL); 15218 (void) XMapRaised(display,windows->command.id); 15219 } 15220 break; 15221 } 15222 case Button2: 15223 { 15224 /* 15225 User pressed the image magnify button. 15226 */ 15227 (void) XMagickCommand(display,resource_info,windows,ZoomCommand, 15228 &display_image,exception); 15229 XMagnifyImage(display,windows,&event,exception); 15230 break; 15231 } 15232 case Button3: 15233 { 15234 if (resource_info->immutable) 15235 { 15236 /* 15237 Select a command from the Virtual menu. 15238 */ 15239 entry=XMenuWidget(display,windows,"Commands",VirtualMenu, 15240 command); 15241 if (entry >= 0) 15242 nexus=XMagickCommand(display,resource_info,windows, 15243 VirtualCommands[entry],&display_image,exception); 15244 break; 15245 } 15246 if (display_image->montage != (char *) NULL) 15247 { 15248 /* 15249 Open or delete a tile from a visual image directory. 15250 */ 15251 nexus=XTileImage(display,resource_info,windows, 15252 display_image,&event,exception); 15253 if (nexus != (Image *) NULL) 15254 *state|=MontageImageState | NextImageState | ExitState; 15255 vid_info.x=(short int) windows->image.x; 15256 vid_info.y=(short int) windows->image.y; 15257 break; 15258 } 15259 /* 15260 Select a command from the Short Cuts menu. 15261 */ 15262 entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu, 15263 command); 15264 if (entry >= 0) 15265 nexus=XMagickCommand(display,resource_info,windows, 15266 ShortCutsCommands[entry],&display_image,exception); 15267 break; 15268 } 15269 case Button4: 15270 { 15271 /* 15272 Wheel up. 15273 */ 15274 XTranslateImage(display,windows,*image,XK_Up); 15275 break; 15276 } 15277 case Button5: 15278 { 15279 /* 15280 Wheel down. 15281 */ 15282 XTranslateImage(display,windows,*image,XK_Down); 15283 break; 15284 } 15285 default: 15286 break; 15287 } 15288 break; 15289 } 15290 if (event.xbutton.window == windows->magnify.id) 15291 { 15292 int 15293 factor; 15294 15295 static const char 15296 *MagnifyMenu[] = 15297 { 15298 "2", 15299 "4", 15300 "5", 15301 "6", 15302 "7", 15303 "8", 15304 "9", 15305 "3", 15306 (char *) NULL, 15307 }; 15308 15309 static KeySym 15310 MagnifyCommands[] = 15311 { 15312 XK_2, 15313 XK_4, 15314 XK_5, 15315 XK_6, 15316 XK_7, 15317 XK_8, 15318 XK_9, 15319 XK_3 15320 }; 15321 15322 /* 15323 Select a magnify factor from the pop-up menu. 15324 */ 15325 factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command); 15326 if (factor >= 0) 15327 XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor], 15328 exception); 15329 break; 15330 } 15331 if (event.xbutton.window == windows->pan.id) 15332 { 15333 switch (event.xbutton.button) 15334 { 15335 case Button4: 15336 { 15337 /* 15338 Wheel up. 15339 */ 15340 XTranslateImage(display,windows,*image,XK_Up); 15341 break; 15342 } 15343 case Button5: 15344 { 15345 /* 15346 Wheel down. 15347 */ 15348 XTranslateImage(display,windows,*image,XK_Down); 15349 break; 15350 } 15351 default: 15352 { 15353 XPanImage(display,windows,&event,exception); 15354 break; 15355 } 15356 } 15357 break; 15358 } 15359 delay=display_image->delay/MagickMax(display_image->ticks_per_second, 15360 1L); 15361 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15362 break; 15363 } 15364 case ButtonRelease: 15365 { 15366 if( IfMagickTrue(display_image->debug) ) 15367 (void) LogMagickEvent(X11Event,GetMagickModule(), 15368 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 15369 event.xbutton.button,event.xbutton.x,event.xbutton.y); 15370 break; 15371 } 15372 case ClientMessage: 15373 { 15374 if( IfMagickTrue(display_image->debug) ) 15375 (void) LogMagickEvent(X11Event,GetMagickModule(), 15376 "Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window, 15377 event.xclient.message_type,event.xclient.format,(unsigned long) 15378 event.xclient.data.l[0]); 15379 if (event.xclient.message_type == windows->im_protocols) 15380 { 15381 if (*event.xclient.data.l == (long) windows->im_update_widget) 15382 { 15383 (void) CloneString(&windows->command.name,MagickTitle); 15384 windows->command.data=MagickMenus; 15385 (void) XCommandWidget(display,windows,CommandMenu, 15386 (XEvent *) NULL); 15387 break; 15388 } 15389 if (*event.xclient.data.l == (long) windows->im_update_colormap) 15390 { 15391 /* 15392 Update graphic context and window colormap. 15393 */ 15394 for (i=0; i < (int) number_windows; i++) 15395 { 15396 if (magick_windows[i]->id == windows->icon.id) 15397 continue; 15398 context_values.background=pixel->background_color.pixel; 15399 context_values.foreground=pixel->foreground_color.pixel; 15400 (void) XChangeGC(display,magick_windows[i]->annotate_context, 15401 context_mask,&context_values); 15402 (void) XChangeGC(display,magick_windows[i]->widget_context, 15403 context_mask,&context_values); 15404 context_values.background=pixel->foreground_color.pixel; 15405 context_values.foreground=pixel->background_color.pixel; 15406 context_values.plane_mask=context_values.background ^ 15407 context_values.foreground; 15408 (void) XChangeGC(display,magick_windows[i]->highlight_context, 15409 (size_t) (context_mask | GCPlaneMask), 15410 &context_values); 15411 magick_windows[i]->attributes.background_pixel= 15412 pixel->background_color.pixel; 15413 magick_windows[i]->attributes.border_pixel= 15414 pixel->border_color.pixel; 15415 magick_windows[i]->attributes.colormap=map_info->colormap; 15416 (void) XChangeWindowAttributes(display,magick_windows[i]->id, 15417 (unsigned long) magick_windows[i]->mask, 15418 &magick_windows[i]->attributes); 15419 } 15420 if( IfMagickTrue(windows->pan.mapped) ) 15421 { 15422 (void) XSetWindowBackgroundPixmap(display,windows->pan.id, 15423 windows->pan.pixmap); 15424 (void) XClearWindow(display,windows->pan.id); 15425 XDrawPanRectangle(display,windows); 15426 } 15427 if (windows->backdrop.id != (Window) NULL) 15428 (void) XInstallColormap(display,map_info->colormap); 15429 break; 15430 } 15431 if (*event.xclient.data.l == (long) windows->im_former_image) 15432 { 15433 *state|=FormerImageState | ExitState; 15434 break; 15435 } 15436 if (*event.xclient.data.l == (long) windows->im_next_image) 15437 { 15438 *state|=NextImageState | ExitState; 15439 break; 15440 } 15441 if (*event.xclient.data.l == (long) windows->im_retain_colors) 15442 { 15443 *state|=RetainColorsState; 15444 break; 15445 } 15446 if (*event.xclient.data.l == (long) windows->im_exit) 15447 { 15448 *state|=ExitState; 15449 break; 15450 } 15451 break; 15452 } 15453 if (event.xclient.message_type == windows->dnd_protocols) 15454 { 15455 Atom 15456 selection, 15457 type; 15458 15459 int 15460 format, 15461 status; 15462 15463 unsigned char 15464 *data; 15465 15466 unsigned long 15467 after, 15468 length; 15469 15470 /* 15471 Display image named by the Drag-and-Drop selection. 15472 */ 15473 if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128)) 15474 break; 15475 selection=XInternAtom(display,"DndSelection",MagickFalse); 15476 status=XGetWindowProperty(display,root_window,selection,0L,(long) 15477 MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format, 15478 &length,&after,&data); 15479 if ((status != Success) || (length == 0)) 15480 break; 15481 if (*event.xclient.data.l == 2) 15482 { 15483 /* 15484 Offix DND. 15485 */ 15486 (void) CopyMagickString(resource_info->image_info->filename, 15487 (char *) data,MaxTextExtent); 15488 } 15489 else 15490 { 15491 /* 15492 XDND. 15493 */ 15494 if (strncmp((char *) data, "file:", 5) != 0) 15495 { 15496 (void) XFree((void *) data); 15497 break; 15498 } 15499 (void) CopyMagickString(resource_info->image_info->filename, 15500 ((char *) data)+5,MaxTextExtent); 15501 } 15502 nexus=ReadImage(resource_info->image_info,exception); 15503 CatchException(exception); 15504 if (nexus != (Image *) NULL) 15505 *state|=NextImageState | ExitState; 15506 (void) XFree((void *) data); 15507 break; 15508 } 15509 /* 15510 If client window delete message, exit. 15511 */ 15512 if (event.xclient.message_type != windows->wm_protocols) 15513 break; 15514 if (*event.xclient.data.l != (long) windows->wm_delete_window) 15515 break; 15516 (void) XWithdrawWindow(display,event.xclient.window, 15517 visual_info->screen); 15518 if (event.xclient.window == windows->image.id) 15519 { 15520 *state|=ExitState; 15521 break; 15522 } 15523 if (event.xclient.window == windows->pan.id) 15524 { 15525 /* 15526 Restore original image size when pan window is deleted. 15527 */ 15528 windows->image.window_changes.width=windows->image.ximage->width; 15529 windows->image.window_changes.height=windows->image.ximage->height; 15530 (void) XConfigureImage(display,resource_info,windows, 15531 display_image,exception); 15532 } 15533 break; 15534 } 15535 case ConfigureNotify: 15536 { 15537 if( IfMagickTrue(display_image->debug) ) 15538 (void) LogMagickEvent(X11Event,GetMagickModule(), 15539 "Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window, 15540 event.xconfigure.width,event.xconfigure.height,event.xconfigure.x, 15541 event.xconfigure.y,event.xconfigure.send_event); 15542 if (event.xconfigure.window == windows->image.id) 15543 { 15544 /* 15545 Image window has a new configuration. 15546 */ 15547 if (event.xconfigure.send_event != 0) 15548 { 15549 XWindowChanges 15550 window_changes; 15551 15552 /* 15553 Position the transient windows relative of the Image window. 15554 */ 15555 if (windows->command.geometry == (char *) NULL) 15556 if( IfMagickFalse(windows->command.mapped) ) 15557 { 15558 windows->command.x=event.xconfigure.x- 15559 windows->command.width-25; 15560 windows->command.y=event.xconfigure.y; 15561 XConstrainWindowPosition(display,&windows->command); 15562 window_changes.x=windows->command.x; 15563 window_changes.y=windows->command.y; 15564 (void) XReconfigureWMWindow(display,windows->command.id, 15565 windows->command.screen,(unsigned int) (CWX | CWY), 15566 &window_changes); 15567 } 15568 if (windows->widget.geometry == (char *) NULL) 15569 if( IfMagickFalse(windows->widget.mapped) ) 15570 { 15571 windows->widget.x=event.xconfigure.x+ 15572 event.xconfigure.width/10; 15573 windows->widget.y=event.xconfigure.y+ 15574 event.xconfigure.height/10; 15575 XConstrainWindowPosition(display,&windows->widget); 15576 window_changes.x=windows->widget.x; 15577 window_changes.y=windows->widget.y; 15578 (void) XReconfigureWMWindow(display,windows->widget.id, 15579 windows->widget.screen,(unsigned int) (CWX | CWY), 15580 &window_changes); 15581 } 15582 if (windows->magnify.geometry == (char *) NULL) 15583 if( IfMagickFalse(windows->magnify.mapped) ) 15584 { 15585 windows->magnify.x=event.xconfigure.x+ 15586 event.xconfigure.width+25; 15587 windows->magnify.y=event.xconfigure.y; 15588 XConstrainWindowPosition(display,&windows->magnify); 15589 window_changes.x=windows->magnify.x; 15590 window_changes.y=windows->magnify.y; 15591 (void) XReconfigureWMWindow(display,windows->magnify.id, 15592 windows->magnify.screen,(unsigned int) (CWX | CWY), 15593 &window_changes); 15594 } 15595 if (windows->pan.geometry == (char *) NULL) 15596 if( IfMagickFalse(windows->pan.mapped) ) 15597 { 15598 windows->pan.x=event.xconfigure.x+ 15599 event.xconfigure.width+25; 15600 windows->pan.y=event.xconfigure.y+ 15601 windows->magnify.height+50; 15602 XConstrainWindowPosition(display,&windows->pan); 15603 window_changes.x=windows->pan.x; 15604 window_changes.y=windows->pan.y; 15605 (void) XReconfigureWMWindow(display,windows->pan.id, 15606 windows->pan.screen,(unsigned int) (CWX | CWY), 15607 &window_changes); 15608 } 15609 } 15610 if ((event.xconfigure.width == (int) windows->image.width) && 15611 (event.xconfigure.height == (int) windows->image.height)) 15612 break; 15613 windows->image.width=(unsigned int) event.xconfigure.width; 15614 windows->image.height=(unsigned int) event.xconfigure.height; 15615 windows->image.x=0; 15616 windows->image.y=0; 15617 if (display_image->montage != (char *) NULL) 15618 { 15619 windows->image.x=vid_info.x; 15620 windows->image.y=vid_info.y; 15621 } 15622 if( IfMagickTrue(windows->image.mapped) && 15623 IfMagickTrue(windows->image.stasis) ) 15624 { 15625 /* 15626 Update image window configuration. 15627 */ 15628 windows->image.window_changes.width=event.xconfigure.width; 15629 windows->image.window_changes.height=event.xconfigure.height; 15630 (void) XConfigureImage(display,resource_info,windows, 15631 display_image,exception); 15632 } 15633 /* 15634 Update pan window configuration. 15635 */ 15636 if ((event.xconfigure.width < windows->image.ximage->width) || 15637 (event.xconfigure.height < windows->image.ximage->height)) 15638 { 15639 (void) XMapRaised(display,windows->pan.id); 15640 XDrawPanRectangle(display,windows); 15641 } 15642 else 15643 if( IfMagickTrue(windows->pan.mapped) ) 15644 (void) XWithdrawWindow(display,windows->pan.id, 15645 windows->pan.screen); 15646 break; 15647 } 15648 if (event.xconfigure.window == windows->magnify.id) 15649 { 15650 unsigned int 15651 magnify; 15652 15653 /* 15654 Magnify window has a new configuration. 15655 */ 15656 windows->magnify.width=(unsigned int) event.xconfigure.width; 15657 windows->magnify.height=(unsigned int) event.xconfigure.height; 15658 if( IfMagickFalse(windows->magnify.mapped) ) 15659 break; 15660 magnify=1; 15661 while ((int) magnify <= event.xconfigure.width) 15662 magnify<<=1; 15663 while ((int) magnify <= event.xconfigure.height) 15664 magnify<<=1; 15665 magnify>>=1; 15666 if (((int) magnify != event.xconfigure.width) || 15667 ((int) magnify != event.xconfigure.height)) 15668 { 15669 window_changes.width=(int) magnify; 15670 window_changes.height=(int) magnify; 15671 (void) XReconfigureWMWindow(display,windows->magnify.id, 15672 windows->magnify.screen,(unsigned int) (CWWidth | CWHeight), 15673 &window_changes); 15674 break; 15675 } 15676 if( IfMagickTrue(windows->magnify.mapped) && 15677 IfMagickTrue(windows->magnify.stasis) ) 15678 { 15679 status=XMakeImage(display,resource_info,&windows->magnify, 15680 display_image,windows->magnify.width,windows->magnify.height, 15681 exception); 15682 XMakeMagnifyImage(display,windows,exception); 15683 } 15684 break; 15685 } 15686 if( IfMagickTrue(windows->magnify.mapped) && 15687 (event.xconfigure.window == windows->pan.id)) 15688 { 15689 /* 15690 Pan icon window has a new configuration. 15691 */ 15692 if (event.xconfigure.send_event != 0) 15693 { 15694 windows->pan.x=event.xconfigure.x; 15695 windows->pan.y=event.xconfigure.y; 15696 } 15697 windows->pan.width=(unsigned int) event.xconfigure.width; 15698 windows->pan.height=(unsigned int) event.xconfigure.height; 15699 break; 15700 } 15701 if (event.xconfigure.window == windows->icon.id) 15702 { 15703 /* 15704 Icon window has a new configuration. 15705 */ 15706 windows->icon.width=(unsigned int) event.xconfigure.width; 15707 windows->icon.height=(unsigned int) event.xconfigure.height; 15708 break; 15709 } 15710 break; 15711 } 15712 case DestroyNotify: 15713 { 15714 /* 15715 Group leader has exited. 15716 */ 15717 if( IfMagickTrue(display_image->debug) ) 15718 (void) LogMagickEvent(X11Event,GetMagickModule(), 15719 "Destroy Notify: 0x%lx",event.xdestroywindow.window); 15720 if (event.xdestroywindow.window == windows->group_leader.id) 15721 { 15722 *state|=ExitState; 15723 break; 15724 } 15725 break; 15726 } 15727 case EnterNotify: 15728 { 15729 /* 15730 Selectively install colormap. 15731 */ 15732 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15733 if (event.xcrossing.mode != NotifyUngrab) 15734 XInstallColormap(display,map_info->colormap); 15735 break; 15736 } 15737 case Expose: 15738 { 15739 if( IfMagickTrue(display_image->debug) ) 15740 (void) LogMagickEvent(X11Event,GetMagickModule(), 15741 "Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window, 15742 event.xexpose.width,event.xexpose.height,event.xexpose.x, 15743 event.xexpose.y); 15744 /* 15745 Refresh windows that are now exposed. 15746 */ 15747 if ((event.xexpose.window == windows->image.id) && 15748 IfMagickTrue(windows->image.mapped) ) 15749 { 15750 XRefreshWindow(display,&windows->image,&event); 15751 delay=display_image->delay/MagickMax( 15752 display_image->ticks_per_second,1L); 15753 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15754 break; 15755 } 15756 if ((event.xexpose.window == windows->magnify.id) && 15757 IfMagickTrue(windows->magnify.mapped)) 15758 { 15759 XMakeMagnifyImage(display,windows,exception); 15760 break; 15761 } 15762 if (event.xexpose.window == windows->pan.id) 15763 { 15764 XDrawPanRectangle(display,windows); 15765 break; 15766 } 15767 if (event.xexpose.window == windows->icon.id) 15768 { 15769 XRefreshWindow(display,&windows->icon,&event); 15770 break; 15771 } 15772 break; 15773 } 15774 case KeyPress: 15775 { 15776 int 15777 length; 15778 15779 /* 15780 Respond to a user key press. 15781 */ 15782 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 15783 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15784 *(command+length)='\0'; 15785 if( IfMagickTrue(display_image->debug) ) 15786 (void) LogMagickEvent(X11Event,GetMagickModule(), 15787 "Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long) 15788 key_symbol,command); 15789 if (event.xkey.window == windows->image.id) 15790 { 15791 command_type=XImageWindowCommand(display,resource_info,windows, 15792 event.xkey.state,key_symbol,&display_image,exception); 15793 if (command_type != NullCommand) 15794 nexus=XMagickCommand(display,resource_info,windows,command_type, 15795 &display_image,exception); 15796 } 15797 if (event.xkey.window == windows->magnify.id) 15798 XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol, 15799 exception); 15800 if (event.xkey.window == windows->pan.id) 15801 { 15802 if ((key_symbol == XK_q) || (key_symbol == XK_Escape)) 15803 (void) XWithdrawWindow(display,windows->pan.id, 15804 windows->pan.screen); 15805 else 15806 if ((key_symbol == XK_F1) || (key_symbol == XK_Help)) 15807 XTextViewWidget(display,resource_info,windows,MagickFalse, 15808 "Help Viewer - Image Pan",ImagePanHelp); 15809 else 15810 XTranslateImage(display,windows,*image,key_symbol); 15811 } 15812 delay=display_image->delay/MagickMax( 15813 display_image->ticks_per_second,1L); 15814 timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1; 15815 break; 15816 } 15817 case KeyRelease: 15818 { 15819 /* 15820 Respond to a user key release. 15821 */ 15822 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 15823 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 15824 if( IfMagickTrue(display_image->debug) ) 15825 (void) LogMagickEvent(X11Event,GetMagickModule(), 15826 "Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command); 15827 break; 15828 } 15829 case LeaveNotify: 15830 { 15831 /* 15832 Selectively uninstall colormap. 15833 */ 15834 if (map_info->colormap != XDefaultColormap(display,visual_info->screen)) 15835 if (event.xcrossing.mode != NotifyUngrab) 15836 XUninstallColormap(display,map_info->colormap); 15837 break; 15838 } 15839 case MapNotify: 15840 { 15841 if( IfMagickTrue(display_image->debug) ) 15842 (void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx", 15843 event.xmap.window); 15844 if (event.xmap.window == windows->backdrop.id) 15845 { 15846 (void) XSetInputFocus(display,event.xmap.window,RevertToParent, 15847 CurrentTime); 15848 windows->backdrop.mapped=MagickTrue; 15849 break; 15850 } 15851 if (event.xmap.window == windows->image.id) 15852 { 15853 if (windows->backdrop.id != (Window) NULL) 15854 (void) XInstallColormap(display,map_info->colormap); 15855 if (LocaleCompare(display_image->magick,"LOGO") == 0) 15856 { 15857 if (LocaleCompare(display_image->filename,"LOGO") == 0) 15858 nexus=XOpenImage(display,resource_info,windows,MagickFalse); 15859 } 15860 if (((int) windows->image.width < windows->image.ximage->width) || 15861 ((int) windows->image.height < windows->image.ximage->height)) 15862 (void) XMapRaised(display,windows->pan.id); 15863 windows->image.mapped=MagickTrue; 15864 break; 15865 } 15866 if (event.xmap.window == windows->magnify.id) 15867 { 15868 XMakeMagnifyImage(display,windows,exception); 15869 windows->magnify.mapped=MagickTrue; 15870 (void) XWithdrawWindow(display,windows->info.id, 15871 windows->info.screen); 15872 break; 15873 } 15874 if (event.xmap.window == windows->pan.id) 15875 { 15876 XMakePanImage(display,resource_info,windows,display_image, 15877 exception); 15878 windows->pan.mapped=MagickTrue; 15879 break; 15880 } 15881 if (event.xmap.window == windows->info.id) 15882 { 15883 windows->info.mapped=MagickTrue; 15884 break; 15885 } 15886 if (event.xmap.window == windows->icon.id) 15887 { 15888 MagickBooleanType 15889 taint; 15890 15891 /* 15892 Create an icon image. 15893 */ 15894 taint=display_image->taint; 15895 XMakeStandardColormap(display,icon_visual,icon_resources, 15896 display_image,icon_map,icon_pixel,exception); 15897 (void) XMakeImage(display,icon_resources,&windows->icon, 15898 display_image,windows->icon.width,windows->icon.height, 15899 exception); 15900 display_image->taint=taint; 15901 (void) XSetWindowBackgroundPixmap(display,windows->icon.id, 15902 windows->icon.pixmap); 15903 (void) XClearWindow(display,windows->icon.id); 15904 (void) XWithdrawWindow(display,windows->info.id, 15905 windows->info.screen); 15906 windows->icon.mapped=MagickTrue; 15907 break; 15908 } 15909 if (event.xmap.window == windows->command.id) 15910 { 15911 windows->command.mapped=MagickTrue; 15912 break; 15913 } 15914 if (event.xmap.window == windows->popup.id) 15915 { 15916 windows->popup.mapped=MagickTrue; 15917 break; 15918 } 15919 if (event.xmap.window == windows->widget.id) 15920 { 15921 windows->widget.mapped=MagickTrue; 15922 break; 15923 } 15924 break; 15925 } 15926 case MappingNotify: 15927 { 15928 (void) XRefreshKeyboardMapping(&event.xmapping); 15929 break; 15930 } 15931 case NoExpose: 15932 break; 15933 case PropertyNotify: 15934 { 15935 Atom 15936 type; 15937 15938 int 15939 format, 15940 status; 15941 15942 unsigned char 15943 *data; 15944 15945 unsigned long 15946 after, 15947 length; 15948 15949 if( IfMagickTrue(display_image->debug) ) 15950 (void) LogMagickEvent(X11Event,GetMagickModule(), 15951 "Property Notify: 0x%lx 0x%lx %d",event.xproperty.window, 15952 event.xproperty.atom,event.xproperty.state); 15953 if (event.xproperty.atom != windows->im_remote_command) 15954 break; 15955 /* 15956 Display image named by the remote command protocol. 15957 */ 15958 status=XGetWindowProperty(display,event.xproperty.window, 15959 event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom) 15960 AnyPropertyType,&type,&format,&length,&after,&data); 15961 if ((status != Success) || (length == 0)) 15962 break; 15963 if (LocaleCompare((char *) data,"-quit") == 0) 15964 { 15965 XClientMessage(display,windows->image.id,windows->im_protocols, 15966 windows->im_exit,CurrentTime); 15967 (void) XFree((void *) data); 15968 break; 15969 } 15970 (void) CopyMagickString(resource_info->image_info->filename, 15971 (char *) data,MaxTextExtent); 15972 (void) XFree((void *) data); 15973 nexus=ReadImage(resource_info->image_info,exception); 15974 CatchException(exception); 15975 if (nexus != (Image *) NULL) 15976 *state|=NextImageState | ExitState; 15977 break; 15978 } 15979 case ReparentNotify: 15980 { 15981 if( IfMagickTrue(display_image->debug) ) 15982 (void) LogMagickEvent(X11Event,GetMagickModule(), 15983 "Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent, 15984 event.xreparent.window); 15985 break; 15986 } 15987 case UnmapNotify: 15988 { 15989 if( IfMagickTrue(display_image->debug) ) 15990 (void) LogMagickEvent(X11Event,GetMagickModule(), 15991 "Unmap Notify: 0x%lx",event.xunmap.window); 15992 if (event.xunmap.window == windows->backdrop.id) 15993 { 15994 windows->backdrop.mapped=MagickFalse; 15995 break; 15996 } 15997 if (event.xunmap.window == windows->image.id) 15998 { 15999 windows->image.mapped=MagickFalse; 16000 break; 16001 } 16002 if (event.xunmap.window == windows->magnify.id) 16003 { 16004 windows->magnify.mapped=MagickFalse; 16005 break; 16006 } 16007 if (event.xunmap.window == windows->pan.id) 16008 { 16009 windows->pan.mapped=MagickFalse; 16010 break; 16011 } 16012 if (event.xunmap.window == windows->info.id) 16013 { 16014 windows->info.mapped=MagickFalse; 16015 break; 16016 } 16017 if (event.xunmap.window == windows->icon.id) 16018 { 16019 if (map_info->colormap == icon_map->colormap) 16020 XConfigureImageColormap(display,resource_info,windows, 16021 display_image,exception); 16022 (void) XFreeStandardColormap(display,icon_visual,icon_map, 16023 icon_pixel); 16024 windows->icon.mapped=MagickFalse; 16025 break; 16026 } 16027 if (event.xunmap.window == windows->command.id) 16028 { 16029 windows->command.mapped=MagickFalse; 16030 break; 16031 } 16032 if (event.xunmap.window == windows->popup.id) 16033 { 16034 if (windows->backdrop.id != (Window) NULL) 16035 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16036 CurrentTime); 16037 windows->popup.mapped=MagickFalse; 16038 break; 16039 } 16040 if (event.xunmap.window == windows->widget.id) 16041 { 16042 if (windows->backdrop.id != (Window) NULL) 16043 (void) XSetInputFocus(display,windows->image.id,RevertToParent, 16044 CurrentTime); 16045 windows->widget.mapped=MagickFalse; 16046 break; 16047 } 16048 break; 16049 } 16050 default: 16051 { 16052 if( IfMagickTrue(display_image->debug) ) 16053 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 16054 event.type); 16055 break; 16056 } 16057 } 16058 } while (!(*state & ExitState)); 16059 if ((*state & ExitState) == 0) 16060 (void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand, 16061 &display_image,exception); 16062 else 16063 if( IfMagickTrue(resource_info->confirm_edit) ) 16064 { 16065 /* 16066 Query user if image has changed. 16067 */ 16068 if( IfMagickFalse(resource_info->immutable) && 16069 IfMagickTrue(display_image->taint)) 16070 { 16071 int 16072 status; 16073 16074 status=XConfirmWidget(display,windows,"Your image changed.", 16075 "Do you want to save it"); 16076 if (status == 0) 16077 *state&=(~ExitState); 16078 else 16079 if (status > 0) 16080 (void) XMagickCommand(display,resource_info,windows,SaveCommand, 16081 &display_image,exception); 16082 } 16083 } 16084 if ((windows->visual_info->klass == GrayScale) || 16085 (windows->visual_info->klass == PseudoColor) || 16086 (windows->visual_info->klass == DirectColor)) 16087 { 16088 /* 16089 Withdraw pan and Magnify window. 16090 */ 16091 if( IfMagickTrue(windows->info.mapped) ) 16092 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 16093 if( IfMagickTrue(windows->magnify.mapped) ) 16094 (void) XWithdrawWindow(display,windows->magnify.id, 16095 windows->magnify.screen); 16096 if( IfMagickTrue(windows->command.mapped) ) 16097 (void) XWithdrawWindow(display,windows->command.id, 16098 windows->command.screen); 16099 } 16100 if( IfMagickTrue(windows->pan.mapped) ) 16101 (void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen); 16102 if( IfMagickFalse(resource_info->backdrop) ) 16103 if (windows->backdrop.mapped) 16104 { 16105 (void) XWithdrawWindow(display,windows->backdrop.id, 16106 windows->backdrop.screen); 16107 (void) XDestroyWindow(display,windows->backdrop.id); 16108 windows->backdrop.id=(Window) NULL; 16109 (void) XWithdrawWindow(display,windows->image.id, 16110 windows->image.screen); 16111 (void) XDestroyWindow(display,windows->image.id); 16112 windows->image.id=(Window) NULL; 16113 } 16114 XSetCursorState(display,windows,MagickTrue); 16115 XCheckRefreshWindows(display,windows); 16116 if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0)) 16117 *state&=(~ExitState); 16118 if (*state & ExitState) 16119 { 16120 /* 16121 Free Standard Colormap. 16122 */ 16123 (void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel); 16124 if (resource_info->map_type == (char *) NULL) 16125 (void) XFreeStandardColormap(display,visual_info,map_info,pixel); 16126 /* 16127 Free X resources. 16128 */ 16129 if (resource_info->copy_image != (Image *) NULL) 16130 { 16131 resource_info->copy_image=DestroyImage(resource_info->copy_image); 16132 resource_info->copy_image=NewImageList(); 16133 } 16134 DestroyXResources(); 16135 } 16136 (void) XSync(display,MagickFalse); 16137 /* 16138 Restore our progress monitor and warning handlers. 16139 */ 16140 (void) SetErrorHandler(warning_handler); 16141 (void) SetWarningHandler(warning_handler); 16142 /* 16143 Change to home directory. 16144 */ 16145 directory=getcwd(working_directory,MaxTextExtent); 16146 (void) directory; 16147 { 16148 int 16149 status; 16150 16151 if (*resource_info->home_directory == '\0') 16152 (void) CopyMagickString(resource_info->home_directory,".",MaxTextExtent); 16153 status=chdir(resource_info->home_directory); 16154 if (status == -1) 16155 (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError, 16156 "UnableToOpenFile","%s",resource_info->home_directory); 16157 } 16158 *image=display_image; 16159 return(nexus); 16160} 16161#else 16162 16163/* 16164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16165% % 16166% % 16167% % 16168+ D i s p l a y I m a g e s % 16169% % 16170% % 16171% % 16172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16173% 16174% DisplayImages() displays an image sequence to any X window screen. It 16175% returns a value other than 0 if successful. Check the exception member 16176% of image to determine the reason for any failure. 16177% 16178% The format of the DisplayImages method is: 16179% 16180% MagickBooleanType DisplayImages(const ImageInfo *image_info, 16181% Image *images,ExceptionInfo *exception) 16182% 16183% A description of each parameter follows: 16184% 16185% o image_info: the image info. 16186% 16187% o image: the image. 16188% 16189% o exception: return any errors or warnings in this structure. 16190% 16191*/ 16192MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 16193 Image *image,ExceptionInfo *exception) 16194{ 16195 assert(image_info != (const ImageInfo *) NULL); 16196 assert(image_info->signature == MagickSignature); 16197 assert(image != (Image *) NULL); 16198 assert(image->signature == MagickSignature); 16199 if( IfMagickTrue(image->debug) ) 16200 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 16201 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16202 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image->filename); 16203 return(MagickFalse); 16204} 16205 16206/* 16207%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16208% % 16209% % 16210% % 16211+ R e m o t e D i s p l a y C o m m a n d % 16212% % 16213% % 16214% % 16215%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16216% 16217% RemoteDisplayCommand() encourages a remote display program to display the 16218% specified image filename. 16219% 16220% The format of the RemoteDisplayCommand method is: 16221% 16222% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image, 16223% const char *window,const char *filename,ExceptionInfo *exception) 16224% 16225% A description of each parameter follows: 16226% 16227% o image_info: the image info. 16228% 16229% o window: Specifies the name or id of an X window. 16230% 16231% o filename: the name of the image filename to display. 16232% 16233% o exception: return any errors or warnings in this structure. 16234% 16235*/ 16236MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 16237 const char *window,const char *filename,ExceptionInfo *exception) 16238{ 16239 assert(image_info != (const ImageInfo *) NULL); 16240 assert(image_info->signature == MagickSignature); 16241 assert(filename != (char *) NULL); 16242 (void) window; 16243 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 16244 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, 16245 "DelegateLibrarySupportNotBuiltIn","'%s' (X11)",image_info->filename); 16246 return(MagickFalse); 16247} 16248#endif 16249