|
MagickCore
6.7.5
|
00001 /* 00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00003 % % 00004 % % 00005 % % 00006 % DDDD IIIII SSSSS PPPP L AAA Y Y % 00007 % D D I SS P P L A A Y Y % 00008 % D D I SSS PPPP L AAAAA Y % 00009 % D D I SS P L A A Y % 00010 % DDDD IIIII SSSSS P LLLLL A A Y % 00011 % % 00012 % % 00013 % MagickCore Methods to Interactively Display and Edit an Image % 00014 % % 00015 % Software Design % 00016 % John Cristy % 00017 % July 1992 % 00018 % % 00019 % % 00020 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization % 00021 % dedicated to making software imaging solutions freely available. % 00022 % % 00023 % You may not use this file except in compliance with the License. You may % 00024 % obtain a copy of the License at % 00025 % % 00026 % http://www.imagemagick.org/script/license.php % 00027 % % 00028 % Unless required by applicable law or agreed to in writing, software % 00029 % distributed under the License is distributed on an "AS IS" BASIS, % 00030 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 00031 % See the License for the specific language governing permissions and % 00032 % limitations under the License. % 00033 % % 00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00035 % 00036 % 00037 */ 00038 00039 /* 00040 Include declarations. 00041 */ 00042 #include "MagickCore/studio.h" 00043 #include "MagickCore/artifact.h" 00044 #include "MagickCore/blob.h" 00045 #include "MagickCore/cache.h" 00046 #include "MagickCore/cache-private.h" 00047 #include "MagickCore/client.h" 00048 #include "MagickCore/color.h" 00049 #include "MagickCore/colorspace.h" 00050 #include "MagickCore/composite.h" 00051 #include "MagickCore/constitute.h" 00052 #include "MagickCore/decorate.h" 00053 #include "MagickCore/delegate.h" 00054 #include "MagickCore/display.h" 00055 #include "MagickCore/display-private.h" 00056 #include "MagickCore/distort.h" 00057 #include "MagickCore/draw.h" 00058 #include "MagickCore/effect.h" 00059 #include "MagickCore/enhance.h" 00060 #include "MagickCore/exception.h" 00061 #include "MagickCore/exception-private.h" 00062 #include "MagickCore/fx.h" 00063 #include "MagickCore/geometry.h" 00064 #include "MagickCore/image.h" 00065 #include "MagickCore/image-private.h" 00066 #include "MagickCore/list.h" 00067 #include "MagickCore/log.h" 00068 #include "MagickCore/magick.h" 00069 #include "MagickCore/memory_.h" 00070 #include "MagickCore/monitor.h" 00071 #include "MagickCore/monitor-private.h" 00072 #include "MagickCore/montage.h" 00073 #include "MagickCore/option.h" 00074 #include "MagickCore/paint.h" 00075 #include "MagickCore/pixel.h" 00076 #include "MagickCore/pixel-accessor.h" 00077 #include "MagickCore/PreRvIcccm.h" 00078 #include "MagickCore/property.h" 00079 #include "MagickCore/quantum.h" 00080 #include "MagickCore/quantum-private.h" 00081 #include "MagickCore/resize.h" 00082 #include "MagickCore/resource_.h" 00083 #include "MagickCore/shear.h" 00084 #include "MagickCore/segment.h" 00085 #include "MagickCore/statistic.h" 00086 #include "MagickCore/string_.h" 00087 #include "MagickCore/string-private.h" 00088 #include "MagickCore/transform.h" 00089 #include "MagickCore/threshold.h" 00090 #include "MagickCore/utility.h" 00091 #include "MagickCore/utility-private.h" 00092 #include "MagickCore/version.h" 00093 #include "MagickCore/widget.h" 00094 #include "MagickCore/widget-private.h" 00095 #include "MagickCore/xwindow.h" 00096 #include "MagickCore/xwindow-private.h" 00097 00098 #if defined(MAGICKCORE_X11_DELEGATE) 00099 /* 00100 Define declarations. 00101 */ 00102 #define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L) 00103 00104 /* 00105 Constant declarations. 00106 */ 00107 static const unsigned char 00108 HighlightBitmap[8] = 00109 { 00110 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 00111 }, 00112 OpaqueBitmap[8] = 00113 { 00114 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 00115 }, 00116 ShadowBitmap[8] = 00117 { 00118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 00119 }; 00120 00121 static const char 00122 *PageSizes[] = 00123 { 00124 "Letter", 00125 "Tabloid", 00126 "Ledger", 00127 "Legal", 00128 "Statement", 00129 "Executive", 00130 "A3", 00131 "A4", 00132 "A5", 00133 "B4", 00134 "B5", 00135 "Folio", 00136 "Quarto", 00137 "10x14", 00138 (char *) NULL 00139 }; 00140 00141 /* 00142 Help widget declarations. 00143 */ 00144 static const char 00145 *ImageAnnotateHelp[] = 00146 { 00147 "In annotate mode, the Command widget has these options:", 00148 "", 00149 " Font Name", 00150 " fixed", 00151 " variable", 00152 " 5x8", 00153 " 6x10", 00154 " 7x13bold", 00155 " 8x13bold", 00156 " 9x15bold", 00157 " 10x20", 00158 " 12x24", 00159 " Browser...", 00160 " Font Color", 00161 " black", 00162 " blue", 00163 " cyan", 00164 " green", 00165 " gray", 00166 " red", 00167 " magenta", 00168 " yellow", 00169 " white", 00170 " transparent", 00171 " Browser...", 00172 " Font Color", 00173 " black", 00174 " blue", 00175 " cyan", 00176 " green", 00177 " gray", 00178 " red", 00179 " magenta", 00180 " yellow", 00181 " white", 00182 " transparent", 00183 " Browser...", 00184 " Rotate Text", 00185 " -90", 00186 " -45", 00187 " -30", 00188 " 0", 00189 " 30", 00190 " 45", 00191 " 90", 00192 " 180", 00193 " Dialog...", 00194 " Help", 00195 " Dismiss", 00196 "", 00197 "Choose a font name from the Font Name sub-menu. Additional", 00198 "font names can be specified with the font browser. You can", 00199 "change the menu names by setting the X resources font1", 00200 "through font9.", 00201 "", 00202 "Choose a font color from the Font Color sub-menu.", 00203 "Additional font colors can be specified with the color", 00204 "browser. You can change the menu colors by setting the X", 00205 "resources pen1 through pen9.", 00206 "", 00207 "If you select the color browser and press Grab, you can", 00208 "choose the font color by moving the pointer to the desired", 00209 "color on the screen and press any button.", 00210 "", 00211 "If you choose to rotate the text, choose Rotate Text from the", 00212 "menu and select an angle. Typically you will only want to", 00213 "rotate one line of text at a time. Depending on the angle you", 00214 "choose, subsequent lines may end up overwriting each other.", 00215 "", 00216 "Choosing a font and its color is optional. The default font", 00217 "is fixed and the default color is black. However, you must", 00218 "choose a location to begin entering text and press button 1.", 00219 "An underscore character will appear at the location of the", 00220 "pointer. The cursor changes to a pencil to indicate you are", 00221 "in text mode. To exit immediately, press Dismiss.", 00222 "", 00223 "In text mode, any key presses will display the character at", 00224 "the location of the underscore and advance the underscore", 00225 "cursor. Enter your text and once completed press Apply to", 00226 "finish your image annotation. To correct errors press BACK", 00227 "SPACE. To delete an entire line of text, press DELETE. Any", 00228 "text that exceeds the boundaries of the image window is", 00229 "automagically continued onto the next line.", 00230 "", 00231 "The actual color you request for the font is saved in the", 00232 "image. However, the color that appears in your image window", 00233 "may be different. For example, on a monochrome screen the", 00234 "text will appear black or white even if you choose the color", 00235 "red as the font color. However, the image saved to a file", 00236 "with -write is written with red lettering. To assure the", 00237 "correct color text in the final image, any PseudoClass image", 00238 "is promoted to DirectClass (see miff(5)). To force a", 00239 "PseudoClass image to remain PseudoClass, use -colors.", 00240 (char *) NULL, 00241 }, 00242 *ImageChopHelp[] = 00243 { 00244 "In chop mode, the Command widget has these options:", 00245 "", 00246 " Direction", 00247 " horizontal", 00248 " vertical", 00249 " Help", 00250 " Dismiss", 00251 "", 00252 "If the you choose the horizontal direction (this the", 00253 "default), the area of the image between the two horizontal", 00254 "endpoints of the chop line is removed. Otherwise, the area", 00255 "of the image between the two vertical endpoints of the chop", 00256 "line is removed.", 00257 "", 00258 "Select a location within the image window to begin your chop,", 00259 "press and hold any button. Next, move the pointer to", 00260 "another location in the image. As you move a line will", 00261 "connect the initial location and the pointer. When you", 00262 "release the button, the area within the image to chop is", 00263 "determined by which direction you choose from the Command", 00264 "widget.", 00265 "", 00266 "To cancel the image chopping, move the pointer back to the", 00267 "starting point of the line and release the button.", 00268 (char *) NULL, 00269 }, 00270 *ImageColorEditHelp[] = 00271 { 00272 "In color edit mode, the Command widget has these options:", 00273 "", 00274 " Method", 00275 " point", 00276 " replace", 00277 " floodfill", 00278 " filltoborder", 00279 " reset", 00280 " Pixel Color", 00281 " black", 00282 " blue", 00283 " cyan", 00284 " green", 00285 " gray", 00286 " red", 00287 " magenta", 00288 " yellow", 00289 " white", 00290 " Browser...", 00291 " Border Color", 00292 " black", 00293 " blue", 00294 " cyan", 00295 " green", 00296 " gray", 00297 " red", 00298 " magenta", 00299 " yellow", 00300 " white", 00301 " Browser...", 00302 " Fuzz", 00303 " 0%", 00304 " 2%", 00305 " 5%", 00306 " 10%", 00307 " 15%", 00308 " Dialog...", 00309 " Undo", 00310 " Help", 00311 " Dismiss", 00312 "", 00313 "Choose a color editing method from the Method sub-menu", 00314 "of the Command widget. The point method recolors any pixel", 00315 "selected with the pointer until the button is released. The", 00316 "replace method recolors any pixel that matches the color of", 00317 "the pixel you select with a button press. Floodfill recolors", 00318 "any pixel that matches the color of the pixel you select with", 00319 "a button press and is a neighbor. Whereas filltoborder recolors", 00320 "any neighbor pixel that is not the border color. Finally reset", 00321 "changes the entire image to the designated color.", 00322 "", 00323 "Next, choose a pixel color from the Pixel Color sub-menu.", 00324 "Additional pixel colors can be specified with the color", 00325 "browser. You can change the menu colors by setting the X", 00326 "resources pen1 through pen9.", 00327 "", 00328 "Now press button 1 to select a pixel within the image window", 00329 "to change its color. Additional pixels may be recolored as", 00330 "prescribed by the method you choose.", 00331 "", 00332 "If the Magnify widget is mapped, it can be helpful in positioning", 00333 "your pointer within the image (refer to button 2).", 00334 "", 00335 "The actual color you request for the pixels is saved in the", 00336 "image. However, the color that appears in your image window", 00337 "may be different. For example, on a monochrome screen the", 00338 "pixel will appear black or white even if you choose the", 00339 "color red as the pixel color. However, the image saved to a", 00340 "file with -write is written with red pixels. To assure the", 00341 "correct color text in the final image, any PseudoClass image", 00342 "is promoted to DirectClass (see miff(5)). To force a", 00343 "PseudoClass image to remain PseudoClass, use -colors.", 00344 (char *) NULL, 00345 }, 00346 *ImageCompositeHelp[] = 00347 { 00348 "First a widget window is displayed requesting you to enter an", 00349 "image name. Press Composite, Grab or type a file name.", 00350 "Press Cancel if you choose not to create a composite image.", 00351 "When you choose Grab, move the pointer to the desired window", 00352 "and press any button.", 00353 "", 00354 "If the Composite image does not have any matte information,", 00355 "you are informed and the file browser is displayed again.", 00356 "Enter the name of a mask image. The image is typically", 00357 "grayscale and the same size as the composite image. If the", 00358 "image is not grayscale, it is converted to grayscale and the", 00359 "resulting intensities are used as matte information.", 00360 "", 00361 "A small window appears showing the location of the cursor in", 00362 "the image window. You are now in composite mode. To exit", 00363 "immediately, press Dismiss. In composite mode, the Command", 00364 "widget has these options:", 00365 "", 00366 " Operators", 00367 " Over", 00368 " In", 00369 " Out", 00370 " Atop", 00371 " Xor", 00372 " Plus", 00373 " Minus", 00374 " Add", 00375 " Subtract", 00376 " Difference", 00377 " Multiply", 00378 " Bumpmap", 00379 " Copy", 00380 " CopyRed", 00381 " CopyGreen", 00382 " CopyBlue", 00383 " CopyOpacity", 00384 " Clear", 00385 " Dissolve", 00386 " Displace", 00387 " Help", 00388 " Dismiss", 00389 "", 00390 "Choose a composite operation from the Operators sub-menu of", 00391 "the Command widget. How each operator behaves is described", 00392 "below. Image window is the image currently displayed on", 00393 "your X server and image is the image obtained with the File", 00394 "Browser widget.", 00395 "", 00396 "Over The result is the union of the two image shapes,", 00397 " with image obscuring image window in the region of", 00398 " overlap.", 00399 "", 00400 "In The result is simply image cut by the shape of", 00401 " image window. None of the image data of image", 00402 " window is in the result.", 00403 "", 00404 "Out The resulting image is image with the shape of", 00405 " image window cut out.", 00406 "", 00407 "Atop The result is the same shape as image image window,", 00408 " with image obscuring image window where the image", 00409 " shapes overlap. Note this differs from over", 00410 " because the portion of image outside image window's", 00411 " shape does not appear in the result.", 00412 "", 00413 "Xor The result is the image data from both image and", 00414 " image window that is outside the overlap region.", 00415 " The overlap region is blank.", 00416 "", 00417 "Plus The result is just the sum of the image data.", 00418 " Output values are cropped to QuantumRange (no overflow).", 00419 "", 00420 "Minus The result of image - image window, with underflow", 00421 " cropped to zero.", 00422 "", 00423 "Add The result of image + image window, with overflow", 00424 " wrapping around (mod 256).", 00425 "", 00426 "Subtract The result of image - image window, with underflow", 00427 " wrapping around (mod 256). The add and subtract", 00428 " operators can be used to perform reversible", 00429 " transformations.", 00430 "", 00431 "Difference", 00432 " The result of abs(image - image window). This", 00433 " useful for comparing two very similar images.", 00434 "", 00435 "Multiply", 00436 " The result of image * image window. This", 00437 " useful for the creation of drop-shadows.", 00438 "", 00439 "Bumpmap The result of surface normals from image * image", 00440 " window.", 00441 "", 00442 "Copy The resulting image is image window replaced with", 00443 " image. Here the matte information is ignored.", 00444 "", 00445 "CopyRed The red layer of the image window is replace with", 00446 " the red layer of the image. The other layers are", 00447 " untouched.", 00448 "", 00449 "CopyGreen", 00450 " The green layer of the image window is replace with", 00451 " the green layer of the image. The other layers are", 00452 " untouched.", 00453 "", 00454 "CopyBlue The blue layer of the image window is replace with", 00455 " the blue layer of the image. The other layers are", 00456 " untouched.", 00457 "", 00458 "CopyOpacity", 00459 " The matte layer of the image window is replace with", 00460 " the matte layer of the image. The other layers are", 00461 " untouched.", 00462 "", 00463 "The image compositor requires a matte, or alpha channel in", 00464 "the image for some operations. This extra channel usually", 00465 "defines a mask which represents a sort of a cookie-cutter", 00466 "for the image. This the case when matte is opaque (full", 00467 "coverage) for pixels inside the shape, zero outside, and", 00468 "between 0 and QuantumRange on the boundary. If image does not", 00469 "have a matte channel, it is initialized with 0 for any pixel", 00470 "matching in color to pixel location (0,0), otherwise QuantumRange.", 00471 "", 00472 "If you choose Dissolve, the composite operator becomes Over. The", 00473 "image matte channel percent transparency is initialized to factor.", 00474 "The image window is initialized to (100-factor). Where factor is the", 00475 "value you specify in the Dialog widget.", 00476 "", 00477 "Displace shifts the image pixels as defined by a displacement", 00478 "map. With this option, image is used as a displacement map.", 00479 "Black, within the displacement map, is a maximum positive", 00480 "displacement. White is a maximum negative displacement and", 00481 "middle gray is neutral. The displacement is scaled to determine", 00482 "the pixel shift. By default, the displacement applies in both the", 00483 "horizontal and vertical directions. However, if you specify a mask,", 00484 "image is the horizontal X displacement and mask the vertical Y", 00485 "displacement.", 00486 "", 00487 "Note that matte information for image window is not retained", 00488 "for colormapped X server visuals (e.g. StaticColor,", 00489 "StaticColor, GrayScale, PseudoColor). Correct compositing", 00490 "behavior may require a TrueColor or DirectColor visual or a", 00491 "Standard Colormap.", 00492 "", 00493 "Choosing a composite operator is optional. The default", 00494 "operator is replace. However, you must choose a location to", 00495 "composite your image and press button 1. Press and hold the", 00496 "button before releasing and an outline of the image will", 00497 "appear to help you identify your location.", 00498 "", 00499 "The actual colors of the composite image is saved. However,", 00500 "the color that appears in image window may be different.", 00501 "For example, on a monochrome screen image window will appear", 00502 "black or white even though your composited image may have", 00503 "many colors. If the image is saved to a file it is written", 00504 "with the correct colors. To assure the correct colors are", 00505 "saved in the final image, any PseudoClass image is promoted", 00506 "to DirectClass (see miff(5)). To force a PseudoClass image", 00507 "to remain PseudoClass, use -colors.", 00508 (char *) NULL, 00509 }, 00510 *ImageCutHelp[] = 00511 { 00512 "In cut mode, the Command widget has these options:", 00513 "", 00514 " Help", 00515 " Dismiss", 00516 "", 00517 "To define a cut region, press button 1 and drag. The", 00518 "cut region is defined by a highlighted rectangle that", 00519 "expands or contracts as it follows the pointer. Once you", 00520 "are satisfied with the cut region, release the button.", 00521 "You are now in rectify mode. In rectify mode, the Command", 00522 "widget has these options:", 00523 "", 00524 " Cut", 00525 " Help", 00526 " Dismiss", 00527 "", 00528 "You can make adjustments by moving the pointer to one of the", 00529 "cut rectangle corners, pressing a button, and dragging.", 00530 "Finally, press Cut to commit your copy region. To", 00531 "exit without cutting the image, press Dismiss.", 00532 (char *) NULL, 00533 }, 00534 *ImageCopyHelp[] = 00535 { 00536 "In copy mode, the Command widget has these options:", 00537 "", 00538 " Help", 00539 " Dismiss", 00540 "", 00541 "To define a copy region, press button 1 and drag. The", 00542 "copy region is defined by a highlighted rectangle that", 00543 "expands or contracts as it follows the pointer. Once you", 00544 "are satisfied with the copy region, release the button.", 00545 "You are now in rectify mode. In rectify mode, the Command", 00546 "widget has these options:", 00547 "", 00548 " Copy", 00549 " Help", 00550 " Dismiss", 00551 "", 00552 "You can make adjustments by moving the pointer to one of the", 00553 "copy rectangle corners, pressing a button, and dragging.", 00554 "Finally, press Copy to commit your copy region. To", 00555 "exit without copying the image, press Dismiss.", 00556 (char *) NULL, 00557 }, 00558 *ImageCropHelp[] = 00559 { 00560 "In crop mode, the Command widget has these options:", 00561 "", 00562 " Help", 00563 " Dismiss", 00564 "", 00565 "To define a cropping region, press button 1 and drag. The", 00566 "cropping region is defined by a highlighted rectangle that", 00567 "expands or contracts as it follows the pointer. Once you", 00568 "are satisfied with the cropping region, release the button.", 00569 "You are now in rectify mode. In rectify mode, the Command", 00570 "widget has these options:", 00571 "", 00572 " Crop", 00573 " Help", 00574 " Dismiss", 00575 "", 00576 "You can make adjustments by moving the pointer to one of the", 00577 "cropping rectangle corners, pressing a button, and dragging.", 00578 "Finally, press Crop to commit your cropping region. To", 00579 "exit without cropping the image, press Dismiss.", 00580 (char *) NULL, 00581 }, 00582 *ImageDrawHelp[] = 00583 { 00584 "The cursor changes to a crosshair to indicate you are in", 00585 "draw mode. To exit immediately, press Dismiss. In draw mode,", 00586 "the Command widget has these options:", 00587 "", 00588 " Element", 00589 " point", 00590 " line", 00591 " rectangle", 00592 " fill rectangle", 00593 " circle", 00594 " fill circle", 00595 " ellipse", 00596 " fill ellipse", 00597 " polygon", 00598 " fill polygon", 00599 " Color", 00600 " black", 00601 " blue", 00602 " cyan", 00603 " green", 00604 " gray", 00605 " red", 00606 " magenta", 00607 " yellow", 00608 " white", 00609 " transparent", 00610 " Browser...", 00611 " Stipple", 00612 " Brick", 00613 " Diagonal", 00614 " Scales", 00615 " Vertical", 00616 " Wavy", 00617 " Translucent", 00618 " Opaque", 00619 " Open...", 00620 " Width", 00621 " 1", 00622 " 2", 00623 " 4", 00624 " 8", 00625 " 16", 00626 " Dialog...", 00627 " Undo", 00628 " Help", 00629 " Dismiss", 00630 "", 00631 "Choose a drawing primitive from the Element sub-menu.", 00632 "", 00633 "Choose a color from the Color sub-menu. Additional", 00634 "colors can be specified with the color browser.", 00635 "", 00636 "If you choose the color browser and press Grab, you can", 00637 "select the color by moving the pointer to the desired", 00638 "color on the screen and press any button. The transparent", 00639 "color updates the image matte channel and is useful for", 00640 "image compositing.", 00641 "", 00642 "Choose a stipple, if appropriate, from the Stipple sub-menu.", 00643 "Additional stipples can be specified with the file browser.", 00644 "Stipples obtained from the file browser must be on disk in the", 00645 "X11 bitmap format.", 00646 "", 00647 "Choose a width, if appropriate, from the Width sub-menu. To", 00648 "choose a specific width select the Dialog widget.", 00649 "", 00650 "Choose a point in the Image window and press button 1 and", 00651 "hold. Next, move the pointer to another location in the", 00652 "image. As you move, a line connects the initial location and", 00653 "the pointer. When you release the button, the image is", 00654 "updated with the primitive you just drew. For polygons, the", 00655 "image is updated when you press and release the button without", 00656 "moving the pointer.", 00657 "", 00658 "To cancel image drawing, move the pointer back to the", 00659 "starting point of the line and release the button.", 00660 (char *) NULL, 00661 }, 00662 *DisplayHelp[] = 00663 { 00664 "BUTTONS", 00665 " The effects of each button press is described below. Three", 00666 " buttons are required. If you have a two button mouse,", 00667 " button 1 and 3 are returned. Press ALT and button 3 to", 00668 " simulate button 2.", 00669 "", 00670 " 1 Press this button to map or unmap the Command widget.", 00671 "", 00672 " 2 Press and drag to define a region of the image to", 00673 " magnify.", 00674 "", 00675 " 3 Press and drag to choose from a select set of commands.", 00676 " This button behaves differently if the image being", 00677 " displayed is a visual image directory. Here, choose a", 00678 " particular tile of the directory and press this button and", 00679 " drag to select a command from a pop-up menu. Choose from", 00680 " these menu items:", 00681 "", 00682 " Open", 00683 " Next", 00684 " Former", 00685 " Delete", 00686 " Update", 00687 "", 00688 " If you choose Open, the image represented by the tile is", 00689 " displayed. To return to the visual image directory, choose", 00690 " Next from the Command widget. Next and Former moves to the", 00691 " next or former image respectively. Choose Delete to delete", 00692 " a particular image tile. Finally, choose Update to", 00693 " synchronize all the image tiles with their respective", 00694 " images.", 00695 "", 00696 "COMMAND WIDGET", 00697 " The Command widget lists a number of sub-menus and commands.", 00698 " They are", 00699 "", 00700 " File", 00701 " Open...", 00702 " Next", 00703 " Former", 00704 " Select...", 00705 " Save...", 00706 " Print...", 00707 " Delete...", 00708 " New...", 00709 " Visual Directory...", 00710 " Quit", 00711 " Edit", 00712 " Undo", 00713 " Redo", 00714 " Cut", 00715 " Copy", 00716 " Paste", 00717 " View", 00718 " Half Size", 00719 " Original Size", 00720 " Double Size", 00721 " Resize...", 00722 " Apply", 00723 " Refresh", 00724 " Restore", 00725 " Transform", 00726 " Crop", 00727 " Chop", 00728 " Flop", 00729 " Flip", 00730 " Rotate Right", 00731 " Rotate Left", 00732 " Rotate...", 00733 " Shear...", 00734 " Roll...", 00735 " Trim Edges", 00736 " Enhance", 00737 " Brightness...", 00738 " Saturation...", 00739 " Hue...", 00740 " Gamma...", 00741 " Sharpen...", 00742 " Dull", 00743 " Contrast Stretch...", 00744 " Sigmoidal Contrast...", 00745 " Normalize", 00746 " Equalize", 00747 " Negate", 00748 " Grayscale", 00749 " Map...", 00750 " Quantize...", 00751 " Effects", 00752 " Despeckle", 00753 " Emboss", 00754 " Reduce Noise", 00755 " Add Noise", 00756 " Sharpen...", 00757 " Blur...", 00758 " Threshold...", 00759 " Edge Detect...", 00760 " Spread...", 00761 " Shade...", 00762 " Painting...", 00763 " Segment...", 00764 " F/X", 00765 " Solarize...", 00766 " Sepia Tone...", 00767 " Swirl...", 00768 " Implode...", 00769 " Vignette...", 00770 " Wave...", 00771 " Oil Painting...", 00772 " Charcoal Drawing...", 00773 " Image Edit", 00774 " Annotate...", 00775 " Draw...", 00776 " Color...", 00777 " Matte...", 00778 " Composite...", 00779 " Add Border...", 00780 " Add Frame...", 00781 " Comment...", 00782 " Launch...", 00783 " Region of Interest...", 00784 " Miscellany", 00785 " Image Info", 00786 " Zoom Image", 00787 " Show Preview...", 00788 " Show Histogram", 00789 " Show Matte", 00790 " Background...", 00791 " Slide Show", 00792 " Preferences...", 00793 " Help", 00794 " Overview", 00795 " Browse Documentation", 00796 " About Display", 00797 "", 00798 " Menu items with a indented triangle have a sub-menu. They", 00799 " are represented above as the indented items. To access a", 00800 " sub-menu item, move the pointer to the appropriate menu and", 00801 " press a button and drag. When you find the desired sub-menu", 00802 " item, release the button and the command is executed. Move", 00803 " the pointer away from the sub-menu if you decide not to", 00804 " execute a particular command.", 00805 "", 00806 "KEYBOARD ACCELERATORS", 00807 " Accelerators are one or two key presses that effect a", 00808 " particular command. The keyboard accelerators that", 00809 " display(1) understands is:", 00810 "", 00811 " Ctl+O Press to open an image from a file.", 00812 "", 00813 " space Press to display the next image.", 00814 "", 00815 " If the image is a multi-paged document such as a Postscript", 00816 " document, you can skip ahead several pages by preceding", 00817 " this command with a number. For example to display the", 00818 " third page beyond the current page, press 3<space>.", 00819 "", 00820 " backspace Press to display the former image.", 00821 "", 00822 " If the image is a multi-paged document such as a Postscript", 00823 " document, you can skip behind several pages by preceding", 00824 " this command with a number. For example to display the", 00825 " third page preceding the current page, press 3<backspace>.", 00826 "", 00827 " Ctl+S Press to write the image to a file.", 00828 "", 00829 " Ctl+P Press to print the image to a Postscript printer.", 00830 "", 00831 " Ctl+D Press to delete an image file.", 00832 "", 00833 " Ctl+N Press to create a blank canvas.", 00834 "", 00835 " Ctl+Q Press to discard all images and exit program.", 00836 "", 00837 " Ctl+Z Press to undo last image transformation.", 00838 "", 00839 " Ctl+R Press to redo last image transformation.", 00840 "", 00841 " Ctl+X Press to cut a region of the image.", 00842 "", 00843 " Ctl+C Press to copy a region of the image.", 00844 "", 00845 " Ctl+V Press to paste a region to the image.", 00846 "", 00847 " < Press to half the image size.", 00848 "", 00849 " - Press to return to the original image size.", 00850 "", 00851 " > Press to double the image size.", 00852 "", 00853 " % Press to resize the image to a width and height you", 00854 " specify.", 00855 "", 00856 "Cmd-A Press to make any image transformations permanent." 00857 "", 00858 " By default, any image size transformations are applied", 00859 " to the original image to create the image displayed on", 00860 " the X server. However, the transformations are not", 00861 " permanent (i.e. the original image does not change", 00862 " size only the X image does). For example, if you", 00863 " press > the X image will appear to double in size,", 00864 " but the original image will in fact remain the same size.", 00865 " To force the original image to double in size, press >", 00866 " followed by Cmd-A.", 00867 "", 00868 " @ Press to refresh the image window.", 00869 "", 00870 " C Press to cut out a rectangular region of the image.", 00871 "", 00872 " [ Press to chop the image.", 00873 "", 00874 " H Press to flop image in the horizontal direction.", 00875 "", 00876 " V Press to flip image in the vertical direction.", 00877 "", 00878 " / Press to rotate the image 90 degrees clockwise.", 00879 "", 00880 " \\ Press to rotate the image 90 degrees counter-clockwise.", 00881 "", 00882 " * Press to rotate the image the number of degrees you", 00883 " specify.", 00884 "", 00885 " S Press to shear the image the number of degrees you", 00886 " specify.", 00887 "", 00888 " R Press to roll the image.", 00889 "", 00890 " T Press to trim the image edges.", 00891 "", 00892 " Shft-H Press to vary the image hue.", 00893 "", 00894 " Shft-S Press to vary the color saturation.", 00895 "", 00896 " Shft-L Press to vary the color brightness.", 00897 "", 00898 " Shft-G Press to gamma correct the image.", 00899 "", 00900 " Shft-C Press to sharpen the image contrast.", 00901 "", 00902 " Shft-Z Press to dull the image contrast.", 00903 "", 00904 " = Press to perform histogram equalization on the image.", 00905 "", 00906 " Shft-N Press to perform histogram normalization on the image.", 00907 "", 00908 " Shft-~ Press to negate the colors of the image.", 00909 "", 00910 " . Press to convert the image colors to gray.", 00911 "", 00912 " Shft-# Press to set the maximum number of unique colors in the", 00913 " image.", 00914 "", 00915 " F2 Press to reduce the speckles in an image.", 00916 "", 00917 " F3 Press to eliminate peak noise from an image.", 00918 "", 00919 " F4 Press to add noise to an image.", 00920 "", 00921 " F5 Press to sharpen an image.", 00922 "", 00923 " F6 Press to delete an image file.", 00924 "", 00925 " F7 Press to threshold the image.", 00926 "", 00927 " F8 Press to detect edges within an image.", 00928 "", 00929 " F9 Press to emboss an image.", 00930 "", 00931 " F10 Press to displace pixels by a random amount.", 00932 "", 00933 " F11 Press to negate all pixels above the threshold level.", 00934 "", 00935 " F12 Press to shade the image using a distant light source.", 00936 "", 00937 " F13 Press to lighten or darken image edges to create a 3-D effect.", 00938 "", 00939 " F14 Press to segment the image by color.", 00940 "", 00941 " Meta-S Press to swirl image pixels about the center.", 00942 "", 00943 " Meta-I Press to implode image pixels about the center.", 00944 "", 00945 " Meta-W Press to alter an image along a sine wave.", 00946 "", 00947 " Meta-P Press to simulate an oil painting.", 00948 "", 00949 " Meta-C Press to simulate a charcoal drawing.", 00950 "", 00951 " Alt-A Press to annotate the image with text.", 00952 "", 00953 " Alt-D Press to draw on an image.", 00954 "", 00955 " Alt-P Press to edit an image pixel color.", 00956 "", 00957 " Alt-M Press to edit the image matte information.", 00958 "", 00959 " Alt-V Press to composite the image with another.", 00960 "", 00961 " Alt-B Press to add a border to the image.", 00962 "", 00963 " Alt-F Press to add an ornamental border to the image.", 00964 "", 00965 " Alt-Shft-!", 00966 " Press to add an image comment.", 00967 "", 00968 " Ctl-A Press to apply image processing techniques to a region", 00969 " of interest.", 00970 "", 00971 " Shft-? Press to display information about the image.", 00972 "", 00973 " Shft-+ Press to map the zoom image window.", 00974 "", 00975 " Shft-P Press to preview an image enhancement, effect, or f/x.", 00976 "", 00977 " F1 Press to display helpful information about display(1).", 00978 "", 00979 " Find Press to browse documentation about ImageMagick.", 00980 "", 00981 " 1-9 Press to change the level of magnification.", 00982 "", 00983 " Use the arrow keys to move the image one pixel up, down,", 00984 " left, or right within the magnify window. Be sure to first", 00985 " map the magnify window by pressing button 2.", 00986 "", 00987 " Press ALT and one of the arrow keys to trim off one pixel", 00988 " from any side of the image.", 00989 (char *) NULL, 00990 }, 00991 *ImageMatteEditHelp[] = 00992 { 00993 "Matte information within an image is useful for some", 00994 "operations such as image compositing (See IMAGE", 00995 "COMPOSITING). This extra channel usually defines a mask", 00996 "which represents a sort of a cookie-cutter for the image.", 00997 "This the case when matte is opaque (full coverage) for", 00998 "pixels inside the shape, zero outside, and between 0 and", 00999 "QuantumRange on the boundary.", 01000 "", 01001 "A small window appears showing the location of the cursor in", 01002 "the image window. You are now in matte edit mode. To exit", 01003 "immediately, press Dismiss. In matte edit mode, the Command", 01004 "widget has these options:", 01005 "", 01006 " Method", 01007 " point", 01008 " replace", 01009 " floodfill", 01010 " filltoborder", 01011 " reset", 01012 " Border Color", 01013 " black", 01014 " blue", 01015 " cyan", 01016 " green", 01017 " gray", 01018 " red", 01019 " magenta", 01020 " yellow", 01021 " white", 01022 " Browser...", 01023 " Fuzz", 01024 " 0%", 01025 " 2%", 01026 " 5%", 01027 " 10%", 01028 " 15%", 01029 " Dialog...", 01030 " Matte", 01031 " Opaque", 01032 " Transparent", 01033 " Dialog...", 01034 " Undo", 01035 " Help", 01036 " Dismiss", 01037 "", 01038 "Choose a matte editing method from the Method sub-menu of", 01039 "the Command widget. The point method changes the matte value", 01040 "of any pixel selected with the pointer until the button is", 01041 "is released. The replace method changes the matte value of", 01042 "any pixel that matches the color of the pixel you select with", 01043 "a button press. Floodfill changes the matte value of any pixel", 01044 "that matches the color of the pixel you select with a button", 01045 "press and is a neighbor. Whereas filltoborder changes the matte", 01046 "value any neighbor pixel that is not the border color. Finally", 01047 "reset changes the entire image to the designated matte value.", 01048 "", 01049 "Choose Matte Value and pick Opaque or Transarent. For other values", 01050 "select the Dialog entry. Here a dialog appears requesting a matte", 01051 "value. The value you select is assigned as the opacity value of the", 01052 "selected pixel or pixels.", 01053 "", 01054 "Now, press any button to select a pixel within the image", 01055 "window to change its matte value.", 01056 "", 01057 "If the Magnify widget is mapped, it can be helpful in positioning", 01058 "your pointer within the image (refer to button 2).", 01059 "", 01060 "Matte information is only valid in a DirectClass image.", 01061 "Therefore, any PseudoClass image is promoted to DirectClass", 01062 "(see miff(5)). Note that matte information for PseudoClass", 01063 "is not retained for colormapped X server visuals (e.g.", 01064 "StaticColor, StaticColor, GrayScale, PseudoColor) unless you", 01065 "immediately save your image to a file (refer to Write).", 01066 "Correct matte editing behavior may require a TrueColor or", 01067 "DirectColor visual or a Standard Colormap.", 01068 (char *) NULL, 01069 }, 01070 *ImagePanHelp[] = 01071 { 01072 "When an image exceeds the width or height of the X server", 01073 "screen, display maps a small panning icon. The rectangle", 01074 "within the panning icon shows the area that is currently", 01075 "displayed in the image window. To pan about the image,", 01076 "press any button and drag the pointer within the panning", 01077 "icon. The pan rectangle moves with the pointer and the", 01078 "image window is updated to reflect the location of the", 01079 "rectangle within the panning icon. When you have selected", 01080 "the area of the image you wish to view, release the button.", 01081 "", 01082 "Use the arrow keys to pan the image one pixel up, down,", 01083 "left, or right within the image window.", 01084 "", 01085 "The panning icon is withdrawn if the image becomes smaller", 01086 "than the dimensions of the X server screen.", 01087 (char *) NULL, 01088 }, 01089 *ImagePasteHelp[] = 01090 { 01091 "A small window appears showing the location of the cursor in", 01092 "the image window. You are now in paste mode. To exit", 01093 "immediately, press Dismiss. In paste mode, the Command", 01094 "widget has these options:", 01095 "", 01096 " Operators", 01097 " over", 01098 " in", 01099 " out", 01100 " atop", 01101 " xor", 01102 " plus", 01103 " minus", 01104 " add", 01105 " subtract", 01106 " difference", 01107 " replace", 01108 " Help", 01109 " Dismiss", 01110 "", 01111 "Choose a composite operation from the Operators sub-menu of", 01112 "the Command widget. How each operator behaves is described", 01113 "below. Image window is the image currently displayed on", 01114 "your X server and image is the image obtained with the File", 01115 "Browser widget.", 01116 "", 01117 "Over The result is the union of the two image shapes,", 01118 " with image obscuring image window in the region of", 01119 " overlap.", 01120 "", 01121 "In The result is simply image cut by the shape of", 01122 " image window. None of the image data of image", 01123 " window is in the result.", 01124 "", 01125 "Out The resulting image is image with the shape of", 01126 " image window cut out.", 01127 "", 01128 "Atop The result is the same shape as image image window,", 01129 " with image obscuring image window where the image", 01130 " shapes overlap. Note this differs from over", 01131 " because the portion of image outside image window's", 01132 " shape does not appear in the result.", 01133 "", 01134 "Xor The result is the image data from both image and", 01135 " image window that is outside the overlap region.", 01136 " The overlap region is blank.", 01137 "", 01138 "Plus The result is just the sum of the image data.", 01139 " Output values are cropped to QuantumRange (no overflow).", 01140 " This operation is independent of the matte", 01141 " channels.", 01142 "", 01143 "Minus The result of image - image window, with underflow", 01144 " cropped to zero.", 01145 "", 01146 "Add The result of image + image window, with overflow", 01147 " wrapping around (mod 256).", 01148 "", 01149 "Subtract The result of image - image window, with underflow", 01150 " wrapping around (mod 256). The add and subtract", 01151 " operators can be used to perform reversible", 01152 " transformations.", 01153 "", 01154 "Difference", 01155 " The result of abs(image - image window). This", 01156 " useful for comparing two very similar images.", 01157 "", 01158 "Copy The resulting image is image window replaced with", 01159 " image. Here the matte information is ignored.", 01160 "", 01161 "CopyRed The red layer of the image window is replace with", 01162 " the red layer of the image. The other layers are", 01163 " untouched.", 01164 "", 01165 "CopyGreen", 01166 " The green layer of the image window is replace with", 01167 " the green layer of the image. The other layers are", 01168 " untouched.", 01169 "", 01170 "CopyBlue The blue layer of the image window is replace with", 01171 " the blue layer of the image. The other layers are", 01172 " untouched.", 01173 "", 01174 "CopyOpacity", 01175 " The matte layer of the image window is replace with", 01176 " the matte layer of the image. The other layers are", 01177 " untouched.", 01178 "", 01179 "The image compositor requires a matte, or alpha channel in", 01180 "the image for some operations. This extra channel usually", 01181 "defines a mask which represents a sort of a cookie-cutter", 01182 "for the image. This the case when matte is opaque (full", 01183 "coverage) for pixels inside the shape, zero outside, and", 01184 "between 0 and QuantumRange on the boundary. If image does not", 01185 "have a matte channel, it is initialized with 0 for any pixel", 01186 "matching in color to pixel location (0,0), otherwise QuantumRange.", 01187 "", 01188 "Note that matte information for image window is not retained", 01189 "for colormapped X server visuals (e.g. StaticColor,", 01190 "StaticColor, GrayScale, PseudoColor). Correct compositing", 01191 "behavior may require a TrueColor or DirectColor visual or a", 01192 "Standard Colormap.", 01193 "", 01194 "Choosing a composite operator is optional. The default", 01195 "operator is replace. However, you must choose a location to", 01196 "paste your image and press button 1. Press and hold the", 01197 "button before releasing and an outline of the image will", 01198 "appear to help you identify your location.", 01199 "", 01200 "The actual colors of the pasted image is saved. However,", 01201 "the color that appears in image window may be different.", 01202 "For example, on a monochrome screen image window will appear", 01203 "black or white even though your pasted image may have", 01204 "many colors. If the image is saved to a file it is written", 01205 "with the correct colors. To assure the correct colors are", 01206 "saved in the final image, any PseudoClass image is promoted", 01207 "to DirectClass (see miff(5)). To force a PseudoClass image", 01208 "to remain PseudoClass, use -colors.", 01209 (char *) NULL, 01210 }, 01211 *ImageROIHelp[] = 01212 { 01213 "In region of interest mode, the Command widget has these", 01214 "options:", 01215 "", 01216 " Help", 01217 " Dismiss", 01218 "", 01219 "To define a region of interest, press button 1 and drag.", 01220 "The region of interest is defined by a highlighted rectangle", 01221 "that expands or contracts as it follows the pointer. Once", 01222 "you are satisfied with the region of interest, release the", 01223 "button. You are now in apply mode. In apply mode the", 01224 "Command widget has these options:", 01225 "", 01226 " File", 01227 " Save...", 01228 " Print...", 01229 " Edit", 01230 " Undo", 01231 " Redo", 01232 " Transform", 01233 " Flop", 01234 " Flip", 01235 " Rotate Right", 01236 " Rotate Left", 01237 " Enhance", 01238 " Hue...", 01239 " Saturation...", 01240 " Brightness...", 01241 " Gamma...", 01242 " Spiff", 01243 " Dull", 01244 " Contrast Stretch", 01245 " Sigmoidal Contrast...", 01246 " Normalize", 01247 " Equalize", 01248 " Negate", 01249 " Grayscale", 01250 " Map...", 01251 " Quantize...", 01252 " Effects", 01253 " Despeckle", 01254 " Emboss", 01255 " Reduce Noise", 01256 " Sharpen...", 01257 " Blur...", 01258 " Threshold...", 01259 " Edge Detect...", 01260 " Spread...", 01261 " Shade...", 01262 " Raise...", 01263 " Segment...", 01264 " F/X", 01265 " Solarize...", 01266 " Sepia Tone...", 01267 " Swirl...", 01268 " Implode...", 01269 " Vignette...", 01270 " Wave...", 01271 " Oil Painting...", 01272 " Charcoal Drawing...", 01273 " Miscellany", 01274 " Image Info", 01275 " Zoom Image", 01276 " Show Preview...", 01277 " Show Histogram", 01278 " Show Matte", 01279 " Help", 01280 " Dismiss", 01281 "", 01282 "You can make adjustments to the region of interest by moving", 01283 "the pointer to one of the rectangle corners, pressing a", 01284 "button, and dragging. Finally, choose an image processing", 01285 "technique from the Command widget. You can choose more than", 01286 "one image processing technique to apply to an area.", 01287 "Alternatively, you can move the region of interest before", 01288 "applying another image processing technique. To exit, press", 01289 "Dismiss.", 01290 (char *) NULL, 01291 }, 01292 *ImageRotateHelp[] = 01293 { 01294 "In rotate mode, the Command widget has these options:", 01295 "", 01296 " Pixel Color", 01297 " black", 01298 " blue", 01299 " cyan", 01300 " green", 01301 " gray", 01302 " red", 01303 " magenta", 01304 " yellow", 01305 " white", 01306 " Browser...", 01307 " Direction", 01308 " horizontal", 01309 " vertical", 01310 " Help", 01311 " Dismiss", 01312 "", 01313 "Choose a background color from the Pixel Color sub-menu.", 01314 "Additional background colors can be specified with the color", 01315 "browser. You can change the menu colors by setting the X", 01316 "resources pen1 through pen9.", 01317 "", 01318 "If you choose the color browser and press Grab, you can", 01319 "select the background color by moving the pointer to the", 01320 "desired color on the screen and press any button.", 01321 "", 01322 "Choose a point in the image window and press this button and", 01323 "hold. Next, move the pointer to another location in the", 01324 "image. As you move a line connects the initial location and", 01325 "the pointer. When you release the button, the degree of", 01326 "image rotation is determined by the slope of the line you", 01327 "just drew. The slope is relative to the direction you", 01328 "choose from the Direction sub-menu of the Command widget.", 01329 "", 01330 "To cancel the image rotation, move the pointer back to the", 01331 "starting point of the line and release the button.", 01332 (char *) NULL, 01333 }; 01334 01335 /* 01336 Enumeration declarations. 01337 */ 01338 typedef enum 01339 { 01340 CopyMode, 01341 CropMode, 01342 CutMode 01343 } ClipboardMode; 01344 01345 typedef enum 01346 { 01347 OpenCommand, 01348 NextCommand, 01349 FormerCommand, 01350 SelectCommand, 01351 SaveCommand, 01352 PrintCommand, 01353 DeleteCommand, 01354 NewCommand, 01355 VisualDirectoryCommand, 01356 QuitCommand, 01357 UndoCommand, 01358 RedoCommand, 01359 CutCommand, 01360 CopyCommand, 01361 PasteCommand, 01362 HalfSizeCommand, 01363 OriginalSizeCommand, 01364 DoubleSizeCommand, 01365 ResizeCommand, 01366 ApplyCommand, 01367 RefreshCommand, 01368 RestoreCommand, 01369 CropCommand, 01370 ChopCommand, 01371 FlopCommand, 01372 FlipCommand, 01373 RotateRightCommand, 01374 RotateLeftCommand, 01375 RotateCommand, 01376 ShearCommand, 01377 RollCommand, 01378 TrimCommand, 01379 HueCommand, 01380 SaturationCommand, 01381 BrightnessCommand, 01382 GammaCommand, 01383 SpiffCommand, 01384 DullCommand, 01385 ContrastStretchCommand, 01386 SigmoidalContrastCommand, 01387 NormalizeCommand, 01388 EqualizeCommand, 01389 NegateCommand, 01390 GrayscaleCommand, 01391 MapCommand, 01392 QuantizeCommand, 01393 DespeckleCommand, 01394 EmbossCommand, 01395 ReduceNoiseCommand, 01396 AddNoiseCommand, 01397 SharpenCommand, 01398 BlurCommand, 01399 ThresholdCommand, 01400 EdgeDetectCommand, 01401 SpreadCommand, 01402 ShadeCommand, 01403 RaiseCommand, 01404 SegmentCommand, 01405 SolarizeCommand, 01406 SepiaToneCommand, 01407 SwirlCommand, 01408 ImplodeCommand, 01409 VignetteCommand, 01410 WaveCommand, 01411 OilPaintCommand, 01412 CharcoalDrawCommand, 01413 AnnotateCommand, 01414 DrawCommand, 01415 ColorCommand, 01416 MatteCommand, 01417 CompositeCommand, 01418 AddBorderCommand, 01419 AddFrameCommand, 01420 CommentCommand, 01421 LaunchCommand, 01422 RegionofInterestCommand, 01423 ROIHelpCommand, 01424 ROIDismissCommand, 01425 InfoCommand, 01426 ZoomCommand, 01427 ShowPreviewCommand, 01428 ShowHistogramCommand, 01429 ShowMatteCommand, 01430 BackgroundCommand, 01431 SlideShowCommand, 01432 PreferencesCommand, 01433 HelpCommand, 01434 BrowseDocumentationCommand, 01435 VersionCommand, 01436 SaveToUndoBufferCommand, 01437 FreeBuffersCommand, 01438 NullCommand 01439 } CommandType; 01440 01441 typedef enum 01442 { 01443 AnnotateNameCommand, 01444 AnnotateFontColorCommand, 01445 AnnotateBackgroundColorCommand, 01446 AnnotateRotateCommand, 01447 AnnotateHelpCommand, 01448 AnnotateDismissCommand, 01449 TextHelpCommand, 01450 TextApplyCommand, 01451 ChopDirectionCommand, 01452 ChopHelpCommand, 01453 ChopDismissCommand, 01454 HorizontalChopCommand, 01455 VerticalChopCommand, 01456 ColorEditMethodCommand, 01457 ColorEditColorCommand, 01458 ColorEditBorderCommand, 01459 ColorEditFuzzCommand, 01460 ColorEditUndoCommand, 01461 ColorEditHelpCommand, 01462 ColorEditDismissCommand, 01463 CompositeOperatorsCommand, 01464 CompositeDissolveCommand, 01465 CompositeDisplaceCommand, 01466 CompositeHelpCommand, 01467 CompositeDismissCommand, 01468 CropHelpCommand, 01469 CropDismissCommand, 01470 RectifyCopyCommand, 01471 RectifyHelpCommand, 01472 RectifyDismissCommand, 01473 DrawElementCommand, 01474 DrawColorCommand, 01475 DrawStippleCommand, 01476 DrawWidthCommand, 01477 DrawUndoCommand, 01478 DrawHelpCommand, 01479 DrawDismissCommand, 01480 MatteEditMethod, 01481 MatteEditBorderCommand, 01482 MatteEditFuzzCommand, 01483 MatteEditValueCommand, 01484 MatteEditUndoCommand, 01485 MatteEditHelpCommand, 01486 MatteEditDismissCommand, 01487 PasteOperatorsCommand, 01488 PasteHelpCommand, 01489 PasteDismissCommand, 01490 RotateColorCommand, 01491 RotateDirectionCommand, 01492 RotateCropCommand, 01493 RotateSharpenCommand, 01494 RotateHelpCommand, 01495 RotateDismissCommand, 01496 HorizontalRotateCommand, 01497 VerticalRotateCommand, 01498 TileLoadCommand, 01499 TileNextCommand, 01500 TileFormerCommand, 01501 TileDeleteCommand, 01502 TileUpdateCommand 01503 } ModeType; 01504 01505 /* 01506 Stipples. 01507 */ 01508 #define BricksWidth 20 01509 #define BricksHeight 20 01510 #define DiagonalWidth 16 01511 #define DiagonalHeight 16 01512 #define HighlightWidth 8 01513 #define HighlightHeight 8 01514 #define OpaqueWidth 8 01515 #define OpaqueHeight 8 01516 #define ScalesWidth 16 01517 #define ScalesHeight 16 01518 #define ShadowWidth 8 01519 #define ShadowHeight 8 01520 #define VerticalWidth 16 01521 #define VerticalHeight 16 01522 #define WavyWidth 16 01523 #define WavyHeight 16 01524 01525 /* 01526 Constant declaration. 01527 */ 01528 static const int 01529 RoiDelta = 8; 01530 01531 static const unsigned char 01532 BricksBitmap[] = 01533 { 01534 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 01535 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 01536 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 01537 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 01538 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01 01539 }, 01540 DiagonalBitmap[] = 01541 { 01542 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 01543 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 01544 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22 01545 }, 01546 ScalesBitmap[] = 01547 { 01548 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80, 01549 0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 01550 0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e 01551 }, 01552 VerticalBitmap[] = 01553 { 01554 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 01555 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 01556 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 01557 }, 01558 WavyBitmap[] = 01559 { 01560 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff, 01561 0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf, 01562 0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f 01563 }; 01564 01565 /* 01566 Function prototypes. 01567 */ 01568 static CommandType 01569 XImageWindowCommand(Display *,XResourceInfo *,XWindows *, 01570 const MagickStatusType,KeySym,Image **,ExceptionInfo *); 01571 01572 static Image 01573 *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType, 01574 Image **,ExceptionInfo *), 01575 *XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType), 01576 *XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *, 01577 ExceptionInfo *), 01578 *XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *, 01579 ExceptionInfo *); 01580 01581 static MagickBooleanType 01582 XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *, 01583 ExceptionInfo *), 01584 XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **, 01585 ExceptionInfo *), 01586 XChopImage(Display *,XResourceInfo *,XWindows *,Image **, 01587 ExceptionInfo *), 01588 XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode, 01589 ExceptionInfo *), 01590 XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **, 01591 ExceptionInfo *), 01592 XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *, 01593 ExceptionInfo *), 01594 XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 01595 XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **, 01596 ExceptionInfo *), 01597 XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **, 01598 ExceptionInfo *), 01599 XPasteImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 01600 XPrintImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 01601 XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **, 01602 ExceptionInfo *), 01603 XROIImage(Display *,XResourceInfo *,XWindows *,Image **,ExceptionInfo *), 01604 XSaveImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 01605 XTrimImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *); 01606 01607 static void 01608 XDrawPanRectangle(Display *,XWindows *), 01609 XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **, 01610 ExceptionInfo *), 01611 XMagnifyImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 01612 XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *,ExceptionInfo *), 01613 XPanImage(Display *,XWindows *,XEvent *,ExceptionInfo *), 01614 XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType, 01615 const KeySym,ExceptionInfo *), 01616 XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *), 01617 XScreenEvent(Display *,XWindows *,XEvent *,ExceptionInfo *), 01618 XTranslateImage(Display *,XWindows *,Image *,const KeySym); 01619 01620 /* 01621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01622 % % 01623 % % 01624 % % 01625 % D i s p l a y I m a g e s % 01626 % % 01627 % % 01628 % % 01629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01630 % 01631 % DisplayImages() displays an image sequence to any X window screen. It 01632 % returns a value other than 0 if successful. Check the exception member 01633 % of image to determine the reason for any failure. 01634 % 01635 % The format of the DisplayImages method is: 01636 % 01637 % MagickBooleanType DisplayImages(const ImageInfo *image_info, 01638 % Image *images,ExceptionInfo *exception) 01639 % 01640 % A description of each parameter follows: 01641 % 01642 % o image_info: the image info. 01643 % 01644 % o image: the image. 01645 % 01646 % o exception: return any errors or warnings in this structure. 01647 % 01648 */ 01649 MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info, 01650 Image *images,ExceptionInfo *exception) 01651 { 01652 char 01653 *argv[1]; 01654 01655 Display 01656 *display; 01657 01658 Image 01659 *image; 01660 01661 register ssize_t 01662 i; 01663 01664 size_t 01665 state; 01666 01667 XrmDatabase 01668 resource_database; 01669 01670 XResourceInfo 01671 resource_info; 01672 01673 assert(image_info != (const ImageInfo *) NULL); 01674 assert(image_info->signature == MagickSignature); 01675 assert(images != (Image *) NULL); 01676 assert(images->signature == MagickSignature); 01677 if (images->debug != MagickFalse) 01678 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename); 01679 display=XOpenDisplay(image_info->server_name); 01680 if (display == (Display *) NULL) 01681 { 01682 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 01683 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 01684 return(MagickFalse); 01685 } 01686 if (exception->severity != UndefinedException) 01687 CatchException(exception); 01688 (void) XSetErrorHandler(XError); 01689 resource_database=XGetResourceDatabase(display,GetClientName()); 01690 (void) ResetMagickMemory(&resource_info,0,sizeof(resource_info)); 01691 XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info); 01692 if (image_info->page != (char *) NULL) 01693 resource_info.image_geometry=AcquireString(image_info->page); 01694 resource_info.immutable=MagickTrue; 01695 argv[0]=AcquireString(GetClientName()); 01696 state=DefaultState; 01697 for (i=0; (state & ExitState) == 0; i++) 01698 { 01699 if ((images->iterations != 0) && (i >= (ssize_t) images->iterations)) 01700 break; 01701 image=GetImageFromList(images,i % GetImageListLength(images)); 01702 (void) XDisplayImage(display,&resource_info,argv,1,&image,&state,exception); 01703 } 01704 SetErrorHandler((ErrorHandler) NULL); 01705 SetWarningHandler((WarningHandler) NULL); 01706 argv[0]=DestroyString(argv[0]); 01707 (void) XCloseDisplay(display); 01708 XDestroyResourceInfo(&resource_info); 01709 if (exception->severity != UndefinedException) 01710 return(MagickFalse); 01711 return(MagickTrue); 01712 } 01713 01714 /* 01715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01716 % % 01717 % % 01718 % % 01719 % R e m o t e D i s p l a y C o m m a n d % 01720 % % 01721 % % 01722 % % 01723 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01724 % 01725 % RemoteDisplayCommand() encourages a remote display program to display the 01726 % specified image filename. 01727 % 01728 % The format of the RemoteDisplayCommand method is: 01729 % 01730 % MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 01731 % const char *window,const char *filename,ExceptionInfo *exception) 01732 % 01733 % A description of each parameter follows: 01734 % 01735 % o image_info: the image info. 01736 % 01737 % o window: Specifies the name or id of an X window. 01738 % 01739 % o filename: the name of the image filename to display. 01740 % 01741 % o exception: return any errors or warnings in this structure. 01742 % 01743 */ 01744 MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info, 01745 const char *window,const char *filename,ExceptionInfo *exception) 01746 { 01747 Display 01748 *display; 01749 01750 MagickStatusType 01751 status; 01752 01753 assert(image_info != (const ImageInfo *) NULL); 01754 assert(image_info->signature == MagickSignature); 01755 assert(filename != (char *) NULL); 01756 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename); 01757 display=XOpenDisplay(image_info->server_name); 01758 if (display == (Display *) NULL) 01759 { 01760 (void) ThrowMagickException(exception,GetMagickModule(),XServerError, 01761 "UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name)); 01762 return(MagickFalse); 01763 } 01764 (void) XSetErrorHandler(XError); 01765 status=XRemoteCommand(display,window,filename); 01766 (void) XCloseDisplay(display); 01767 return(status != 0 ? MagickTrue : MagickFalse); 01768 } 01769 01770 /* 01771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01772 % % 01773 % % 01774 % % 01775 + X A n n o t a t e E d i t I m a g e % 01776 % % 01777 % % 01778 % % 01779 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01780 % 01781 % XAnnotateEditImage() annotates the image with text. 01782 % 01783 % The format of the XAnnotateEditImage method is: 01784 % 01785 % MagickBooleanType XAnnotateEditImage(Display *display, 01786 % XResourceInfo *resource_info,XWindows *windows,Image *image, 01787 % ExceptionInfo *exception) 01788 % 01789 % A description of each parameter follows: 01790 % 01791 % o display: Specifies a connection to an X server; returned from 01792 % XOpenDisplay. 01793 % 01794 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 01795 % 01796 % o windows: Specifies a pointer to a XWindows structure. 01797 % 01798 % o image: the image; returned from ReadImage. 01799 % 01800 */ 01801 01802 static inline ssize_t MagickMax(const ssize_t x,const ssize_t y) 01803 { 01804 if (x > y) 01805 return(x); 01806 return(y); 01807 } 01808 01809 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y) 01810 { 01811 if (x < y) 01812 return(x); 01813 return(y); 01814 } 01815 01816 static MagickBooleanType XAnnotateEditImage(Display *display, 01817 XResourceInfo *resource_info,XWindows *windows,Image *image, 01818 ExceptionInfo *exception) 01819 { 01820 static const char 01821 *AnnotateMenu[] = 01822 { 01823 "Font Name", 01824 "Font Color", 01825 "Box Color", 01826 "Rotate Text", 01827 "Help", 01828 "Dismiss", 01829 (char *) NULL 01830 }, 01831 *TextMenu[] = 01832 { 01833 "Help", 01834 "Apply", 01835 (char *) NULL 01836 }; 01837 01838 static const ModeType 01839 AnnotateCommands[] = 01840 { 01841 AnnotateNameCommand, 01842 AnnotateFontColorCommand, 01843 AnnotateBackgroundColorCommand, 01844 AnnotateRotateCommand, 01845 AnnotateHelpCommand, 01846 AnnotateDismissCommand 01847 }, 01848 TextCommands[] = 01849 { 01850 TextHelpCommand, 01851 TextApplyCommand 01852 }; 01853 01854 static MagickBooleanType 01855 transparent_box = MagickTrue, 01856 transparent_pen = MagickFalse; 01857 01858 static MagickRealType 01859 degrees = 0.0; 01860 01861 static unsigned int 01862 box_id = MaxNumberPens-2, 01863 font_id = 0, 01864 pen_id = 0; 01865 01866 char 01867 command[MaxTextExtent], 01868 text[MaxTextExtent]; 01869 01870 const char 01871 *ColorMenu[MaxNumberPens+1]; 01872 01873 Cursor 01874 cursor; 01875 01876 GC 01877 annotate_context; 01878 01879 int 01880 id, 01881 pen_number, 01882 status, 01883 x, 01884 y; 01885 01886 KeySym 01887 key_symbol; 01888 01889 register char 01890 *p; 01891 01892 register ssize_t 01893 i; 01894 01895 unsigned int 01896 height, 01897 width; 01898 01899 size_t 01900 state; 01901 01902 XAnnotateInfo 01903 *annotate_info, 01904 *previous_info; 01905 01906 XColor 01907 color; 01908 01909 XFontStruct 01910 *font_info; 01911 01912 XEvent 01913 event, 01914 text_event; 01915 01916 /* 01917 Map Command widget. 01918 */ 01919 (void) CloneString(&windows->command.name,"Annotate"); 01920 windows->command.data=4; 01921 (void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL); 01922 (void) XMapRaised(display,windows->command.id); 01923 XClientMessage(display,windows->image.id,windows->im_protocols, 01924 windows->im_update_widget,CurrentTime); 01925 /* 01926 Track pointer until button 1 is pressed. 01927 */ 01928 XQueryPosition(display,windows->image.id,&x,&y); 01929 (void) XSelectInput(display,windows->image.id, 01930 windows->image.attributes.event_mask | PointerMotionMask); 01931 cursor=XCreateFontCursor(display,XC_left_side); 01932 (void) XCheckDefineCursor(display,windows->image.id,cursor); 01933 state=DefaultState; 01934 do 01935 { 01936 if (windows->info.mapped != MagickFalse) 01937 { 01938 /* 01939 Display pointer position. 01940 */ 01941 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 01942 x+windows->image.x,y+windows->image.y); 01943 XInfoWidget(display,windows,text); 01944 } 01945 /* 01946 Wait for next event. 01947 */ 01948 XScreenEvent(display,windows,&event,exception); 01949 if (event.xany.window == windows->command.id) 01950 { 01951 /* 01952 Select a command from the Command widget. 01953 */ 01954 id=XCommandWidget(display,windows,AnnotateMenu,&event); 01955 (void) XCheckDefineCursor(display,windows->image.id,cursor); 01956 if (id < 0) 01957 continue; 01958 switch (AnnotateCommands[id]) 01959 { 01960 case AnnotateNameCommand: 01961 { 01962 const char 01963 *FontMenu[MaxNumberFonts]; 01964 01965 int 01966 font_number; 01967 01968 /* 01969 Initialize menu selections. 01970 */ 01971 for (i=0; i < MaxNumberFonts; i++) 01972 FontMenu[i]=resource_info->font_name[i]; 01973 FontMenu[MaxNumberFonts-2]="Browser..."; 01974 FontMenu[MaxNumberFonts-1]=(const char *) NULL; 01975 /* 01976 Select a font name from the pop-up menu. 01977 */ 01978 font_number=XMenuWidget(display,windows,AnnotateMenu[id], 01979 (const char **) FontMenu,command); 01980 if (font_number < 0) 01981 break; 01982 if (font_number == (MaxNumberFonts-2)) 01983 { 01984 static char 01985 font_name[MaxTextExtent] = "fixed"; 01986 01987 /* 01988 Select a font name from a browser. 01989 */ 01990 resource_info->font_name[font_number]=font_name; 01991 XFontBrowserWidget(display,windows,"Select",font_name); 01992 if (*font_name == '\0') 01993 break; 01994 } 01995 /* 01996 Initialize font info. 01997 */ 01998 font_info=XLoadQueryFont(display,resource_info->font_name[ 01999 font_number]); 02000 if (font_info == (XFontStruct *) NULL) 02001 { 02002 XNoticeWidget(display,windows,"Unable to load font:", 02003 resource_info->font_name[font_number]); 02004 break; 02005 } 02006 font_id=(unsigned int) font_number; 02007 (void) XFreeFont(display,font_info); 02008 break; 02009 } 02010 case AnnotateFontColorCommand: 02011 { 02012 /* 02013 Initialize menu selections. 02014 */ 02015 for (i=0; i < (int) (MaxNumberPens-2); i++) 02016 ColorMenu[i]=resource_info->pen_colors[i]; 02017 ColorMenu[MaxNumberPens-2]="transparent"; 02018 ColorMenu[MaxNumberPens-1]="Browser..."; 02019 ColorMenu[MaxNumberPens]=(const char *) NULL; 02020 /* 02021 Select a pen color from the pop-up menu. 02022 */ 02023 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 02024 (const char **) ColorMenu,command); 02025 if (pen_number < 0) 02026 break; 02027 transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue : 02028 MagickFalse; 02029 if (transparent_pen != MagickFalse) 02030 break; 02031 if (pen_number == (MaxNumberPens-1)) 02032 { 02033 static char 02034 color_name[MaxTextExtent] = "gray"; 02035 02036 /* 02037 Select a pen color from a dialog. 02038 */ 02039 resource_info->pen_colors[pen_number]=color_name; 02040 XColorBrowserWidget(display,windows,"Select",color_name); 02041 if (*color_name == '\0') 02042 break; 02043 } 02044 /* 02045 Set pen color. 02046 */ 02047 (void) XParseColor(display,windows->map_info->colormap, 02048 resource_info->pen_colors[pen_number],&color); 02049 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 02050 (unsigned int) MaxColors,&color); 02051 windows->pixel_info->pen_colors[pen_number]=color; 02052 pen_id=(unsigned int) pen_number; 02053 break; 02054 } 02055 case AnnotateBackgroundColorCommand: 02056 { 02057 /* 02058 Initialize menu selections. 02059 */ 02060 for (i=0; i < (int) (MaxNumberPens-2); i++) 02061 ColorMenu[i]=resource_info->pen_colors[i]; 02062 ColorMenu[MaxNumberPens-2]="transparent"; 02063 ColorMenu[MaxNumberPens-1]="Browser..."; 02064 ColorMenu[MaxNumberPens]=(const char *) NULL; 02065 /* 02066 Select a pen color from the pop-up menu. 02067 */ 02068 pen_number=XMenuWidget(display,windows,AnnotateMenu[id], 02069 (const char **) ColorMenu,command); 02070 if (pen_number < 0) 02071 break; 02072 transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue : 02073 MagickFalse; 02074 if (transparent_box != MagickFalse) 02075 break; 02076 if (pen_number == (MaxNumberPens-1)) 02077 { 02078 static char 02079 color_name[MaxTextExtent] = "gray"; 02080 02081 /* 02082 Select a pen color from a dialog. 02083 */ 02084 resource_info->pen_colors[pen_number]=color_name; 02085 XColorBrowserWidget(display,windows,"Select",color_name); 02086 if (*color_name == '\0') 02087 break; 02088 } 02089 /* 02090 Set pen color. 02091 */ 02092 (void) XParseColor(display,windows->map_info->colormap, 02093 resource_info->pen_colors[pen_number],&color); 02094 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 02095 (unsigned int) MaxColors,&color); 02096 windows->pixel_info->pen_colors[pen_number]=color; 02097 box_id=(unsigned int) pen_number; 02098 break; 02099 } 02100 case AnnotateRotateCommand: 02101 { 02102 int 02103 entry; 02104 02105 static char 02106 angle[MaxTextExtent] = "30.0"; 02107 02108 static const char 02109 *RotateMenu[] = 02110 { 02111 "-90", 02112 "-45", 02113 "-30", 02114 "0", 02115 "30", 02116 "45", 02117 "90", 02118 "180", 02119 "Dialog...", 02120 (char *) NULL, 02121 }; 02122 02123 /* 02124 Select a command from the pop-up menu. 02125 */ 02126 entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu, 02127 command); 02128 if (entry < 0) 02129 break; 02130 if (entry != 8) 02131 { 02132 degrees=StringToDouble(RotateMenu[entry],(char **) NULL); 02133 break; 02134 } 02135 (void) XDialogWidget(display,windows,"OK","Enter rotation angle:", 02136 angle); 02137 if (*angle == '\0') 02138 break; 02139 degrees=StringToDouble(angle,(char **) NULL); 02140 break; 02141 } 02142 case AnnotateHelpCommand: 02143 { 02144 XTextViewWidget(display,resource_info,windows,MagickFalse, 02145 "Help Viewer - Image Annotation",ImageAnnotateHelp); 02146 break; 02147 } 02148 case AnnotateDismissCommand: 02149 { 02150 /* 02151 Prematurely exit. 02152 */ 02153 state|=EscapeState; 02154 state|=ExitState; 02155 break; 02156 } 02157 default: 02158 break; 02159 } 02160 continue; 02161 } 02162 switch (event.type) 02163 { 02164 case ButtonPress: 02165 { 02166 if (event.xbutton.button != Button1) 02167 break; 02168 if (event.xbutton.window != windows->image.id) 02169 break; 02170 /* 02171 Change to text entering mode. 02172 */ 02173 x=event.xbutton.x; 02174 y=event.xbutton.y; 02175 state|=ExitState; 02176 break; 02177 } 02178 case ButtonRelease: 02179 break; 02180 case Expose: 02181 break; 02182 case KeyPress: 02183 { 02184 if (event.xkey.window != windows->image.id) 02185 break; 02186 /* 02187 Respond to a user key press. 02188 */ 02189 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 02190 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 02191 switch ((int) key_symbol) 02192 { 02193 case XK_Escape: 02194 case XK_F20: 02195 { 02196 /* 02197 Prematurely exit. 02198 */ 02199 state|=EscapeState; 02200 state|=ExitState; 02201 break; 02202 } 02203 case XK_F1: 02204 case XK_Help: 02205 { 02206 XTextViewWidget(display,resource_info,windows,MagickFalse, 02207 "Help Viewer - Image Annotation",ImageAnnotateHelp); 02208 break; 02209 } 02210 default: 02211 { 02212 (void) XBell(display,0); 02213 break; 02214 } 02215 } 02216 break; 02217 } 02218 case MotionNotify: 02219 { 02220 /* 02221 Map and unmap Info widget as cursor crosses its boundaries. 02222 */ 02223 x=event.xmotion.x; 02224 y=event.xmotion.y; 02225 if (windows->info.mapped != MagickFalse) 02226 { 02227 if ((x < (int) (windows->info.x+windows->info.width)) && 02228 (y < (int) (windows->info.y+windows->info.height))) 02229 (void) XWithdrawWindow(display,windows->info.id, 02230 windows->info.screen); 02231 } 02232 else 02233 if ((x > (int) (windows->info.x+windows->info.width)) || 02234 (y > (int) (windows->info.y+windows->info.height))) 02235 (void) XMapWindow(display,windows->info.id); 02236 break; 02237 } 02238 default: 02239 break; 02240 } 02241 } while ((state & ExitState) == 0); 02242 (void) XSelectInput(display,windows->image.id, 02243 windows->image.attributes.event_mask); 02244 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 02245 if ((state & EscapeState) != 0) 02246 return(MagickTrue); 02247 /* 02248 Set font info and check boundary conditions. 02249 */ 02250 font_info=XLoadQueryFont(display,resource_info->font_name[font_id]); 02251 if (font_info == (XFontStruct *) NULL) 02252 { 02253 XNoticeWidget(display,windows,"Unable to load font:", 02254 resource_info->font_name[font_id]); 02255 font_info=windows->font_info; 02256 } 02257 if ((x+font_info->max_bounds.width) >= (int) windows->image.width) 02258 x=(int) windows->image.width-font_info->max_bounds.width; 02259 if (y < (int) (font_info->ascent+font_info->descent)) 02260 y=(int) font_info->ascent+font_info->descent; 02261 if (((int) font_info->max_bounds.width > (int) windows->image.width) || 02262 ((font_info->ascent+font_info->descent) >= (int) windows->image.height)) 02263 return(MagickFalse); 02264 /* 02265 Initialize annotate structure. 02266 */ 02267 annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info)); 02268 if (annotate_info == (XAnnotateInfo *) NULL) 02269 return(MagickFalse); 02270 XGetAnnotateInfo(annotate_info); 02271 annotate_info->x=x; 02272 annotate_info->y=y; 02273 if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse)) 02274 annotate_info->stencil=OpaqueStencil; 02275 else 02276 if (transparent_box == MagickFalse) 02277 annotate_info->stencil=BackgroundStencil; 02278 else 02279 annotate_info->stencil=ForegroundStencil; 02280 annotate_info->height=(unsigned int) font_info->ascent+font_info->descent; 02281 annotate_info->degrees=degrees; 02282 annotate_info->font_info=font_info; 02283 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 02284 windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL, 02285 sizeof(*annotate_info->text)); 02286 if (annotate_info->text == (char *) NULL) 02287 return(MagickFalse); 02288 /* 02289 Create cursor and set graphic context. 02290 */ 02291 cursor=XCreateFontCursor(display,XC_pencil); 02292 (void) XCheckDefineCursor(display,windows->image.id,cursor); 02293 annotate_context=windows->image.annotate_context; 02294 (void) XSetFont(display,annotate_context,font_info->fid); 02295 (void) XSetBackground(display,annotate_context, 02296 windows->pixel_info->pen_colors[box_id].pixel); 02297 (void) XSetForeground(display,annotate_context, 02298 windows->pixel_info->pen_colors[pen_id].pixel); 02299 /* 02300 Begin annotating the image with text. 02301 */ 02302 (void) CloneString(&windows->command.name,"Text"); 02303 windows->command.data=0; 02304 (void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL); 02305 state=DefaultState; 02306 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 02307 text_event.xexpose.width=(int) font_info->max_bounds.width; 02308 text_event.xexpose.height=font_info->max_bounds.ascent+ 02309 font_info->max_bounds.descent; 02310 p=annotate_info->text; 02311 do 02312 { 02313 /* 02314 Display text cursor. 02315 */ 02316 *p='\0'; 02317 (void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1); 02318 /* 02319 Wait for next event. 02320 */ 02321 XScreenEvent(display,windows,&event,exception); 02322 if (event.xany.window == windows->command.id) 02323 { 02324 /* 02325 Select a command from the Command widget. 02326 */ 02327 (void) XSetBackground(display,annotate_context, 02328 windows->pixel_info->background_color.pixel); 02329 (void) XSetForeground(display,annotate_context, 02330 windows->pixel_info->foreground_color.pixel); 02331 id=XCommandWidget(display,windows,AnnotateMenu,&event); 02332 (void) XSetBackground(display,annotate_context, 02333 windows->pixel_info->pen_colors[box_id].pixel); 02334 (void) XSetForeground(display,annotate_context, 02335 windows->pixel_info->pen_colors[pen_id].pixel); 02336 if (id < 0) 02337 continue; 02338 switch (TextCommands[id]) 02339 { 02340 case TextHelpCommand: 02341 { 02342 XTextViewWidget(display,resource_info,windows,MagickFalse, 02343 "Help Viewer - Image Annotation",ImageAnnotateHelp); 02344 (void) XCheckDefineCursor(display,windows->image.id,cursor); 02345 break; 02346 } 02347 case TextApplyCommand: 02348 { 02349 /* 02350 Finished annotating. 02351 */ 02352 annotate_info->width=(unsigned int) XTextWidth(font_info, 02353 annotate_info->text,(int) strlen(annotate_info->text)); 02354 XRefreshWindow(display,&windows->image,&text_event); 02355 state|=ExitState; 02356 break; 02357 } 02358 default: 02359 break; 02360 } 02361 continue; 02362 } 02363 /* 02364 Erase text cursor. 02365 */ 02366 text_event.xexpose.x=x; 02367 text_event.xexpose.y=y-font_info->max_bounds.ascent; 02368 (void) XClearArea(display,windows->image.id,x,text_event.xexpose.y, 02369 (unsigned int) text_event.xexpose.width,(unsigned int) 02370 text_event.xexpose.height,MagickFalse); 02371 XRefreshWindow(display,&windows->image,&text_event); 02372 switch (event.type) 02373 { 02374 case ButtonPress: 02375 { 02376 if (event.xbutton.window != windows->image.id) 02377 break; 02378 if (event.xbutton.button == Button2) 02379 { 02380 /* 02381 Request primary selection. 02382 */ 02383 (void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING, 02384 windows->image.id,CurrentTime); 02385 break; 02386 } 02387 break; 02388 } 02389 case Expose: 02390 { 02391 if (event.xexpose.count == 0) 02392 { 02393 XAnnotateInfo 02394 *text_info; 02395 02396 /* 02397 Refresh Image window. 02398 */ 02399 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 02400 text_info=annotate_info; 02401 while (text_info != (XAnnotateInfo *) NULL) 02402 { 02403 if (annotate_info->stencil == ForegroundStencil) 02404 (void) XDrawString(display,windows->image.id,annotate_context, 02405 text_info->x,text_info->y,text_info->text, 02406 (int) strlen(text_info->text)); 02407 else 02408 (void) XDrawImageString(display,windows->image.id, 02409 annotate_context,text_info->x,text_info->y,text_info->text, 02410 (int) strlen(text_info->text)); 02411 text_info=text_info->previous; 02412 } 02413 (void) XDrawString(display,windows->image.id,annotate_context, 02414 x,y,"_",1); 02415 } 02416 break; 02417 } 02418 case KeyPress: 02419 { 02420 int 02421 length; 02422 02423 if (event.xkey.window != windows->image.id) 02424 break; 02425 /* 02426 Respond to a user key press. 02427 */ 02428 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 02429 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 02430 *(command+length)='\0'; 02431 if (((event.xkey.state & ControlMask) != 0) || 02432 ((event.xkey.state & Mod1Mask) != 0)) 02433 state|=ModifierState; 02434 if ((state & ModifierState) != 0) 02435 switch ((int) key_symbol) 02436 { 02437 case XK_u: 02438 case XK_U: 02439 { 02440 key_symbol=DeleteCommand; 02441 break; 02442 } 02443 default: 02444 break; 02445 } 02446 switch ((int) key_symbol) 02447 { 02448 case XK_BackSpace: 02449 { 02450 /* 02451 Erase one character. 02452 */ 02453 if (p == annotate_info->text) 02454 { 02455 if (annotate_info->previous == (XAnnotateInfo *) NULL) 02456 break; 02457 else 02458 { 02459 /* 02460 Go to end of the previous line of text. 02461 */ 02462 annotate_info=annotate_info->previous; 02463 p=annotate_info->text; 02464 x=annotate_info->x+annotate_info->width; 02465 y=annotate_info->y; 02466 if (annotate_info->width != 0) 02467 p+=strlen(annotate_info->text); 02468 break; 02469 } 02470 } 02471 p--; 02472 x-=XTextWidth(font_info,p,1); 02473 text_event.xexpose.x=x; 02474 text_event.xexpose.y=y-font_info->max_bounds.ascent; 02475 XRefreshWindow(display,&windows->image,&text_event); 02476 break; 02477 } 02478 case XK_bracketleft: 02479 { 02480 key_symbol=XK_Escape; 02481 break; 02482 } 02483 case DeleteCommand: 02484 { 02485 /* 02486 Erase the entire line of text. 02487 */ 02488 while (p != annotate_info->text) 02489 { 02490 p--; 02491 x-=XTextWidth(font_info,p,1); 02492 text_event.xexpose.x=x; 02493 XRefreshWindow(display,&windows->image,&text_event); 02494 } 02495 break; 02496 } 02497 case XK_Escape: 02498 case XK_F20: 02499 { 02500 /* 02501 Finished annotating. 02502 */ 02503 annotate_info->width=(unsigned int) XTextWidth(font_info, 02504 annotate_info->text,(int) strlen(annotate_info->text)); 02505 XRefreshWindow(display,&windows->image,&text_event); 02506 state|=ExitState; 02507 break; 02508 } 02509 default: 02510 { 02511 /* 02512 Draw a single character on the Image window. 02513 */ 02514 if ((state & ModifierState) != 0) 02515 break; 02516 if (*command == '\0') 02517 break; 02518 *p=(*command); 02519 if (annotate_info->stencil == ForegroundStencil) 02520 (void) XDrawString(display,windows->image.id,annotate_context, 02521 x,y,p,1); 02522 else 02523 (void) XDrawImageString(display,windows->image.id, 02524 annotate_context,x,y,p,1); 02525 x+=XTextWidth(font_info,p,1); 02526 p++; 02527 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 02528 break; 02529 } 02530 case XK_Return: 02531 case XK_KP_Enter: 02532 { 02533 /* 02534 Advance to the next line of text. 02535 */ 02536 *p='\0'; 02537 annotate_info->width=(unsigned int) XTextWidth(font_info, 02538 annotate_info->text,(int) strlen(annotate_info->text)); 02539 if (annotate_info->next != (XAnnotateInfo *) NULL) 02540 { 02541 /* 02542 Line of text already exists. 02543 */ 02544 annotate_info=annotate_info->next; 02545 x=annotate_info->x; 02546 y=annotate_info->y; 02547 p=annotate_info->text; 02548 break; 02549 } 02550 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 02551 sizeof(*annotate_info->next)); 02552 if (annotate_info->next == (XAnnotateInfo *) NULL) 02553 return(MagickFalse); 02554 *annotate_info->next=(*annotate_info); 02555 annotate_info->next->previous=annotate_info; 02556 annotate_info=annotate_info->next; 02557 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 02558 windows->image.width/MagickMax((ssize_t) 02559 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 02560 if (annotate_info->text == (char *) NULL) 02561 return(MagickFalse); 02562 annotate_info->y+=annotate_info->height; 02563 if (annotate_info->y > (int) windows->image.height) 02564 annotate_info->y=(int) annotate_info->height; 02565 annotate_info->next=(XAnnotateInfo *) NULL; 02566 x=annotate_info->x; 02567 y=annotate_info->y; 02568 p=annotate_info->text; 02569 break; 02570 } 02571 } 02572 break; 02573 } 02574 case KeyRelease: 02575 { 02576 /* 02577 Respond to a user key release. 02578 */ 02579 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 02580 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 02581 state&=(~ModifierState); 02582 break; 02583 } 02584 case SelectionNotify: 02585 { 02586 Atom 02587 type; 02588 02589 int 02590 format; 02591 02592 unsigned char 02593 *data; 02594 02595 unsigned long 02596 after, 02597 length; 02598 02599 /* 02600 Obtain response from primary selection. 02601 */ 02602 if (event.xselection.property == (Atom) None) 02603 break; 02604 status=XGetWindowProperty(display,event.xselection.requestor, 02605 event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING, 02606 &type,&format,&length,&after,&data); 02607 if ((status != Success) || (type != XA_STRING) || (format == 32) || 02608 (length == 0)) 02609 break; 02610 /* 02611 Annotate Image window with primary selection. 02612 */ 02613 for (i=0; i < (ssize_t) length; i++) 02614 { 02615 if ((char) data[i] != '\n') 02616 { 02617 /* 02618 Draw a single character on the Image window. 02619 */ 02620 *p=(char) data[i]; 02621 (void) XDrawString(display,windows->image.id,annotate_context, 02622 x,y,p,1); 02623 x+=XTextWidth(font_info,p,1); 02624 p++; 02625 if ((x+font_info->max_bounds.width) < (int) windows->image.width) 02626 continue; 02627 } 02628 /* 02629 Advance to the next line of text. 02630 */ 02631 *p='\0'; 02632 annotate_info->width=(unsigned int) XTextWidth(font_info, 02633 annotate_info->text,(int) strlen(annotate_info->text)); 02634 if (annotate_info->next != (XAnnotateInfo *) NULL) 02635 { 02636 /* 02637 Line of text already exists. 02638 */ 02639 annotate_info=annotate_info->next; 02640 x=annotate_info->x; 02641 y=annotate_info->y; 02642 p=annotate_info->text; 02643 continue; 02644 } 02645 annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory( 02646 sizeof(*annotate_info->next)); 02647 if (annotate_info->next == (XAnnotateInfo *) NULL) 02648 return(MagickFalse); 02649 *annotate_info->next=(*annotate_info); 02650 annotate_info->next->previous=annotate_info; 02651 annotate_info=annotate_info->next; 02652 annotate_info->text=(char *) AcquireQuantumMemory((size_t) 02653 windows->image.width/MagickMax((ssize_t) 02654 font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text)); 02655 if (annotate_info->text == (char *) NULL) 02656 return(MagickFalse); 02657 annotate_info->y+=annotate_info->height; 02658 if (annotate_info->y > (int) windows->image.height) 02659 annotate_info->y=(int) annotate_info->height; 02660 annotate_info->next=(XAnnotateInfo *) NULL; 02661 x=annotate_info->x; 02662 y=annotate_info->y; 02663 p=annotate_info->text; 02664 } 02665 (void) XFree((void *) data); 02666 break; 02667 } 02668 default: 02669 break; 02670 } 02671 } while ((state & ExitState) == 0); 02672 (void) XFreeCursor(display,cursor); 02673 /* 02674 Annotation is relative to image configuration. 02675 */ 02676 width=(unsigned int) image->columns; 02677 height=(unsigned int) image->rows; 02678 x=0; 02679 y=0; 02680 if (windows->image.crop_geometry != (char *) NULL) 02681 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 02682 /* 02683 Initialize annotated image. 02684 */ 02685 XSetCursorState(display,windows,MagickTrue); 02686 XCheckRefreshWindows(display,windows); 02687 while (annotate_info != (XAnnotateInfo *) NULL) 02688 { 02689 if (annotate_info->width == 0) 02690 { 02691 /* 02692 No text on this line-- go to the next line of text. 02693 */ 02694 previous_info=annotate_info->previous; 02695 annotate_info->text=(char *) 02696 RelinquishMagickMemory(annotate_info->text); 02697 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 02698 annotate_info=previous_info; 02699 continue; 02700 } 02701 /* 02702 Determine pixel index for box and pen color. 02703 */ 02704 windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id]; 02705 if (windows->pixel_info->colors != 0) 02706 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 02707 if (windows->pixel_info->pixels[i] == 02708 windows->pixel_info->pen_colors[box_id].pixel) 02709 { 02710 windows->pixel_info->box_index=(unsigned short) i; 02711 break; 02712 } 02713 windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id]; 02714 if (windows->pixel_info->colors != 0) 02715 for (i=0; i < (ssize_t) windows->pixel_info->colors; i++) 02716 if (windows->pixel_info->pixels[i] == 02717 windows->pixel_info->pen_colors[pen_id].pixel) 02718 { 02719 windows->pixel_info->pen_index=(unsigned short) i; 02720 break; 02721 } 02722 /* 02723 Define the annotate geometry string. 02724 */ 02725 annotate_info->x=(int) 02726 width*(annotate_info->x+windows->image.x)/windows->image.ximage->width; 02727 annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+ 02728 windows->image.y)/windows->image.ximage->height; 02729 (void) FormatLocaleString(annotate_info->geometry,MaxTextExtent, 02730 "%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width, 02731 height*annotate_info->height/windows->image.ximage->height, 02732 annotate_info->x+x,annotate_info->y+y); 02733 /* 02734 Annotate image with text. 02735 */ 02736 status=XAnnotateImage(display,windows->pixel_info,annotate_info,image, 02737 exception); 02738 if (status == 0) 02739 return(MagickFalse); 02740 /* 02741 Free up memory. 02742 */ 02743 previous_info=annotate_info->previous; 02744 annotate_info->text=DestroyString(annotate_info->text); 02745 annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info); 02746 annotate_info=previous_info; 02747 } 02748 (void) XSetForeground(display,annotate_context, 02749 windows->pixel_info->foreground_color.pixel); 02750 (void) XSetBackground(display,annotate_context, 02751 windows->pixel_info->background_color.pixel); 02752 (void) XSetFont(display,annotate_context,windows->font_info->fid); 02753 XSetCursorState(display,windows,MagickFalse); 02754 (void) XFreeFont(display,font_info); 02755 /* 02756 Update image configuration. 02757 */ 02758 XConfigureImageColormap(display,resource_info,windows,image,exception); 02759 (void) XConfigureImage(display,resource_info,windows,image,exception); 02760 return(MagickTrue); 02761 } 02762 02763 /* 02764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02765 % % 02766 % % 02767 % % 02768 + X B a c k g r o u n d I m a g e % 02769 % % 02770 % % 02771 % % 02772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02773 % 02774 % XBackgroundImage() displays the image in the background of a window. 02775 % 02776 % The format of the XBackgroundImage method is: 02777 % 02778 % MagickBooleanType XBackgroundImage(Display *display, 02779 % XResourceInfo *resource_info,XWindows *windows,Image **image, 02780 % ExceptionInfo *exception) 02781 % 02782 % A description of each parameter follows: 02783 % 02784 % o display: Specifies a connection to an X server; returned from 02785 % XOpenDisplay. 02786 % 02787 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 02788 % 02789 % o windows: Specifies a pointer to a XWindows structure. 02790 % 02791 % o image: the image. 02792 % 02793 % o exception: return any errors or warnings in this structure. 02794 % 02795 */ 02796 static MagickBooleanType XBackgroundImage(Display *display, 02797 XResourceInfo *resource_info,XWindows *windows,Image **image, 02798 ExceptionInfo *exception) 02799 { 02800 #define BackgroundImageTag "Background/Image" 02801 02802 int 02803 status; 02804 02805 static char 02806 window_id[MaxTextExtent] = "root"; 02807 02808 XResourceInfo 02809 background_resources; 02810 02811 /* 02812 Put image in background. 02813 */ 02814 status=XDialogWidget(display,windows,"Background", 02815 "Enter window id (id 0x00 selects window with pointer):",window_id); 02816 if (*window_id == '\0') 02817 return(MagickFalse); 02818 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 02819 exception); 02820 XInfoWidget(display,windows,BackgroundImageTag); 02821 XSetCursorState(display,windows,MagickTrue); 02822 XCheckRefreshWindows(display,windows); 02823 background_resources=(*resource_info); 02824 background_resources.window_id=window_id; 02825 background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse; 02826 status=XDisplayBackgroundImage(display,&background_resources,*image, 02827 exception); 02828 if (status != MagickFalse) 02829 XClientMessage(display,windows->image.id,windows->im_protocols, 02830 windows->im_retain_colors,CurrentTime); 02831 XSetCursorState(display,windows,MagickFalse); 02832 (void) XMagickCommand(display,resource_info,windows,UndoCommand,image, 02833 exception); 02834 return(MagickTrue); 02835 } 02836 02837 /* 02838 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02839 % % 02840 % % 02841 % % 02842 + X C h o p I m a g e % 02843 % % 02844 % % 02845 % % 02846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 02847 % 02848 % XChopImage() chops the X image. 02849 % 02850 % The format of the XChopImage method is: 02851 % 02852 % MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info, 02853 % XWindows *windows,Image **image,ExceptionInfo *exception) 02854 % 02855 % A description of each parameter follows: 02856 % 02857 % o display: Specifies a connection to an X server; returned from 02858 % XOpenDisplay. 02859 % 02860 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 02861 % 02862 % o windows: Specifies a pointer to a XWindows structure. 02863 % 02864 % o image: the image. 02865 % 02866 % o exception: return any errors or warnings in this structure. 02867 % 02868 */ 02869 static MagickBooleanType XChopImage(Display *display, 02870 XResourceInfo *resource_info,XWindows *windows,Image **image, 02871 ExceptionInfo *exception) 02872 { 02873 static const char 02874 *ChopMenu[] = 02875 { 02876 "Direction", 02877 "Help", 02878 "Dismiss", 02879 (char *) NULL 02880 }; 02881 02882 static ModeType 02883 direction = HorizontalChopCommand; 02884 02885 static const ModeType 02886 ChopCommands[] = 02887 { 02888 ChopDirectionCommand, 02889 ChopHelpCommand, 02890 ChopDismissCommand 02891 }, 02892 DirectionCommands[] = 02893 { 02894 HorizontalChopCommand, 02895 VerticalChopCommand 02896 }; 02897 02898 char 02899 text[MaxTextExtent]; 02900 02901 Image 02902 *chop_image; 02903 02904 int 02905 id, 02906 x, 02907 y; 02908 02909 MagickRealType 02910 scale_factor; 02911 02912 RectangleInfo 02913 chop_info; 02914 02915 unsigned int 02916 distance, 02917 height, 02918 width; 02919 02920 size_t 02921 state; 02922 02923 XEvent 02924 event; 02925 02926 XSegment 02927 segment_info; 02928 02929 /* 02930 Map Command widget. 02931 */ 02932 (void) CloneString(&windows->command.name,"Chop"); 02933 windows->command.data=1; 02934 (void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL); 02935 (void) XMapRaised(display,windows->command.id); 02936 XClientMessage(display,windows->image.id,windows->im_protocols, 02937 windows->im_update_widget,CurrentTime); 02938 /* 02939 Track pointer until button 1 is pressed. 02940 */ 02941 XQueryPosition(display,windows->image.id,&x,&y); 02942 (void) XSelectInput(display,windows->image.id, 02943 windows->image.attributes.event_mask | PointerMotionMask); 02944 state=DefaultState; 02945 do 02946 { 02947 if (windows->info.mapped != MagickFalse) 02948 { 02949 /* 02950 Display pointer position. 02951 */ 02952 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 02953 x+windows->image.x,y+windows->image.y); 02954 XInfoWidget(display,windows,text); 02955 } 02956 /* 02957 Wait for next event. 02958 */ 02959 XScreenEvent(display,windows,&event,exception); 02960 if (event.xany.window == windows->command.id) 02961 { 02962 /* 02963 Select a command from the Command widget. 02964 */ 02965 id=XCommandWidget(display,windows,ChopMenu,&event); 02966 if (id < 0) 02967 continue; 02968 switch (ChopCommands[id]) 02969 { 02970 case ChopDirectionCommand: 02971 { 02972 char 02973 command[MaxTextExtent]; 02974 02975 static const char 02976 *Directions[] = 02977 { 02978 "horizontal", 02979 "vertical", 02980 (char *) NULL, 02981 }; 02982 02983 /* 02984 Select a command from the pop-up menu. 02985 */ 02986 id=XMenuWidget(display,windows,ChopMenu[id],Directions,command); 02987 if (id >= 0) 02988 direction=DirectionCommands[id]; 02989 break; 02990 } 02991 case ChopHelpCommand: 02992 { 02993 XTextViewWidget(display,resource_info,windows,MagickFalse, 02994 "Help Viewer - Image Chop",ImageChopHelp); 02995 break; 02996 } 02997 case ChopDismissCommand: 02998 { 02999 /* 03000 Prematurely exit. 03001 */ 03002 state|=EscapeState; 03003 state|=ExitState; 03004 break; 03005 } 03006 default: 03007 break; 03008 } 03009 continue; 03010 } 03011 switch (event.type) 03012 { 03013 case ButtonPress: 03014 { 03015 if (event.xbutton.button != Button1) 03016 break; 03017 if (event.xbutton.window != windows->image.id) 03018 break; 03019 /* 03020 User has committed to start point of chopping line. 03021 */ 03022 segment_info.x1=(short int) event.xbutton.x; 03023 segment_info.x2=(short int) event.xbutton.x; 03024 segment_info.y1=(short int) event.xbutton.y; 03025 segment_info.y2=(short int) event.xbutton.y; 03026 state|=ExitState; 03027 break; 03028 } 03029 case ButtonRelease: 03030 break; 03031 case Expose: 03032 break; 03033 case KeyPress: 03034 { 03035 char 03036 command[MaxTextExtent]; 03037 03038 KeySym 03039 key_symbol; 03040 03041 if (event.xkey.window != windows->image.id) 03042 break; 03043 /* 03044 Respond to a user key press. 03045 */ 03046 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 03047 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 03048 switch ((int) key_symbol) 03049 { 03050 case XK_Escape: 03051 case XK_F20: 03052 { 03053 /* 03054 Prematurely exit. 03055 */ 03056 state|=EscapeState; 03057 state|=ExitState; 03058 break; 03059 } 03060 case XK_F1: 03061 case XK_Help: 03062 { 03063 (void) XSetFunction(display,windows->image.highlight_context, 03064 GXcopy); 03065 XTextViewWidget(display,resource_info,windows,MagickFalse, 03066 "Help Viewer - Image Chop",ImageChopHelp); 03067 (void) XSetFunction(display,windows->image.highlight_context, 03068 GXinvert); 03069 break; 03070 } 03071 default: 03072 { 03073 (void) XBell(display,0); 03074 break; 03075 } 03076 } 03077 break; 03078 } 03079 case MotionNotify: 03080 { 03081 /* 03082 Map and unmap Info widget as text cursor crosses its boundaries. 03083 */ 03084 x=event.xmotion.x; 03085 y=event.xmotion.y; 03086 if (windows->info.mapped != MagickFalse) 03087 { 03088 if ((x < (int) (windows->info.x+windows->info.width)) && 03089 (y < (int) (windows->info.y+windows->info.height))) 03090 (void) XWithdrawWindow(display,windows->info.id, 03091 windows->info.screen); 03092 } 03093 else 03094 if ((x > (int) (windows->info.x+windows->info.width)) || 03095 (y > (int) (windows->info.y+windows->info.height))) 03096 (void) XMapWindow(display,windows->info.id); 03097 } 03098 } 03099 } while ((state & ExitState) == 0); 03100 (void) XSelectInput(display,windows->image.id, 03101 windows->image.attributes.event_mask); 03102 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 03103 if ((state & EscapeState) != 0) 03104 return(MagickTrue); 03105 /* 03106 Draw line as pointer moves until the mouse button is released. 03107 */ 03108 chop_info.width=0; 03109 chop_info.height=0; 03110 chop_info.x=0; 03111 chop_info.y=0; 03112 distance=0; 03113 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 03114 state=DefaultState; 03115 do 03116 { 03117 if (distance > 9) 03118 { 03119 /* 03120 Display info and draw chopping line. 03121 */ 03122 if (windows->info.mapped == MagickFalse) 03123 (void) XMapWindow(display,windows->info.id); 03124 (void) FormatLocaleString(text,MaxTextExtent, 03125 " %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double) 03126 chop_info.height,(double) chop_info.x,(double) chop_info.y); 03127 XInfoWidget(display,windows,text); 03128 XHighlightLine(display,windows->image.id, 03129 windows->image.highlight_context,&segment_info); 03130 } 03131 else 03132 if (windows->info.mapped != MagickFalse) 03133 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 03134 /* 03135 Wait for next event. 03136 */ 03137 XScreenEvent(display,windows,&event,exception); 03138 if (distance > 9) 03139 XHighlightLine(display,windows->image.id, 03140 windows->image.highlight_context,&segment_info); 03141 switch (event.type) 03142 { 03143 case ButtonPress: 03144 { 03145 segment_info.x2=(short int) event.xmotion.x; 03146 segment_info.y2=(short int) event.xmotion.y; 03147 break; 03148 } 03149 case ButtonRelease: 03150 { 03151 /* 03152 User has committed to chopping line. 03153 */ 03154 segment_info.x2=(short int) event.xbutton.x; 03155 segment_info.y2=(short int) event.xbutton.y; 03156 state|=ExitState; 03157 break; 03158 } 03159 case Expose: 03160 break; 03161 case MotionNotify: 03162 { 03163 segment_info.x2=(short int) event.xmotion.x; 03164 segment_info.y2=(short int) event.xmotion.y; 03165 } 03166 default: 03167 break; 03168 } 03169 /* 03170 Check boundary conditions. 03171 */ 03172 if (segment_info.x2 < 0) 03173 segment_info.x2=0; 03174 else 03175 if (segment_info.x2 > windows->image.ximage->width) 03176 segment_info.x2=windows->image.ximage->width; 03177 if (segment_info.y2 < 0) 03178 segment_info.y2=0; 03179 else 03180 if (segment_info.y2 > windows->image.ximage->height) 03181 segment_info.y2=windows->image.ximage->height; 03182 distance=(unsigned int) 03183 (((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+ 03184 ((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1))); 03185 /* 03186 Compute chopping geometry. 03187 */ 03188 if (direction == HorizontalChopCommand) 03189 { 03190 chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1); 03191 chop_info.x=(ssize_t) windows->image.x+segment_info.x1; 03192 chop_info.height=0; 03193 chop_info.y=0; 03194 if (segment_info.x1 > (int) segment_info.x2) 03195 { 03196 chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1); 03197 chop_info.x=(ssize_t) windows->image.x+segment_info.x2; 03198 } 03199 } 03200 else 03201 { 03202 chop_info.width=0; 03203 chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1); 03204 chop_info.x=0; 03205 chop_info.y=(ssize_t) windows->image.y+segment_info.y1; 03206 if (segment_info.y1 > segment_info.y2) 03207 { 03208 chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1); 03209 chop_info.y=(ssize_t) windows->image.y+segment_info.y2; 03210 } 03211 } 03212 } while ((state & ExitState) == 0); 03213 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 03214 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 03215 if (distance <= 9) 03216 return(MagickTrue); 03217 /* 03218 Image chopping is relative to image configuration. 03219 */ 03220 (void) XMagickCommand(display,resource_info,windows,ApplyCommand,image, 03221 exception); 03222 XSetCursorState(display,windows,MagickTrue); 03223 XCheckRefreshWindows(display,windows); 03224 windows->image.window_changes.width=windows->image.ximage->width- 03225 (unsigned int) chop_info.width; 03226 windows->image.window_changes.height=windows->image.ximage->height- 03227 (unsigned int) chop_info.height; 03228 width=(unsigned int) (*image)->columns; 03229 height=(unsigned int) (*image)->rows; 03230 x=0; 03231 y=0; 03232 if (windows->image.crop_geometry != (char *) NULL) 03233 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 03234 scale_factor=(MagickRealType) width/windows->image.ximage->width; 03235 chop_info.x+=x; 03236 chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5); 03237 chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5); 03238 scale_factor=(MagickRealType) height/windows->image.ximage->height; 03239 chop_info.y+=y; 03240 chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5); 03241 chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5); 03242 /* 03243 Chop image. 03244 */ 03245 chop_image=ChopImage(*image,&chop_info,exception); 03246 XSetCursorState(display,windows,MagickFalse); 03247 if (chop_image == (Image *) NULL) 03248 return(MagickFalse); 03249 *image=DestroyImage(*image); 03250 *image=chop_image; 03251 /* 03252 Update image configuration. 03253 */ 03254 XConfigureImageColormap(display,resource_info,windows,*image,exception); 03255 (void) XConfigureImage(display,resource_info,windows,*image,exception); 03256 return(MagickTrue); 03257 } 03258 03259 /* 03260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03261 % % 03262 % % 03263 % % 03264 + X C o l o r E d i t I m a g e % 03265 % % 03266 % % 03267 % % 03268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03269 % 03270 % XColorEditImage() allows the user to interactively change the color of one 03271 % pixel for a DirectColor image or one colormap entry for a PseudoClass image. 03272 % 03273 % The format of the XColorEditImage method is: 03274 % 03275 % MagickBooleanType XColorEditImage(Display *display, 03276 % XResourceInfo *resource_info,XWindows *windows,Image **image, 03277 % ExceptionInfo *exception) 03278 % 03279 % A description of each parameter follows: 03280 % 03281 % o display: Specifies a connection to an X server; returned from 03282 % XOpenDisplay. 03283 % 03284 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 03285 % 03286 % o windows: Specifies a pointer to a XWindows structure. 03287 % 03288 % o image: the image; returned from ReadImage. 03289 % 03290 % o exception: return any errors or warnings in this structure. 03291 % 03292 */ 03293 static MagickBooleanType XColorEditImage(Display *display, 03294 XResourceInfo *resource_info,XWindows *windows,Image **image, 03295 ExceptionInfo *exception) 03296 { 03297 static const char 03298 *ColorEditMenu[] = 03299 { 03300 "Method", 03301 "Pixel Color", 03302 "Border Color", 03303 "Fuzz", 03304 "Undo", 03305 "Help", 03306 "Dismiss", 03307 (char *) NULL 03308 }; 03309 03310 static const ModeType 03311 ColorEditCommands[] = 03312 { 03313 ColorEditMethodCommand, 03314 ColorEditColorCommand, 03315 ColorEditBorderCommand, 03316 ColorEditFuzzCommand, 03317 ColorEditUndoCommand, 03318 ColorEditHelpCommand, 03319 ColorEditDismissCommand 03320 }; 03321 03322 static PaintMethod 03323 method = PointMethod; 03324 03325 static unsigned int 03326 pen_id = 0; 03327 03328 static XColor 03329 border_color = { 0, 0, 0, 0, 0, 0 }; 03330 03331 char 03332 command[MaxTextExtent], 03333 text[MaxTextExtent]; 03334 03335 Cursor 03336 cursor; 03337 03338 int 03339 entry, 03340 id, 03341 x, 03342 x_offset, 03343 y, 03344 y_offset; 03345 03346 register Quantum 03347 *q; 03348 03349 register ssize_t 03350 i; 03351 03352 unsigned int 03353 height, 03354 width; 03355 03356 size_t 03357 state; 03358 03359 XColor 03360 color; 03361 03362 XEvent 03363 event; 03364 03365 /* 03366 Map Command widget. 03367 */ 03368 (void) CloneString(&windows->command.name,"Color Edit"); 03369 windows->command.data=4; 03370 (void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL); 03371 (void) XMapRaised(display,windows->command.id); 03372 XClientMessage(display,windows->image.id,windows->im_protocols, 03373 windows->im_update_widget,CurrentTime); 03374 /* 03375 Make cursor. 03376 */ 03377 cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap, 03378 resource_info->background_color,resource_info->foreground_color); 03379 (void) XCheckDefineCursor(display,windows->image.id,cursor); 03380 /* 03381 Track pointer until button 1 is pressed. 03382 */ 03383 XQueryPosition(display,windows->image.id,&x,&y); 03384 (void) XSelectInput(display,windows->image.id, 03385 windows->image.attributes.event_mask | PointerMotionMask); 03386 state=DefaultState; 03387 do 03388 { 03389 if (windows->info.mapped != MagickFalse) 03390 { 03391 /* 03392 Display pointer position. 03393 */ 03394 (void) FormatLocaleString(text,MaxTextExtent," %+d%+d ", 03395 x+windows->image.x,y+windows->image.y); 03396 XInfoWidget(display,windows,text); 03397 } 03398 /* 03399 Wait for next event. 03400 */ 03401 XScreenEvent(display,windows,&event,exception); 03402 if (event.xany.window == windows->command.id) 03403 { 03404 /* 03405 Select a command from the Command widget. 03406 */ 03407 id=XCommandWidget(display,windows,ColorEditMenu,&event); 03408 if (id < 0) 03409 { 03410 (void) XCheckDefineCursor(display,windows->image.id,cursor); 03411 continue; 03412 } 03413 switch (ColorEditCommands[id]) 03414 { 03415 case ColorEditMethodCommand: 03416 { 03417 char 03418 **methods; 03419 03420 /* 03421 Select a method from the pop-up menu. 03422 */ 03423 methods=(char **) GetCommandOptions(MagickMethodOptions); 03424 if (methods == (char **) NULL) 03425 break; 03426 entry=XMenuWidget(display,windows,ColorEditMenu[id], 03427 (const char **) methods,command); 03428 if (entry >= 0) 03429 method=(PaintMethod) ParseCommandOption(MagickMethodOptions, 03430 MagickFalse,methods[entry]); 03431 methods=DestroyStringList(methods); 03432 break; 03433 } 03434 case ColorEditColorCommand: 03435 { 03436 const char 03437 *ColorMenu[MaxNumberPens]; 03438 03439 int 03440 pen_number; 03441 03442 /* 03443 Initialize menu selections. 03444 */ 03445 for (i=0; i < (int) (MaxNumberPens-2); i++) 03446 ColorMenu[i]=resource_info->pen_colors[i]; 03447 ColorMenu[MaxNumberPens-2]="Browser..."; 03448 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 03449 /* 03450 Select a pen color from the pop-up menu. 03451 */ 03452 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 03453 (const char **) ColorMenu,command); 03454 if (pen_number < 0) 03455 break; 03456 if (pen_number == (MaxNumberPens-2)) 03457 { 03458 static char 03459 color_name[MaxTextExtent] = "gray"; 03460 03461 /* 03462 Select a pen color from a dialog. 03463 */ 03464 resource_info->pen_colors[pen_number]=color_name; 03465 XColorBrowserWidget(display,windows,"Select",color_name); 03466 if (*color_name == '\0') 03467 break; 03468 } 03469 /* 03470 Set pen color. 03471 */ 03472 (void) XParseColor(display,windows->map_info->colormap, 03473 resource_info->pen_colors[pen_number],&color); 03474 XBestPixel(display,windows->map_info->colormap,(XColor *) NULL, 03475 (unsigned int) MaxColors,&color); 03476 windows->pixel_info->pen_colors[pen_number]=color; 03477 pen_id=(unsigned int) pen_number; 03478 break; 03479 } 03480 case ColorEditBorderCommand: 03481 { 03482 const char 03483 *ColorMenu[MaxNumberPens]; 03484 03485 int 03486 pen_number; 03487 03488 /* 03489 Initialize menu selections. 03490 */ 03491 for (i=0; i < (int) (MaxNumberPens-2); i++) 03492 ColorMenu[i]=resource_info->pen_colors[i]; 03493 ColorMenu[MaxNumberPens-2]="Browser..."; 03494 ColorMenu[MaxNumberPens-1]=(const char *) NULL; 03495 /* 03496 Select a pen color from the pop-up menu. 03497 */ 03498 pen_number=XMenuWidget(display,windows,ColorEditMenu[id], 03499 (const char **) ColorMenu,command); 03500 if (pen_number < 0) 03501 break; 03502 if (pen_number == (MaxNumberPens-2)) 03503 { 03504 static char 03505 color_name[MaxTextExtent] = "gray"; 03506 03507 /* 03508 Select a pen color from a dialog. 03509 */ 03510 resource_info->pen_colors[pen_number]=color_name; 03511 XColorBrowserWidget(display,windows,"Select",color_name); 03512 if (*color_name == '\0') 03513 break; 03514 } 03515 /* 03516 Set border color. 03517 */ 03518 (void) XParseColor(display,windows->map_info->colormap, 03519 resource_info->pen_colors[pen_number],&border_color); 03520 break; 03521 } 03522 case ColorEditFuzzCommand: 03523 { 03524 static char 03525 fuzz[MaxTextExtent]; 03526 03527 static const char 03528 *FuzzMenu[] = 03529 { 03530 "0%", 03531 "2%", 03532 "5%", 03533 "10%", 03534 "15%", 03535 "Dialog...", 03536 (char *) NULL, 03537 }; 03538 03539 /* 03540 Select a command from the pop-up menu. 03541 */ 03542 entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu, 03543 command); 03544 if (entry < 0) 03545 break; 03546 if (entry != 5) 03547 { 03548 (*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double) 03549 QuantumRange+1.0); 03550 break; 03551 } 03552 (void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent); 03553 (void) XDialogWidget(display,windows,"Ok", 03554 "Enter fuzz factor (0.0 - 99.9%):",fuzz); 03555 if (*fuzz == '\0') 03556 break; 03557 (void) ConcatenateMagickString(fuzz,"%",MaxTextExtent); 03558 (*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+ 03559 1.0); 03560 break; 03561 } 03562 case ColorEditUndoCommand: 03563 { 03564 (void) XMagickCommand(display,resource_info,windows,UndoCommand, 03565 image,exception); 03566 break; 03567 } 03568 case ColorEditHelpCommand: 03569 default: 03570 { 03571 XTextViewWidget(display,resource_info,windows,MagickFalse, 03572 "Help Viewer - Image Annotation",ImageColorEditHelp); 03573 break; 03574 } 03575 case ColorEditDismissCommand: 03576 { 03577 /* 03578 Prematurely exit. 03579 */ 03580 state|=EscapeState; 03581 state|=ExitState; 03582 break; 03583 } 03584 } 03585 (void) XCheckDefineCursor(display,windows->image.id,cursor); 03586 continue; 03587 } 03588 switch (event.type) 03589 { 03590 case ButtonPress: 03591 { 03592 if (event.xbutton.button != Button1) 03593 break; 03594 if ((event.xbutton.window != windows->image.id) && 03595 (event.xbutton.window != windows->magnify.id)) 03596 break; 03597 /* 03598 exit loop. 03599 */ 03600 x=event.xbutton.x; 03601 y=event.xbutton.y; 03602 (void) XMagickCommand(display,resource_info,windows, 03603 SaveToUndoBufferCommand,image,exception); 03604 state|=UpdateConfigurationState; 03605 break; 03606 } 03607 case ButtonRelease: 03608 { 03609 if (event.xbutton.button != Button1) 03610 break; 03611 if ((event.xbutton.window != windows->image.id) && 03612 (event.xbutton.window != windows->magnify.id)) 03613 break; 03614 /* 03615 Update colormap information. 03616 */ 03617 x=event.xbutton.x; 03618 y=event.xbutton.y; 03619 XConfigureImageColormap(display,resource_info,windows,*image,exception); 03620 (void) XConfigureImage(display,resource_info,windows,*image,exception); 03621 XInfoWidget(display,windows,text); 03622 (void) XCheckDefineCursor(display,windows->image.id,cursor); 03623 state&=(~UpdateConfigurationState); 03624 break; 03625 } 03626 case Expose: 03627 break; 03628 case KeyPress: 03629 { 03630 KeySym 03631 key_symbol; 03632 03633 if (event.xkey.window == windows->magnify.id) 03634 { 03635 Window 03636 window; 03637 03638 window=windows->magnify.id; 03639 while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ; 03640 } 03641 if (event.xkey.window != windows->image.id) 03642 break; 03643 /* 03644 Respond to a user key press. 03645 */ 03646 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 03647 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 03648 switch ((int) key_symbol) 03649 { 03650 case XK_Escape: 03651 case XK_F20: 03652 { 03653 /* 03654 Prematurely exit. 03655 */ 03656 state|=ExitState; 03657 break; 03658 } 03659 case XK_F1: 03660 case XK_Help: 03661 { 03662 XTextViewWidget(display,resource_info,windows,MagickFalse, 03663 "Help Viewer - Image Annotation",ImageColorEditHelp); 03664 break; 03665 } 03666 default: 03667 { 03668 (void) XBell(display,0); 03669 break; 03670 } 03671 } 03672 break; 03673 } 03674 case MotionNotify: 03675 { 03676 /* 03677 Map and unmap Info widget as cursor crosses its boundaries. 03678 */ 03679 x=event.xmotion.x; 03680 y=event.xmotion.y; 03681 if (windows->info.mapped != MagickFalse) 03682 { 03683 if ((x < (int) (windows->info.x+windows->info.width)) && 03684 (y < (int) (windows->info.y+windows->info.height))) 03685 (void) XWithdrawWindow(display,windows->info.id, 03686 windows->info.screen); 03687 } 03688 else 03689 if ((x > (int) (windows->info.x+windows->info.width)) || 03690 (y > (int) (windows->info.y+windows->info.height))) 03691 (void) XMapWindow(display,windows->info.id); 03692 break; 03693 } 03694 default: 03695 break; 03696 } 03697 if (event.xany.window == windows->magnify.id) 03698 { 03699 x=windows->magnify.x-windows->image.x; 03700 y=windows->magnify.y-windows->image.y; 03701 } 03702 x_offset=x; 03703 y_offset=y; 03704 if ((state & UpdateConfigurationState) != 0) 03705 { 03706 CacheView 03707 *image_view; 03708 03709 int 03710 x, 03711 y; 03712 03713 /* 03714 Pixel edit is relative to image configuration. 03715 */ 03716 (void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1, 03717 MagickTrue); 03718 color=windows->pixel_info->pen_colors[pen_id]; 03719 XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel); 03720 width=(unsigned int) (*image)->columns; 03721 height=(unsigned int) (*image)->rows; 03722 x=0; 03723 y=0; 03724 if (windows->image.crop_geometry != (char *) NULL) 03725 (void) XParseGeometry(windows->image.crop_geometry,&x,&y, 03726 &width,&height); 03727 x_offset=(int) 03728 (width*(windows->image.x+x_offset)/windows->image.ximage->width+x); 03729 y_offset=(int) 03730 (height*(windows->image.y+y_offset)/windows->image.ximage->height+y); 03731 if ((x_offset < 0) || (y_offset < 0)) 03732 continue; 03733 if ((x_offset >= (int) (*image)->columns) || 03734 (y_offset >= (int) (*image)->rows)) 03735 continue; 03736 image_view=AcquireCacheView(*image); 03737 switch (method) 03738 { 03739 case PointMethod: 03740 default: 03741 { 03742 /* 03743 Update color information using point algorithm. 03744 */ 03745 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 03746 return(MagickFalse); 03747 q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset, 03748 (ssize_t) y_offset,1,1,exception); 03749 if (q == (Quantum *) NULL) 03750 break; 03751 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 03752 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 03753 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 03754 (void) SyncCacheViewAuthenticPixels(image_view,exception); 03755 break; 03756 } 03757 case ReplaceMethod: 03758 { 03759 PixelInfo 03760 pixel, 03761 target; 03762 03763 Quantum 03764 virtual_pixel[CompositePixelChannel]; 03765 03766 /* 03767 Update color information using replace algorithm. 03768 */ 03769 (void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset, 03770 (ssize_t) y_offset,virtual_pixel,exception); 03771 target.red=virtual_pixel[RedPixelChannel]; 03772 target.green=virtual_pixel[GreenPixelChannel]; 03773 target.blue=virtual_pixel[BluePixelChannel]; 03774 target.alpha=virtual_pixel[AlphaPixelChannel]; 03775 if ((*image)->storage_class == DirectClass) 03776 { 03777 for (y=0; y < (int) (*image)->rows; y++) 03778 { 03779 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 03780 (*image)->columns,1,exception); 03781 if (q == (Quantum *) NULL) 03782 break; 03783 for (x=0; x < (int) (*image)->columns; x++) 03784 { 03785 GetPixelInfoPixel(*image,q,&pixel); 03786 if (IsFuzzyEquivalencePixelInfo(&pixel,&target)) 03787 { 03788 SetPixelRed(*image,ScaleShortToQuantum( 03789 color.red),q); 03790 SetPixelGreen(*image,ScaleShortToQuantum( 03791 color.green),q); 03792 SetPixelBlue(*image,ScaleShortToQuantum( 03793 color.blue),q); 03794 } 03795 q+=GetPixelChannels(*image); 03796 } 03797 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 03798 break; 03799 } 03800 } 03801 else 03802 { 03803 for (i=0; i < (ssize_t) (*image)->colors; i++) 03804 if (IsFuzzyEquivalencePixelInfo((*image)->colormap+i,&target)) 03805 { 03806 (*image)->colormap[i].red=ScaleShortToQuantum( 03807 color.red); 03808 (*image)->colormap[i].green=ScaleShortToQuantum( 03809 color.green); 03810 (*image)->colormap[i].blue=ScaleShortToQuantum( 03811 color.blue); 03812 } 03813 (void) SyncImage(*image,exception); 03814 } 03815 break; 03816 } 03817 case FloodfillMethod: 03818 case FillToBorderMethod: 03819 { 03820 DrawInfo 03821 *draw_info; 03822 03823 PixelInfo 03824 target; 03825 03826 /* 03827 Update color information using floodfill algorithm. 03828 */ 03829 (void) GetOneVirtualPixelInfo(*image, 03830 GetPixelCacheVirtualMethod(*image),(ssize_t) x_offset,(ssize_t) 03831 y_offset,&target,exception); 03832 if (method == FillToBorderMethod) 03833 { 03834 target.red=(MagickRealType) 03835 ScaleShortToQuantum(border_color.red); 03836 target.green=(MagickRealType) 03837 ScaleShortToQuantum(border_color.green); 03838 target.blue=(MagickRealType) 03839 ScaleShortToQuantum(border_color.blue); 03840 } 03841 draw_info=CloneDrawInfo(resource_info->image_info, 03842 (DrawInfo *) NULL); 03843 (void) QueryColorCompliance(resource_info->pen_colors[pen_id], 03844 AllCompliance,&draw_info->fill,exception); 03845 (void) FloodfillPaintImage(*image,draw_info,&target,(ssize_t) 03846 x_offset,(ssize_t) y_offset,method == FloodfillMethod ? 03847 MagickFalse : MagickTrue,exception); 03848 draw_info=DestroyDrawInfo(draw_info); 03849 break; 03850 } 03851 case ResetMethod: 03852 { 03853 /* 03854 Update color information using reset algorithm. 03855 */ 03856 if (SetImageStorageClass(*image,DirectClass,exception) == MagickFalse) 03857 return(MagickFalse); 03858 for (y=0; y < (int) (*image)->rows; y++) 03859 { 03860 q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y, 03861 (*image)->columns,1,exception); 03862 if (q == (Quantum *) NULL) 03863 break; 03864 for (x=0; x < (int) (*image)->columns; x++) 03865 { 03866 SetPixelRed(*image,ScaleShortToQuantum(color.red),q); 03867 SetPixelGreen(*image,ScaleShortToQuantum(color.green),q); 03868 SetPixelBlue(*image,ScaleShortToQuantum(color.blue),q); 03869 q+=GetPixelChannels(*image); 03870 } 03871 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 03872 break; 03873 } 03874 break; 03875 } 03876 } 03877 image_view=DestroyCacheView(image_view); 03878 state&=(~UpdateConfigurationState); 03879 } 03880 } while ((state & ExitState) == 0); 03881 (void) XSelectInput(display,windows->image.id, 03882 windows->image.attributes.event_mask); 03883 XSetCursorState(display,windows,MagickFalse); 03884 (void) XFreeCursor(display,cursor); 03885 return(MagickTrue); 03886 } 03887 03888 /* 03889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03890 % % 03891 % % 03892 % % 03893 + X C o m p o s i t e I m a g e % 03894 % % 03895 % % 03896 % % 03897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 03898 % 03899 % XCompositeImage() requests an image name from the user, reads the image and 03900 % composites it with the X window image at a location the user chooses with 03901 % the pointer. 03902 % 03903 % The format of the XCompositeImage method is: 03904 % 03905 % MagickBooleanType XCompositeImage(Display *display, 03906 % XResourceInfo *resource_info,XWindows *windows,Image *image, 03907 % ExceptionInfo *exception) 03908 % 03909 % A description of each parameter follows: 03910 % 03911 % o display: Specifies a connection to an X server; returned from 03912 % XOpenDisplay. 03913 % 03914 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 03915 % 03916 % o windows: Specifies a pointer to a XWindows structure. 03917 % 03918 % o image: the image; returned from ReadImage. 03919 % 03920 % o exception: return any errors or warnings in this structure. 03921 % 03922 */ 03923 static MagickBooleanType XCompositeImage(Display *display, 03924 XResourceInfo *resource_info,XWindows *windows,Image *image, 03925 ExceptionInfo *exception) 03926 { 03927 static char 03928 displacement_geometry[MaxTextExtent] = "30x30", 03929 filename[MaxTextExtent] = "\0"; 03930 03931 static const char 03932 *CompositeMenu[] = 03933 { 03934 "Operators", 03935 "Dissolve", 03936 "Displace", 03937 "Help", 03938 "Dismiss", 03939 (char *) NULL 03940 }; 03941 03942 static CompositeOperator 03943 compose = CopyCompositeOp; 03944 03945 static const ModeType 03946 CompositeCommands[] = 03947 { 03948 CompositeOperatorsCommand, 03949 CompositeDissolveCommand, 03950 CompositeDisplaceCommand, 03951 CompositeHelpCommand, 03952 CompositeDismissCommand 03953 }; 03954 03955 char 03956 text[MaxTextExtent]; 03957 03958 Cursor 03959 cursor; 03960 03961 Image 03962 *composite_image; 03963 03964 int 03965 entry, 03966 id, 03967 x, 03968 y; 03969 03970 MagickRealType 03971 blend, 03972 scale_factor; 03973 03974 RectangleInfo 03975 highlight_info, 03976 composite_info; 03977 03978 unsigned int 03979 height, 03980 width; 03981 03982 size_t 03983 state; 03984 03985 XEvent 03986 event; 03987 03988 /* 03989 Request image file name from user. 03990 */ 03991 XFileBrowserWidget(display,windows,"Composite",filename); 03992 if (*filename == '\0') 03993 return(MagickTrue); 03994 /* 03995 Read image. 03996 */ 03997 XSetCursorState(display,windows,MagickTrue); 03998 XCheckRefreshWindows(display,windows); 03999 (void) CopyMagickString(resource_info->image_info->filename,filename, 04000 MaxTextExtent); 04001 composite_image=ReadImage(resource_info->image_info,exception); 04002 CatchException(exception); 04003 XSetCursorState(display,windows,MagickFalse); 04004 if (composite_image == (Image *) NULL) 04005 return(MagickFalse); 04006 /* 04007 Map Command widget. 04008 */ 04009 (void) CloneString(&windows->command.name,"Composite"); 04010 windows->command.data=1; 04011 (void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL); 04012 (void) XMapRaised(display,windows->command.id); 04013 XClientMessage(display,windows->image.id,windows->im_protocols, 04014 windows->im_update_widget,CurrentTime); 04015 /* 04016 Track pointer until button 1 is pressed. 04017 */ 04018 XQueryPosition(display,windows->image.id,&x,&y); 04019 (void) XSelectInput(display,windows->image.id, 04020 windows->image.attributes.event_mask | PointerMotionMask); 04021 composite_info.x=(ssize_t) windows->image.x+x; 04022 composite_info.y=(ssize_t) windows->image.y+y; 04023 composite_info.width=0; 04024 composite_info.height=0; 04025 cursor=XCreateFontCursor(display,XC_ul_angle); 04026 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 04027 blend=0.0; 04028 state=DefaultState; 04029 do 04030 { 04031 if (windows->info.mapped != MagickFalse) 04032 { 04033 /* 04034 Display pointer position. 04035 */ 04036 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 04037 (long) composite_info.x,(long) composite_info.y); 04038 XInfoWidget(display,windows,text); 04039 } 04040 highlight_info=composite_info; 04041 highlight_info.x=composite_info.x-windows->image.x; 04042 highlight_info.y=composite_info.y-windows->image.y; 04043 XHighlightRectangle(display,windows->image.id, 04044 windows->image.highlight_context,&highlight_info); 04045 /* 04046 Wait for next event. 04047 */ 04048 XScreenEvent(display,windows,&event,exception); 04049 XHighlightRectangle(display,windows->image.id, 04050 windows->image.highlight_context,&highlight_info); 04051 if (event.xany.window == windows->command.id) 04052 { 04053 /* 04054 Select a command from the Command widget. 04055 */ 04056 id=XCommandWidget(display,windows,CompositeMenu,&event); 04057 if (id < 0) 04058 continue; 04059 switch (CompositeCommands[id]) 04060 { 04061 case CompositeOperatorsCommand: 04062 { 04063 char 04064 command[MaxTextExtent], 04065 **operators; 04066 04067 /* 04068 Select a command from the pop-up menu. 04069 */ 04070 operators=GetCommandOptions(MagickComposeOptions); 04071 if (operators == (char **) NULL) 04072 break; 04073 entry=XMenuWidget(display,windows,CompositeMenu[id], 04074 (const char **) operators,command); 04075 if (entry >= 0) 04076 compose=(CompositeOperator) ParseCommandOption( 04077 MagickComposeOptions,MagickFalse,operators[entry]); 04078 operators=DestroyStringList(operators); 04079 break; 04080 } 04081 case CompositeDissolveCommand: 04082 { 04083 static char 04084 factor[MaxTextExtent] = "20.0"; 04085 04086 /* 04087 Dissolve the two images a given percent. 04088 */ 04089 (void) XSetFunction(display,windows->image.highlight_context, 04090 GXcopy); 04091 (void) XDialogWidget(display,windows,"Dissolve", 04092 "Enter the blend factor (0.0 - 99.9%):",factor); 04093 (void) XSetFunction(display,windows->image.highlight_context, 04094 GXinvert); 04095 if (*factor == '\0') 04096 break; 04097 blend=StringToDouble(factor,(char **) NULL); 04098 compose=DissolveCompositeOp; 04099 break; 04100 } 04101 case CompositeDisplaceCommand: 04102 { 04103 /* 04104 Get horizontal and vertical scale displacement geometry. 04105 */ 04106 (void) XSetFunction(display,windows->image.highlight_context, 04107 GXcopy); 04108 (void) XDialogWidget(display,windows,"Displace", 04109 "Enter the horizontal and vertical scale:",displacement_geometry); 04110 (void) XSetFunction(display,windows->image.highlight_context, 04111 GXinvert); 04112 if (*displacement_geometry == '\0') 04113 break; 04114 compose=DisplaceCompositeOp; 04115 break; 04116 } 04117 case CompositeHelpCommand: 04118 { 04119 (void) XSetFunction(display,windows->image.highlight_context, 04120 GXcopy); 04121 XTextViewWidget(display,resource_info,windows,MagickFalse, 04122 "Help Viewer - Image Composite",ImageCompositeHelp); 04123 (void) XSetFunction(display,windows->image.highlight_context, 04124 GXinvert); 04125 break; 04126 } 04127 case CompositeDismissCommand: 04128 { 04129 /* 04130 Prematurely exit. 04131 */ 04132 state|=EscapeState; 04133 state|=ExitState; 04134 break; 04135 } 04136 default: 04137 break; 04138 } 04139 continue; 04140 } 04141 switch (event.type) 04142 { 04143 case ButtonPress: 04144 { 04145 if (image->debug != MagickFalse) 04146 (void) LogMagickEvent(X11Event,GetMagickModule(), 04147 "Button Press: 0x%lx %u +%d+%d",event.xbutton.window, 04148 event.xbutton.button,event.xbutton.x,event.xbutton.y); 04149 if (event.xbutton.button != Button1) 04150 break; 04151 if (event.xbutton.window != windows->image.id) 04152 break; 04153 /* 04154 Change cursor. 04155 */ 04156 composite_info.width=composite_image->columns; 04157 composite_info.height=composite_image->rows; 04158 (void) XCheckDefineCursor(display,windows->image.id,cursor); 04159 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 04160 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 04161 break; 04162 } 04163 case ButtonRelease: 04164 { 04165 if (image->debug != MagickFalse) 04166 (void) LogMagickEvent(X11Event,GetMagickModule(), 04167 "Button Release: 0x%lx %u +%d+%d",event.xbutton.window, 04168 event.xbutton.button,event.xbutton.x,event.xbutton.y); 04169 if (event.xbutton.button != Button1) 04170 break; 04171 if (event.xbutton.window != windows->image.id) 04172 break; 04173 if ((composite_info.width != 0) && (composite_info.height != 0)) 04174 { 04175 /* 04176 User has selected the location of the composite image. 04177 */ 04178 composite_info.x=(ssize_t) windows->image.x+event.xbutton.x; 04179 composite_info.y=(ssize_t) windows->image.y+event.xbutton.y; 04180 state|=ExitState; 04181 } 04182 break; 04183 } 04184 case Expose: 04185 break; 04186 case KeyPress: 04187 { 04188 char 04189 command[MaxTextExtent]; 04190 04191 KeySym 04192 key_symbol; 04193 04194 int 04195 length; 04196 04197 if (event.xkey.window != windows->image.id) 04198 break; 04199 /* 04200 Respond to a user key press. 04201 */ 04202 length=XLookupString((XKeyEvent *) &event.xkey,command,(int) 04203 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 04204 *(command+length)='\0'; 04205 if (image->debug != MagickFalse) 04206 (void) LogMagickEvent(X11Event,GetMagickModule(), 04207 "Key press: 0x%lx (%s)",(unsigned long) key_symbol,command); 04208 switch ((int) key_symbol) 04209 { 04210 case XK_Escape: 04211 case XK_F20: 04212 { 04213 /* 04214 Prematurely exit. 04215 */ 04216 composite_image=DestroyImage(composite_image); 04217 state|=EscapeState; 04218 state|=ExitState; 04219 break; 04220 } 04221 case XK_F1: 04222 case XK_Help: 04223 { 04224 (void) XSetFunction(display,windows->image.highlight_context, 04225 GXcopy); 04226 XTextViewWidget(display,resource_info,windows,MagickFalse, 04227 "Help Viewer - Image Composite",ImageCompositeHelp); 04228 (void) XSetFunction(display,windows->image.highlight_context, 04229 GXinvert); 04230 break; 04231 } 04232 default: 04233 { 04234 (void) XBell(display,0); 04235 break; 04236 } 04237 } 04238 break; 04239 } 04240 case MotionNotify: 04241 { 04242 /* 04243 Map and unmap Info widget as text cursor crosses its boundaries. 04244 */ 04245 x=event.xmotion.x; 04246 y=event.xmotion.y; 04247 if (windows->info.mapped != MagickFalse) 04248 { 04249 if ((x < (int) (windows->info.x+windows->info.width)) && 04250 (y < (int) (windows->info.y+windows->info.height))) 04251 (void) XWithdrawWindow(display,windows->info.id, 04252 windows->info.screen); 04253 } 04254 else 04255 if ((x > (int) (windows->info.x+windows->info.width)) || 04256 (y > (int) (windows->info.y+windows->info.height))) 04257 (void) XMapWindow(display,windows->info.id); 04258 composite_info.x=(ssize_t) windows->image.x+x; 04259 composite_info.y=(ssize_t) windows->image.y+y; 04260 break; 04261 } 04262 default: 04263 { 04264 if (image->debug != MagickFalse) 04265 (void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d", 04266 event.type); 04267 break; 04268 } 04269 } 04270 } while ((state & ExitState) == 0); 04271 (void) XSelectInput(display,windows->image.id, 04272 windows->image.attributes.event_mask); 04273 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 04274 XSetCursorState(display,windows,MagickFalse); 04275 (void) XFreeCursor(display,cursor); 04276 if ((state & EscapeState) != 0) 04277 return(MagickTrue); 04278 /* 04279 Image compositing is relative to image configuration. 04280 */ 04281 XSetCursorState(display,windows,MagickTrue); 04282 XCheckRefreshWindows(display,windows); 04283 width=(unsigned int) image->columns; 04284 height=(unsigned int) image->rows; 04285 x=0; 04286 y=0; 04287 if (windows->image.crop_geometry != (char *) NULL) 04288 (void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height); 04289 scale_factor=(MagickRealType) width/windows->image.ximage->width; 04290 composite_info.x+=x; 04291 composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5); 04292 composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5); 04293 scale_factor=(MagickRealType) height/windows->image.ximage->height; 04294 composite_info.y+=y; 04295 composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5); 04296 composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5); 04297 if ((composite_info.width != composite_image->columns) || 04298 (composite_info.height != composite_image->rows)) 04299 { 04300 Image 04301 *resize_image; 04302 04303 /* 04304 Scale composite image. 04305 */ 04306 resize_image=ResizeImage(composite_image,composite_info.width, 04307 composite_info.height,composite_image->filter,composite_image->blur, 04308 exception); 04309 composite_image=DestroyImage(composite_image); 04310 if (resize_image == (Image *) NULL) 04311 { 04312 XSetCursorState(display,windows,MagickFalse); 04313 return(MagickFalse); 04314 } 04315 composite_image=resize_image; 04316 } 04317 if (compose == DisplaceCompositeOp) 04318 (void) SetImageArtifact(composite_image,"compose:args", 04319 displacement_geometry); 04320 if (blend != 0.0) 04321 { 04322 CacheView 04323 *image_view; 04324 04325 int 04326 y; 04327 04328 Quantum 04329 opacity; 04330 04331 register int 04332 x; 04333 04334 register Quantum 04335 *q; 04336 04337 /* 04338 Create mattes for blending. 04339 */ 04340 (void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel,exception); 04341 opacity=(Quantum) (ScaleQuantumToChar((Quantum) QuantumRange)- 04342 ((ssize_t) ScaleQuantumToChar((Quantum) QuantumRange)*blend)/100); 04343 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse) 04344 return(MagickFalse); 04345 image->matte=MagickTrue; 04346 image_view=AcquireCacheView(image); 04347 for (y=0; y < (int) image->rows; y++) 04348 { 04349 q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1, 04350 exception); 04351 if (q == (Quantum *) NULL) 04352 break; 04353 for (x=0; x < (int) image->columns; x++) 04354 { 04355 SetPixelAlpha(image,opacity,q); 04356 q+=GetPixelChannels(image); 04357 } 04358 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) 04359 break; 04360 } 04361 image_view=DestroyCacheView(image_view); 04362 } 04363 /* 04364 Composite image with X Image window. 04365 */ 04366 (void) CompositeImage(image,compose,composite_image,composite_info.x, 04367 composite_info.y,exception); 04368 composite_image=DestroyImage(composite_image); 04369 XSetCursorState(display,windows,MagickFalse); 04370 /* 04371 Update image configuration. 04372 */ 04373 XConfigureImageColormap(display,resource_info,windows,image,exception); 04374 (void) XConfigureImage(display,resource_info,windows,image,exception); 04375 return(MagickTrue); 04376 } 04377 04378 /* 04379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 04380 % % 04381 % % 04382 % % 04383 + X C o n f i g u r e I m a g e % 04384 % % 04385 % % 04386 % % 04387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 04388 % 04389 % XConfigureImage() creates a new X image. It also notifies the window 04390 % manager of the new image size and configures the transient widows. 04391 % 04392 % The format of the XConfigureImage method is: 04393 % 04394 % MagickBooleanType XConfigureImage(Display *display, 04395 % XResourceInfo *resource_info,XWindows *windows,Image *image, 04396 % ExceptionInfo *exception) 04397 % 04398 % A description of each parameter follows: 04399 % 04400 % o display: Specifies a connection to an X server; returned from 04401 % XOpenDisplay. 04402 % 04403 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 04404 % 04405 % o windows: Specifies a pointer to a XWindows structure. 04406 % 04407 % o image: the image. 04408 % 04409 % o exception: return any errors or warnings in this structure. 04410 % 04411 % o exception: return any errors or warnings in this structure. 04412 % 04413 */ 04414 static MagickBooleanType XConfigureImage(Display *display, 04415 XResourceInfo *resource_info,XWindows *windows,Image *image, 04416 ExceptionInfo *exception) 04417 { 04418 char 04419 geometry[MaxTextExtent]; 04420 04421 MagickStatusType 04422 status; 04423 04424 size_t 04425 mask, 04426 height, 04427 width; 04428 04429 ssize_t 04430 x, 04431 y; 04432 04433 XSizeHints 04434 *size_hints; 04435 04436 XWindowChanges 04437 window_changes; 04438 04439 /* 04440 Dismiss if window dimensions are zero. 04441 */ 04442 width=(unsigned int) windows->image.window_changes.width; 04443 height=(unsigned int) windows->image.window_changes.height; 04444 if (image->debug != MagickFalse) 04445 (void) LogMagickEvent(X11Event,GetMagickModule(), 04446 "Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width, 04447 windows->image.ximage->height,(double) width,(double) height); 04448 if ((width*height) == 0) 04449 return(MagickTrue); 04450 x=0; 04451 y=0; 04452 /* 04453 Resize image to fit Image window dimensions. 04454 */ 04455 XSetCursorState(display,windows,MagickTrue); 04456 (void) XFlush(display); 04457 if (((int) width != windows->image.ximage->width) || 04458 ((int) height != windows->image.ximage->height)) 04459 image->taint=MagickTrue; 04460 windows->magnify.x=(int) 04461 width*windows->magnify.x/windows->image.ximage->width; 04462 windows->magnify.y=(int) 04463 height*windows->magnify.y/windows->image.ximage->height; 04464 windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width); 04465 windows->image.y=(int) 04466 (height*windows->image.y/windows->image.ximage->height); 04467 status=XMakeImage(display,resource_info,&windows->image,image, 04468 (unsigned int) width,(unsigned int) height,exception); 04469 if (status == MagickFalse) 04470 XNoticeWidget(display,windows,"Unable to configure X image:", 04471 windows->image.name); 04472 /* 04473 Notify window manager of the new configuration. 04474 */ 04475 if (resource_info->image_geometry != (char *) NULL) 04476 (void) FormatLocaleString(geometry,MaxTextExtent,"%s>!", 04477 resource_info->image_geometry); 04478 else 04479 (void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!", 04480 XDisplayWidth(display,windows->image.screen), 04481 XDisplayHeight(display,windows->image.screen)); 04482 (void) ParseMetaGeometry(geometry,&x,&y,&width,&height); 04483 window_changes.width=(int) width; 04484 if (window_changes.width > XDisplayWidth(display,windows->image.screen)) 04485 window_changes.width=XDisplayWidth(display,windows->image.screen); 04486 window_changes.height=(int) height; 04487 if (window_changes.height > XDisplayHeight(display,windows->image.screen)) 04488 window_changes.height=XDisplayHeight(display,windows->image.screen); 04489 mask=(size_t) (CWWidth | CWHeight); 04490 if (resource_info->backdrop) 04491 { 04492 mask|=CWX | CWY; 04493 window_changes.x=(int) 04494 ((XDisplayWidth(display,windows->image.screen)/2)-(width/2)); 04495 window_changes.y=(int) 04496 ((XDisplayHeight(display,windows->image.screen)/2)-(height/2)); 04497 } 04498 (void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen, 04499 (unsigned int) mask,&window_changes); 04500 (void) XClearWindow(display,windows->image.id); 04501 XRefreshWindow(display,&windows->image,(XEvent *) NULL); 04502 /* 04503 Update Magnify window configuration. 04504 */ 04505 if (windows->magnify.mapped != MagickFalse) 04506 XMakeMagnifyImage(display,windows,exception); 04507 windows->pan.crop_geometry=windows->image.crop_geometry; 04508 XBestIconSize(display,&windows->pan,image); 04509 while (((windows->pan.width << 1) < MaxIconSize) && 04510 ((windows->pan.height << 1) < MaxIconSize)) 04511 { 04512 windows->pan.width<<=1; 04513 windows->pan.height<<=1; 04514 } 04515 if (windows->pan.geometry != (char *) NULL) 04516 (void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y, 04517 &windows->pan.width,&windows->pan.height); 04518 window_changes.width=(int) windows->pan.width; 04519 window_changes.height=(int) windows->pan.height; 04520 size_hints=XAllocSizeHints(); 04521 if (size_hints != (XSizeHints *) NULL) 04522 { 04523 /* 04524 Set new size hints. 04525 */ 04526 size_hints->flags=PSize | PMinSize | PMaxSize; 04527 size_hints->width=window_changes.width; 04528 size_hints->height=window_changes.height; 04529 size_hints->min_width=size_hints->width; 04530 size_hints->min_height=size_hints->height; 04531 size_hints->max_width=size_hints->width; 04532 size_hints->max_height=size_hints->height; 04533 (void) XSetNormalHints(display,windows->pan.id,size_hints); 04534 (void) XFree((void *) size_hints); 04535 } 04536 (void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen, 04537 (unsigned int) (CWWidth | CWHeight),&window_changes); 04538 /* 04539 Update icon window configuration. 04540 */ 04541 windows->icon.crop_geometry=windows->image.crop_geometry; 04542 XBestIconSize(display,&windows->icon,image); 04543 window_changes.width=(int) windows->icon.width; 04544 window_changes.height=(int) windows->icon.height; 04545 (void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen, 04546 (unsigned int) (CWWidth | CWHeight),&window_changes); 04547 XSetCursorState(display,windows,MagickFalse); 04548 return(status != 0 ? MagickTrue : MagickFalse); 04549 } 04550 04551 /* 04552 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 04553 % % 04554 % % 04555 % % 04556 + X C r o p I m a g e % 04557 % % 04558 % % 04559 % % 04560 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 04561 % 04562 % XCropImage() allows the user to select a region of the image and crop, copy, 04563 % or cut it. For copy or cut, the image can subsequently be composited onto 04564 % the image with XPasteImage. 04565 % 04566 % The format of the XCropImage method is: 04567 % 04568 % MagickBooleanType XCropImage(Display *display, 04569 % XResourceInfo *resource_info,XWindows *windows,Image *image, 04570 % const ClipboardMode mode,ExceptionInfo *exception) 04571 % 04572 % A description of each parameter follows: 04573 % 04574 % o display: Specifies a connection to an X server; returned from 04575 % XOpenDisplay. 04576 % 04577 % o resource_info: Specifies a pointer to a X11 XResourceInfo structure. 04578 % 04579 % o windows: Specifies a pointer to a XWindows structure. 04580 % 04581 % o image: the image; returned from ReadImage. 04582 % 04583 % o mode: This unsigned value specified whether the image should be 04584 % cropped, copied, or cut. 04585 % 04586 % o exception: return any errors or warnings in this structure. 04587 % 04588 */ 04589 static MagickBooleanType XCropImage(Display *display, 04590 XResourceInfo *resource_info,XWindows *windows,Image *image, 04591 const ClipboardMode mode,ExceptionInfo *exception) 04592 { 04593 static const char 04594 *CropModeMenu[] = 04595 { 04596 "Help", 04597 "Dismiss", 04598 (char *) NULL 04599 }, 04600 *RectifyModeMenu[] = 04601 { 04602 "Crop", 04603 "Help", 04604 "Dismiss", 04605 (char *) NULL 04606 }; 04607 04608 static const ModeType 04609 CropCommands[] = 04610 { 04611 CropHelpCommand, 04612 CropDismissCommand 04613 }, 04614 RectifyCommands[] = 04615 { 04616 RectifyCopyCommand, 04617 RectifyHelpCommand, 04618 RectifyDismissCommand 04619 }; 04620 04621 CacheView 04622 *image_view; 04623 04624 char 04625 command[MaxTextExtent], 04626 text[MaxTextExtent]; 04627 04628 Cursor 04629 cursor; 04630 04631 int 04632 id, 04633 x, 04634 y; 04635 04636 KeySym 04637 key_symbol; 04638 04639 Image 04640 *crop_image; 04641 04642 MagickRealType 04643 scale_factor; 04644 04645 RectangleInfo 04646 crop_info, 04647 highlight_info; 04648 04649 register Quantum 04650 *q; 04651 04652 unsigned int 04653 height, 04654 width; 04655 04656 size_t 04657 state; 04658 04659 XEvent 04660 event; 04661 04662 /* 04663 Map Command widget. 04664 */ 04665 switch (mode) 04666 { 04667 case CopyMode: 04668 { 04669 (void) CloneString(&windows->command.name,"Copy"); 04670 break; 04671 } 04672 case CropMode: 04673 { 04674 (void) CloneString(&windows->command.name,"Crop"); 04675 break; 04676 } 04677 case CutMode: 04678 { 04679 (void) CloneString(&windows->command.name,"Cut"); 04680 break; 04681 } 04682 } 04683 RectifyModeMenu[0]=windows->command.name; 04684 windows->command.data=0; 04685 (void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL); 04686 (void) XMapRaised(display,windows->command.id); 04687 XClientMessage(display,windows->image.id,windows->im_protocols, 04688 windows->im_update_widget,CurrentTime); 04689 /* 04690 Track pointer until button 1 is pressed. 04691 */ 04692 XQueryPosition(display,windows->image.id,&x,&y); 04693 (void) XSelectInput(display,windows->image.id, 04694 windows->image.attributes.event_mask | PointerMotionMask); 04695 crop_info.x=(ssize_t) windows->image.x+x; 04696 crop_info.y=(ssize_t) windows->image.y+y; 04697 crop_info.width=0; 04698 crop_info.height=0; 04699 cursor=XCreateFontCursor(display,XC_fleur); 04700 state=DefaultState; 04701 do 04702 { 04703 if (windows->info.mapped != MagickFalse) 04704 { 04705 /* 04706 Display pointer position. 04707 */ 04708 (void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ", 04709 (long) crop_info.x,(long) crop_info.y); 04710 XInfoWidget(display,windows,text); 04711 } 04712 /* 04713 Wait for next event. 04714 */ 04715 XScreenEvent(display,windows,&event,exception); 04716 if (event.xany.window == windows->command.id) 04717 { 04718 /* 04719 Select a command from the Command widget. 04720 */ 04721 id=XCommandWidget(display,windows,CropModeMenu,&event); 04722 if (id < 0) 04723 continue; 04724 switch (CropCommands[id]) 04725 { 04726 case CropHelpCommand: 04727 { 04728 switch (mode) 04729 { 04730 case CopyMode: 04731 { 04732 XTextViewWidget(display,resource_info,windows,MagickFalse, 04733 "Help Viewer - Image Copy",ImageCopyHelp); 04734 break; 04735 } 04736 case CropMode: 04737 { 04738 XTextViewWidget(display,resource_info,windows,MagickFalse, 04739 "Help Viewer - Image Crop",ImageCropHelp); 04740 break; 04741 } 04742 case CutMode: 04743 { 04744 XTextViewWidget(display,resource_info,windows,MagickFalse, 04745 "Help Viewer - Image Cut",ImageCutHelp); 04746 break; 04747 } 04748 } 04749 break; 04750 } 04751 case CropDismissCommand: 04752 { 04753 /* 04754 Prematurely exit. 04755 */ 04756 state|=EscapeState; 04757 state|=ExitState; 04758 break; 04759 } 04760 default: 04761 break; 04762 } 04763 continue; 04764 } 04765 switch (event.type) 04766 { 04767 case ButtonPress: 04768 { 04769 if (event.xbutton.button != Button1) 04770 break; 04771 if (event.xbutton.window != windows->image.id) 04772 break; 04773 /* 04774 Note first corner of cropping rectangle-- exit loop. 04775 */ 04776 (void) XCheckDefineCursor(display,windows->image.id,cursor); 04777 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 04778 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 04779 state|=ExitState; 04780 break; 04781 } 04782 case ButtonRelease: 04783 break; 04784 case Expose: 04785 break; 04786 case KeyPress: 04787 { 04788 if (event.xkey.window != windows->image.id) 04789 break; 04790 /* 04791 Respond to a user key press. 04792 */ 04793 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 04794 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 04795 switch ((int) key_symbol) 04796 { 04797 case XK_Escape: 04798 case XK_F20: 04799 { 04800 /* 04801 Prematurely exit. 04802 */ 04803 state|=EscapeState; 04804 state|=ExitState; 04805 break; 04806 } 04807 case XK_F1: 04808 case XK_Help: 04809 { 04810 switch (mode) 04811 { 04812 case CopyMode: 04813 { 04814 XTextViewWidget(display,resource_info,windows,MagickFalse, 04815 "Help Viewer - Image Copy",ImageCopyHelp); 04816 break; 04817 } 04818 case CropMode: 04819 { 04820 XTextViewWidget(display,resource_info,windows,MagickFalse, 04821 "Help Viewer - Image Crop",ImageCropHelp); 04822 break; 04823 } 04824 case CutMode: 04825 { 04826 XTextViewWidget(display,resource_info,windows,MagickFalse, 04827 "Help Viewer - Image Cut",ImageCutHelp); 04828 break; 04829 } 04830 } 04831 break; 04832 } 04833 default: 04834 { 04835 (void) XBell(display,0); 04836 break; 04837 } 04838 } 04839 break; 04840 } 04841 case MotionNotify: 04842 { 04843 if (event.xmotion.window != windows->image.id) 04844 break; 04845 /* 04846 Map and unmap Info widget as text cursor crosses its boundaries. 04847 */ 04848 x=event.xmotion.x; 04849 y=event.xmotion.y; 04850 if (windows->info.mapped != MagickFalse) 04851 { 04852 if ((x < (int) (windows->info.x+windows->info.width)) && 04853 (y < (int) (windows->info.y+windows->info.height))) 04854 (void) XWithdrawWindow(display,windows->info.id, 04855 windows->info.screen); 04856 } 04857 else 04858 if ((x > (int) (windows->info.x+windows->info.width)) || 04859 (y > (int) (windows->info.y+windows->info.height))) 04860 (void) XMapWindow(display,windows->info.id); 04861 crop_info.x=(ssize_t) windows->image.x+x; 04862 crop_info.y=(ssize_t) windows->image.y+y; 04863 break; 04864 } 04865 default: 04866 break; 04867 } 04868 } while ((state & ExitState) == 0); 04869 (void) XSelectInput(display,windows->image.id, 04870 windows->image.attributes.event_mask); 04871 if ((state & EscapeState) != 0) 04872 { 04873 /* 04874 User want to exit without cropping. 04875 */ 04876 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 04877 (void) XFreeCursor(display,cursor); 04878 return(MagickTrue); 04879 } 04880 (void) XSetFunction(display,windows->image.highlight_context,GXinvert); 04881 do 04882 { 04883 /* 04884 Size rectangle as pointer moves until the mouse button is released. 04885 */ 04886 x=(int) crop_info.x; 04887 y=(int) crop_info.y; 04888 crop_info.width=0; 04889 crop_info.height=0; 04890 state=DefaultState; 04891 do 04892 { 04893 highlight_info=crop_info; 04894 highlight_info.x=crop_info.x-windows->image.x; 04895 highlight_info.y=crop_info.y-windows->image.y; 04896 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 04897 { 04898 /* 04899 Display info and draw cropping rectangle. 04900 */ 04901 if (windows->info.mapped == MagickFalse) 04902 (void) XMapWindow(display,windows->info.id); 04903 (void) FormatLocaleString(text,MaxTextExtent, 04904 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 04905 crop_info.height,(double) crop_info.x,(double) crop_info.y); 04906 XInfoWidget(display,windows,text); 04907 XHighlightRectangle(display,windows->image.id, 04908 windows->image.highlight_context,&highlight_info); 04909 } 04910 else 04911 if (windows->info.mapped != MagickFalse) 04912 (void) XWithdrawWindow(display,windows->info.id,windows->info.screen); 04913 /* 04914 Wait for next event. 04915 */ 04916 XScreenEvent(display,windows,&event,exception); 04917 if ((highlight_info.width > 3) && (highlight_info.height > 3)) 04918 XHighlightRectangle(display,windows->image.id, 04919 windows->image.highlight_context,&highlight_info); 04920 switch (event.type) 04921 { 04922 case ButtonPress: 04923 { 04924 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 04925 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 04926 break; 04927 } 04928 case ButtonRelease: 04929 { 04930 /* 04931 User has committed to cropping rectangle. 04932 */ 04933 crop_info.x=(ssize_t) windows->image.x+event.xbutton.x; 04934 crop_info.y=(ssize_t) windows->image.y+event.xbutton.y; 04935 XSetCursorState(display,windows,MagickFalse); 04936 state|=ExitState; 04937 windows->command.data=0; 04938 (void) XCommandWidget(display,windows,RectifyModeMenu, 04939 (XEvent *) NULL); 04940 break; 04941 } 04942 case Expose: 04943 break; 04944 case MotionNotify: 04945 { 04946 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 04947 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 04948 } 04949 default: 04950 break; 04951 } 04952 if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) || 04953 ((state & ExitState) != 0)) 04954 { 04955 /* 04956 Check boundary conditions. 04957 */ 04958 if (crop_info.x < 0) 04959 crop_info.x=0; 04960 else 04961 if (crop_info.x > (ssize_t) windows->image.ximage->width) 04962 crop_info.x=(ssize_t) windows->image.ximage->width; 04963 if ((int) crop_info.x < x) 04964 crop_info.width=(unsigned int) (x-crop_info.x); 04965 else 04966 { 04967 crop_info.width=(unsigned int) (crop_info.x-x); 04968 crop_info.x=(ssize_t) x; 04969 } 04970 if (crop_info.y < 0) 04971 crop_info.y=0; 04972 else 04973 if (crop_info.y > (ssize_t) windows->image.ximage->height) 04974 crop_info.y=(ssize_t) windows->image.ximage->height; 04975 if ((int) crop_info.y < y) 04976 crop_info.height=(unsigned int) (y-crop_info.y); 04977 else 04978 { 04979 crop_info.height=(unsigned int) (crop_info.y-y); 04980 crop_info.y=(ssize_t) y; 04981 } 04982 } 04983 } while ((state & ExitState) == 0); 04984 /* 04985 Wait for user to grab a corner of the rectangle or press return. 04986 */ 04987 state=DefaultState; 04988 (void) XMapWindow(display,windows->info.id); 04989 do 04990 { 04991 if (windows->info.mapped != MagickFalse) 04992 { 04993 /* 04994 Display pointer position. 04995 */ 04996 (void) FormatLocaleString(text,MaxTextExtent, 04997 " %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 04998 crop_info.height,(double) crop_info.x,(double) crop_info.y); 04999 XInfoWidget(display,windows,text); 05000 } 05001 highlight_info=crop_info; 05002 highlight_info.x=crop_info.x-windows->image.x; 05003 highlight_info.y=crop_info.y-windows->image.y; 05004 if ((highlight_info.width <= 3) || (highlight_info.height <= 3)) 05005 { 05006 state|=EscapeState; 05007 state|=ExitState; 05008 break; 05009 } 05010 XHighlightRectangle(display,windows->image.id, 05011 windows->image.highlight_context,&highlight_info); 05012 XScreenEvent(display,windows,&event,exception); 05013 if (event.xany.window == windows->command.id) 05014 { 05015 /* 05016 Select a command from the Command widget. 05017 */ 05018 (void) XSetFunction(display,windows->image.highlight_context,GXcopy); 05019 id=XCommandWidget(display,windows,RectifyModeMenu,&event); 05020 (void) XSetFunction(display,windows->image.highlight_context, 05021 GXinvert); 05022 XHighlightRectangle(display,windows->image.id, 05023 windows->image.highlight_context,&highlight_info); 05024 if (id >= 0) 05025 switch (RectifyCommands[id]) 05026 { 05027 case RectifyCopyCommand: 05028 { 05029 state|=ExitState; 05030 break; 05031 } 05032 case RectifyHelpCommand: 05033 { 05034 (void) XSetFunction(display,windows->image.highlight_context, 05035 GXcopy); 05036 switch (mode) 05037 { 05038 case CopyMode: 05039 { 05040 XTextViewWidget(display,resource_info,windows,MagickFalse, 05041 "Help Viewer - Image Copy",ImageCopyHelp); 05042 break; 05043 } 05044 case CropMode: 05045 { 05046 XTextViewWidget(display,resource_info,windows,MagickFalse, 05047 "Help Viewer - Image Crop",ImageCropHelp); 05048 break; 05049 } 05050 case CutMode: 05051 { 05052 XTextViewWidget(display,resource_info,windows,MagickFalse, 05053 "Help Viewer - Image Cut",ImageCutHelp); 05054 break; 05055 } 05056 } 05057 (void) XSetFunction(display,windows->image.highlight_context, 05058 GXinvert); 05059 break; 05060 } 05061 case RectifyDismissCommand: 05062 { 05063 /* 05064 Prematurely exit. 05065 */ 05066 state|=EscapeState; 05067 state|=ExitState; 05068 break; 05069 } 05070 default: 05071 break; 05072 } 05073 continue; 05074 } 05075 XHighlightRectangle(display,windows->image.id, 05076 windows->image.highlight_context,&highlight_info); 05077 switch (event.type) 05078 { 05079 case ButtonPress: 05080 { 05081 if (event.xbutton.button != Button1) 05082 break; 05083 if (event.xbutton.window != windows->image.id) 05084 break; 05085 x=windows->image.x+event.xbutton.x; 05086 y=windows->image.y+event.xbutton.y; 05087 if ((x < (int) (crop_info.x+RoiDelta)) && 05088 (x > (int) (crop_info.x-RoiDelta)) && 05089 (y < (int) (crop_info.y+RoiDelta)) && 05090 (y > (int) (crop_info.y-RoiDelta))) 05091 { 05092 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 05093 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 05094 state|=UpdateConfigurationState; 05095 break; 05096 } 05097 if ((x < (int) (crop_info.x+RoiDelta)) && 05098 (x > (int) (crop_info.x-RoiDelta)) && 05099 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 05100 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 05101 { 05102 crop_info.x=(ssize_t) (crop_info.x+crop_info.width); 05103 state|=UpdateConfigurationState; 05104 break; 05105 } 05106 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 05107 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 05108 (y < (int) (crop_info.y+RoiDelta)) && 05109 (y > (int) (crop_info.y-RoiDelta))) 05110 { 05111 crop_info.y=(ssize_t) (crop_info.y+crop_info.height); 05112 state|=UpdateConfigurationState; 05113 break; 05114 } 05115 if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) && 05116 (x > (int) (crop_info.x+crop_info.width-RoiDelta)) && 05117 (y < (int) (crop_info.y+crop_info.height+RoiDelta)) && 05118 (y > (int) (crop_info.y+crop_info.height-RoiDelta))) 05119 { 05120 state|=UpdateConfigurationState; 05121 break; 05122 } 05123 } 05124 case ButtonRelease: 05125 { 05126 if (event.xbutton.window == windows->pan.id) 05127 if ((highlight_info.x != crop_info.x-windows->image.x) || 05128 (highlight_info.y != crop_info.y-windows->image.y)) 05129 XHighlightRectangle(display,windows->image.id, 05130 windows->image.highlight_context,&highlight_info); 05131 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 05132 event.xbutton.time); 05133 break; 05134 } 05135 case Expose: 05136 { 05137 if (event.xexpose.window == windows->image.id) 05138 if (event.xexpose.count == 0) 05139 { 05140 event.xexpose.x=(int) highlight_info.x; 05141 event.xexpose.y=(int) highlight_info.y; 05142 event.xexpose.width=(int) highlight_info.width; 05143 event.xexpose.height=(int) highlight_info.height; 05144 XRefreshWindow(display,&windows->image,&event); 05145 } 05146 if (event.xexpose.window == windows->info.id) 05147 if (event.xexpose.count == 0) 05148 XInfoWidget(display,windows,text); 05149 break; 05150 } 05151 case KeyPress: 05152 { 05153 if (event.xkey.window != windows->image.id) 05154 break; 05155 /* 05156 Respond to a user key press. 05157 */ 05158 (void) XLookupString((XKeyEvent *) &event.xkey,command,(int) 05159 sizeof(command),&key_symbol,(XComposeStatus *) NULL); 05160 switch ((int) key_symbol) 05161 { 05162 case XK_Escape: 05163 case XK_F20: 05164 state|=EscapeState; 05165 case XK_Return: 05166 { 05167 state|=ExitState; 05168 break; 05169 } 05170 case XK_Home: 05171 case XK_KP_Home: 05172 { 05173 crop_info.x=(ssize_t) (windows->image.width/2L- 05174 crop_info.width/2L); 05175 crop_info.y=(ssize_t) (windows->image.height/2L- 05176 crop_info.height/2L); 05177 break; 05178 } 05179 case XK_Left: 05180 case XK_KP_Left: 05181 { 05182 crop_info.x--; 05183 break; 05184 } 05185 case XK_Up: 05186 case XK_KP_Up: 05187 case XK_Next: 05188 { 05189 crop_info.y--; 05190 break; 05191 } 05192 case XK_Right: 05193 case XK_KP_Right: 05194 { 05195 crop_info.x++; 05196 break; 05197 } 05198 case XK_Prior: 05199 case XK_Down: 05200 case XK_KP_Down: 05201 { 05202 crop_info.y++; 05203 break; 05204 } 05205 case XK_F1: 05206 case XK_Help: 05207 { 05208 (void) XSetFunction(display,windows->image.highlight_context, 05209 GXcopy); 05210 switch (mode) 05211 { 05212 case CopyMode: 05213 { 05214 XTextViewWidget(display,resource_info,windows,MagickFalse, 05215 "Help Viewer - Image Copy",ImageCopyHelp); 05216 break; 05217 } 05218 case CropMode: 05219 { 05220 XTextViewWidget(display,resource_info,windows,MagickFalse, 05221 "Help Viewer - Image Cropg",ImageCropHelp); 05222 break; 05223 } 05224 case CutMode: 05225 { 05226 XTextViewWidget(display,resource_info,windows,MagickFalse, 05227 "Help Viewer - Image Cutg",ImageCutHelp); 05228 break; 05229 } 05230 } 05231 (void) XSetFunction(display,windows->image.highlight_context, 05232 GXinvert); 05233 break; 05234 } 05235 default: 05236 { 05237 (void) XBell(display,0); 05238 break; 05239 } 05240 } 05241 (void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id, 05242 event.xkey.time); 05243 break; 05244 } 05245 case KeyRelease: 05246 break; 05247 case MotionNotify: 05248 { 05249 if (event.xmotion.window != windows->image.id) 05250 break; 05251 /* 05252 Map and unmap Info widget as text cursor crosses its boundaries. 05253 */ 05254 x=event.xmotion.x; 05255 y=event.xmotion.y; 05256 if (windows->info.mapped != MagickFalse) 05257 { 05258 if ((x < (int) (windows->info.x+windows->info.width)) && 05259 (y < (int) (windows->info.y+windows->info.height))) 05260 (void) XWithdrawWindow(display,windows->info.id, 05261 windows->info.screen); 05262 } 05263 else 05264 if ((x > (int) (windows->info.x+windows->info.width)) || 05265 (y > (int) (windows->info.y+windows->info.height))) 05266 (void) XMapWindow(display,windows->info.id); 05267 crop_info.x=(ssize_t) windows->image.x+event.xmotion.x; 05268 crop_info.y=(ssize_t) windows->image.y+event.xmotion.y; 05269 break; 05270 } 05271 case SelectionRequest: 05272 { 05273 XSelectionEvent 05274 notify; 05275 05276 XSelectionRequestEvent 05277 *request; 05278 05279 /* 05280 Set primary selection. 05281 */ 05282 (void) FormatLocaleString(text,MaxTextExtent, 05283 "%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double) 05284 crop_info.height,(double) crop_info.x,(double) crop_info.y); 05285 request=(&(event.xselectionrequest)); 05286 (void) XChangeProperty(request->display,request->requestor, 05287 request->property,request->target,8,PropModeReplace, 05288 (unsigned char *) text,(int) strlen(text)); 05289 notify.type=SelectionNotify; 05290 notify.display=request->display; 05291 notify.requestor=request->requestor; 05292 notify.selection=request->selection; 05293 notify.target=request->target; 05294 notify.time=request->time; 05295 if (request->property == None) 05296 notify.property=request->target; 05297 else 05298 notify.property=request->property; 05299 (void) XSendEvent(request->display,request->requestor,False,0, 05300 (XEvent *) &