16116 lines
507 KiB
C
16116 lines
507 KiB
C
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
% DDDD IIIII SSSSS PPPP L AAA Y Y %
|
||
% D D I SS P P L A A Y Y %
|
||
% D D I SSS PPPP L AAAAA Y %
|
||
% D D I SS P L A A Y %
|
||
% DDDD IIIII SSSSS P LLLLL A A Y %
|
||
% %
|
||
% %
|
||
% MagickCore Methods to Interactively Display and Edit an Image %
|
||
% %
|
||
% Software Design %
|
||
% John Cristy %
|
||
% July 1992 %
|
||
% %
|
||
% %
|
||
% Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization %
|
||
% dedicated to making software imaging solutions freely available. %
|
||
% %
|
||
% You may not use this file except in compliance with the License. You may %
|
||
% obtain a copy of the License at %
|
||
% %
|
||
% http://www.imagemagick.org/script/license.php %
|
||
% %
|
||
% Unless required by applicable law or agreed to in writing, software %
|
||
% distributed under the License is distributed on an "AS IS" BASIS, %
|
||
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
|
||
% See the License for the specific language governing permissions and %
|
||
% limitations under the License. %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
%
|
||
*/
|
||
|
||
/*
|
||
Include declarations.
|
||
*/
|
||
#include "magick/studio.h"
|
||
#include "magick/artifact.h"
|
||
#include "magick/attribute.h"
|
||
#include "magick/blob.h"
|
||
#include "magick/cache.h"
|
||
#include "magick/channel.h"
|
||
#include "magick/client.h"
|
||
#include "magick/color.h"
|
||
#include "magick/colorspace.h"
|
||
#include "magick/composite.h"
|
||
#include "magick/constitute.h"
|
||
#include "magick/decorate.h"
|
||
#include "magick/delegate.h"
|
||
#include "magick/display.h"
|
||
#include "magick/display-private.h"
|
||
#include "magick/distort.h"
|
||
#include "magick/draw.h"
|
||
#include "magick/effect.h"
|
||
#include "magick/enhance.h"
|
||
#include "magick/exception.h"
|
||
#include "magick/exception-private.h"
|
||
#include "magick/fx.h"
|
||
#include "magick/geometry.h"
|
||
#include "magick/image.h"
|
||
#include "magick/image-private.h"
|
||
#include "magick/list.h"
|
||
#include "magick/log.h"
|
||
#include "magick/magick.h"
|
||
#include "magick/memory_.h"
|
||
#include "magick/monitor.h"
|
||
#include "magick/monitor-private.h"
|
||
#include "magick/montage.h"
|
||
#include "magick/option.h"
|
||
#include "magick/paint.h"
|
||
#include "magick/pixel.h"
|
||
#include "magick/pixel-private.h"
|
||
#include "magick/PreRvIcccm.h"
|
||
#include "magick/property.h"
|
||
#include "magick/quantum.h"
|
||
#include "magick/resize.h"
|
||
#include "magick/resource_.h"
|
||
#include "magick/shear.h"
|
||
#include "magick/segment.h"
|
||
#include "magick/statistic.h"
|
||
#include "magick/string_.h"
|
||
#include "magick/string-private.h"
|
||
#include "magick/transform.h"
|
||
#include "magick/threshold.h"
|
||
#include "magick/utility.h"
|
||
#include "magick/utility-private.h"
|
||
#include "magick/version.h"
|
||
#include "magick/widget.h"
|
||
#include "magick/xwindow-private.h"
|
||
|
||
#if defined(MAGICKCORE_X11_DELEGATE)
|
||
/*
|
||
Define declarations.
|
||
*/
|
||
#define MaxColors MagickMin((ssize_t) windows->visual_info->colormap_size,256L)
|
||
|
||
/*
|
||
Constant declarations.
|
||
*/
|
||
static const unsigned char
|
||
HighlightBitmap[8] =
|
||
{
|
||
0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55
|
||
},
|
||
OpaqueBitmap[8] =
|
||
{
|
||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||
},
|
||
ShadowBitmap[8] =
|
||
{
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||
};
|
||
|
||
static const char
|
||
*PageSizes[] =
|
||
{
|
||
"Letter",
|
||
"Tabloid",
|
||
"Ledger",
|
||
"Legal",
|
||
"Statement",
|
||
"Executive",
|
||
"A3",
|
||
"A4",
|
||
"A5",
|
||
"B4",
|
||
"B5",
|
||
"Folio",
|
||
"Quarto",
|
||
"10x14",
|
||
(char *) NULL
|
||
};
|
||
|
||
/*
|
||
Help widget declarations.
|
||
*/
|
||
static const char
|
||
*ImageAnnotateHelp[] =
|
||
{
|
||
"In annotate mode, the Command widget has these options:",
|
||
"",
|
||
" Font Name",
|
||
" fixed",
|
||
" variable",
|
||
" 5x8",
|
||
" 6x10",
|
||
" 7x13bold",
|
||
" 8x13bold",
|
||
" 9x15bold",
|
||
" 10x20",
|
||
" 12x24",
|
||
" Browser...",
|
||
" Font Color",
|
||
" black",
|
||
" blue",
|
||
" cyan",
|
||
" green",
|
||
" gray",
|
||
" red",
|
||
" magenta",
|
||
" yellow",
|
||
" white",
|
||
" transparent",
|
||
" Browser...",
|
||
" Font Color",
|
||
" black",
|
||
" blue",
|
||
" cyan",
|
||
" green",
|
||
" gray",
|
||
" red",
|
||
" magenta",
|
||
" yellow",
|
||
" white",
|
||
" transparent",
|
||
" Browser...",
|
||
" Rotate Text",
|
||
" -90",
|
||
" -45",
|
||
" -30",
|
||
" 0",
|
||
" 30",
|
||
" 45",
|
||
" 90",
|
||
" 180",
|
||
" Dialog...",
|
||
" Help",
|
||
" Dismiss",
|
||
"",
|
||
"Choose a font name from the Font Name sub-menu. Additional",
|
||
"font names can be specified with the font browser. You can",
|
||
"change the menu names by setting the X resources font1",
|
||
"through font9.",
|
||
"",
|
||
"Choose a font color from the Font Color sub-menu.",
|
||
"Additional font colors can be specified with the color",
|
||
"browser. You can change the menu colors by setting the X",
|
||
"resources pen1 through pen9.",
|
||
"",
|
||
"If you select the color browser and press Grab, you can",
|
||
"choose the font color by moving the pointer to the desired",
|
||
"color on the screen and press any button.",
|
||
"",
|
||
"If you choose to rotate the text, choose Rotate Text from the",
|
||
"menu and select an angle. Typically you will only want to",
|
||
"rotate one line of text at a time. Depending on the angle you",
|
||
"choose, subsequent lines may end up overwriting each other.",
|
||
"",
|
||
"Choosing a font and its color is optional. The default font",
|
||
"is fixed and the default color is black. However, you must",
|
||
"choose a location to begin entering text and press button 1.",
|
||
"An underscore character will appear at the location of the",
|
||
"pointer. The cursor changes to a pencil to indicate you are",
|
||
"in text mode. To exit immediately, press Dismiss.",
|
||
"",
|
||
"In text mode, any key presses will display the character at",
|
||
"the location of the underscore and advance the underscore",
|
||
"cursor. Enter your text and once completed press Apply to",
|
||
"finish your image annotation. To correct errors press BACK",
|
||
"SPACE. To delete an entire line of text, press DELETE. Any",
|
||
"text that exceeds the boundaries of the image window is",
|
||
"automagically continued onto the next line.",
|
||
"",
|
||
"The actual color you request for the font is saved in the",
|
||
"image. However, the color that appears in your image window",
|
||
"may be different. For example, on a monochrome screen the",
|
||
"text will appear black or white even if you choose the color",
|
||
"red as the font color. However, the image saved to a file",
|
||
"with -write is written with red lettering. To assure the",
|
||
"correct color text in the final image, any PseudoClass image",
|
||
"is promoted to DirectClass (see miff(5)). To force a",
|
||
"PseudoClass image to remain PseudoClass, use -colors.",
|
||
(char *) NULL,
|
||
},
|
||
*ImageChopHelp[] =
|
||
{
|
||
"In chop mode, the Command widget has these options:",
|
||
"",
|
||
" Direction",
|
||
" horizontal",
|
||
" vertical",
|
||
" Help",
|
||
" Dismiss",
|
||
"",
|
||
"If the you choose the horizontal direction (this the",
|
||
"default), the area of the image between the two horizontal",
|
||
"endpoints of the chop line is removed. Otherwise, the area",
|
||
"of the image between the two vertical endpoints of the chop",
|
||
"line is removed.",
|
||
"",
|
||
"Select a location within the image window to begin your chop,",
|
||
"press and hold any button. Next, move the pointer to",
|
||
"another location in the image. As you move a line will",
|
||
"connect the initial location and the pointer. When you",
|
||
"release the button, the area within the image to chop is",
|
||
"determined by which direction you choose from the Command",
|
||
"widget.",
|
||
"",
|
||
"To cancel the image chopping, move the pointer back to the",
|
||
"starting point of the line and release the button.",
|
||
(char *) NULL,
|
||
},
|
||
*ImageColorEditHelp[] =
|
||
{
|
||
"In color edit mode, the Command widget has these options:",
|
||
"",
|
||
" Method",
|
||
" point",
|
||
" replace",
|
||
" floodfill",
|
||
" filltoborder",
|
||
" reset",
|
||
" Pixel Color",
|
||
" black",
|
||
" blue",
|
||
" cyan",
|
||
" green",
|
||
" gray",
|
||
" red",
|
||
" magenta",
|
||
" yellow",
|
||
" white",
|
||
" Browser...",
|
||
" Border Color",
|
||
" black",
|
||
" blue",
|
||
" cyan",
|
||
" green",
|
||
" gray",
|
||
" red",
|
||
" magenta",
|
||
" yellow",
|
||
" white",
|
||
" Browser...",
|
||
" Fuzz",
|
||
" 0%",
|
||
" 2%",
|
||
" 5%",
|
||
" 10%",
|
||
" 15%",
|
||
" Dialog...",
|
||
" Undo",
|
||
" Help",
|
||
" Dismiss",
|
||
"",
|
||
"Choose a color editing method from the Method sub-menu",
|
||
"of the Command widget. The point method recolors any pixel",
|
||
"selected with the pointer until the button is released. The",
|
||
"replace method recolors any pixel that matches the color of",
|
||
"the pixel you select with a button press. Floodfill recolors",
|
||
"any pixel that matches the color of the pixel you select with",
|
||
"a button press and is a neighbor. Whereas filltoborder recolors",
|
||
"any neighbor pixel that is not the border color. Finally reset",
|
||
"changes the entire image to the designated color.",
|
||
"",
|
||
"Next, choose a pixel color from the Pixel Color sub-menu.",
|
||
"Additional pixel colors can be specified with the color",
|
||
"browser. You can change the menu colors by setting the X",
|
||
"resources pen1 through pen9.",
|
||
"",
|
||
"Now press button 1 to select a pixel within the image window",
|
||
"to change its color. Additional pixels may be recolored as",
|
||
"prescribed by the method you choose.",
|
||
"",
|
||
"If the Magnify widget is mapped, it can be helpful in positioning",
|
||
"your pointer within the image (refer to button 2).",
|
||
"",
|
||
"The actual color you request for the pixels is saved in the",
|
||
"image. However, the color that appears in your image window",
|
||
"may be different. For example, on a monochrome screen the",
|
||
"pixel will appear black or white even if you choose the",
|
||
"color red as the pixel color. However, the image saved to a",
|
||
"file with -write is written with red pixels. To assure the",
|
||
"correct color text in the final image, any PseudoClass image",
|
||
"is promoted to DirectClass (see miff(5)). To force a",
|
||
"PseudoClass image to remain PseudoClass, use -colors.",
|
||
(char *) NULL,
|
||
},
|
||
*ImageCompositeHelp[] =
|
||
{
|
||
"First a widget window is displayed requesting you to enter an",
|
||
"image name. Press Composite, Grab or type a file name.",
|
||
"Press Cancel if you choose not to create a composite image.",
|
||
"When you choose Grab, move the pointer to the desired window",
|
||
"and press any button.",
|
||
"",
|
||
"If the Composite image does not have any matte information,",
|
||
"you are informed and the file browser is displayed again.",
|
||
"Enter the name of a mask image. The image is typically",
|
||
"grayscale and the same size as the composite image. If the",
|
||
"image is not grayscale, it is converted to grayscale and the",
|
||
"resulting intensities are used as matte information.",
|
||
"",
|
||
"A small window appears showing the location of the cursor in",
|
||
"the image window. You are now in composite mode. To exit",
|
||
"immediately, press Dismiss. In composite mode, the Command",
|
||
"widget has these options:",
|
||
"",
|
||
" Operators",
|
||
" Over",
|
||
" In",
|
||
" Out",
|
||
" Atop",
|
||
" Xor",
|
||
" Plus",
|
||
" Minus",
|
||
" Add",
|
||
" Subtract",
|
||
" Difference",
|
||
" Multiply",
|
||
" Bumpmap",
|
||
" Copy",
|
||
" CopyRed",
|
||
" CopyGreen",
|
||
" CopyBlue",
|
||
" CopyOpacity",
|
||
" Clear",
|
||
" Dissolve",
|
||
" Displace",
|
||
" Help",
|
||
" Dismiss",
|
||
"",
|
||
"Choose a composite operation from the Operators sub-menu of",
|
||
"the Command widget. How each operator behaves is described",
|
||
"below. Image window is the image currently displayed on",
|
||
"your X server and image is the image obtained with the File",
|
||
"Browser widget.",
|
||
"",
|
||
"Over The result is the union of the two image shapes,",
|
||
" with image obscuring image window in the region of",
|
||
" overlap.",
|
||
"",
|
||
"In The result is simply image cut by the shape of",
|
||
" image window. None of the image data of image",
|
||
" window is in the result.",
|
||
"",
|
||
"Out The resulting image is image with the shape of",
|
||
" image window cut out.",
|
||
"",
|
||
"Atop The result is the same shape as image image window,",
|
||
" with image obscuring image window where the image",
|
||
" shapes overlap. Note this differs from over",
|
||
" because the portion of image outside image window's",
|
||
" shape does not appear in the result.",
|
||
"",
|
||
"Xor The result is the image data from both image and",
|
||
" image window that is outside the overlap region.",
|
||
" The overlap region is blank.",
|
||
"",
|
||
"Plus The result is just the sum of the image data.",
|
||
" Output values are cropped to QuantumRange (no overflow).",
|
||
"",
|
||
"Minus The result of image - image window, with underflow",
|
||
" cropped to zero.",
|
||
"",
|
||
"Add The result of image + image window, with overflow",
|
||
" wrapping around (mod 256).",
|
||
"",
|
||
"Subtract The result of image - image window, with underflow",
|
||
" wrapping around (mod 256). The add and subtract",
|
||
" operators can be used to perform reversible",
|
||
" transformations.",
|
||
"",
|
||
"Difference",
|
||
" The result of abs(image - image window). This",
|
||
" useful for comparing two very similar images.",
|
||
"",
|
||
"Multiply",
|
||
" The result of image * image window. This",
|
||
" useful for the creation of drop-shadows.",
|
||
"",
|
||
"Bumpmap The result of surface normals from image * image",
|
||
" window.",
|
||
"",
|
||
"Copy The resulting image is image window replaced with",
|
||
" image. Here the matte information is ignored.",
|
||
"",
|
||
"CopyRed The red layer of the image window is replace with",
|
||
" the red layer of the image. The other layers are",
|
||
" untouched.",
|
||
"",
|
||
"CopyGreen",
|
||
" The green layer of the image window is replace with",
|
||
" the green layer of the image. The other layers are",
|
||
" untouched.",
|
||
"",
|
||
"CopyBlue The blue layer of the image window is replace with",
|
||
" the blue layer of the image. The other layers are",
|
||
" untouched.",
|
||
"",
|
||
"CopyOpacity",
|
||
" The matte layer of the image window is replace with",
|
||
" the matte layer of the image. The other layers are",
|
||
" untouched.",
|
||
"",
|
||
"The image compositor requires a matte, or alpha channel in",
|
||
"the image for some operations. This extra channel usually",
|
||
"defines a mask which represents a sort of a cookie-cutter",
|
||
"for the image. This the case when matte is opaque (full",
|
||
"coverage) for pixels inside the shape, zero outside, and",
|
||
"between 0 and QuantumRange on the boundary. If image does not",
|
||
"have a matte channel, it is initialized with 0 for any pixel",
|
||
"matching in color to pixel location (0,0), otherwise QuantumRange.",
|
||
"",
|
||
"If you choose Dissolve, the composite operator becomes Over. The",
|
||
"image matte channel percent transparency is initialized to factor.",
|
||
"The image window is initialized to (100-factor). Where factor is the",
|
||
"value you specify in the Dialog widget.",
|
||
"",
|
||
"Displace shifts the image pixels as defined by a displacement",
|
||
"map. With this option, image is used as a displacement map.",
|
||
"Black, within the displacement map, is a maximum positive",
|
||
"displacement. White is a maximum negative displacement and",
|
||
"middle gray is neutral. The displacement is scaled to determine",
|
||
"the pixel shift. By default, the displacement applies in both the",
|
||
"horizontal and vertical directions. However, if you specify a mask,",
|
||
"image is the horizontal X displacement and mask the vertical Y",
|
||
"displacement.",
|
||
"",
|
||
"Note that matte information for image window is not retained",
|
||
"for colormapped X server visuals (e.g. StaticColor,",
|
||
"StaticColor, GrayScale, PseudoColor). Correct compositing",
|
||
"behavior may require a TrueColor or DirectColor visual or a",
|
||
"Standard Colormap.",
|
||
"",
|
||
"Choosing a composite operator is optional. The default",
|
||
"operator is replace. However, you must choose a location to",
|
||
"composite your image and press button 1. Press and hold the",
|
||
"button before releasing and an outline of the image will",
|
||
"appear to help you identify your location.",
|
||
"",
|
||
"The actual colors of the composite image is saved. However,",
|
||
"the color that appears in image window may be different.",
|
||
"For example, on a monochrome screen image window will appear",
|
||
"black or white even though your composited image may have",
|
||
"many colors. If the image is saved to a file it is written",
|
||
"with the correct colors. To assure the correct colors are",
|
||
"saved in the final image, any PseudoClass image is promoted",
|
||
"to DirectClass (see miff(5)). To force a PseudoClass image",
|
||
"to remain PseudoClass, use -colors.",
|
||
(char *) NULL,
|
||
},
|
||
*ImageCutHelp[] =
|
||
{
|
||
"In cut mode, the Command widget has these options:",
|
||
"",
|
||
" Help",
|
||
" Dismiss",
|
||
"",
|
||
"To define a cut region, press button 1 and drag. The",
|
||
"cut region is defined by a highlighted rectangle that",
|
||
"expands or contracts as it follows the pointer. Once you",
|
||
"are satisfied with the cut region, release the button.",
|
||
"You are now in rectify mode. In rectify mode, the Command",
|
||
"widget has these options:",
|
||
"",
|
||
" Cut",
|
||
" Help",
|
||
" Dismiss",
|
||
"",
|
||
"You can make adjustments by moving the pointer to one of the",
|
||
"cut rectangle corners, pressing a button, and dragging.",
|
||
"Finally, press Cut to commit your copy region. To",
|
||
"exit without cutting the image, press Dismiss.",
|
||
(char *) NULL,
|
||
},
|
||
*ImageCopyHelp[] =
|
||
{
|
||
"In copy mode, the Command widget has these options:",
|
||
"",
|
||
" Help",
|
||
" Dismiss",
|
||
"",
|
||
"To define a copy region, press button 1 and drag. The",
|
||
"copy region is defined by a highlighted rectangle that",
|
||
"expands or contracts as it follows the pointer. Once you",
|
||
"are satisfied with the copy region, release the button.",
|
||
"You are now in rectify mode. In rectify mode, the Command",
|
||
"widget has these options:",
|
||
"",
|
||
" Copy",
|
||
" Help",
|
||
" Dismiss",
|
||
"",
|
||
"You can make adjustments by moving the pointer to one of the",
|
||
"copy rectangle corners, pressing a button, and dragging.",
|
||
"Finally, press Copy to commit your copy region. To",
|
||
"exit without copying the image, press Dismiss.",
|
||
(char *) NULL,
|
||
},
|
||
*ImageCropHelp[] =
|
||
{
|
||
"In crop mode, the Command widget has these options:",
|
||
"",
|
||
" Help",
|
||
" Dismiss",
|
||
"",
|
||
"To define a cropping region, press button 1 and drag. The",
|
||
"cropping region is defined by a highlighted rectangle that",
|
||
"expands or contracts as it follows the pointer. Once you",
|
||
"are satisfied with the cropping region, release the button.",
|
||
"You are now in rectify mode. In rectify mode, the Command",
|
||
"widget has these options:",
|
||
"",
|
||
" Crop",
|
||
" Help",
|
||
" Dismiss",
|
||
"",
|
||
"You can make adjustments by moving the pointer to one of the",
|
||
"cropping rectangle corners, pressing a button, and dragging.",
|
||
"Finally, press Crop to commit your cropping region. To",
|
||
"exit without cropping the image, press Dismiss.",
|
||
(char *) NULL,
|
||
},
|
||
*ImageDrawHelp[] =
|
||
{
|
||
"The cursor changes to a crosshair to indicate you are in",
|
||
"draw mode. To exit immediately, press Dismiss. In draw mode,",
|
||
"the Command widget has these options:",
|
||
"",
|
||
" Element",
|
||
" point",
|
||
" line",
|
||
" rectangle",
|
||
" fill rectangle",
|
||
" circle",
|
||
" fill circle",
|
||
" ellipse",
|
||
" fill ellipse",
|
||
" polygon",
|
||
" fill polygon",
|
||
" Color",
|
||
" black",
|
||
" blue",
|
||
" cyan",
|
||
" green",
|
||
" gray",
|
||
" red",
|
||
" magenta",
|
||
" yellow",
|
||
" white",
|
||
" transparent",
|
||
" Browser...",
|
||
" Stipple",
|
||
" Brick",
|
||
" Diagonal",
|
||
" Scales",
|
||
" Vertical",
|
||
" Wavy",
|
||
" Translucent",
|
||
" Opaque",
|
||
" Open...",
|
||
" Width",
|
||
" 1",
|
||
" 2",
|
||
" 4",
|
||
" 8",
|
||
" 16",
|
||
" Dialog...",
|
||
" Undo",
|
||
" Help",
|
||
" Dismiss",
|
||
"",
|
||
"Choose a drawing primitive from the Element sub-menu.",
|
||
"",
|
||
"Choose a color from the Color sub-menu. Additional",
|
||
"colors can be specified with the color browser.",
|
||
"",
|
||
"If you choose the color browser and press Grab, you can",
|
||
"select the color by moving the pointer to the desired",
|
||
"color on the screen and press any button. The transparent",
|
||
"color updates the image matte channel and is useful for",
|
||
"image compositing.",
|
||
"",
|
||
"Choose a stipple, if appropriate, from the Stipple sub-menu.",
|
||
"Additional stipples can be specified with the file browser.",
|
||
"Stipples obtained from the file browser must be on disk in the",
|
||
"X11 bitmap format.",
|
||
"",
|
||
"Choose a width, if appropriate, from the Width sub-menu. To",
|
||
"choose a specific width select the Dialog widget.",
|
||
"",
|
||
"Choose a point in the Image window and press button 1 and",
|
||
"hold. Next, move the pointer to another location in the",
|
||
"image. As you move, a line connects the initial location and",
|
||
"the pointer. When you release the button, the image is",
|
||
"updated with the primitive you just drew. For polygons, the",
|
||
"image is updated when you press and release the button without",
|
||
"moving the pointer.",
|
||
"",
|
||
"To cancel image drawing, move the pointer back to the",
|
||
"starting point of the line and release the button.",
|
||
(char *) NULL,
|
||
},
|
||
*DisplayHelp[] =
|
||
{
|
||
"BUTTONS",
|
||
" The effects of each button press is described below. Three",
|
||
" buttons are required. If you have a two button mouse,",
|
||
" button 1 and 3 are returned. Press ALT and button 3 to",
|
||
" simulate button 2.",
|
||
"",
|
||
" 1 Press this button to map or unmap the Command widget.",
|
||
"",
|
||
" 2 Press and drag to define a region of the image to",
|
||
" magnify.",
|
||
"",
|
||
" 3 Press and drag to choose from a select set of commands.",
|
||
" This button behaves differently if the image being",
|
||
" displayed is a visual image directory. Here, choose a",
|
||
" particular tile of the directory and press this button and",
|
||
" drag to select a command from a pop-up menu. Choose from",
|
||
" these menu items:",
|
||
"",
|
||
" Open",
|
||
" Next",
|
||
" Former",
|
||
" Delete",
|
||
" Update",
|
||
"",
|
||
" If you choose Open, the image represented by the tile is",
|
||
" displayed. To return to the visual image directory, choose",
|
||
" Next from the Command widget. Next and Former moves to the",
|
||
" next or former image respectively. Choose Delete to delete",
|
||
" a particular image tile. Finally, choose Update to",
|
||
" synchronize all the image tiles with their respective",
|
||
" images.",
|
||
"",
|
||
"COMMAND WIDGET",
|
||
" The Command widget lists a number of sub-menus and commands.",
|
||
" They are",
|
||
"",
|
||
" File",
|
||
" Open...",
|
||
" Next",
|
||
" Former",
|
||
" Select...",
|
||
" Save...",
|
||
" Print...",
|
||
" Delete...",
|
||
" New...",
|
||
" Visual Directory...",
|
||
" Quit",
|
||
" Edit",
|
||
" Undo",
|
||
" Redo",
|
||
" Cut",
|
||
" Copy",
|
||
" Paste",
|
||
" View",
|
||
" Half Size",
|
||
" Original Size",
|
||
" Double Size",
|
||
" Resize...",
|
||
" Apply",
|
||
" Refresh",
|
||
" Restore",
|
||
" Transform",
|
||
" Crop",
|
||
" Chop",
|
||
" Flop",
|
||
" Flip",
|
||
" Rotate Right",
|
||
" Rotate Left",
|
||
" Rotate...",
|
||
" Shear...",
|
||
" Roll...",
|
||
" Trim Edges",
|
||
" Enhance",
|
||
" Brightness...",
|
||
" Saturation...",
|
||
" Hue...",
|
||
" Gamma...",
|
||
" Sharpen...",
|
||
" Dull",
|
||
" Contrast Stretch...",
|
||
" Sigmoidal Contrast...",
|
||
" Normalize",
|
||
" Equalize",
|
||
" Negate",
|
||
" Grayscale",
|
||
" Map...",
|
||
" Quantize...",
|
||
" Effects",
|
||
" Despeckle",
|
||
" Emboss",
|
||
" Reduce Noise",
|
||
" Add Noise",
|
||
" Sharpen...",
|
||
" Blur...",
|
||
" Threshold...",
|
||
" Edge Detect...",
|
||
" Spread...",
|
||
" Shade...",
|
||
" Painting...",
|
||
" Segment...",
|
||
" F/X",
|
||
" Solarize...",
|
||
" Sepia Tone...",
|
||
" Swirl...",
|
||
" Implode...",
|
||
" Vignette...",
|
||
" Wave...",
|
||
" Oil Painting...",
|
||
" Charcoal Drawing...",
|
||
" Image Edit",
|
||
" Annotate...",
|
||
" Draw...",
|
||
" Color...",
|
||
" Matte...",
|
||
" Composite...",
|
||
" Add Border...",
|
||
" Add Frame...",
|
||
" Comment...",
|
||
" Launch...",
|
||
" Region of Interest...",
|
||
" Miscellany",
|
||
" Image Info",
|
||
" Zoom Image",
|
||
" Show Preview...",
|
||
" Show Histogram",
|
||
" Show Matte",
|
||
" Background...",
|
||
" Slide Show",
|
||
" Preferences...",
|
||
" Help",
|
||
" Overview",
|
||
" Browse Documentation",
|
||
" About Display",
|
||
"",
|
||
" Menu items with a indented triangle have a sub-menu. They",
|
||
" are represented above as the indented items. To access a",
|
||
" sub-menu item, move the pointer to the appropriate menu and",
|
||
" press a button and drag. When you find the desired sub-menu",
|
||
" item, release the button and the command is executed. Move",
|
||
" the pointer away from the sub-menu if you decide not to",
|
||
" execute a particular command.",
|
||
"",
|
||
"KEYBOARD ACCELERATORS",
|
||
" Accelerators are one or two key presses that effect a",
|
||
" particular command. The keyboard accelerators that",
|
||
" display(1) understands is:",
|
||
"",
|
||
" Ctl+O Press to open an image from a file.",
|
||
"",
|
||
" space Press to display the next image.",
|
||
"",
|
||
" If the image is a multi-paged document such as a Postscript",
|
||
" document, you can skip ahead several pages by preceding",
|
||
" this command with a number. For example to display the",
|
||
" third page beyond the current page, press 3<space>.",
|
||
"",
|
||
" backspace Press to display the former image.",
|
||
"",
|
||
" If the image is a multi-paged document such as a Postscript",
|
||
" document, you can skip behind several pages by preceding",
|
||
" this command with a number. For example to display the",
|
||
" third page preceding the current page, press 3<backspace>.",
|
||
"",
|
||
" Ctl+S Press to write the image to a file.",
|
||
"",
|
||
" Ctl+P Press to print the image to a Postscript printer.",
|
||
"",
|
||
" Ctl+D Press to delete an image file.",
|
||
"",
|
||
" Ctl+N Press to create a blank canvas.",
|
||
"",
|
||
" Ctl+Q Press to discard all images and exit program.",
|
||
"",
|
||
" Ctl+Z Press to undo last image transformation.",
|
||
"",
|
||
" Ctl+R Press to redo last image transformation.",
|
||
"",
|
||
" Ctl+X Press to cut a region of the image.",
|
||
"",
|
||
" Ctl+C Press to copy a region of the image.",
|
||
"",
|
||
" Ctl+V Press to paste a region to the image.",
|
||
"",
|
||
" < Press to half the image size.",
|
||
"",
|
||
" - Press to return to the original image size.",
|
||
"",
|
||
" > Press to double the image size.",
|
||
"",
|
||
" % Press to resize the image to a width and height you",
|
||
" specify.",
|
||
"",
|
||
"Cmd-A Press to make any image transformations permanent."
|
||
"",
|
||
" By default, any image size transformations are applied",
|
||
" to the original image to create the image displayed on",
|
||
" the X server. However, the transformations are not",
|
||
" permanent (i.e. the original image does not change",
|
||
" size only the X image does). For example, if you",
|
||
" press > the X image will appear to double in size,",
|
||
" but the original image will in fact remain the same size.",
|
||
" To force the original image to double in size, press >",
|
||
" followed by Cmd-A.",
|
||
"",
|
||
" @ Press to refresh the image window.",
|
||
"",
|
||
" C Press to cut out a rectangular region of the image.",
|
||
"",
|
||
" [ Press to chop the image.",
|
||
"",
|
||
" H Press to flop image in the horizontal direction.",
|
||
"",
|
||
" V Press to flip image in the vertical direction.",
|
||
"",
|
||
" / Press to rotate the image 90 degrees clockwise.",
|
||
"",
|
||
" \\ Press to rotate the image 90 degrees counter-clockwise.",
|
||
"",
|
||
" * Press to rotate the image the number of degrees you",
|
||
" specify.",
|
||
"",
|
||
" S Press to shear the image the number of degrees you",
|
||
" specify.",
|
||
"",
|
||
" R Press to roll the image.",
|
||
"",
|
||
" T Press to trim the image edges.",
|
||
"",
|
||
" Shft-H Press to vary the image hue.",
|
||
"",
|
||
" Shft-S Press to vary the color saturation.",
|
||
"",
|
||
" Shft-L Press to vary the color brightness.",
|
||
"",
|
||
" Shft-G Press to gamma correct the image.",
|
||
"",
|
||
" Shft-C Press to sharpen the image contrast.",
|
||
"",
|
||
" Shft-Z Press to dull the image contrast.",
|
||
"",
|
||
" = Press to perform histogram equalization on the image.",
|
||
"",
|
||
" Shft-N Press to perform histogram normalization on the image.",
|
||
"",
|
||
" Shft-~ Press to negate the colors of the image.",
|
||
"",
|
||
" . Press to convert the image colors to gray.",
|
||
"",
|
||
" Shft-# Press to set the maximum number of unique colors in the",
|
||
" image.",
|
||
"",
|
||
" F2 Press to reduce the speckles in an image.",
|
||
"",
|
||
" F3 Press to eliminate peak noise from an image.",
|
||
"",
|
||
" F4 Press to add noise to an image.",
|
||
"",
|
||
" F5 Press to sharpen an image.",
|
||
"",
|
||
" F6 Press to delete an image file.",
|
||
"",
|
||
" F7 Press to threshold the image.",
|
||
"",
|
||
" F8 Press to detect edges within an image.",
|
||
"",
|
||
" F9 Press to emboss an image.",
|
||
"",
|
||
" F10 Press to displace pixels by a random amount.",
|
||
"",
|
||
" F11 Press to negate all pixels above the threshold level.",
|
||
"",
|
||
" F12 Press to shade the image using a distant light source.",
|
||
"",
|
||
" F13 Press to lighten or darken image edges to create a 3-D effect.",
|
||
"",
|
||
" F14 Press to segment the image by color.",
|
||
"",
|
||
" Meta-S Press to swirl image pixels about the center.",
|
||
"",
|
||
" Meta-I Press to implode image pixels about the center.",
|
||
"",
|
||
" Meta-W Press to alter an image along a sine wave.",
|
||
"",
|
||
" Meta-P Press to simulate an oil painting.",
|
||
"",
|
||
" Meta-C Press to simulate a charcoal drawing.",
|
||
"",
|
||
" Alt-A Press to annotate the image with text.",
|
||
"",
|
||
" Alt-D Press to draw on an image.",
|
||
"",
|
||
" Alt-P Press to edit an image pixel color.",
|
||
"",
|
||
" Alt-M Press to edit the image matte information.",
|
||
"",
|
||
" Alt-V Press to composite the image with another.",
|
||
"",
|
||
" Alt-B Press to add a border to the image.",
|
||
"",
|
||
" Alt-F Press to add an ornamental border to the image.",
|
||
"",
|
||
" Alt-Shft-!",
|
||
" Press to add an image comment.",
|
||
"",
|
||
" Ctl-A Press to apply image processing techniques to a region",
|
||
" of interest.",
|
||
"",
|
||
" Shft-? Press to display information about the image.",
|
||
"",
|
||
" Shft-+ Press to map the zoom image window.",
|
||
"",
|
||
" Shft-P Press to preview an image enhancement, effect, or f/x.",
|
||
"",
|
||
" F1 Press to display helpful information about display(1).",
|
||
"",
|
||
" Find Press to browse documentation about ImageMagick.",
|
||
"",
|
||
" 1-9 Press to change the level of magnification.",
|
||
"",
|
||
" Use the arrow keys to move the image one pixel up, down,",
|
||
" left, or right within the magnify window. Be sure to first",
|
||
" map the magnify window by pressing button 2.",
|
||
"",
|
||
" Press ALT and one of the arrow keys to trim off one pixel",
|
||
" from any side of the image.",
|
||
(char *) NULL,
|
||
},
|
||
*ImageMatteEditHelp[] =
|
||
{
|
||
"Matte information within an image is useful for some",
|
||
"operations such as image compositing (See IMAGE",
|
||
"COMPOSITING). This extra channel usually defines a mask",
|
||
"which represents a sort of a cookie-cutter for the image.",
|
||
"This the case when matte is opaque (full coverage) for",
|
||
"pixels inside the shape, zero outside, and between 0 and",
|
||
"QuantumRange on the boundary.",
|
||
"",
|
||
"A small window appears showing the location of the cursor in",
|
||
"the image window. You are now in matte edit mode. To exit",
|
||
"immediately, press Dismiss. In matte edit mode, the Command",
|
||
"widget has these options:",
|
||
"",
|
||
" Method",
|
||
" point",
|
||
" replace",
|
||
" floodfill",
|
||
" filltoborder",
|
||
" reset",
|
||
" Border Color",
|
||
" black",
|
||
" blue",
|
||
" cyan",
|
||
" green",
|
||
" gray",
|
||
" red",
|
||
" magenta",
|
||
" yellow",
|
||
" white",
|
||
" Browser...",
|
||
" Fuzz",
|
||
" 0%",
|
||
" 2%",
|
||
" 5%",
|
||
" 10%",
|
||
" 15%",
|
||
" Dialog...",
|
||
" Matte",
|
||
" Opaque",
|
||
" Transparent",
|
||
" Dialog...",
|
||
" Undo",
|
||
" Help",
|
||
" Dismiss",
|
||
"",
|
||
"Choose a matte editing method from the Method sub-menu of",
|
||
"the Command widget. The point method changes the matte value",
|
||
"of any pixel selected with the pointer until the button is",
|
||
"is released. The replace method changes the matte value of",
|
||
"any pixel that matches the color of the pixel you select with",
|
||
"a button press. Floodfill changes the matte value of any pixel",
|
||
"that matches the color of the pixel you select with a button",
|
||
"press and is a neighbor. Whereas filltoborder changes the matte",
|
||
"value any neighbor pixel that is not the border color. Finally",
|
||
"reset changes the entire image to the designated matte value.",
|
||
"",
|
||
"Choose Matte Value and pick Opaque or Transarent. For other values",
|
||
"select the Dialog entry. Here a dialog appears requesting a matte",
|
||
"value. The value you select is assigned as the opacity value of the",
|
||
"selected pixel or pixels.",
|
||
"",
|
||
"Now, press any button to select a pixel within the image",
|
||
"window to change its matte value.",
|
||
"",
|
||
"If the Magnify widget is mapped, it can be helpful in positioning",
|
||
"your pointer within the image (refer to button 2).",
|
||
"",
|
||
"Matte information is only valid in a DirectClass image.",
|
||
"Therefore, any PseudoClass image is promoted to DirectClass",
|
||
"(see miff(5)). Note that matte information for PseudoClass",
|
||
"is not retained for colormapped X server visuals (e.g.",
|
||
"StaticColor, StaticColor, GrayScale, PseudoColor) unless you",
|
||
"immediately save your image to a file (refer to Write).",
|
||
"Correct matte editing behavior may require a TrueColor or",
|
||
"DirectColor visual or a Standard Colormap.",
|
||
(char *) NULL,
|
||
},
|
||
*ImagePanHelp[] =
|
||
{
|
||
"When an image exceeds the width or height of the X server",
|
||
"screen, display maps a small panning icon. The rectangle",
|
||
"within the panning icon shows the area that is currently",
|
||
"displayed in the image window. To pan about the image,",
|
||
"press any button and drag the pointer within the panning",
|
||
"icon. The pan rectangle moves with the pointer and the",
|
||
"image window is updated to reflect the location of the",
|
||
"rectangle within the panning icon. When you have selected",
|
||
"the area of the image you wish to view, release the button.",
|
||
"",
|
||
"Use the arrow keys to pan the image one pixel up, down,",
|
||
"left, or right within the image window.",
|
||
"",
|
||
"The panning icon is withdrawn if the image becomes smaller",
|
||
"than the dimensions of the X server screen.",
|
||
(char *) NULL,
|
||
},
|
||
*ImagePasteHelp[] =
|
||
{
|
||
"A small window appears showing the location of the cursor in",
|
||
"the image window. You are now in paste mode. To exit",
|
||
"immediately, press Dismiss. In paste mode, the Command",
|
||
"widget has these options:",
|
||
"",
|
||
" Operators",
|
||
" over",
|
||
" in",
|
||
" out",
|
||
" atop",
|
||
" xor",
|
||
" plus",
|
||
" minus",
|
||
" add",
|
||
" subtract",
|
||
" difference",
|
||
" replace",
|
||
" Help",
|
||
" Dismiss",
|
||
"",
|
||
"Choose a composite operation from the Operators sub-menu of",
|
||
"the Command widget. How each operator behaves is described",
|
||
"below. Image window is the image currently displayed on",
|
||
"your X server and image is the image obtained with the File",
|
||
"Browser widget.",
|
||
"",
|
||
"Over The result is the union of the two image shapes,",
|
||
" with image obscuring image window in the region of",
|
||
" overlap.",
|
||
"",
|
||
"In The result is simply image cut by the shape of",
|
||
" image window. None of the image data of image",
|
||
" window is in the result.",
|
||
"",
|
||
"Out The resulting image is image with the shape of",
|
||
" image window cut out.",
|
||
"",
|
||
"Atop The result is the same shape as image image window,",
|
||
" with image obscuring image window where the image",
|
||
" shapes overlap. Note this differs from over",
|
||
" because the portion of image outside image window's",
|
||
" shape does not appear in the result.",
|
||
"",
|
||
"Xor The result is the image data from both image and",
|
||
" image window that is outside the overlap region.",
|
||
" The overlap region is blank.",
|
||
"",
|
||
"Plus The result is just the sum of the image data.",
|
||
" Output values are cropped to QuantumRange (no overflow).",
|
||
" This operation is independent of the matte",
|
||
" channels.",
|
||
"",
|
||
"Minus The result of image - image window, with underflow",
|
||
" cropped to zero.",
|
||
"",
|
||
"Add The result of image + image window, with overflow",
|
||
" wrapping around (mod 256).",
|
||
"",
|
||
"Subtract The result of image - image window, with underflow",
|
||
" wrapping around (mod 256). The add and subtract",
|
||
" operators can be used to perform reversible",
|
||
" transformations.",
|
||
"",
|
||
"Difference",
|
||
" The result of abs(image - image window). This",
|
||
" useful for comparing two very similar images.",
|
||
"",
|
||
"Copy The resulting image is image window replaced with",
|
||
" image. Here the matte information is ignored.",
|
||
"",
|
||
"CopyRed The red layer of the image window is replace with",
|
||
" the red layer of the image. The other layers are",
|
||
" untouched.",
|
||
"",
|
||
"CopyGreen",
|
||
" The green layer of the image window is replace with",
|
||
" the green layer of the image. The other layers are",
|
||
" untouched.",
|
||
"",
|
||
"CopyBlue The blue layer of the image window is replace with",
|
||
" the blue layer of the image. The other layers are",
|
||
" untouched.",
|
||
"",
|
||
"CopyOpacity",
|
||
" The matte layer of the image window is replace with",
|
||
" the matte layer of the image. The other layers are",
|
||
" untouched.",
|
||
"",
|
||
"The image compositor requires a matte, or alpha channel in",
|
||
"the image for some operations. This extra channel usually",
|
||
"defines a mask which represents a sort of a cookie-cutter",
|
||
"for the image. This the case when matte is opaque (full",
|
||
"coverage) for pixels inside the shape, zero outside, and",
|
||
"between 0 and QuantumRange on the boundary. If image does not",
|
||
"have a matte channel, it is initialized with 0 for any pixel",
|
||
"matching in color to pixel location (0,0), otherwise QuantumRange.",
|
||
"",
|
||
"Note that matte information for image window is not retained",
|
||
"for colormapped X server visuals (e.g. StaticColor,",
|
||
"StaticColor, GrayScale, PseudoColor). Correct compositing",
|
||
"behavior may require a TrueColor or DirectColor visual or a",
|
||
"Standard Colormap.",
|
||
"",
|
||
"Choosing a composite operator is optional. The default",
|
||
"operator is replace. However, you must choose a location to",
|
||
"paste your image and press button 1. Press and hold the",
|
||
"button before releasing and an outline of the image will",
|
||
"appear to help you identify your location.",
|
||
"",
|
||
"The actual colors of the pasted image is saved. However,",
|
||
"the color that appears in image window may be different.",
|
||
"For example, on a monochrome screen image window will appear",
|
||
"black or white even though your pasted image may have",
|
||
"many colors. If the image is saved to a file it is written",
|
||
"with the correct colors. To assure the correct colors are",
|
||
"saved in the final image, any PseudoClass image is promoted",
|
||
"to DirectClass (see miff(5)). To force a PseudoClass image",
|
||
"to remain PseudoClass, use -colors.",
|
||
(char *) NULL,
|
||
},
|
||
*ImageROIHelp[] =
|
||
{
|
||
"In region of interest mode, the Command widget has these",
|
||
"options:",
|
||
"",
|
||
" Help",
|
||
" Dismiss",
|
||
"",
|
||
"To define a region of interest, press button 1 and drag.",
|
||
"The region of interest is defined by a highlighted rectangle",
|
||
"that expands or contracts as it follows the pointer. Once",
|
||
"you are satisfied with the region of interest, release the",
|
||
"button. You are now in apply mode. In apply mode the",
|
||
"Command widget has these options:",
|
||
"",
|
||
" File",
|
||
" Save...",
|
||
" Print...",
|
||
" Edit",
|
||
" Undo",
|
||
" Redo",
|
||
" Transform",
|
||
" Flop",
|
||
" Flip",
|
||
" Rotate Right",
|
||
" Rotate Left",
|
||
" Enhance",
|
||
" Hue...",
|
||
" Saturation...",
|
||
" Brightness...",
|
||
" Gamma...",
|
||
" Spiff",
|
||
" Dull",
|
||
" Contrast Stretch",
|
||
" Sigmoidal Contrast...",
|
||
" Normalize",
|
||
" Equalize",
|
||
" Negate",
|
||
" Grayscale",
|
||
" Map...",
|
||
" Quantize...",
|
||
" Effects",
|
||
" Despeckle",
|
||
" Emboss",
|
||
" Reduce Noise",
|
||
" Sharpen...",
|
||
" Blur...",
|
||
" Threshold...",
|
||
" Edge Detect...",
|
||
" Spread...",
|
||
" Shade...",
|
||
" Raise...",
|
||
" Segment...",
|
||
" F/X",
|
||
" Solarize...",
|
||
" Sepia Tone...",
|
||
" Swirl...",
|
||
" Implode...",
|
||
" Vignette...",
|
||
" Wave...",
|
||
" Oil Painting...",
|
||
" Charcoal Drawing...",
|
||
" Miscellany",
|
||
" Image Info",
|
||
" Zoom Image",
|
||
" Show Preview...",
|
||
" Show Histogram",
|
||
" Show Matte",
|
||
" Help",
|
||
" Dismiss",
|
||
"",
|
||
"You can make adjustments to the region of interest by moving",
|
||
"the pointer to one of the rectangle corners, pressing a",
|
||
"button, and dragging. Finally, choose an image processing",
|
||
"technique from the Command widget. You can choose more than",
|
||
"one image processing technique to apply to an area.",
|
||
"Alternatively, you can move the region of interest before",
|
||
"applying another image processing technique. To exit, press",
|
||
"Dismiss.",
|
||
(char *) NULL,
|
||
},
|
||
*ImageRotateHelp[] =
|
||
{
|
||
"In rotate mode, the Command widget has these options:",
|
||
"",
|
||
" Pixel Color",
|
||
" black",
|
||
" blue",
|
||
" cyan",
|
||
" green",
|
||
" gray",
|
||
" red",
|
||
" magenta",
|
||
" yellow",
|
||
" white",
|
||
" Browser...",
|
||
" Direction",
|
||
" horizontal",
|
||
" vertical",
|
||
" Help",
|
||
" Dismiss",
|
||
"",
|
||
"Choose a background color from the Pixel Color sub-menu.",
|
||
"Additional background colors can be specified with the color",
|
||
"browser. You can change the menu colors by setting the X",
|
||
"resources pen1 through pen9.",
|
||
"",
|
||
"If you choose the color browser and press Grab, you can",
|
||
"select the background color by moving the pointer to the",
|
||
"desired color on the screen and press any button.",
|
||
"",
|
||
"Choose a point in the image window and press this button and",
|
||
"hold. Next, move the pointer to another location in the",
|
||
"image. As you move a line connects the initial location and",
|
||
"the pointer. When you release the button, the degree of",
|
||
"image rotation is determined by the slope of the line you",
|
||
"just drew. The slope is relative to the direction you",
|
||
"choose from the Direction sub-menu of the Command widget.",
|
||
"",
|
||
"To cancel the image rotation, move the pointer back to the",
|
||
"starting point of the line and release the button.",
|
||
(char *) NULL,
|
||
};
|
||
|
||
/*
|
||
Enumeration declarations.
|
||
*/
|
||
typedef enum
|
||
{
|
||
CopyMode,
|
||
CropMode,
|
||
CutMode
|
||
} ClipboardMode;
|
||
|
||
typedef enum
|
||
{
|
||
OpenCommand,
|
||
NextCommand,
|
||
FormerCommand,
|
||
SelectCommand,
|
||
SaveCommand,
|
||
PrintCommand,
|
||
DeleteCommand,
|
||
NewCommand,
|
||
VisualDirectoryCommand,
|
||
QuitCommand,
|
||
UndoCommand,
|
||
RedoCommand,
|
||
CutCommand,
|
||
CopyCommand,
|
||
PasteCommand,
|
||
HalfSizeCommand,
|
||
OriginalSizeCommand,
|
||
DoubleSizeCommand,
|
||
ResizeCommand,
|
||
ApplyCommand,
|
||
RefreshCommand,
|
||
RestoreCommand,
|
||
CropCommand,
|
||
ChopCommand,
|
||
FlopCommand,
|
||
FlipCommand,
|
||
RotateRightCommand,
|
||
RotateLeftCommand,
|
||
RotateCommand,
|
||
ShearCommand,
|
||
RollCommand,
|
||
TrimCommand,
|
||
HueCommand,
|
||
SaturationCommand,
|
||
BrightnessCommand,
|
||
GammaCommand,
|
||
SpiffCommand,
|
||
DullCommand,
|
||
ContrastStretchCommand,
|
||
SigmoidalContrastCommand,
|
||
NormalizeCommand,
|
||
EqualizeCommand,
|
||
NegateCommand,
|
||
GrayscaleCommand,
|
||
MapCommand,
|
||
QuantizeCommand,
|
||
DespeckleCommand,
|
||
EmbossCommand,
|
||
ReduceNoiseCommand,
|
||
AddNoiseCommand,
|
||
SharpenCommand,
|
||
BlurCommand,
|
||
ThresholdCommand,
|
||
EdgeDetectCommand,
|
||
SpreadCommand,
|
||
ShadeCommand,
|
||
RaiseCommand,
|
||
SegmentCommand,
|
||
SolarizeCommand,
|
||
SepiaToneCommand,
|
||
SwirlCommand,
|
||
ImplodeCommand,
|
||
VignetteCommand,
|
||
WaveCommand,
|
||
OilPaintCommand,
|
||
CharcoalDrawCommand,
|
||
AnnotateCommand,
|
||
DrawCommand,
|
||
ColorCommand,
|
||
MatteCommand,
|
||
CompositeCommand,
|
||
AddBorderCommand,
|
||
AddFrameCommand,
|
||
CommentCommand,
|
||
LaunchCommand,
|
||
RegionofInterestCommand,
|
||
ROIHelpCommand,
|
||
ROIDismissCommand,
|
||
InfoCommand,
|
||
ZoomCommand,
|
||
ShowPreviewCommand,
|
||
ShowHistogramCommand,
|
||
ShowMatteCommand,
|
||
BackgroundCommand,
|
||
SlideShowCommand,
|
||
PreferencesCommand,
|
||
HelpCommand,
|
||
BrowseDocumentationCommand,
|
||
VersionCommand,
|
||
SaveToUndoBufferCommand,
|
||
FreeBuffersCommand,
|
||
NullCommand
|
||
} CommandType;
|
||
|
||
typedef enum
|
||
{
|
||
AnnotateNameCommand,
|
||
AnnotateFontColorCommand,
|
||
AnnotateBackgroundColorCommand,
|
||
AnnotateRotateCommand,
|
||
AnnotateHelpCommand,
|
||
AnnotateDismissCommand,
|
||
TextHelpCommand,
|
||
TextApplyCommand,
|
||
ChopDirectionCommand,
|
||
ChopHelpCommand,
|
||
ChopDismissCommand,
|
||
HorizontalChopCommand,
|
||
VerticalChopCommand,
|
||
ColorEditMethodCommand,
|
||
ColorEditColorCommand,
|
||
ColorEditBorderCommand,
|
||
ColorEditFuzzCommand,
|
||
ColorEditUndoCommand,
|
||
ColorEditHelpCommand,
|
||
ColorEditDismissCommand,
|
||
CompositeOperatorsCommand,
|
||
CompositeDissolveCommand,
|
||
CompositeDisplaceCommand,
|
||
CompositeHelpCommand,
|
||
CompositeDismissCommand,
|
||
CropHelpCommand,
|
||
CropDismissCommand,
|
||
RectifyCopyCommand,
|
||
RectifyHelpCommand,
|
||
RectifyDismissCommand,
|
||
DrawElementCommand,
|
||
DrawColorCommand,
|
||
DrawStippleCommand,
|
||
DrawWidthCommand,
|
||
DrawUndoCommand,
|
||
DrawHelpCommand,
|
||
DrawDismissCommand,
|
||
MatteEditMethod,
|
||
MatteEditBorderCommand,
|
||
MatteEditFuzzCommand,
|
||
MatteEditValueCommand,
|
||
MatteEditUndoCommand,
|
||
MatteEditHelpCommand,
|
||
MatteEditDismissCommand,
|
||
PasteOperatorsCommand,
|
||
PasteHelpCommand,
|
||
PasteDismissCommand,
|
||
RotateColorCommand,
|
||
RotateDirectionCommand,
|
||
RotateCropCommand,
|
||
RotateSharpenCommand,
|
||
RotateHelpCommand,
|
||
RotateDismissCommand,
|
||
HorizontalRotateCommand,
|
||
VerticalRotateCommand,
|
||
TileLoadCommand,
|
||
TileNextCommand,
|
||
TileFormerCommand,
|
||
TileDeleteCommand,
|
||
TileUpdateCommand
|
||
} ModeType;
|
||
|
||
/*
|
||
Stipples.
|
||
*/
|
||
#define BricksWidth 20
|
||
#define BricksHeight 20
|
||
#define DiagonalWidth 16
|
||
#define DiagonalHeight 16
|
||
#define HighlightWidth 8
|
||
#define HighlightHeight 8
|
||
#define OpaqueWidth 8
|
||
#define OpaqueHeight 8
|
||
#define ScalesWidth 16
|
||
#define ScalesHeight 16
|
||
#define ShadowWidth 8
|
||
#define ShadowHeight 8
|
||
#define VerticalWidth 16
|
||
#define VerticalHeight 16
|
||
#define WavyWidth 16
|
||
#define WavyHeight 16
|
||
|
||
/*
|
||
Constant declaration.
|
||
*/
|
||
static const int
|
||
RoiDelta = 8;
|
||
|
||
static const unsigned char
|
||
BricksBitmap[] =
|
||
{
|
||
0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00,
|
||
0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01,
|
||
0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0xff, 0xff, 0x0f, 0x03, 0x0c, 0x00,
|
||
0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0x03, 0x0c, 0x00, 0xff, 0xff, 0x0f,
|
||
0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01, 0x60, 0x80, 0x01
|
||
},
|
||
DiagonalBitmap[] =
|
||
{
|
||
0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88,
|
||
0x11, 0x11, 0x22, 0x22, 0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22,
|
||
0x44, 0x44, 0x88, 0x88, 0x11, 0x11, 0x22, 0x22
|
||
},
|
||
ScalesBitmap[] =
|
||
{
|
||
0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3, 0x80, 0x80, 0x80, 0x80,
|
||
0x41, 0x41, 0x3e, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0xe3, 0xe3,
|
||
0x80, 0x80, 0x80, 0x80, 0x41, 0x41, 0x3e, 0x3e
|
||
},
|
||
VerticalBitmap[] =
|
||
{
|
||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
|
||
},
|
||
WavyBitmap[] =
|
||
{
|
||
0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfb, 0xff,
|
||
0xe7, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0xff, 0xe7, 0xff, 0xdf, 0xff, 0xbf,
|
||
0xff, 0xbf, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f
|
||
};
|
||
|
||
/*
|
||
Function prototypes.
|
||
*/
|
||
static CommandType
|
||
XImageWindowCommand(Display *,XResourceInfo *,XWindows *,
|
||
const MagickStatusType,KeySym,Image **);
|
||
|
||
static Image
|
||
*XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
|
||
Image **),
|
||
*XOpenImage(Display *,XResourceInfo *,XWindows *,const MagickBooleanType),
|
||
*XTileImage(Display *,XResourceInfo *,XWindows *,Image *,XEvent *),
|
||
*XVisualDirectoryImage(Display *,XResourceInfo *,XWindows *);
|
||
|
||
static MagickBooleanType
|
||
XAnnotateEditImage(Display *,XResourceInfo *,XWindows *,Image *),
|
||
XDrawEditImage(Display *,XResourceInfo *,XWindows *,Image **),
|
||
XChopImage(Display *,XResourceInfo *,XWindows *,Image **),
|
||
XCropImage(Display *,XResourceInfo *,XWindows *,Image *,const ClipboardMode),
|
||
XBackgroundImage(Display *,XResourceInfo *,XWindows *,Image **),
|
||
XColorEditImage(Display *,XResourceInfo *,XWindows *,Image **),
|
||
XCompositeImage(Display *,XResourceInfo *,XWindows *,Image *),
|
||
XConfigureImage(Display *,XResourceInfo *,XWindows *,Image *),
|
||
XMatteEditImage(Display *,XResourceInfo *,XWindows *,Image **),
|
||
XPasteImage(Display *,XResourceInfo *,XWindows *,Image *),
|
||
XPrintImage(Display *,XResourceInfo *,XWindows *,Image *),
|
||
XRotateImage(Display *,XResourceInfo *,XWindows *,double,Image **),
|
||
XROIImage(Display *,XResourceInfo *,XWindows *,Image **),
|
||
XSaveImage(Display *,XResourceInfo *,XWindows *,Image *),
|
||
XTrimImage(Display *,XResourceInfo *,XWindows *,Image *);
|
||
|
||
static void
|
||
XDrawPanRectangle(Display *,XWindows *),
|
||
XImageCache(Display *,XResourceInfo *,XWindows *,const CommandType,Image **),
|
||
XMagnifyImage(Display *,XWindows *,XEvent *),
|
||
XMakePanImage(Display *,XResourceInfo *,XWindows *,Image *),
|
||
XPanImage(Display *,XWindows *,XEvent *),
|
||
XMagnifyWindowCommand(Display *,XWindows *,const MagickStatusType,
|
||
const KeySym),
|
||
XSetCropGeometry(Display *,XWindows *,RectangleInfo *,Image *),
|
||
XScreenEvent(Display *,XWindows *,XEvent *),
|
||
XTranslateImage(Display *,XWindows *,Image *,const KeySym);
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
% D i s p l a y I m a g e s %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% DisplayImages() displays an image sequence to any X window screen. It
|
||
% returns a value other than 0 if successful. Check the exception member
|
||
% of image to determine the reason for any failure.
|
||
%
|
||
% The format of the DisplayImages method is:
|
||
%
|
||
% MagickBooleanType DisplayImages(const ImageInfo *image_info,
|
||
% Image *images)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o image_info: the image info.
|
||
%
|
||
% o image: the image.
|
||
%
|
||
*/
|
||
MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
|
||
Image *images)
|
||
{
|
||
char
|
||
*argv[1];
|
||
|
||
Display
|
||
*display;
|
||
|
||
Image
|
||
*image;
|
||
|
||
register ssize_t
|
||
i;
|
||
|
||
size_t
|
||
state;
|
||
|
||
XrmDatabase
|
||
resource_database;
|
||
|
||
XResourceInfo
|
||
resource_info;
|
||
|
||
assert(image_info != (const ImageInfo *) NULL);
|
||
assert(image_info->signature == MagickSignature);
|
||
assert(images != (Image *) NULL);
|
||
assert(images->signature == MagickSignature);
|
||
if (images->debug != MagickFalse)
|
||
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
|
||
display=XOpenDisplay(image_info->server_name);
|
||
if (display == (Display *) NULL)
|
||
{
|
||
(void) ThrowMagickException(&images->exception,GetMagickModule(),
|
||
XServerError,"UnableToOpenXServer","`%s'",XDisplayName(
|
||
image_info->server_name));
|
||
return(MagickFalse);
|
||
}
|
||
if (images->exception.severity != UndefinedException)
|
||
CatchException(&images->exception);
|
||
(void) XSetErrorHandler(XError);
|
||
resource_database=XGetResourceDatabase(display,GetClientName());
|
||
(void) ResetMagickMemory(&resource_info,0,sizeof(resource_info));
|
||
XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
|
||
if (image_info->page != (char *) NULL)
|
||
resource_info.image_geometry=AcquireString(image_info->page);
|
||
resource_info.immutable=MagickTrue;
|
||
argv[0]=AcquireString(GetClientName());
|
||
state=DefaultState;
|
||
for (i=0; (state & ExitState) == 0; i++)
|
||
{
|
||
if ((images->iterations != 0) && (i >= (ssize_t) images->iterations))
|
||
break;
|
||
image=GetImageFromList(images,i % GetImageListLength(images));
|
||
(void) XDisplayImage(display,&resource_info,argv,1,&image,&state);
|
||
}
|
||
(void) SetErrorHandler((ErrorHandler) NULL);
|
||
(void) SetWarningHandler((WarningHandler) NULL);
|
||
argv[0]=DestroyString(argv[0]);
|
||
(void) XCloseDisplay(display);
|
||
XDestroyResourceInfo(&resource_info);
|
||
if (images->exception.severity != UndefinedException)
|
||
return(MagickFalse);
|
||
return(MagickTrue);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
% R e m o t e D i s p l a y C o m m a n d %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% RemoteDisplayCommand() encourages a remote display program to display the
|
||
% specified image filename.
|
||
%
|
||
% The format of the RemoteDisplayCommand method is:
|
||
%
|
||
% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
|
||
% const char *window,const char *filename,ExceptionInfo *exception)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o image_info: the image info.
|
||
%
|
||
% o window: Specifies the name or id of an X window.
|
||
%
|
||
% o filename: the name of the image filename to display.
|
||
%
|
||
% o exception: return any errors or warnings in this structure.
|
||
%
|
||
*/
|
||
MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
|
||
const char *window,const char *filename,ExceptionInfo *exception)
|
||
{
|
||
Display
|
||
*display;
|
||
|
||
MagickStatusType
|
||
status;
|
||
|
||
assert(image_info != (const ImageInfo *) NULL);
|
||
assert(image_info->signature == MagickSignature);
|
||
assert(filename != (char *) NULL);
|
||
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
|
||
display=XOpenDisplay(image_info->server_name);
|
||
if (display == (Display *) NULL)
|
||
{
|
||
(void) ThrowMagickException(exception,GetMagickModule(),XServerError,
|
||
"UnableToOpenXServer","`%s'",XDisplayName(image_info->server_name));
|
||
return(MagickFalse);
|
||
}
|
||
(void) XSetErrorHandler(XError);
|
||
status=XRemoteCommand(display,window,filename);
|
||
(void) XCloseDisplay(display);
|
||
return(status != 0 ? MagickTrue : MagickFalse);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X A n n o t a t e E d i t I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XAnnotateEditImage() annotates the image with text.
|
||
%
|
||
% The format of the XAnnotateEditImage method is:
|
||
%
|
||
% MagickBooleanType XAnnotateEditImage(Display *display,
|
||
% XResourceInfo *resource_info,XWindows *windows,Image *image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image; returned from ReadImage.
|
||
%
|
||
*/
|
||
|
||
static inline ssize_t MagickMax(const ssize_t x,const ssize_t y)
|
||
{
|
||
if (x > y)
|
||
return(x);
|
||
return(y);
|
||
}
|
||
|
||
static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
|
||
{
|
||
if (x < y)
|
||
return(x);
|
||
return(y);
|
||
}
|
||
|
||
static MagickBooleanType XAnnotateEditImage(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows,Image *image)
|
||
{
|
||
static const char
|
||
*AnnotateMenu[] =
|
||
{
|
||
"Font Name",
|
||
"Font Color",
|
||
"Box Color",
|
||
"Rotate Text",
|
||
"Help",
|
||
"Dismiss",
|
||
(char *) NULL
|
||
},
|
||
*TextMenu[] =
|
||
{
|
||
"Help",
|
||
"Apply",
|
||
(char *) NULL
|
||
};
|
||
|
||
static const ModeType
|
||
AnnotateCommands[] =
|
||
{
|
||
AnnotateNameCommand,
|
||
AnnotateFontColorCommand,
|
||
AnnotateBackgroundColorCommand,
|
||
AnnotateRotateCommand,
|
||
AnnotateHelpCommand,
|
||
AnnotateDismissCommand
|
||
},
|
||
TextCommands[] =
|
||
{
|
||
TextHelpCommand,
|
||
TextApplyCommand
|
||
};
|
||
|
||
static MagickBooleanType
|
||
transparent_box = MagickTrue,
|
||
transparent_pen = MagickFalse;
|
||
|
||
static MagickRealType
|
||
degrees = 0.0;
|
||
|
||
static unsigned int
|
||
box_id = MaxNumberPens-2,
|
||
font_id = 0,
|
||
pen_id = 0;
|
||
|
||
char
|
||
command[MaxTextExtent],
|
||
text[MaxTextExtent];
|
||
|
||
const char
|
||
*ColorMenu[MaxNumberPens+1];
|
||
|
||
Cursor
|
||
cursor;
|
||
|
||
GC
|
||
annotate_context;
|
||
|
||
int
|
||
id,
|
||
pen_number,
|
||
status,
|
||
x,
|
||
y;
|
||
|
||
KeySym
|
||
key_symbol;
|
||
|
||
register char
|
||
*p;
|
||
|
||
register ssize_t
|
||
i;
|
||
|
||
unsigned int
|
||
height,
|
||
width;
|
||
|
||
size_t
|
||
state;
|
||
|
||
XAnnotateInfo
|
||
*annotate_info,
|
||
*previous_info;
|
||
|
||
XColor
|
||
color;
|
||
|
||
XFontStruct
|
||
*font_info;
|
||
|
||
XEvent
|
||
event,
|
||
text_event;
|
||
|
||
/*
|
||
Map Command widget.
|
||
*/
|
||
(void) CloneString(&windows->command.name,"Annotate");
|
||
windows->command.data=4;
|
||
(void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL);
|
||
(void) XMapRaised(display,windows->command.id);
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_update_widget,CurrentTime);
|
||
/*
|
||
Track pointer until button 1 is pressed.
|
||
*/
|
||
XQueryPosition(display,windows->image.id,&x,&y);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask | PointerMotionMask);
|
||
cursor=XCreateFontCursor(display,XC_left_side);
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
state=DefaultState;
|
||
do
|
||
{
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
/*
|
||
Display pointer position.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
|
||
x+windows->image.x,y+windows->image.y);
|
||
XInfoWidget(display,windows,text);
|
||
}
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,&event);
|
||
if (event.xany.window == windows->command.id)
|
||
{
|
||
/*
|
||
Select a command from the Command widget.
|
||
*/
|
||
id=XCommandWidget(display,windows,AnnotateMenu,&event);
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
if (id < 0)
|
||
continue;
|
||
switch (AnnotateCommands[id])
|
||
{
|
||
case AnnotateNameCommand:
|
||
{
|
||
const char
|
||
*FontMenu[MaxNumberFonts];
|
||
|
||
int
|
||
font_number;
|
||
|
||
/*
|
||
Initialize menu selections.
|
||
*/
|
||
for (i=0; i < MaxNumberFonts; i++)
|
||
FontMenu[i]=resource_info->font_name[i];
|
||
FontMenu[MaxNumberFonts-2]="Browser...";
|
||
FontMenu[MaxNumberFonts-1]=(const char *) NULL;
|
||
/*
|
||
Select a font name from the pop-up menu.
|
||
*/
|
||
font_number=XMenuWidget(display,windows,AnnotateMenu[id],
|
||
(const char **) FontMenu,command);
|
||
if (font_number < 0)
|
||
break;
|
||
if (font_number == (MaxNumberFonts-2))
|
||
{
|
||
static char
|
||
font_name[MaxTextExtent] = "fixed";
|
||
|
||
/*
|
||
Select a font name from a browser.
|
||
*/
|
||
resource_info->font_name[font_number]=font_name;
|
||
XFontBrowserWidget(display,windows,"Select",font_name);
|
||
if (*font_name == '\0')
|
||
break;
|
||
}
|
||
/*
|
||
Initialize font info.
|
||
*/
|
||
font_info=XLoadQueryFont(display,resource_info->font_name[
|
||
font_number]);
|
||
if (font_info == (XFontStruct *) NULL)
|
||
{
|
||
XNoticeWidget(display,windows,"Unable to load font:",
|
||
resource_info->font_name[font_number]);
|
||
break;
|
||
}
|
||
font_id=(unsigned int) font_number;
|
||
(void) XFreeFont(display,font_info);
|
||
break;
|
||
}
|
||
case AnnotateFontColorCommand:
|
||
{
|
||
/*
|
||
Initialize menu selections.
|
||
*/
|
||
for (i=0; i < (int) (MaxNumberPens-2); i++)
|
||
ColorMenu[i]=resource_info->pen_colors[i];
|
||
ColorMenu[MaxNumberPens-2]="transparent";
|
||
ColorMenu[MaxNumberPens-1]="Browser...";
|
||
ColorMenu[MaxNumberPens]=(const char *) NULL;
|
||
/*
|
||
Select a pen color from the pop-up menu.
|
||
*/
|
||
pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
|
||
(const char **) ColorMenu,command);
|
||
if (pen_number < 0)
|
||
break;
|
||
transparent_pen=pen_number == (MaxNumberPens-2) ? MagickTrue :
|
||
MagickFalse;
|
||
if (transparent_pen != MagickFalse)
|
||
break;
|
||
if (pen_number == (MaxNumberPens-1))
|
||
{
|
||
static char
|
||
color_name[MaxTextExtent] = "gray";
|
||
|
||
/*
|
||
Select a pen color from a dialog.
|
||
*/
|
||
resource_info->pen_colors[pen_number]=color_name;
|
||
XColorBrowserWidget(display,windows,"Select",color_name);
|
||
if (*color_name == '\0')
|
||
break;
|
||
}
|
||
/*
|
||
Set pen color.
|
||
*/
|
||
(void) XParseColor(display,windows->map_info->colormap,
|
||
resource_info->pen_colors[pen_number],&color);
|
||
XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
|
||
(unsigned int) MaxColors,&color);
|
||
windows->pixel_info->pen_colors[pen_number]=color;
|
||
pen_id=(unsigned int) pen_number;
|
||
break;
|
||
}
|
||
case AnnotateBackgroundColorCommand:
|
||
{
|
||
/*
|
||
Initialize menu selections.
|
||
*/
|
||
for (i=0; i < (int) (MaxNumberPens-2); i++)
|
||
ColorMenu[i]=resource_info->pen_colors[i];
|
||
ColorMenu[MaxNumberPens-2]="transparent";
|
||
ColorMenu[MaxNumberPens-1]="Browser...";
|
||
ColorMenu[MaxNumberPens]=(const char *) NULL;
|
||
/*
|
||
Select a pen color from the pop-up menu.
|
||
*/
|
||
pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
|
||
(const char **) ColorMenu,command);
|
||
if (pen_number < 0)
|
||
break;
|
||
transparent_box=pen_number == (MaxNumberPens-2) ? MagickTrue :
|
||
MagickFalse;
|
||
if (transparent_box != MagickFalse)
|
||
break;
|
||
if (pen_number == (MaxNumberPens-1))
|
||
{
|
||
static char
|
||
color_name[MaxTextExtent] = "gray";
|
||
|
||
/*
|
||
Select a pen color from a dialog.
|
||
*/
|
||
resource_info->pen_colors[pen_number]=color_name;
|
||
XColorBrowserWidget(display,windows,"Select",color_name);
|
||
if (*color_name == '\0')
|
||
break;
|
||
}
|
||
/*
|
||
Set pen color.
|
||
*/
|
||
(void) XParseColor(display,windows->map_info->colormap,
|
||
resource_info->pen_colors[pen_number],&color);
|
||
XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
|
||
(unsigned int) MaxColors,&color);
|
||
windows->pixel_info->pen_colors[pen_number]=color;
|
||
box_id=(unsigned int) pen_number;
|
||
break;
|
||
}
|
||
case AnnotateRotateCommand:
|
||
{
|
||
int
|
||
entry;
|
||
|
||
static char
|
||
angle[MaxTextExtent] = "30.0";
|
||
|
||
static const char
|
||
*RotateMenu[] =
|
||
{
|
||
"-90",
|
||
"-45",
|
||
"-30",
|
||
"0",
|
||
"30",
|
||
"45",
|
||
"90",
|
||
"180",
|
||
"Dialog...",
|
||
(char *) NULL,
|
||
};
|
||
|
||
/*
|
||
Select a command from the pop-up menu.
|
||
*/
|
||
entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu,
|
||
command);
|
||
if (entry < 0)
|
||
break;
|
||
if (entry != 8)
|
||
{
|
||
degrees=StringToDouble(RotateMenu[entry],(char **) NULL);
|
||
break;
|
||
}
|
||
(void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
|
||
angle);
|
||
if (*angle == '\0')
|
||
break;
|
||
degrees=StringToDouble(angle,(char **) NULL);
|
||
break;
|
||
}
|
||
case AnnotateHelpCommand:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Annotation",ImageAnnotateHelp);
|
||
break;
|
||
}
|
||
case AnnotateDismissCommand:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
continue;
|
||
}
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
if (event.xbutton.button != Button1)
|
||
break;
|
||
if (event.xbutton.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Change to text entering mode.
|
||
*/
|
||
x=event.xbutton.x;
|
||
y=event.xbutton.y;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case ButtonRelease:
|
||
break;
|
||
case Expose:
|
||
break;
|
||
case KeyPress:
|
||
{
|
||
if (event.xkey.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Respond to a user key press.
|
||
*/
|
||
(void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
switch ((int) key_symbol)
|
||
{
|
||
case XK_Escape:
|
||
case XK_F20:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case XK_F1:
|
||
case XK_Help:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Annotation",ImageAnnotateHelp);
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
(void) XBell(display,0);
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case MotionNotify:
|
||
{
|
||
/*
|
||
Map and unmap Info widget as cursor crosses its boundaries.
|
||
*/
|
||
x=event.xmotion.x;
|
||
y=event.xmotion.y;
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
if ((x < (int) (windows->info.x+windows->info.width)) &&
|
||
(y < (int) (windows->info.y+windows->info.height)))
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
}
|
||
else
|
||
if ((x > (int) (windows->info.x+windows->info.width)) ||
|
||
(y > (int) (windows->info.y+windows->info.height)))
|
||
(void) XMapWindow(display,windows->info.id);
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
} while ((state & ExitState) == 0);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask);
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
if ((state & EscapeState) != 0)
|
||
return(MagickTrue);
|
||
/*
|
||
Set font info and check boundary conditions.
|
||
*/
|
||
font_info=XLoadQueryFont(display,resource_info->font_name[font_id]);
|
||
if (font_info == (XFontStruct *) NULL)
|
||
{
|
||
XNoticeWidget(display,windows,"Unable to load font:",
|
||
resource_info->font_name[font_id]);
|
||
font_info=windows->font_info;
|
||
}
|
||
if ((x+font_info->max_bounds.width) >= (int) windows->image.width)
|
||
x=(int) windows->image.width-font_info->max_bounds.width;
|
||
if (y < (int) (font_info->ascent+font_info->descent))
|
||
y=(int) font_info->ascent+font_info->descent;
|
||
if (((int) font_info->max_bounds.width > (int) windows->image.width) ||
|
||
((font_info->ascent+font_info->descent) >= (int) windows->image.height))
|
||
return(MagickFalse);
|
||
/*
|
||
Initialize annotate structure.
|
||
*/
|
||
annotate_info=(XAnnotateInfo *) AcquireMagickMemory(sizeof(*annotate_info));
|
||
if (annotate_info == (XAnnotateInfo *) NULL)
|
||
return(MagickFalse);
|
||
XGetAnnotateInfo(annotate_info);
|
||
annotate_info->x=x;
|
||
annotate_info->y=y;
|
||
if ((transparent_box == MagickFalse) && (transparent_pen == MagickFalse))
|
||
annotate_info->stencil=OpaqueStencil;
|
||
else
|
||
if (transparent_box == MagickFalse)
|
||
annotate_info->stencil=BackgroundStencil;
|
||
else
|
||
annotate_info->stencil=ForegroundStencil;
|
||
annotate_info->height=(unsigned int) font_info->ascent+font_info->descent;
|
||
annotate_info->degrees=degrees;
|
||
annotate_info->font_info=font_info;
|
||
annotate_info->text=(char *) AcquireQuantumMemory((size_t)
|
||
windows->image.width/MagickMax((ssize_t) font_info->min_bounds.width,1)+2UL,
|
||
sizeof(*annotate_info->text));
|
||
if (annotate_info->text == (char *) NULL)
|
||
return(MagickFalse);
|
||
/*
|
||
Create cursor and set graphic context.
|
||
*/
|
||
cursor=XCreateFontCursor(display,XC_pencil);
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
annotate_context=windows->image.annotate_context;
|
||
(void) XSetFont(display,annotate_context,font_info->fid);
|
||
(void) XSetBackground(display,annotate_context,
|
||
windows->pixel_info->pen_colors[box_id].pixel);
|
||
(void) XSetForeground(display,annotate_context,
|
||
windows->pixel_info->pen_colors[pen_id].pixel);
|
||
/*
|
||
Begin annotating the image with text.
|
||
*/
|
||
(void) CloneString(&windows->command.name,"Text");
|
||
windows->command.data=0;
|
||
(void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL);
|
||
state=DefaultState;
|
||
(void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
|
||
text_event.xexpose.width=(int) font_info->max_bounds.width;
|
||
text_event.xexpose.height=font_info->max_bounds.ascent+
|
||
font_info->max_bounds.descent;
|
||
p=annotate_info->text;
|
||
do
|
||
{
|
||
/*
|
||
Display text cursor.
|
||
*/
|
||
*p='\0';
|
||
(void) XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,&event);
|
||
if (event.xany.window == windows->command.id)
|
||
{
|
||
/*
|
||
Select a command from the Command widget.
|
||
*/
|
||
(void) XSetBackground(display,annotate_context,
|
||
windows->pixel_info->background_color.pixel);
|
||
(void) XSetForeground(display,annotate_context,
|
||
windows->pixel_info->foreground_color.pixel);
|
||
id=XCommandWidget(display,windows,AnnotateMenu,&event);
|
||
(void) XSetBackground(display,annotate_context,
|
||
windows->pixel_info->pen_colors[box_id].pixel);
|
||
(void) XSetForeground(display,annotate_context,
|
||
windows->pixel_info->pen_colors[pen_id].pixel);
|
||
if (id < 0)
|
||
continue;
|
||
switch (TextCommands[id])
|
||
{
|
||
case TextHelpCommand:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Annotation",ImageAnnotateHelp);
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
break;
|
||
}
|
||
case TextApplyCommand:
|
||
{
|
||
/*
|
||
Finished annotating.
|
||
*/
|
||
annotate_info->width=(unsigned int) XTextWidth(font_info,
|
||
annotate_info->text,(int) strlen(annotate_info->text));
|
||
XRefreshWindow(display,&windows->image,&text_event);
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
continue;
|
||
}
|
||
/*
|
||
Erase text cursor.
|
||
*/
|
||
text_event.xexpose.x=x;
|
||
text_event.xexpose.y=y-font_info->max_bounds.ascent;
|
||
(void) XClearArea(display,windows->image.id,x,text_event.xexpose.y,
|
||
(unsigned int) text_event.xexpose.width,(unsigned int)
|
||
text_event.xexpose.height,MagickFalse);
|
||
XRefreshWindow(display,&windows->image,&text_event);
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
if (event.xbutton.window != windows->image.id)
|
||
break;
|
||
if (event.xbutton.button == Button2)
|
||
{
|
||
/*
|
||
Request primary selection.
|
||
*/
|
||
(void) XConvertSelection(display,XA_PRIMARY,XA_STRING,XA_STRING,
|
||
windows->image.id,CurrentTime);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case Expose:
|
||
{
|
||
if (event.xexpose.count == 0)
|
||
{
|
||
XAnnotateInfo
|
||
*text_info;
|
||
|
||
/*
|
||
Refresh Image window.
|
||
*/
|
||
XRefreshWindow(display,&windows->image,(XEvent *) NULL);
|
||
text_info=annotate_info;
|
||
while (text_info != (XAnnotateInfo *) NULL)
|
||
{
|
||
if (annotate_info->stencil == ForegroundStencil)
|
||
(void) XDrawString(display,windows->image.id,annotate_context,
|
||
text_info->x,text_info->y,text_info->text,
|
||
(int) strlen(text_info->text));
|
||
else
|
||
(void) XDrawImageString(display,windows->image.id,
|
||
annotate_context,text_info->x,text_info->y,text_info->text,
|
||
(int) strlen(text_info->text));
|
||
text_info=text_info->previous;
|
||
}
|
||
(void) XDrawString(display,windows->image.id,annotate_context,
|
||
x,y,"_",1);
|
||
}
|
||
break;
|
||
}
|
||
case KeyPress:
|
||
{
|
||
int
|
||
length;
|
||
|
||
if (event.xkey.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Respond to a user key press.
|
||
*/
|
||
length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
*(command+length)='\0';
|
||
if (((event.xkey.state & ControlMask) != 0) ||
|
||
((event.xkey.state & Mod1Mask) != 0))
|
||
state|=ModifierState;
|
||
if ((state & ModifierState) != 0)
|
||
switch ((int) key_symbol)
|
||
{
|
||
case XK_u:
|
||
case XK_U:
|
||
{
|
||
key_symbol=DeleteCommand;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
switch ((int) key_symbol)
|
||
{
|
||
case XK_BackSpace:
|
||
{
|
||
/*
|
||
Erase one character.
|
||
*/
|
||
if (p == annotate_info->text)
|
||
{
|
||
if (annotate_info->previous == (XAnnotateInfo *) NULL)
|
||
break;
|
||
else
|
||
{
|
||
/*
|
||
Go to end of the previous line of text.
|
||
*/
|
||
annotate_info=annotate_info->previous;
|
||
p=annotate_info->text;
|
||
x=annotate_info->x+annotate_info->width;
|
||
y=annotate_info->y;
|
||
if (annotate_info->width != 0)
|
||
p+=strlen(annotate_info->text);
|
||
break;
|
||
}
|
||
}
|
||
p--;
|
||
x-=XTextWidth(font_info,p,1);
|
||
text_event.xexpose.x=x;
|
||
text_event.xexpose.y=y-font_info->max_bounds.ascent;
|
||
XRefreshWindow(display,&windows->image,&text_event);
|
||
break;
|
||
}
|
||
case XK_bracketleft:
|
||
{
|
||
key_symbol=XK_Escape;
|
||
break;
|
||
}
|
||
case DeleteCommand:
|
||
{
|
||
/*
|
||
Erase the entire line of text.
|
||
*/
|
||
while (p != annotate_info->text)
|
||
{
|
||
p--;
|
||
x-=XTextWidth(font_info,p,1);
|
||
text_event.xexpose.x=x;
|
||
XRefreshWindow(display,&windows->image,&text_event);
|
||
}
|
||
break;
|
||
}
|
||
case XK_Escape:
|
||
case XK_F20:
|
||
{
|
||
/*
|
||
Finished annotating.
|
||
*/
|
||
annotate_info->width=(unsigned int) XTextWidth(font_info,
|
||
annotate_info->text,(int) strlen(annotate_info->text));
|
||
XRefreshWindow(display,&windows->image,&text_event);
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
/*
|
||
Draw a single character on the Image window.
|
||
*/
|
||
if ((state & ModifierState) != 0)
|
||
break;
|
||
if (*command == '\0')
|
||
break;
|
||
*p=(*command);
|
||
if (annotate_info->stencil == ForegroundStencil)
|
||
(void) XDrawString(display,windows->image.id,annotate_context,
|
||
x,y,p,1);
|
||
else
|
||
(void) XDrawImageString(display,windows->image.id,
|
||
annotate_context,x,y,p,1);
|
||
x+=XTextWidth(font_info,p,1);
|
||
p++;
|
||
if ((x+font_info->max_bounds.width) < (int) windows->image.width)
|
||
break;
|
||
}
|
||
case XK_Return:
|
||
case XK_KP_Enter:
|
||
{
|
||
/*
|
||
Advance to the next line of text.
|
||
*/
|
||
*p='\0';
|
||
annotate_info->width=(unsigned int) XTextWidth(font_info,
|
||
annotate_info->text,(int) strlen(annotate_info->text));
|
||
if (annotate_info->next != (XAnnotateInfo *) NULL)
|
||
{
|
||
/*
|
||
Line of text already exists.
|
||
*/
|
||
annotate_info=annotate_info->next;
|
||
x=annotate_info->x;
|
||
y=annotate_info->y;
|
||
p=annotate_info->text;
|
||
break;
|
||
}
|
||
annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
|
||
sizeof(*annotate_info->next));
|
||
if (annotate_info->next == (XAnnotateInfo *) NULL)
|
||
return(MagickFalse);
|
||
*annotate_info->next=(*annotate_info);
|
||
annotate_info->next->previous=annotate_info;
|
||
annotate_info=annotate_info->next;
|
||
annotate_info->text=(char *) AcquireQuantumMemory((size_t)
|
||
windows->image.width/MagickMax((ssize_t)
|
||
font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
|
||
if (annotate_info->text == (char *) NULL)
|
||
return(MagickFalse);
|
||
annotate_info->y+=annotate_info->height;
|
||
if (annotate_info->y > (int) windows->image.height)
|
||
annotate_info->y=(int) annotate_info->height;
|
||
annotate_info->next=(XAnnotateInfo *) NULL;
|
||
x=annotate_info->x;
|
||
y=annotate_info->y;
|
||
p=annotate_info->text;
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case KeyRelease:
|
||
{
|
||
/*
|
||
Respond to a user key release.
|
||
*/
|
||
(void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
state&=(~ModifierState);
|
||
break;
|
||
}
|
||
case SelectionNotify:
|
||
{
|
||
Atom
|
||
type;
|
||
|
||
int
|
||
format;
|
||
|
||
unsigned char
|
||
*data;
|
||
|
||
unsigned long
|
||
after,
|
||
length;
|
||
|
||
/*
|
||
Obtain response from primary selection.
|
||
*/
|
||
if (event.xselection.property == (Atom) None)
|
||
break;
|
||
status=XGetWindowProperty(display,event.xselection.requestor,
|
||
event.xselection.property,0L,(long) MaxTextExtent,True,XA_STRING,
|
||
&type,&format,&length,&after,&data);
|
||
if ((status != Success) || (type != XA_STRING) || (format == 32) ||
|
||
(length == 0))
|
||
break;
|
||
/*
|
||
Annotate Image window with primary selection.
|
||
*/
|
||
for (i=0; i < (ssize_t) length; i++)
|
||
{
|
||
if ((char) data[i] != '\n')
|
||
{
|
||
/*
|
||
Draw a single character on the Image window.
|
||
*/
|
||
*p=(char) data[i];
|
||
(void) XDrawString(display,windows->image.id,annotate_context,
|
||
x,y,p,1);
|
||
x+=XTextWidth(font_info,p,1);
|
||
p++;
|
||
if ((x+font_info->max_bounds.width) < (int) windows->image.width)
|
||
continue;
|
||
}
|
||
/*
|
||
Advance to the next line of text.
|
||
*/
|
||
*p='\0';
|
||
annotate_info->width=(unsigned int) XTextWidth(font_info,
|
||
annotate_info->text,(int) strlen(annotate_info->text));
|
||
if (annotate_info->next != (XAnnotateInfo *) NULL)
|
||
{
|
||
/*
|
||
Line of text already exists.
|
||
*/
|
||
annotate_info=annotate_info->next;
|
||
x=annotate_info->x;
|
||
y=annotate_info->y;
|
||
p=annotate_info->text;
|
||
continue;
|
||
}
|
||
annotate_info->next=(XAnnotateInfo *) AcquireMagickMemory(
|
||
sizeof(*annotate_info->next));
|
||
if (annotate_info->next == (XAnnotateInfo *) NULL)
|
||
return(MagickFalse);
|
||
*annotate_info->next=(*annotate_info);
|
||
annotate_info->next->previous=annotate_info;
|
||
annotate_info=annotate_info->next;
|
||
annotate_info->text=(char *) AcquireQuantumMemory((size_t)
|
||
windows->image.width/MagickMax((ssize_t)
|
||
font_info->min_bounds.width,1)+2UL,sizeof(*annotate_info->text));
|
||
if (annotate_info->text == (char *) NULL)
|
||
return(MagickFalse);
|
||
annotate_info->y+=annotate_info->height;
|
||
if (annotate_info->y > (int) windows->image.height)
|
||
annotate_info->y=(int) annotate_info->height;
|
||
annotate_info->next=(XAnnotateInfo *) NULL;
|
||
x=annotate_info->x;
|
||
y=annotate_info->y;
|
||
p=annotate_info->text;
|
||
}
|
||
(void) XFree((void *) data);
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
} while ((state & ExitState) == 0);
|
||
(void) XFreeCursor(display,cursor);
|
||
/*
|
||
Annotation is relative to image configuration.
|
||
*/
|
||
width=(unsigned int) image->columns;
|
||
height=(unsigned int) image->rows;
|
||
x=0;
|
||
y=0;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
|
||
/*
|
||
Initialize annotated image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
while (annotate_info != (XAnnotateInfo *) NULL)
|
||
{
|
||
if (annotate_info->width == 0)
|
||
{
|
||
/*
|
||
No text on this line-- go to the next line of text.
|
||
*/
|
||
previous_info=annotate_info->previous;
|
||
annotate_info->text=(char *)
|
||
RelinquishMagickMemory(annotate_info->text);
|
||
annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
|
||
annotate_info=previous_info;
|
||
continue;
|
||
}
|
||
/*
|
||
Determine pixel index for box and pen color.
|
||
*/
|
||
windows->pixel_info->box_color=windows->pixel_info->pen_colors[box_id];
|
||
if (windows->pixel_info->colors != 0)
|
||
for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
|
||
if (windows->pixel_info->pixels[i] ==
|
||
windows->pixel_info->pen_colors[box_id].pixel)
|
||
{
|
||
windows->pixel_info->box_index=(unsigned short) i;
|
||
break;
|
||
}
|
||
windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
|
||
if (windows->pixel_info->colors != 0)
|
||
for (i=0; i < (ssize_t) windows->pixel_info->colors; i++)
|
||
if (windows->pixel_info->pixels[i] ==
|
||
windows->pixel_info->pen_colors[pen_id].pixel)
|
||
{
|
||
windows->pixel_info->pen_index=(unsigned short) i;
|
||
break;
|
||
}
|
||
/*
|
||
Define the annotate geometry string.
|
||
*/
|
||
annotate_info->x=(int)
|
||
width*(annotate_info->x+windows->image.x)/windows->image.ximage->width;
|
||
annotate_info->y=(int) height*(annotate_info->y-font_info->ascent+
|
||
windows->image.y)/windows->image.ximage->height;
|
||
(void) FormatLocaleString(annotate_info->geometry,MaxTextExtent,
|
||
"%ux%u%+d%+d",width*annotate_info->width/windows->image.ximage->width,
|
||
height*annotate_info->height/windows->image.ximage->height,
|
||
annotate_info->x+x,annotate_info->y+y);
|
||
/*
|
||
Annotate image with text.
|
||
*/
|
||
status=XAnnotateImage(display,windows->pixel_info,annotate_info,image);
|
||
if (status == 0)
|
||
return(MagickFalse);
|
||
/*
|
||
Free up memory.
|
||
*/
|
||
previous_info=annotate_info->previous;
|
||
annotate_info->text=DestroyString(annotate_info->text);
|
||
annotate_info=(XAnnotateInfo *) RelinquishMagickMemory(annotate_info);
|
||
annotate_info=previous_info;
|
||
}
|
||
(void) XSetForeground(display,annotate_context,
|
||
windows->pixel_info->foreground_color.pixel);
|
||
(void) XSetBackground(display,annotate_context,
|
||
windows->pixel_info->background_color.pixel);
|
||
(void) XSetFont(display,annotate_context,windows->font_info->fid);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
(void) XFreeFont(display,font_info);
|
||
/*
|
||
Update image configuration.
|
||
*/
|
||
XConfigureImageColormap(display,resource_info,windows,image);
|
||
(void) XConfigureImage(display,resource_info,windows,image);
|
||
return(MagickTrue);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X B a c k g r o u n d I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XBackgroundImage() displays the image in the background of a window.
|
||
%
|
||
% The format of the XBackgroundImage method is:
|
||
%
|
||
% MagickBooleanType XBackgroundImage(Display *display,
|
||
% XResourceInfo *resource_info,XWindows *windows,Image **image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image.
|
||
%
|
||
*/
|
||
static MagickBooleanType XBackgroundImage(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows,Image **image)
|
||
{
|
||
#define BackgroundImageTag "Background/Image"
|
||
|
||
int
|
||
status;
|
||
|
||
static char
|
||
window_id[MaxTextExtent] = "root";
|
||
|
||
XResourceInfo
|
||
background_resources;
|
||
|
||
/*
|
||
Put image in background.
|
||
*/
|
||
status=XDialogWidget(display,windows,"Background",
|
||
"Enter window id (id 0x00 selects window with pointer):",window_id);
|
||
if (*window_id == '\0')
|
||
return(MagickFalse);
|
||
(void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
|
||
XInfoWidget(display,windows,BackgroundImageTag);
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
background_resources=(*resource_info);
|
||
background_resources.window_id=window_id;
|
||
background_resources.backdrop=status != 0 ? MagickTrue : MagickFalse;
|
||
status=XDisplayBackgroundImage(display,&background_resources,*image);
|
||
if (status != MagickFalse)
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_retain_colors,CurrentTime);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
(void) XMagickCommand(display,resource_info,windows,UndoCommand,image);
|
||
return(MagickTrue);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X C h o p I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XChopImage() chops the X image.
|
||
%
|
||
% The format of the XChopImage method is:
|
||
%
|
||
% MagickBooleanType XChopImage(Display *display,XResourceInfo *resource_info,
|
||
% XWindows *windows,Image **image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image.
|
||
%
|
||
*/
|
||
static MagickBooleanType XChopImage(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows,Image **image)
|
||
{
|
||
static const char
|
||
*ChopMenu[] =
|
||
{
|
||
"Direction",
|
||
"Help",
|
||
"Dismiss",
|
||
(char *) NULL
|
||
};
|
||
|
||
static ModeType
|
||
direction = HorizontalChopCommand;
|
||
|
||
static const ModeType
|
||
ChopCommands[] =
|
||
{
|
||
ChopDirectionCommand,
|
||
ChopHelpCommand,
|
||
ChopDismissCommand
|
||
},
|
||
DirectionCommands[] =
|
||
{
|
||
HorizontalChopCommand,
|
||
VerticalChopCommand
|
||
};
|
||
|
||
char
|
||
text[MaxTextExtent];
|
||
|
||
Image
|
||
*chop_image;
|
||
|
||
int
|
||
id,
|
||
x,
|
||
y;
|
||
|
||
MagickRealType
|
||
scale_factor;
|
||
|
||
RectangleInfo
|
||
chop_info;
|
||
|
||
unsigned int
|
||
distance,
|
||
height,
|
||
width;
|
||
|
||
size_t
|
||
state;
|
||
|
||
XEvent
|
||
event;
|
||
|
||
XSegment
|
||
segment_info;
|
||
|
||
/*
|
||
Map Command widget.
|
||
*/
|
||
(void) CloneString(&windows->command.name,"Chop");
|
||
windows->command.data=1;
|
||
(void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL);
|
||
(void) XMapRaised(display,windows->command.id);
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_update_widget,CurrentTime);
|
||
/*
|
||
Track pointer until button 1 is pressed.
|
||
*/
|
||
XQueryPosition(display,windows->image.id,&x,&y);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask | PointerMotionMask);
|
||
state=DefaultState;
|
||
do
|
||
{
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
/*
|
||
Display pointer position.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
|
||
x+windows->image.x,y+windows->image.y);
|
||
XInfoWidget(display,windows,text);
|
||
}
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,&event);
|
||
if (event.xany.window == windows->command.id)
|
||
{
|
||
/*
|
||
Select a command from the Command widget.
|
||
*/
|
||
id=XCommandWidget(display,windows,ChopMenu,&event);
|
||
if (id < 0)
|
||
continue;
|
||
switch (ChopCommands[id])
|
||
{
|
||
case ChopDirectionCommand:
|
||
{
|
||
char
|
||
command[MaxTextExtent];
|
||
|
||
static const char
|
||
*Directions[] =
|
||
{
|
||
"horizontal",
|
||
"vertical",
|
||
(char *) NULL,
|
||
};
|
||
|
||
/*
|
||
Select a command from the pop-up menu.
|
||
*/
|
||
id=XMenuWidget(display,windows,ChopMenu[id],Directions,command);
|
||
if (id >= 0)
|
||
direction=DirectionCommands[id];
|
||
break;
|
||
}
|
||
case ChopHelpCommand:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Chop",ImageChopHelp);
|
||
break;
|
||
}
|
||
case ChopDismissCommand:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
continue;
|
||
}
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
if (event.xbutton.button != Button1)
|
||
break;
|
||
if (event.xbutton.window != windows->image.id)
|
||
break;
|
||
/*
|
||
User has committed to start point of chopping line.
|
||
*/
|
||
segment_info.x1=(short int) event.xbutton.x;
|
||
segment_info.x2=(short int) event.xbutton.x;
|
||
segment_info.y1=(short int) event.xbutton.y;
|
||
segment_info.y2=(short int) event.xbutton.y;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case ButtonRelease:
|
||
break;
|
||
case Expose:
|
||
break;
|
||
case KeyPress:
|
||
{
|
||
char
|
||
command[MaxTextExtent];
|
||
|
||
KeySym
|
||
key_symbol;
|
||
|
||
if (event.xkey.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Respond to a user key press.
|
||
*/
|
||
(void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
switch ((int) key_symbol)
|
||
{
|
||
case XK_Escape:
|
||
case XK_F20:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case XK_F1:
|
||
case XK_Help:
|
||
{
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXcopy);
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Chop",ImageChopHelp);
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXinvert);
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
(void) XBell(display,0);
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case MotionNotify:
|
||
{
|
||
/*
|
||
Map and unmap Info widget as text cursor crosses its boundaries.
|
||
*/
|
||
x=event.xmotion.x;
|
||
y=event.xmotion.y;
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
if ((x < (int) (windows->info.x+windows->info.width)) &&
|
||
(y < (int) (windows->info.y+windows->info.height)))
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
}
|
||
else
|
||
if ((x > (int) (windows->info.x+windows->info.width)) ||
|
||
(y > (int) (windows->info.y+windows->info.height)))
|
||
(void) XMapWindow(display,windows->info.id);
|
||
}
|
||
}
|
||
} while ((state & ExitState) == 0);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask);
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
if ((state & EscapeState) != 0)
|
||
return(MagickTrue);
|
||
/*
|
||
Draw line as pointer moves until the mouse button is released.
|
||
*/
|
||
chop_info.width=0;
|
||
chop_info.height=0;
|
||
chop_info.x=0;
|
||
chop_info.y=0;
|
||
distance=0;
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXinvert);
|
||
state=DefaultState;
|
||
do
|
||
{
|
||
if (distance > 9)
|
||
{
|
||
/*
|
||
Display info and draw chopping line.
|
||
*/
|
||
if (windows->info.mapped == MagickFalse)
|
||
(void) XMapWindow(display,windows->info.id);
|
||
(void) FormatLocaleString(text,MaxTextExtent,
|
||
" %.20gx%.20g%+.20g%+.20g",(double) chop_info.width,(double)
|
||
chop_info.height,(double) chop_info.x,(double) chop_info.y);
|
||
XInfoWidget(display,windows,text);
|
||
XHighlightLine(display,windows->image.id,
|
||
windows->image.highlight_context,&segment_info);
|
||
}
|
||
else
|
||
if (windows->info.mapped != MagickFalse)
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,&event);
|
||
if (distance > 9)
|
||
XHighlightLine(display,windows->image.id,
|
||
windows->image.highlight_context,&segment_info);
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
segment_info.x2=(short int) event.xmotion.x;
|
||
segment_info.y2=(short int) event.xmotion.y;
|
||
break;
|
||
}
|
||
case ButtonRelease:
|
||
{
|
||
/*
|
||
User has committed to chopping line.
|
||
*/
|
||
segment_info.x2=(short int) event.xbutton.x;
|
||
segment_info.y2=(short int) event.xbutton.y;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case Expose:
|
||
break;
|
||
case MotionNotify:
|
||
{
|
||
segment_info.x2=(short int) event.xmotion.x;
|
||
segment_info.y2=(short int) event.xmotion.y;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
/*
|
||
Check boundary conditions.
|
||
*/
|
||
if (segment_info.x2 < 0)
|
||
segment_info.x2=0;
|
||
else
|
||
if (segment_info.x2 > windows->image.ximage->width)
|
||
segment_info.x2=windows->image.ximage->width;
|
||
if (segment_info.y2 < 0)
|
||
segment_info.y2=0;
|
||
else
|
||
if (segment_info.y2 > windows->image.ximage->height)
|
||
segment_info.y2=windows->image.ximage->height;
|
||
distance=(unsigned int)
|
||
(((segment_info.x2-segment_info.x1)*(segment_info.x2-segment_info.x1))+
|
||
((segment_info.y2-segment_info.y1)*(segment_info.y2-segment_info.y1)));
|
||
/*
|
||
Compute chopping geometry.
|
||
*/
|
||
if (direction == HorizontalChopCommand)
|
||
{
|
||
chop_info.width=(size_t) (segment_info.x2-segment_info.x1+1);
|
||
chop_info.x=(ssize_t) windows->image.x+segment_info.x1;
|
||
chop_info.height=0;
|
||
chop_info.y=0;
|
||
if (segment_info.x1 > (int) segment_info.x2)
|
||
{
|
||
chop_info.width=(size_t) (segment_info.x1-segment_info.x2+1);
|
||
chop_info.x=(ssize_t) windows->image.x+segment_info.x2;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
chop_info.width=0;
|
||
chop_info.height=(size_t) (segment_info.y2-segment_info.y1+1);
|
||
chop_info.x=0;
|
||
chop_info.y=(ssize_t) windows->image.y+segment_info.y1;
|
||
if (segment_info.y1 > segment_info.y2)
|
||
{
|
||
chop_info.height=(size_t) (segment_info.y1-segment_info.y2+1);
|
||
chop_info.y=(ssize_t) windows->image.y+segment_info.y2;
|
||
}
|
||
}
|
||
} while ((state & ExitState) == 0);
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXcopy);
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
if (distance <= 9)
|
||
return(MagickTrue);
|
||
/*
|
||
Image chopping is relative to image configuration.
|
||
*/
|
||
(void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
windows->image.window_changes.width=windows->image.ximage->width-
|
||
(unsigned int) chop_info.width;
|
||
windows->image.window_changes.height=windows->image.ximage->height-
|
||
(unsigned int) chop_info.height;
|
||
width=(unsigned int) (*image)->columns;
|
||
height=(unsigned int) (*image)->rows;
|
||
x=0;
|
||
y=0;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
|
||
scale_factor=(MagickRealType) width/windows->image.ximage->width;
|
||
chop_info.x+=x;
|
||
chop_info.x=(ssize_t) (scale_factor*chop_info.x+0.5);
|
||
chop_info.width=(unsigned int) (scale_factor*chop_info.width+0.5);
|
||
scale_factor=(MagickRealType) height/windows->image.ximage->height;
|
||
chop_info.y+=y;
|
||
chop_info.y=(ssize_t) (scale_factor*chop_info.y+0.5);
|
||
chop_info.height=(unsigned int) (scale_factor*chop_info.height+0.5);
|
||
/*
|
||
Chop image.
|
||
*/
|
||
chop_image=ChopImage(*image,&chop_info,&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (chop_image == (Image *) NULL)
|
||
return(MagickFalse);
|
||
*image=DestroyImage(*image);
|
||
*image=chop_image;
|
||
/*
|
||
Update image configuration.
|
||
*/
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
return(MagickTrue);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X C o l o r E d i t I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XColorEditImage() allows the user to interactively change the color of one
|
||
% pixel for a DirectColor image or one colormap entry for a PseudoClass image.
|
||
%
|
||
% The format of the XColorEditImage method is:
|
||
%
|
||
% MagickBooleanType XColorEditImage(Display *display,
|
||
% XResourceInfo *resource_info,XWindows *windows,Image **image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image; returned from ReadImage.
|
||
%
|
||
*/
|
||
|
||
|
||
static MagickBooleanType XColorEditImage(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows,Image **image)
|
||
{
|
||
static const char
|
||
*ColorEditMenu[] =
|
||
{
|
||
"Method",
|
||
"Pixel Color",
|
||
"Border Color",
|
||
"Fuzz",
|
||
"Undo",
|
||
"Help",
|
||
"Dismiss",
|
||
(char *) NULL
|
||
};
|
||
|
||
static const ModeType
|
||
ColorEditCommands[] =
|
||
{
|
||
ColorEditMethodCommand,
|
||
ColorEditColorCommand,
|
||
ColorEditBorderCommand,
|
||
ColorEditFuzzCommand,
|
||
ColorEditUndoCommand,
|
||
ColorEditHelpCommand,
|
||
ColorEditDismissCommand
|
||
};
|
||
|
||
static PaintMethod
|
||
method = PointMethod;
|
||
|
||
static unsigned int
|
||
pen_id = 0;
|
||
|
||
static XColor
|
||
border_color = { 0, 0, 0, 0, 0, 0 };
|
||
|
||
char
|
||
command[MaxTextExtent],
|
||
text[MaxTextExtent];
|
||
|
||
Cursor
|
||
cursor;
|
||
|
||
ExceptionInfo
|
||
*exception;
|
||
|
||
int
|
||
entry,
|
||
id,
|
||
x,
|
||
x_offset,
|
||
y,
|
||
y_offset;
|
||
|
||
register PixelPacket
|
||
*q;
|
||
|
||
register ssize_t
|
||
i;
|
||
|
||
unsigned int
|
||
height,
|
||
width;
|
||
|
||
size_t
|
||
state;
|
||
|
||
XColor
|
||
color;
|
||
|
||
XEvent
|
||
event;
|
||
|
||
/*
|
||
Map Command widget.
|
||
*/
|
||
(void) CloneString(&windows->command.name,"Color Edit");
|
||
windows->command.data=4;
|
||
(void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL);
|
||
(void) XMapRaised(display,windows->command.id);
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_update_widget,CurrentTime);
|
||
/*
|
||
Make cursor.
|
||
*/
|
||
cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
|
||
resource_info->background_color,resource_info->foreground_color);
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
/*
|
||
Track pointer until button 1 is pressed.
|
||
*/
|
||
XQueryPosition(display,windows->image.id,&x,&y);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask | PointerMotionMask);
|
||
state=DefaultState;
|
||
do
|
||
{
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
/*
|
||
Display pointer position.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
|
||
x+windows->image.x,y+windows->image.y);
|
||
XInfoWidget(display,windows,text);
|
||
}
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,&event);
|
||
if (event.xany.window == windows->command.id)
|
||
{
|
||
/*
|
||
Select a command from the Command widget.
|
||
*/
|
||
id=XCommandWidget(display,windows,ColorEditMenu,&event);
|
||
if (id < 0)
|
||
{
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
continue;
|
||
}
|
||
switch (ColorEditCommands[id])
|
||
{
|
||
case ColorEditMethodCommand:
|
||
{
|
||
char
|
||
**methods;
|
||
|
||
/*
|
||
Select a method from the pop-up menu.
|
||
*/
|
||
methods=(char **) GetCommandOptions(MagickMethodOptions);
|
||
if (methods == (char **) NULL)
|
||
break;
|
||
entry=XMenuWidget(display,windows,ColorEditMenu[id],
|
||
(const char **) methods,command);
|
||
if (entry >= 0)
|
||
method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
|
||
MagickFalse,methods[entry]);
|
||
methods=DestroyStringList(methods);
|
||
break;
|
||
}
|
||
case ColorEditColorCommand:
|
||
{
|
||
const char
|
||
*ColorMenu[MaxNumberPens];
|
||
|
||
int
|
||
pen_number;
|
||
|
||
/*
|
||
Initialize menu selections.
|
||
*/
|
||
for (i=0; i < (int) (MaxNumberPens-2); i++)
|
||
ColorMenu[i]=resource_info->pen_colors[i];
|
||
ColorMenu[MaxNumberPens-2]="Browser...";
|
||
ColorMenu[MaxNumberPens-1]=(const char *) NULL;
|
||
/*
|
||
Select a pen color from the pop-up menu.
|
||
*/
|
||
pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
|
||
(const char **) ColorMenu,command);
|
||
if (pen_number < 0)
|
||
break;
|
||
if (pen_number == (MaxNumberPens-2))
|
||
{
|
||
static char
|
||
color_name[MaxTextExtent] = "gray";
|
||
|
||
/*
|
||
Select a pen color from a dialog.
|
||
*/
|
||
resource_info->pen_colors[pen_number]=color_name;
|
||
XColorBrowserWidget(display,windows,"Select",color_name);
|
||
if (*color_name == '\0')
|
||
break;
|
||
}
|
||
/*
|
||
Set pen color.
|
||
*/
|
||
(void) XParseColor(display,windows->map_info->colormap,
|
||
resource_info->pen_colors[pen_number],&color);
|
||
XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
|
||
(unsigned int) MaxColors,&color);
|
||
windows->pixel_info->pen_colors[pen_number]=color;
|
||
pen_id=(unsigned int) pen_number;
|
||
break;
|
||
}
|
||
case ColorEditBorderCommand:
|
||
{
|
||
const char
|
||
*ColorMenu[MaxNumberPens];
|
||
|
||
int
|
||
pen_number;
|
||
|
||
/*
|
||
Initialize menu selections.
|
||
*/
|
||
for (i=0; i < (int) (MaxNumberPens-2); i++)
|
||
ColorMenu[i]=resource_info->pen_colors[i];
|
||
ColorMenu[MaxNumberPens-2]="Browser...";
|
||
ColorMenu[MaxNumberPens-1]=(const char *) NULL;
|
||
/*
|
||
Select a pen color from the pop-up menu.
|
||
*/
|
||
pen_number=XMenuWidget(display,windows,ColorEditMenu[id],
|
||
(const char **) ColorMenu,command);
|
||
if (pen_number < 0)
|
||
break;
|
||
if (pen_number == (MaxNumberPens-2))
|
||
{
|
||
static char
|
||
color_name[MaxTextExtent] = "gray";
|
||
|
||
/*
|
||
Select a pen color from a dialog.
|
||
*/
|
||
resource_info->pen_colors[pen_number]=color_name;
|
||
XColorBrowserWidget(display,windows,"Select",color_name);
|
||
if (*color_name == '\0')
|
||
break;
|
||
}
|
||
/*
|
||
Set border color.
|
||
*/
|
||
(void) XParseColor(display,windows->map_info->colormap,
|
||
resource_info->pen_colors[pen_number],&border_color);
|
||
break;
|
||
}
|
||
case ColorEditFuzzCommand:
|
||
{
|
||
static char
|
||
fuzz[MaxTextExtent];
|
||
|
||
static const char
|
||
*FuzzMenu[] =
|
||
{
|
||
"0%",
|
||
"2%",
|
||
"5%",
|
||
"10%",
|
||
"15%",
|
||
"Dialog...",
|
||
(char *) NULL,
|
||
};
|
||
|
||
/*
|
||
Select a command from the pop-up menu.
|
||
*/
|
||
entry=XMenuWidget(display,windows,ColorEditMenu[id],FuzzMenu,
|
||
command);
|
||
if (entry < 0)
|
||
break;
|
||
if (entry != 5)
|
||
{
|
||
(*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
|
||
QuantumRange+1.0);
|
||
break;
|
||
}
|
||
(void) (void) CopyMagickString(fuzz,"20%",MaxTextExtent);
|
||
(void) XDialogWidget(display,windows,"Ok",
|
||
"Enter fuzz factor (0.0 - 99.9%):",fuzz);
|
||
if (*fuzz == '\0')
|
||
break;
|
||
(void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
|
||
(*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
|
||
1.0);
|
||
break;
|
||
}
|
||
case ColorEditUndoCommand:
|
||
{
|
||
(void) XMagickCommand(display,resource_info,windows,UndoCommand,
|
||
image);
|
||
break;
|
||
}
|
||
case ColorEditHelpCommand:
|
||
default:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Annotation",ImageColorEditHelp);
|
||
break;
|
||
}
|
||
case ColorEditDismissCommand:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
}
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
continue;
|
||
}
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
if (event.xbutton.button != Button1)
|
||
break;
|
||
if ((event.xbutton.window != windows->image.id) &&
|
||
(event.xbutton.window != windows->magnify.id))
|
||
break;
|
||
/*
|
||
exit loop.
|
||
*/
|
||
x=event.xbutton.x;
|
||
y=event.xbutton.y;
|
||
(void) XMagickCommand(display,resource_info,windows,
|
||
SaveToUndoBufferCommand,image);
|
||
state|=UpdateConfigurationState;
|
||
break;
|
||
}
|
||
case ButtonRelease:
|
||
{
|
||
if (event.xbutton.button != Button1)
|
||
break;
|
||
if ((event.xbutton.window != windows->image.id) &&
|
||
(event.xbutton.window != windows->magnify.id))
|
||
break;
|
||
/*
|
||
Update colormap information.
|
||
*/
|
||
x=event.xbutton.x;
|
||
y=event.xbutton.y;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
XInfoWidget(display,windows,text);
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
state&=(~UpdateConfigurationState);
|
||
break;
|
||
}
|
||
case Expose:
|
||
break;
|
||
case KeyPress:
|
||
{
|
||
KeySym
|
||
key_symbol;
|
||
|
||
if (event.xkey.window == windows->magnify.id)
|
||
{
|
||
Window
|
||
window;
|
||
|
||
window=windows->magnify.id;
|
||
while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
|
||
}
|
||
if (event.xkey.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Respond to a user key press.
|
||
*/
|
||
(void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
switch ((int) key_symbol)
|
||
{
|
||
case XK_Escape:
|
||
case XK_F20:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case XK_F1:
|
||
case XK_Help:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Annotation",ImageColorEditHelp);
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
(void) XBell(display,0);
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case MotionNotify:
|
||
{
|
||
/*
|
||
Map and unmap Info widget as cursor crosses its boundaries.
|
||
*/
|
||
x=event.xmotion.x;
|
||
y=event.xmotion.y;
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
if ((x < (int) (windows->info.x+windows->info.width)) &&
|
||
(y < (int) (windows->info.y+windows->info.height)))
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
}
|
||
else
|
||
if ((x > (int) (windows->info.x+windows->info.width)) ||
|
||
(y > (int) (windows->info.y+windows->info.height)))
|
||
(void) XMapWindow(display,windows->info.id);
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
if (event.xany.window == windows->magnify.id)
|
||
{
|
||
x=windows->magnify.x-windows->image.x;
|
||
y=windows->magnify.y-windows->image.y;
|
||
}
|
||
x_offset=x;
|
||
y_offset=y;
|
||
if ((state & UpdateConfigurationState) != 0)
|
||
{
|
||
CacheView
|
||
*image_view;
|
||
|
||
int
|
||
x,
|
||
y;
|
||
|
||
/*
|
||
Pixel edit is relative to image configuration.
|
||
*/
|
||
(void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
|
||
MagickTrue);
|
||
color=windows->pixel_info->pen_colors[pen_id];
|
||
XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel);
|
||
width=(unsigned int) (*image)->columns;
|
||
height=(unsigned int) (*image)->rows;
|
||
x=0;
|
||
y=0;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,
|
||
&width,&height);
|
||
x_offset=(int)
|
||
(width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
|
||
y_offset=(int)
|
||
(height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
|
||
if ((x_offset < 0) || (y_offset < 0))
|
||
continue;
|
||
if ((x_offset >= (int) (*image)->columns) ||
|
||
(y_offset >= (int) (*image)->rows))
|
||
continue;
|
||
exception=(&(*image)->exception);
|
||
image_view=AcquireAuthenticCacheView(*image,exception);
|
||
switch (method)
|
||
{
|
||
case PointMethod:
|
||
default:
|
||
{
|
||
/*
|
||
Update color information using point algorithm.
|
||
*/
|
||
if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
|
||
return(MagickFalse);
|
||
q=GetCacheViewAuthenticPixels(image_view,(ssize_t)x_offset,
|
||
(ssize_t)y_offset,1,1,exception);
|
||
if (q == (PixelPacket *) NULL)
|
||
break;
|
||
q->red=ScaleShortToQuantum(color.red);
|
||
q->green=ScaleShortToQuantum(color.green);
|
||
q->blue=ScaleShortToQuantum(color.blue);
|
||
(void) SyncCacheViewAuthenticPixels(image_view,
|
||
&(*image)->exception);
|
||
break;
|
||
}
|
||
case ReplaceMethod:
|
||
{
|
||
PixelPacket
|
||
target;
|
||
|
||
/*
|
||
Update color information using replace algorithm.
|
||
*/
|
||
(void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
|
||
(ssize_t) y_offset,&target,&(*image)->exception);
|
||
if ((*image)->storage_class == DirectClass)
|
||
{
|
||
for (y=0; y < (int) (*image)->rows; y++)
|
||
{
|
||
q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
|
||
(*image)->columns,1,exception);
|
||
if (q == (PixelPacket *) NULL)
|
||
break;
|
||
for (x=0; x < (int) (*image)->columns; x++)
|
||
{
|
||
if (IsColorSimilar(*image,q,&target))
|
||
{
|
||
q->red=ScaleShortToQuantum(color.red);
|
||
q->green=ScaleShortToQuantum(color.green);
|
||
q->blue=ScaleShortToQuantum(color.blue);
|
||
}
|
||
q++;
|
||
}
|
||
if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
for (i=0; i < (ssize_t) (*image)->colors; i++)
|
||
if (IsColorSimilar(*image,(*image)->colormap+i,&target))
|
||
{
|
||
(*image)->colormap[i].red=ScaleShortToQuantum(color.red);
|
||
(*image)->colormap[i].green=ScaleShortToQuantum(
|
||
color.green);
|
||
(*image)->colormap[i].blue=ScaleShortToQuantum(
|
||
color.blue);
|
||
}
|
||
(void) SyncImage(*image);
|
||
}
|
||
break;
|
||
}
|
||
case FloodfillMethod:
|
||
case FillToBorderMethod:
|
||
{
|
||
DrawInfo
|
||
*draw_info;
|
||
|
||
MagickPixelPacket
|
||
target;
|
||
|
||
/*
|
||
Update color information using floodfill algorithm.
|
||
*/
|
||
(void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
|
||
(ssize_t) y_offset,&target,exception);
|
||
if (method == FillToBorderMethod)
|
||
{
|
||
target.red=(MagickRealType)
|
||
ScaleShortToQuantum(border_color.red);
|
||
target.green=(MagickRealType)
|
||
ScaleShortToQuantum(border_color.green);
|
||
target.blue=(MagickRealType)
|
||
ScaleShortToQuantum(border_color.blue);
|
||
}
|
||
draw_info=CloneDrawInfo(resource_info->image_info,
|
||
(DrawInfo *) NULL);
|
||
(void) QueryColorDatabase(resource_info->pen_colors[pen_id],
|
||
&draw_info->fill,exception);
|
||
(void) FloodfillPaintImage(*image,DefaultChannels,draw_info,&target,
|
||
(ssize_t) x_offset,(ssize_t) y_offset,
|
||
method == FloodfillMethod ? MagickFalse : MagickTrue);
|
||
draw_info=DestroyDrawInfo(draw_info);
|
||
break;
|
||
}
|
||
case ResetMethod:
|
||
{
|
||
/*
|
||
Update color information using reset algorithm.
|
||
*/
|
||
if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
|
||
return(MagickFalse);
|
||
for (y=0; y < (int) (*image)->rows; y++)
|
||
{
|
||
q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
|
||
(*image)->columns,1,exception);
|
||
if (q == (PixelPacket *) NULL)
|
||
break;
|
||
for (x=0; x < (int) (*image)->columns; x++)
|
||
{
|
||
q->red=ScaleShortToQuantum(color.red);
|
||
q->green=ScaleShortToQuantum(color.green);
|
||
q->blue=ScaleShortToQuantum(color.blue);
|
||
q++;
|
||
}
|
||
if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
image_view=DestroyCacheView(image_view);
|
||
state&=(~UpdateConfigurationState);
|
||
}
|
||
} while ((state & ExitState) == 0);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
(void) XFreeCursor(display,cursor);
|
||
return(MagickTrue);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X C o m p o s i t e I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XCompositeImage() requests an image name from the user, reads the image and
|
||
% composites it with the X window image at a location the user chooses with
|
||
% the pointer.
|
||
%
|
||
% The format of the XCompositeImage method is:
|
||
%
|
||
% MagickBooleanType XCompositeImage(Display *display,
|
||
% XResourceInfo *resource_info,XWindows *windows,Image *image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image; returned from ReadImage.
|
||
%
|
||
*/
|
||
static MagickBooleanType XCompositeImage(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows,Image *image)
|
||
{
|
||
static char
|
||
displacement_geometry[MaxTextExtent] = "30x30",
|
||
filename[MaxTextExtent] = "\0";
|
||
|
||
static const char
|
||
*CompositeMenu[] =
|
||
{
|
||
"Operators",
|
||
"Dissolve",
|
||
"Displace",
|
||
"Help",
|
||
"Dismiss",
|
||
(char *) NULL
|
||
};
|
||
|
||
static CompositeOperator
|
||
compose = CopyCompositeOp;
|
||
|
||
static const ModeType
|
||
CompositeCommands[] =
|
||
{
|
||
CompositeOperatorsCommand,
|
||
CompositeDissolveCommand,
|
||
CompositeDisplaceCommand,
|
||
CompositeHelpCommand,
|
||
CompositeDismissCommand
|
||
};
|
||
|
||
char
|
||
text[MaxTextExtent];
|
||
|
||
Cursor
|
||
cursor;
|
||
|
||
Image
|
||
*composite_image;
|
||
|
||
int
|
||
entry,
|
||
id,
|
||
x,
|
||
y;
|
||
|
||
MagickRealType
|
||
blend,
|
||
scale_factor;
|
||
|
||
RectangleInfo
|
||
highlight_info,
|
||
composite_info;
|
||
|
||
unsigned int
|
||
height,
|
||
width;
|
||
|
||
size_t
|
||
state;
|
||
|
||
XEvent
|
||
event;
|
||
|
||
/*
|
||
Request image file name from user.
|
||
*/
|
||
XFileBrowserWidget(display,windows,"Composite",filename);
|
||
if (*filename == '\0')
|
||
return(MagickTrue);
|
||
/*
|
||
Read image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) CopyMagickString(resource_info->image_info->filename,filename,
|
||
MaxTextExtent);
|
||
composite_image=ReadImage(resource_info->image_info,&image->exception);
|
||
CatchException(&image->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (composite_image == (Image *) NULL)
|
||
return(MagickFalse);
|
||
/*
|
||
Map Command widget.
|
||
*/
|
||
(void) CloneString(&windows->command.name,"Composite");
|
||
windows->command.data=1;
|
||
(void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL);
|
||
(void) XMapRaised(display,windows->command.id);
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_update_widget,CurrentTime);
|
||
/*
|
||
Track pointer until button 1 is pressed.
|
||
*/
|
||
XQueryPosition(display,windows->image.id,&x,&y);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask | PointerMotionMask);
|
||
composite_info.x=(ssize_t) windows->image.x+x;
|
||
composite_info.y=(ssize_t) windows->image.y+y;
|
||
composite_info.width=0;
|
||
composite_info.height=0;
|
||
cursor=XCreateFontCursor(display,XC_ul_angle);
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXinvert);
|
||
blend=0.0;
|
||
state=DefaultState;
|
||
do
|
||
{
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
/*
|
||
Display pointer position.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
|
||
(long) composite_info.x,(long) composite_info.y);
|
||
XInfoWidget(display,windows,text);
|
||
}
|
||
highlight_info=composite_info;
|
||
highlight_info.x=composite_info.x-windows->image.x;
|
||
highlight_info.y=composite_info.y-windows->image.y;
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&highlight_info);
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,&event);
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&highlight_info);
|
||
if (event.xany.window == windows->command.id)
|
||
{
|
||
/*
|
||
Select a command from the Command widget.
|
||
*/
|
||
id=XCommandWidget(display,windows,CompositeMenu,&event);
|
||
if (id < 0)
|
||
continue;
|
||
switch (CompositeCommands[id])
|
||
{
|
||
case CompositeOperatorsCommand:
|
||
{
|
||
char
|
||
command[MaxTextExtent],
|
||
**operators;
|
||
|
||
/*
|
||
Select a command from the pop-up menu.
|
||
*/
|
||
operators=GetCommandOptions(MagickComposeOptions);
|
||
if (operators == (char **) NULL)
|
||
break;
|
||
entry=XMenuWidget(display,windows,CompositeMenu[id],
|
||
(const char **) operators,command);
|
||
if (entry >= 0)
|
||
compose=(CompositeOperator) ParseCommandOption(
|
||
MagickComposeOptions,MagickFalse,operators[entry]);
|
||
operators=DestroyStringList(operators);
|
||
break;
|
||
}
|
||
case CompositeDissolveCommand:
|
||
{
|
||
static char
|
||
factor[MaxTextExtent] = "20.0";
|
||
|
||
/*
|
||
Dissolve the two images a given percent.
|
||
*/
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXcopy);
|
||
(void) XDialogWidget(display,windows,"Dissolve",
|
||
"Enter the blend factor (0.0 - 99.9%):",factor);
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXinvert);
|
||
if (*factor == '\0')
|
||
break;
|
||
blend=StringToDouble(factor,(char **) NULL);
|
||
compose=DissolveCompositeOp;
|
||
break;
|
||
}
|
||
case CompositeDisplaceCommand:
|
||
{
|
||
/*
|
||
Get horizontal and vertical scale displacement geometry.
|
||
*/
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXcopy);
|
||
(void) XDialogWidget(display,windows,"Displace",
|
||
"Enter the horizontal and vertical scale:",displacement_geometry);
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXinvert);
|
||
if (*displacement_geometry == '\0')
|
||
break;
|
||
compose=DisplaceCompositeOp;
|
||
break;
|
||
}
|
||
case CompositeHelpCommand:
|
||
{
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXcopy);
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Composite",ImageCompositeHelp);
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXinvert);
|
||
break;
|
||
}
|
||
case CompositeDismissCommand:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
continue;
|
||
}
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
if (image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
|
||
event.xbutton.button,event.xbutton.x,event.xbutton.y);
|
||
if (event.xbutton.button != Button1)
|
||
break;
|
||
if (event.xbutton.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Change cursor.
|
||
*/
|
||
composite_info.width=composite_image->columns;
|
||
composite_info.height=composite_image->rows;
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
|
||
composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
|
||
break;
|
||
}
|
||
case ButtonRelease:
|
||
{
|
||
if (image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
|
||
event.xbutton.button,event.xbutton.x,event.xbutton.y);
|
||
if (event.xbutton.button != Button1)
|
||
break;
|
||
if (event.xbutton.window != windows->image.id)
|
||
break;
|
||
if ((composite_info.width != 0) && (composite_info.height != 0))
|
||
{
|
||
/*
|
||
User has selected the location of the composite image.
|
||
*/
|
||
composite_info.x=(ssize_t) windows->image.x+event.xbutton.x;
|
||
composite_info.y=(ssize_t) windows->image.y+event.xbutton.y;
|
||
state|=ExitState;
|
||
}
|
||
break;
|
||
}
|
||
case Expose:
|
||
break;
|
||
case KeyPress:
|
||
{
|
||
char
|
||
command[MaxTextExtent];
|
||
|
||
KeySym
|
||
key_symbol;
|
||
|
||
int
|
||
length;
|
||
|
||
if (event.xkey.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Respond to a user key press.
|
||
*/
|
||
length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
*(command+length)='\0';
|
||
if (image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Key press: 0x%lx (%s)",(unsigned long) key_symbol,command);
|
||
switch ((int) key_symbol)
|
||
{
|
||
case XK_Escape:
|
||
case XK_F20:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
composite_image=DestroyImage(composite_image);
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case XK_F1:
|
||
case XK_Help:
|
||
{
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXcopy);
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Composite",ImageCompositeHelp);
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXinvert);
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
(void) XBell(display,0);
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case MotionNotify:
|
||
{
|
||
/*
|
||
Map and unmap Info widget as text cursor crosses its boundaries.
|
||
*/
|
||
x=event.xmotion.x;
|
||
y=event.xmotion.y;
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
if ((x < (int) (windows->info.x+windows->info.width)) &&
|
||
(y < (int) (windows->info.y+windows->info.height)))
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
}
|
||
else
|
||
if ((x > (int) (windows->info.x+windows->info.width)) ||
|
||
(y > (int) (windows->info.y+windows->info.height)))
|
||
(void) XMapWindow(display,windows->info.id);
|
||
composite_info.x=(ssize_t) windows->image.x+x;
|
||
composite_info.y=(ssize_t) windows->image.y+y;
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
if (image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
|
||
event.type);
|
||
break;
|
||
}
|
||
}
|
||
} while ((state & ExitState) == 0);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask);
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXcopy);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
(void) XFreeCursor(display,cursor);
|
||
if ((state & EscapeState) != 0)
|
||
return(MagickTrue);
|
||
/*
|
||
Image compositing is relative to image configuration.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
width=(unsigned int) image->columns;
|
||
height=(unsigned int) image->rows;
|
||
x=0;
|
||
y=0;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
|
||
scale_factor=(MagickRealType) width/windows->image.ximage->width;
|
||
composite_info.x+=x;
|
||
composite_info.x=(ssize_t) (scale_factor*composite_info.x+0.5);
|
||
composite_info.width=(unsigned int) (scale_factor*composite_info.width+0.5);
|
||
scale_factor=(MagickRealType) height/windows->image.ximage->height;
|
||
composite_info.y+=y;
|
||
composite_info.y=(ssize_t) (scale_factor*composite_info.y+0.5);
|
||
composite_info.height=(unsigned int) (scale_factor*composite_info.height+0.5);
|
||
if ((composite_info.width != composite_image->columns) ||
|
||
(composite_info.height != composite_image->rows))
|
||
{
|
||
Image
|
||
*resize_image;
|
||
|
||
/*
|
||
Scale composite image.
|
||
*/
|
||
resize_image=ResizeImage(composite_image,composite_info.width,
|
||
composite_info.height,composite_image->filter,composite_image->blur,
|
||
&image->exception);
|
||
composite_image=DestroyImage(composite_image);
|
||
if (resize_image == (Image *) NULL)
|
||
{
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
return(MagickFalse);
|
||
}
|
||
composite_image=resize_image;
|
||
}
|
||
if (compose == DisplaceCompositeOp)
|
||
(void) SetImageArtifact(composite_image,"compose:args",
|
||
displacement_geometry);
|
||
if (blend != 0.0)
|
||
{
|
||
CacheView
|
||
*image_view;
|
||
|
||
ExceptionInfo
|
||
*exception;
|
||
|
||
int
|
||
y;
|
||
|
||
Quantum
|
||
opacity;
|
||
|
||
register int
|
||
x;
|
||
|
||
register PixelPacket
|
||
*q;
|
||
|
||
/*
|
||
Create mattes for blending.
|
||
*/
|
||
(void) SetImageAlphaChannel(composite_image,OpaqueAlphaChannel);
|
||
opacity=(Quantum) (ScaleQuantumToChar(QuantumRange)-
|
||
((ssize_t) ScaleQuantumToChar(QuantumRange)*blend)/100);
|
||
if (SetImageStorageClass(image,DirectClass) == MagickFalse)
|
||
return(MagickFalse);
|
||
image->matte=MagickTrue;
|
||
exception=(&image->exception);
|
||
image_view=AcquireAuthenticCacheView(image,exception);
|
||
for (y=0; y < (int) image->rows; y++)
|
||
{
|
||
q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,image->columns,1,
|
||
exception);
|
||
if (q == (PixelPacket *) NULL)
|
||
break;
|
||
for (x=0; x < (int) image->columns; x++)
|
||
{
|
||
q->opacity=opacity;
|
||
q++;
|
||
}
|
||
if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
|
||
break;
|
||
}
|
||
image_view=DestroyCacheView(image_view);
|
||
}
|
||
/*
|
||
Composite image with X Image window.
|
||
*/
|
||
(void) CompositeImage(image,compose,composite_image,composite_info.x,
|
||
composite_info.y);
|
||
composite_image=DestroyImage(composite_image);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
/*
|
||
Update image configuration.
|
||
*/
|
||
XConfigureImageColormap(display,resource_info,windows,image);
|
||
(void) XConfigureImage(display,resource_info,windows,image);
|
||
return(MagickTrue);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X C o n f i g u r e I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XConfigureImage() creates a new X image. It also notifies the window
|
||
% manager of the new image size and configures the transient widows.
|
||
%
|
||
% The format of the XConfigureImage method is:
|
||
%
|
||
% MagickBooleanType XConfigureImage(Display *display,
|
||
% XResourceInfo *resource_info,XWindows *windows,Image *image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image.
|
||
%
|
||
%
|
||
*/
|
||
static MagickBooleanType XConfigureImage(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows,Image *image)
|
||
{
|
||
char
|
||
geometry[MaxTextExtent];
|
||
|
||
MagickStatusType
|
||
status;
|
||
|
||
size_t
|
||
mask,
|
||
height,
|
||
width;
|
||
|
||
ssize_t
|
||
x,
|
||
y;
|
||
|
||
XSizeHints
|
||
*size_hints;
|
||
|
||
XWindowChanges
|
||
window_changes;
|
||
|
||
/*
|
||
Dismiss if window dimensions are zero.
|
||
*/
|
||
width=(unsigned int) windows->image.window_changes.width;
|
||
height=(unsigned int) windows->image.window_changes.height;
|
||
if (image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Configure Image: %dx%d=>%.20gx%.20g",windows->image.ximage->width,
|
||
windows->image.ximage->height,(double) width,(double) height);
|
||
if ((width*height) == 0)
|
||
return(MagickTrue);
|
||
x=0;
|
||
y=0;
|
||
/*
|
||
Resize image to fit Image window dimensions.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
(void) XFlush(display);
|
||
if (((int) width != windows->image.ximage->width) ||
|
||
((int) height != windows->image.ximage->height))
|
||
image->taint=MagickTrue;
|
||
windows->magnify.x=(int)
|
||
width*windows->magnify.x/windows->image.ximage->width;
|
||
windows->magnify.y=(int)
|
||
height*windows->magnify.y/windows->image.ximage->height;
|
||
windows->image.x=(int) (width*windows->image.x/windows->image.ximage->width);
|
||
windows->image.y=(int)
|
||
(height*windows->image.y/windows->image.ximage->height);
|
||
status=XMakeImage(display,resource_info,&windows->image,image,
|
||
(unsigned int) width,(unsigned int) height);
|
||
if (status == MagickFalse)
|
||
XNoticeWidget(display,windows,"Unable to configure X image:",
|
||
windows->image.name);
|
||
/*
|
||
Notify window manager of the new configuration.
|
||
*/
|
||
if (resource_info->image_geometry != (char *) NULL)
|
||
(void) FormatLocaleString(geometry,MaxTextExtent,"%s>!",
|
||
resource_info->image_geometry);
|
||
else
|
||
(void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
|
||
XDisplayWidth(display,windows->image.screen),
|
||
XDisplayHeight(display,windows->image.screen));
|
||
(void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
|
||
window_changes.width=(int) width;
|
||
if (window_changes.width > XDisplayWidth(display,windows->image.screen))
|
||
window_changes.width=XDisplayWidth(display,windows->image.screen);
|
||
window_changes.height=(int) height;
|
||
if (window_changes.height > XDisplayHeight(display,windows->image.screen))
|
||
window_changes.height=XDisplayHeight(display,windows->image.screen);
|
||
mask=(size_t) (CWWidth | CWHeight);
|
||
if (resource_info->backdrop)
|
||
{
|
||
mask|=CWX | CWY;
|
||
window_changes.x=(int)
|
||
((XDisplayWidth(display,windows->image.screen)/2)-(width/2));
|
||
window_changes.y=(int)
|
||
((XDisplayHeight(display,windows->image.screen)/2)-(height/2));
|
||
}
|
||
(void) XReconfigureWMWindow(display,windows->image.id,windows->image.screen,
|
||
(unsigned int) mask,&window_changes);
|
||
(void) XClearWindow(display,windows->image.id);
|
||
XRefreshWindow(display,&windows->image,(XEvent *) NULL);
|
||
/*
|
||
Update Magnify window configuration.
|
||
*/
|
||
if (windows->magnify.mapped != MagickFalse)
|
||
XMakeMagnifyImage(display,windows);
|
||
windows->pan.crop_geometry=windows->image.crop_geometry;
|
||
XBestIconSize(display,&windows->pan,image);
|
||
while (((windows->pan.width << 1) < MaxIconSize) &&
|
||
((windows->pan.height << 1) < MaxIconSize))
|
||
{
|
||
windows->pan.width<<=1;
|
||
windows->pan.height<<=1;
|
||
}
|
||
if (windows->pan.geometry != (char *) NULL)
|
||
(void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
|
||
&windows->pan.width,&windows->pan.height);
|
||
window_changes.width=(int) windows->pan.width;
|
||
window_changes.height=(int) windows->pan.height;
|
||
size_hints=XAllocSizeHints();
|
||
if (size_hints != (XSizeHints *) NULL)
|
||
{
|
||
/*
|
||
Set new size hints.
|
||
*/
|
||
size_hints->flags=PSize | PMinSize | PMaxSize;
|
||
size_hints->width=window_changes.width;
|
||
size_hints->height=window_changes.height;
|
||
size_hints->min_width=size_hints->width;
|
||
size_hints->min_height=size_hints->height;
|
||
size_hints->max_width=size_hints->width;
|
||
size_hints->max_height=size_hints->height;
|
||
(void) XSetNormalHints(display,windows->pan.id,size_hints);
|
||
(void) XFree((void *) size_hints);
|
||
}
|
||
(void) XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen,
|
||
(unsigned int) (CWWidth | CWHeight),&window_changes);
|
||
/*
|
||
Update icon window configuration.
|
||
*/
|
||
windows->icon.crop_geometry=windows->image.crop_geometry;
|
||
XBestIconSize(display,&windows->icon,image);
|
||
window_changes.width=(int) windows->icon.width;
|
||
window_changes.height=(int) windows->icon.height;
|
||
(void) XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen,
|
||
(unsigned int) (CWWidth | CWHeight),&window_changes);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
return(status != 0 ? MagickTrue : MagickFalse);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X C r o p I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XCropImage() allows the user to select a region of the image and crop, copy,
|
||
% or cut it. For copy or cut, the image can subsequently be composited onto
|
||
% the image with XPasteImage.
|
||
%
|
||
% The format of the XCropImage method is:
|
||
%
|
||
% MagickBooleanType XCropImage(Display *display,
|
||
% XResourceInfo *resource_info,XWindows *windows,Image *image,
|
||
% const ClipboardMode mode)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image; returned from ReadImage.
|
||
%
|
||
% o mode: This unsigned value specified whether the image should be
|
||
% cropped, copied, or cut.
|
||
%
|
||
*/
|
||
static MagickBooleanType XCropImage(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows,Image *image,
|
||
const ClipboardMode mode)
|
||
{
|
||
static const char
|
||
*CropModeMenu[] =
|
||
{
|
||
"Help",
|
||
"Dismiss",
|
||
(char *) NULL
|
||
},
|
||
*RectifyModeMenu[] =
|
||
{
|
||
"Crop",
|
||
"Help",
|
||
"Dismiss",
|
||
(char *) NULL
|
||
};
|
||
|
||
static const ModeType
|
||
CropCommands[] =
|
||
{
|
||
CropHelpCommand,
|
||
CropDismissCommand
|
||
},
|
||
RectifyCommands[] =
|
||
{
|
||
RectifyCopyCommand,
|
||
RectifyHelpCommand,
|
||
RectifyDismissCommand
|
||
};
|
||
|
||
CacheView
|
||
*image_view;
|
||
|
||
char
|
||
command[MaxTextExtent],
|
||
text[MaxTextExtent];
|
||
|
||
Cursor
|
||
cursor;
|
||
|
||
ExceptionInfo
|
||
*exception;
|
||
|
||
int
|
||
id,
|
||
x,
|
||
y;
|
||
|
||
KeySym
|
||
key_symbol;
|
||
|
||
Image
|
||
*crop_image;
|
||
|
||
MagickRealType
|
||
scale_factor;
|
||
|
||
RectangleInfo
|
||
crop_info,
|
||
highlight_info;
|
||
|
||
register PixelPacket
|
||
*q;
|
||
|
||
unsigned int
|
||
height,
|
||
width;
|
||
|
||
size_t
|
||
state;
|
||
|
||
XEvent
|
||
event;
|
||
|
||
/*
|
||
Map Command widget.
|
||
*/
|
||
switch (mode)
|
||
{
|
||
case CopyMode:
|
||
{
|
||
(void) CloneString(&windows->command.name,"Copy");
|
||
break;
|
||
}
|
||
case CropMode:
|
||
{
|
||
(void) CloneString(&windows->command.name,"Crop");
|
||
break;
|
||
}
|
||
case CutMode:
|
||
{
|
||
(void) CloneString(&windows->command.name,"Cut");
|
||
break;
|
||
}
|
||
}
|
||
RectifyModeMenu[0]=windows->command.name;
|
||
windows->command.data=0;
|
||
(void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL);
|
||
(void) XMapRaised(display,windows->command.id);
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_update_widget,CurrentTime);
|
||
/*
|
||
Track pointer until button 1 is pressed.
|
||
*/
|
||
XQueryPosition(display,windows->image.id,&x,&y);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask | PointerMotionMask);
|
||
crop_info.x=(ssize_t) windows->image.x+x;
|
||
crop_info.y=(ssize_t) windows->image.y+y;
|
||
crop_info.width=0;
|
||
crop_info.height=0;
|
||
cursor=XCreateFontCursor(display,XC_fleur);
|
||
state=DefaultState;
|
||
do
|
||
{
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
/*
|
||
Display pointer position.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
|
||
(long) crop_info.x,(long) crop_info.y);
|
||
XInfoWidget(display,windows,text);
|
||
}
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,&event);
|
||
if (event.xany.window == windows->command.id)
|
||
{
|
||
/*
|
||
Select a command from the Command widget.
|
||
*/
|
||
id=XCommandWidget(display,windows,CropModeMenu,&event);
|
||
if (id < 0)
|
||
continue;
|
||
switch (CropCommands[id])
|
||
{
|
||
case CropHelpCommand:
|
||
{
|
||
switch (mode)
|
||
{
|
||
case CopyMode:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Copy",ImageCopyHelp);
|
||
break;
|
||
}
|
||
case CropMode:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Crop",ImageCropHelp);
|
||
break;
|
||
}
|
||
case CutMode:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Cut",ImageCutHelp);
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case CropDismissCommand:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
continue;
|
||
}
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
if (event.xbutton.button != Button1)
|
||
break;
|
||
if (event.xbutton.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Note first corner of cropping rectangle-- exit loop.
|
||
*/
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
|
||
crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case ButtonRelease:
|
||
break;
|
||
case Expose:
|
||
break;
|
||
case KeyPress:
|
||
{
|
||
if (event.xkey.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Respond to a user key press.
|
||
*/
|
||
(void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
switch ((int) key_symbol)
|
||
{
|
||
case XK_Escape:
|
||
case XK_F20:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case XK_F1:
|
||
case XK_Help:
|
||
{
|
||
switch (mode)
|
||
{
|
||
case CopyMode:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Copy",ImageCopyHelp);
|
||
break;
|
||
}
|
||
case CropMode:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Crop",ImageCropHelp);
|
||
break;
|
||
}
|
||
case CutMode:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Cut",ImageCutHelp);
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
(void) XBell(display,0);
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case MotionNotify:
|
||
{
|
||
if (event.xmotion.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Map and unmap Info widget as text cursor crosses its boundaries.
|
||
*/
|
||
x=event.xmotion.x;
|
||
y=event.xmotion.y;
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
if ((x < (int) (windows->info.x+windows->info.width)) &&
|
||
(y < (int) (windows->info.y+windows->info.height)))
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
}
|
||
else
|
||
if ((x > (int) (windows->info.x+windows->info.width)) ||
|
||
(y > (int) (windows->info.y+windows->info.height)))
|
||
(void) XMapWindow(display,windows->info.id);
|
||
crop_info.x=(ssize_t) windows->image.x+x;
|
||
crop_info.y=(ssize_t) windows->image.y+y;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
} while ((state & ExitState) == 0);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask);
|
||
if ((state & EscapeState) != 0)
|
||
{
|
||
/*
|
||
User want to exit without cropping.
|
||
*/
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
(void) XFreeCursor(display,cursor);
|
||
return(MagickTrue);
|
||
}
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXinvert);
|
||
do
|
||
{
|
||
/*
|
||
Size rectangle as pointer moves until the mouse button is released.
|
||
*/
|
||
x=(int) crop_info.x;
|
||
y=(int) crop_info.y;
|
||
crop_info.width=0;
|
||
crop_info.height=0;
|
||
state=DefaultState;
|
||
do
|
||
{
|
||
highlight_info=crop_info;
|
||
highlight_info.x=crop_info.x-windows->image.x;
|
||
highlight_info.y=crop_info.y-windows->image.y;
|
||
if ((highlight_info.width > 3) && (highlight_info.height > 3))
|
||
{
|
||
/*
|
||
Display info and draw cropping rectangle.
|
||
*/
|
||
if (windows->info.mapped == MagickFalse)
|
||
(void) XMapWindow(display,windows->info.id);
|
||
(void) FormatLocaleString(text,MaxTextExtent,
|
||
" %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
|
||
crop_info.height,(double) crop_info.x,(double) crop_info.y);
|
||
XInfoWidget(display,windows,text);
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&highlight_info);
|
||
}
|
||
else
|
||
if (windows->info.mapped != MagickFalse)
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,&event);
|
||
if ((highlight_info.width > 3) && (highlight_info.height > 3))
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&highlight_info);
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
|
||
crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
|
||
break;
|
||
}
|
||
case ButtonRelease:
|
||
{
|
||
/*
|
||
User has committed to cropping rectangle.
|
||
*/
|
||
crop_info.x=(ssize_t) windows->image.x+event.xbutton.x;
|
||
crop_info.y=(ssize_t) windows->image.y+event.xbutton.y;
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
state|=ExitState;
|
||
windows->command.data=0;
|
||
(void) XCommandWidget(display,windows,RectifyModeMenu,
|
||
(XEvent *) NULL);
|
||
break;
|
||
}
|
||
case Expose:
|
||
break;
|
||
case MotionNotify:
|
||
{
|
||
crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
|
||
crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
if ((((int) crop_info.x != x) && ((int) crop_info.y != y)) ||
|
||
((state & ExitState) != 0))
|
||
{
|
||
/*
|
||
Check boundary conditions.
|
||
*/
|
||
if (crop_info.x < 0)
|
||
crop_info.x=0;
|
||
else
|
||
if (crop_info.x > (ssize_t) windows->image.ximage->width)
|
||
crop_info.x=(ssize_t) windows->image.ximage->width;
|
||
if ((int) crop_info.x < x)
|
||
crop_info.width=(unsigned int) (x-crop_info.x);
|
||
else
|
||
{
|
||
crop_info.width=(unsigned int) (crop_info.x-x);
|
||
crop_info.x=(ssize_t) x;
|
||
}
|
||
if (crop_info.y < 0)
|
||
crop_info.y=0;
|
||
else
|
||
if (crop_info.y > (ssize_t) windows->image.ximage->height)
|
||
crop_info.y=(ssize_t) windows->image.ximage->height;
|
||
if ((int) crop_info.y < y)
|
||
crop_info.height=(unsigned int) (y-crop_info.y);
|
||
else
|
||
{
|
||
crop_info.height=(unsigned int) (crop_info.y-y);
|
||
crop_info.y=(ssize_t) y;
|
||
}
|
||
}
|
||
} while ((state & ExitState) == 0);
|
||
/*
|
||
Wait for user to grab a corner of the rectangle or press return.
|
||
*/
|
||
state=DefaultState;
|
||
(void) XMapWindow(display,windows->info.id);
|
||
do
|
||
{
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
/*
|
||
Display pointer position.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent,
|
||
" %.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
|
||
crop_info.height,(double) crop_info.x,(double) crop_info.y);
|
||
XInfoWidget(display,windows,text);
|
||
}
|
||
highlight_info=crop_info;
|
||
highlight_info.x=crop_info.x-windows->image.x;
|
||
highlight_info.y=crop_info.y-windows->image.y;
|
||
if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
|
||
{
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&highlight_info);
|
||
XScreenEvent(display,windows,&event);
|
||
if (event.xany.window == windows->command.id)
|
||
{
|
||
/*
|
||
Select a command from the Command widget.
|
||
*/
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXcopy);
|
||
id=XCommandWidget(display,windows,RectifyModeMenu,&event);
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXinvert);
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&highlight_info);
|
||
if (id >= 0)
|
||
switch (RectifyCommands[id])
|
||
{
|
||
case RectifyCopyCommand:
|
||
{
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case RectifyHelpCommand:
|
||
{
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXcopy);
|
||
switch (mode)
|
||
{
|
||
case CopyMode:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Copy",ImageCopyHelp);
|
||
break;
|
||
}
|
||
case CropMode:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Crop",ImageCropHelp);
|
||
break;
|
||
}
|
||
case CutMode:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Cut",ImageCutHelp);
|
||
break;
|
||
}
|
||
}
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXinvert);
|
||
break;
|
||
}
|
||
case RectifyDismissCommand:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
continue;
|
||
}
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&highlight_info);
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
if (event.xbutton.button != Button1)
|
||
break;
|
||
if (event.xbutton.window != windows->image.id)
|
||
break;
|
||
x=windows->image.x+event.xbutton.x;
|
||
y=windows->image.y+event.xbutton.y;
|
||
if ((x < (int) (crop_info.x+RoiDelta)) &&
|
||
(x > (int) (crop_info.x-RoiDelta)) &&
|
||
(y < (int) (crop_info.y+RoiDelta)) &&
|
||
(y > (int) (crop_info.y-RoiDelta)))
|
||
{
|
||
crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
|
||
crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
|
||
state|=UpdateConfigurationState;
|
||
break;
|
||
}
|
||
if ((x < (int) (crop_info.x+RoiDelta)) &&
|
||
(x > (int) (crop_info.x-RoiDelta)) &&
|
||
(y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
|
||
(y > (int) (crop_info.y+crop_info.height-RoiDelta)))
|
||
{
|
||
crop_info.x=(ssize_t) (crop_info.x+crop_info.width);
|
||
state|=UpdateConfigurationState;
|
||
break;
|
||
}
|
||
if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
|
||
(x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
|
||
(y < (int) (crop_info.y+RoiDelta)) &&
|
||
(y > (int) (crop_info.y-RoiDelta)))
|
||
{
|
||
crop_info.y=(ssize_t) (crop_info.y+crop_info.height);
|
||
state|=UpdateConfigurationState;
|
||
break;
|
||
}
|
||
if ((x < (int) (crop_info.x+crop_info.width+RoiDelta)) &&
|
||
(x > (int) (crop_info.x+crop_info.width-RoiDelta)) &&
|
||
(y < (int) (crop_info.y+crop_info.height+RoiDelta)) &&
|
||
(y > (int) (crop_info.y+crop_info.height-RoiDelta)))
|
||
{
|
||
state|=UpdateConfigurationState;
|
||
break;
|
||
}
|
||
}
|
||
case ButtonRelease:
|
||
{
|
||
if (event.xbutton.window == windows->pan.id)
|
||
if ((highlight_info.x != crop_info.x-windows->image.x) ||
|
||
(highlight_info.y != crop_info.y-windows->image.y))
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&highlight_info);
|
||
(void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
|
||
event.xbutton.time);
|
||
break;
|
||
}
|
||
case Expose:
|
||
{
|
||
if (event.xexpose.window == windows->image.id)
|
||
if (event.xexpose.count == 0)
|
||
{
|
||
event.xexpose.x=(int) highlight_info.x;
|
||
event.xexpose.y=(int) highlight_info.y;
|
||
event.xexpose.width=(int) highlight_info.width;
|
||
event.xexpose.height=(int) highlight_info.height;
|
||
XRefreshWindow(display,&windows->image,&event);
|
||
}
|
||
if (event.xexpose.window == windows->info.id)
|
||
if (event.xexpose.count == 0)
|
||
XInfoWidget(display,windows,text);
|
||
break;
|
||
}
|
||
case KeyPress:
|
||
{
|
||
if (event.xkey.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Respond to a user key press.
|
||
*/
|
||
(void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
switch ((int) key_symbol)
|
||
{
|
||
case XK_Escape:
|
||
case XK_F20:
|
||
state|=EscapeState;
|
||
case XK_Return:
|
||
{
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case XK_Home:
|
||
case XK_KP_Home:
|
||
{
|
||
crop_info.x=(ssize_t) (windows->image.width/2L-
|
||
crop_info.width/2L);
|
||
crop_info.y=(ssize_t) (windows->image.height/2L-
|
||
crop_info.height/2L);
|
||
break;
|
||
}
|
||
case XK_Left:
|
||
case XK_KP_Left:
|
||
{
|
||
crop_info.x--;
|
||
break;
|
||
}
|
||
case XK_Up:
|
||
case XK_KP_Up:
|
||
case XK_Next:
|
||
{
|
||
crop_info.y--;
|
||
break;
|
||
}
|
||
case XK_Right:
|
||
case XK_KP_Right:
|
||
{
|
||
crop_info.x++;
|
||
break;
|
||
}
|
||
case XK_Prior:
|
||
case XK_Down:
|
||
case XK_KP_Down:
|
||
{
|
||
crop_info.y++;
|
||
break;
|
||
}
|
||
case XK_F1:
|
||
case XK_Help:
|
||
{
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXcopy);
|
||
switch (mode)
|
||
{
|
||
case CopyMode:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Copy",ImageCopyHelp);
|
||
break;
|
||
}
|
||
case CropMode:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Cropg",ImageCropHelp);
|
||
break;
|
||
}
|
||
case CutMode:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Cutg",ImageCutHelp);
|
||
break;
|
||
}
|
||
}
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXinvert);
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
(void) XBell(display,0);
|
||
break;
|
||
}
|
||
}
|
||
(void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
|
||
event.xkey.time);
|
||
break;
|
||
}
|
||
case KeyRelease:
|
||
break;
|
||
case MotionNotify:
|
||
{
|
||
if (event.xmotion.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Map and unmap Info widget as text cursor crosses its boundaries.
|
||
*/
|
||
x=event.xmotion.x;
|
||
y=event.xmotion.y;
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
if ((x < (int) (windows->info.x+windows->info.width)) &&
|
||
(y < (int) (windows->info.y+windows->info.height)))
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
}
|
||
else
|
||
if ((x > (int) (windows->info.x+windows->info.width)) ||
|
||
(y > (int) (windows->info.y+windows->info.height)))
|
||
(void) XMapWindow(display,windows->info.id);
|
||
crop_info.x=(ssize_t) windows->image.x+event.xmotion.x;
|
||
crop_info.y=(ssize_t) windows->image.y+event.xmotion.y;
|
||
break;
|
||
}
|
||
case SelectionRequest:
|
||
{
|
||
XSelectionEvent
|
||
notify;
|
||
|
||
XSelectionRequestEvent
|
||
*request;
|
||
|
||
/*
|
||
Set primary selection.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent,
|
||
"%.20gx%.20g%+.20g%+.20g",(double) crop_info.width,(double)
|
||
crop_info.height,(double) crop_info.x,(double) crop_info.y);
|
||
request=(&(event.xselectionrequest));
|
||
(void) XChangeProperty(request->display,request->requestor,
|
||
request->property,request->target,8,PropModeReplace,
|
||
(unsigned char *) text,(int) strlen(text));
|
||
notify.type=SelectionNotify;
|
||
notify.display=request->display;
|
||
notify.requestor=request->requestor;
|
||
notify.selection=request->selection;
|
||
notify.target=request->target;
|
||
notify.time=request->time;
|
||
if (request->property == None)
|
||
notify.property=request->target;
|
||
else
|
||
notify.property=request->property;
|
||
(void) XSendEvent(request->display,request->requestor,False,0,
|
||
(XEvent *) ¬ify);
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
if ((state & UpdateConfigurationState) != 0)
|
||
{
|
||
(void) XPutBackEvent(display,&event);
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
break;
|
||
}
|
||
} while ((state & ExitState) == 0);
|
||
} while ((state & ExitState) == 0);
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXcopy);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if ((state & EscapeState) != 0)
|
||
return(MagickTrue);
|
||
if (mode == CropMode)
|
||
if (((int) crop_info.width != windows->image.ximage->width) ||
|
||
((int) crop_info.height != windows->image.ximage->height))
|
||
{
|
||
/*
|
||
Reconfigure Image window as defined by cropping rectangle.
|
||
*/
|
||
XSetCropGeometry(display,windows,&crop_info,image);
|
||
windows->image.window_changes.width=(int) crop_info.width;
|
||
windows->image.window_changes.height=(int) crop_info.height;
|
||
(void) XConfigureImage(display,resource_info,windows,image);
|
||
return(MagickTrue);
|
||
}
|
||
/*
|
||
Copy image before applying image transforms.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
width=(unsigned int) image->columns;
|
||
height=(unsigned int) image->rows;
|
||
x=0;
|
||
y=0;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
|
||
scale_factor=(MagickRealType) width/windows->image.ximage->width;
|
||
crop_info.x+=x;
|
||
crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
|
||
crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
|
||
scale_factor=(MagickRealType) height/windows->image.ximage->height;
|
||
crop_info.y+=y;
|
||
crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
|
||
crop_info.height=(unsigned int) (scale_factor*crop_info.height+0.5);
|
||
crop_image=CropImage(image,&crop_info,&image->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (crop_image == (Image *) NULL)
|
||
return(MagickFalse);
|
||
if (resource_info->copy_image != (Image *) NULL)
|
||
resource_info->copy_image=DestroyImage(resource_info->copy_image);
|
||
resource_info->copy_image=crop_image;
|
||
if (mode == CopyMode)
|
||
{
|
||
(void) XConfigureImage(display,resource_info,windows,image);
|
||
return(MagickTrue);
|
||
}
|
||
/*
|
||
Cut image.
|
||
*/
|
||
if (SetImageStorageClass(image,DirectClass) == MagickFalse)
|
||
return(MagickFalse);
|
||
image->matte=MagickTrue;
|
||
exception=(&image->exception);
|
||
image_view=AcquireAuthenticCacheView(image,exception);
|
||
for (y=0; y < (int) crop_info.height; y++)
|
||
{
|
||
q=GetCacheViewAuthenticPixels(image_view,crop_info.x,y+crop_info.y,
|
||
crop_info.width,1,exception);
|
||
if (q == (PixelPacket *) NULL)
|
||
break;
|
||
for (x=0; x < (int) crop_info.width; x++)
|
||
{
|
||
q->opacity=(Quantum) TransparentOpacity;
|
||
q++;
|
||
}
|
||
if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
|
||
break;
|
||
}
|
||
image_view=DestroyCacheView(image_view);
|
||
/*
|
||
Update image configuration.
|
||
*/
|
||
XConfigureImageColormap(display,resource_info,windows,image);
|
||
(void) XConfigureImage(display,resource_info,windows,image);
|
||
return(MagickTrue);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X D r a w I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XDrawEditImage() draws a graphic element (point, line, rectangle, etc.) on
|
||
% the image.
|
||
%
|
||
% The format of the XDrawEditImage method is:
|
||
%
|
||
% MagickBooleanType XDrawEditImage(Display *display,
|
||
% XResourceInfo *resource_info,XWindows *windows,Image **image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image.
|
||
%
|
||
*/
|
||
static MagickBooleanType XDrawEditImage(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows,Image **image)
|
||
{
|
||
static const char
|
||
*DrawMenu[] =
|
||
{
|
||
"Element",
|
||
"Color",
|
||
"Stipple",
|
||
"Width",
|
||
"Undo",
|
||
"Help",
|
||
"Dismiss",
|
||
(char *) NULL
|
||
};
|
||
|
||
static ElementType
|
||
element = PointElement;
|
||
|
||
static const ModeType
|
||
DrawCommands[] =
|
||
{
|
||
DrawElementCommand,
|
||
DrawColorCommand,
|
||
DrawStippleCommand,
|
||
DrawWidthCommand,
|
||
DrawUndoCommand,
|
||
DrawHelpCommand,
|
||
DrawDismissCommand
|
||
};
|
||
|
||
static Pixmap
|
||
stipple = (Pixmap) NULL;
|
||
|
||
static unsigned int
|
||
pen_id = 0,
|
||
line_width = 1;
|
||
|
||
char
|
||
command[MaxTextExtent],
|
||
text[MaxTextExtent];
|
||
|
||
Cursor
|
||
cursor;
|
||
|
||
int
|
||
entry,
|
||
id,
|
||
number_coordinates,
|
||
x,
|
||
y;
|
||
|
||
MagickRealType
|
||
degrees;
|
||
|
||
MagickStatusType
|
||
status;
|
||
|
||
RectangleInfo
|
||
rectangle_info;
|
||
|
||
register int
|
||
i;
|
||
|
||
unsigned int
|
||
distance,
|
||
height,
|
||
max_coordinates,
|
||
width;
|
||
|
||
size_t
|
||
state;
|
||
|
||
Window
|
||
root_window;
|
||
|
||
XDrawInfo
|
||
draw_info;
|
||
|
||
XEvent
|
||
event;
|
||
|
||
XPoint
|
||
*coordinate_info;
|
||
|
||
XSegment
|
||
line_info;
|
||
|
||
/*
|
||
Allocate polygon info.
|
||
*/
|
||
max_coordinates=2048;
|
||
coordinate_info=(XPoint *) AcquireQuantumMemory((size_t) max_coordinates,
|
||
sizeof(*coordinate_info));
|
||
if (coordinate_info == (XPoint *) NULL)
|
||
{
|
||
(void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
|
||
ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
|
||
return(MagickFalse);
|
||
}
|
||
/*
|
||
Map Command widget.
|
||
*/
|
||
(void) CloneString(&windows->command.name,"Draw");
|
||
windows->command.data=4;
|
||
(void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL);
|
||
(void) XMapRaised(display,windows->command.id);
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_update_widget,CurrentTime);
|
||
/*
|
||
Wait for first button press.
|
||
*/
|
||
root_window=XRootWindow(display,XDefaultScreen(display));
|
||
draw_info.stencil=OpaqueStencil;
|
||
status=MagickTrue;
|
||
cursor=XCreateFontCursor(display,XC_tcross);
|
||
for ( ; ; )
|
||
{
|
||
XQueryPosition(display,windows->image.id,&x,&y);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask | PointerMotionMask);
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
state=DefaultState;
|
||
do
|
||
{
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
/*
|
||
Display pointer position.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
|
||
x+windows->image.x,y+windows->image.y);
|
||
XInfoWidget(display,windows,text);
|
||
}
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,&event);
|
||
if (event.xany.window == windows->command.id)
|
||
{
|
||
/*
|
||
Select a command from the Command widget.
|
||
*/
|
||
id=XCommandWidget(display,windows,DrawMenu,&event);
|
||
if (id < 0)
|
||
continue;
|
||
switch (DrawCommands[id])
|
||
{
|
||
case DrawElementCommand:
|
||
{
|
||
static const char
|
||
*Elements[] =
|
||
{
|
||
"point",
|
||
"line",
|
||
"rectangle",
|
||
"fill rectangle",
|
||
"circle",
|
||
"fill circle",
|
||
"ellipse",
|
||
"fill ellipse",
|
||
"polygon",
|
||
"fill polygon",
|
||
(char *) NULL,
|
||
};
|
||
|
||
/*
|
||
Select a command from the pop-up menu.
|
||
*/
|
||
element=(ElementType) (XMenuWidget(display,windows,
|
||
DrawMenu[id],Elements,command)+1);
|
||
break;
|
||
}
|
||
case DrawColorCommand:
|
||
{
|
||
const char
|
||
*ColorMenu[MaxNumberPens+1];
|
||
|
||
int
|
||
pen_number;
|
||
|
||
MagickBooleanType
|
||
transparent;
|
||
|
||
XColor
|
||
color;
|
||
|
||
/*
|
||
Initialize menu selections.
|
||
*/
|
||
for (i=0; i < (int) (MaxNumberPens-2); i++)
|
||
ColorMenu[i]=resource_info->pen_colors[i];
|
||
ColorMenu[MaxNumberPens-2]="transparent";
|
||
ColorMenu[MaxNumberPens-1]="Browser...";
|
||
ColorMenu[MaxNumberPens]=(char *) NULL;
|
||
/*
|
||
Select a pen color from the pop-up menu.
|
||
*/
|
||
pen_number=XMenuWidget(display,windows,DrawMenu[id],
|
||
(const char **) ColorMenu,command);
|
||
if (pen_number < 0)
|
||
break;
|
||
transparent=pen_number == (MaxNumberPens-2) ? MagickTrue :
|
||
MagickFalse;
|
||
if (transparent != MagickFalse)
|
||
{
|
||
draw_info.stencil=TransparentStencil;
|
||
break;
|
||
}
|
||
if (pen_number == (MaxNumberPens-1))
|
||
{
|
||
static char
|
||
color_name[MaxTextExtent] = "gray";
|
||
|
||
/*
|
||
Select a pen color from a dialog.
|
||
*/
|
||
resource_info->pen_colors[pen_number]=color_name;
|
||
XColorBrowserWidget(display,windows,"Select",color_name);
|
||
if (*color_name == '\0')
|
||
break;
|
||
}
|
||
/*
|
||
Set pen color.
|
||
*/
|
||
(void) XParseColor(display,windows->map_info->colormap,
|
||
resource_info->pen_colors[pen_number],&color);
|
||
XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
|
||
(unsigned int) MaxColors,&color);
|
||
windows->pixel_info->pen_colors[pen_number]=color;
|
||
pen_id=(unsigned int) pen_number;
|
||
draw_info.stencil=OpaqueStencil;
|
||
break;
|
||
}
|
||
case DrawStippleCommand:
|
||
{
|
||
Image
|
||
*stipple_image;
|
||
|
||
ImageInfo
|
||
*image_info;
|
||
|
||
int
|
||
status;
|
||
|
||
static char
|
||
filename[MaxTextExtent] = "\0";
|
||
|
||
static const char
|
||
*StipplesMenu[] =
|
||
{
|
||
"Brick",
|
||
"Diagonal",
|
||
"Scales",
|
||
"Vertical",
|
||
"Wavy",
|
||
"Translucent",
|
||
"Opaque",
|
||
(char *) NULL,
|
||
(char *) NULL,
|
||
};
|
||
|
||
/*
|
||
Select a command from the pop-up menu.
|
||
*/
|
||
StipplesMenu[7]="Open...";
|
||
entry=XMenuWidget(display,windows,DrawMenu[id],StipplesMenu,
|
||
command);
|
||
if (entry < 0)
|
||
break;
|
||
if (stipple != (Pixmap) NULL)
|
||
(void) XFreePixmap(display,stipple);
|
||
stipple=(Pixmap) NULL;
|
||
if (entry != 7)
|
||
{
|
||
switch (entry)
|
||
{
|
||
case 0:
|
||
{
|
||
stipple=XCreateBitmapFromData(display,root_window,
|
||
(char *) BricksBitmap,BricksWidth,BricksHeight);
|
||
break;
|
||
}
|
||
case 1:
|
||
{
|
||
stipple=XCreateBitmapFromData(display,root_window,
|
||
(char *) DiagonalBitmap,DiagonalWidth,DiagonalHeight);
|
||
break;
|
||
}
|
||
case 2:
|
||
{
|
||
stipple=XCreateBitmapFromData(display,root_window,
|
||
(char *) ScalesBitmap,ScalesWidth,ScalesHeight);
|
||
break;
|
||
}
|
||
case 3:
|
||
{
|
||
stipple=XCreateBitmapFromData(display,root_window,
|
||
(char *) VerticalBitmap,VerticalWidth,VerticalHeight);
|
||
break;
|
||
}
|
||
case 4:
|
||
{
|
||
stipple=XCreateBitmapFromData(display,root_window,
|
||
(char *) WavyBitmap,WavyWidth,WavyHeight);
|
||
break;
|
||
}
|
||
case 5:
|
||
{
|
||
stipple=XCreateBitmapFromData(display,root_window,
|
||
(char *) HighlightBitmap,HighlightWidth,
|
||
HighlightHeight);
|
||
break;
|
||
}
|
||
case 6:
|
||
default:
|
||
{
|
||
stipple=XCreateBitmapFromData(display,root_window,
|
||
(char *) OpaqueBitmap,OpaqueWidth,OpaqueHeight);
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
XFileBrowserWidget(display,windows,"Stipple",filename);
|
||
if (*filename == '\0')
|
||
break;
|
||
/*
|
||
Read image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
image_info=AcquireImageInfo();
|
||
(void) CopyMagickString(image_info->filename,filename,
|
||
MaxTextExtent);
|
||
stipple_image=ReadImage(image_info,&(*image)->exception);
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (stipple_image == (Image *) NULL)
|
||
break;
|
||
(void) AcquireUniqueFileResource(filename);
|
||
(void) FormatLocaleString(stipple_image->filename,MaxTextExtent,
|
||
"xbm:%s",filename);
|
||
(void) WriteImage(image_info,stipple_image);
|
||
stipple_image=DestroyImage(stipple_image);
|
||
image_info=DestroyImageInfo(image_info);
|
||
status=XReadBitmapFile(display,root_window,filename,&width,
|
||
&height,&stipple,&x,&y);
|
||
(void) RelinquishUniqueFileResource(filename);
|
||
if ((status != BitmapSuccess) != 0)
|
||
XNoticeWidget(display,windows,"Unable to read X bitmap image:",
|
||
filename);
|
||
break;
|
||
}
|
||
case DrawWidthCommand:
|
||
{
|
||
static char
|
||
width[MaxTextExtent] = "0";
|
||
|
||
static const char
|
||
*WidthsMenu[] =
|
||
{
|
||
"1",
|
||
"2",
|
||
"4",
|
||
"8",
|
||
"16",
|
||
"Dialog...",
|
||
(char *) NULL,
|
||
};
|
||
|
||
/*
|
||
Select a command from the pop-up menu.
|
||
*/
|
||
entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu,
|
||
command);
|
||
if (entry < 0)
|
||
break;
|
||
if (entry != 5)
|
||
{
|
||
line_width=(unsigned int) StringToUnsignedLong(
|
||
WidthsMenu[entry]);
|
||
break;
|
||
}
|
||
(void) XDialogWidget(display,windows,"Ok","Enter line width:",
|
||
width);
|
||
if (*width == '\0')
|
||
break;
|
||
line_width=(unsigned int) StringToUnsignedLong(width);
|
||
break;
|
||
}
|
||
case DrawUndoCommand:
|
||
{
|
||
(void) XMagickCommand(display,resource_info,windows,UndoCommand,
|
||
image);
|
||
break;
|
||
}
|
||
case DrawHelpCommand:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Rotation",ImageDrawHelp);
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
break;
|
||
}
|
||
case DrawDismissCommand:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
continue;
|
||
}
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
if (event.xbutton.button != Button1)
|
||
break;
|
||
if (event.xbutton.window != windows->image.id)
|
||
break;
|
||
/*
|
||
exit loop.
|
||
*/
|
||
x=event.xbutton.x;
|
||
y=event.xbutton.y;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case ButtonRelease:
|
||
break;
|
||
case Expose:
|
||
break;
|
||
case KeyPress:
|
||
{
|
||
KeySym
|
||
key_symbol;
|
||
|
||
if (event.xkey.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Respond to a user key press.
|
||
*/
|
||
(void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
switch ((int) key_symbol)
|
||
{
|
||
case XK_Escape:
|
||
case XK_F20:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case XK_F1:
|
||
case XK_Help:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Rotation",ImageDrawHelp);
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
(void) XBell(display,0);
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case MotionNotify:
|
||
{
|
||
/*
|
||
Map and unmap Info widget as text cursor crosses its boundaries.
|
||
*/
|
||
x=event.xmotion.x;
|
||
y=event.xmotion.y;
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
if ((x < (int) (windows->info.x+windows->info.width)) &&
|
||
(y < (int) (windows->info.y+windows->info.height)))
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
}
|
||
else
|
||
if ((x > (int) (windows->info.x+windows->info.width)) ||
|
||
(y > (int) (windows->info.y+windows->info.height)))
|
||
(void) XMapWindow(display,windows->info.id);
|
||
break;
|
||
}
|
||
}
|
||
} while ((state & ExitState) == 0);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask);
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
if ((state & EscapeState) != 0)
|
||
break;
|
||
/*
|
||
Draw element as pointer moves until the button is released.
|
||
*/
|
||
distance=0;
|
||
degrees=0.0;
|
||
line_info.x1=x;
|
||
line_info.y1=y;
|
||
line_info.x2=x;
|
||
line_info.y2=y;
|
||
rectangle_info.x=(ssize_t) x;
|
||
rectangle_info.y=(ssize_t) y;
|
||
rectangle_info.width=0;
|
||
rectangle_info.height=0;
|
||
number_coordinates=1;
|
||
coordinate_info->x=x;
|
||
coordinate_info->y=y;
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXinvert);
|
||
state=DefaultState;
|
||
do
|
||
{
|
||
switch (element)
|
||
{
|
||
case PointElement:
|
||
default:
|
||
{
|
||
if (number_coordinates > 1)
|
||
{
|
||
(void) XDrawLines(display,windows->image.id,
|
||
windows->image.highlight_context,coordinate_info,
|
||
number_coordinates,CoordModeOrigin);
|
||
(void) FormatLocaleString(text,MaxTextExtent," %+d%+d",
|
||
coordinate_info[number_coordinates-1].x,
|
||
coordinate_info[number_coordinates-1].y);
|
||
XInfoWidget(display,windows,text);
|
||
}
|
||
break;
|
||
}
|
||
case LineElement:
|
||
{
|
||
if (distance > 9)
|
||
{
|
||
/*
|
||
Display angle of the line.
|
||
*/
|
||
degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
|
||
line_info.y1),(double) (line_info.x2-line_info.x1)));
|
||
(void) FormatLocaleString(text,MaxTextExtent," %g",
|
||
(double) degrees);
|
||
XInfoWidget(display,windows,text);
|
||
XHighlightLine(display,windows->image.id,
|
||
windows->image.highlight_context,&line_info);
|
||
}
|
||
else
|
||
if (windows->info.mapped != MagickFalse)
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
break;
|
||
}
|
||
case RectangleElement:
|
||
case FillRectangleElement:
|
||
{
|
||
if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
|
||
{
|
||
/*
|
||
Display info and draw drawing rectangle.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent,
|
||
" %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
|
||
(double) rectangle_info.height,(double) rectangle_info.x,
|
||
(double) rectangle_info.y);
|
||
XInfoWidget(display,windows,text);
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&rectangle_info);
|
||
}
|
||
else
|
||
if (windows->info.mapped != MagickFalse)
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
break;
|
||
}
|
||
case CircleElement:
|
||
case FillCircleElement:
|
||
case EllipseElement:
|
||
case FillEllipseElement:
|
||
{
|
||
if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
|
||
{
|
||
/*
|
||
Display info and draw drawing rectangle.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent,
|
||
" %.20gx%.20g%+.20g%+.20g",(double) rectangle_info.width,
|
||
(double) rectangle_info.height,(double) rectangle_info.x,
|
||
(double) rectangle_info.y);
|
||
XInfoWidget(display,windows,text);
|
||
XHighlightEllipse(display,windows->image.id,
|
||
windows->image.highlight_context,&rectangle_info);
|
||
}
|
||
else
|
||
if (windows->info.mapped != MagickFalse)
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
break;
|
||
}
|
||
case PolygonElement:
|
||
case FillPolygonElement:
|
||
{
|
||
if (number_coordinates > 1)
|
||
(void) XDrawLines(display,windows->image.id,
|
||
windows->image.highlight_context,coordinate_info,
|
||
number_coordinates,CoordModeOrigin);
|
||
if (distance > 9)
|
||
{
|
||
/*
|
||
Display angle of the line.
|
||
*/
|
||
degrees=RadiansToDegrees(-atan2((double) (line_info.y2-
|
||
line_info.y1),(double) (line_info.x2-line_info.x1)));
|
||
(void) FormatLocaleString(text,MaxTextExtent," %g",
|
||
(double) degrees);
|
||
XInfoWidget(display,windows,text);
|
||
XHighlightLine(display,windows->image.id,
|
||
windows->image.highlight_context,&line_info);
|
||
}
|
||
else
|
||
if (windows->info.mapped != MagickFalse)
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
break;
|
||
}
|
||
}
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,&event);
|
||
switch (element)
|
||
{
|
||
case PointElement:
|
||
default:
|
||
{
|
||
if (number_coordinates > 1)
|
||
(void) XDrawLines(display,windows->image.id,
|
||
windows->image.highlight_context,coordinate_info,
|
||
number_coordinates,CoordModeOrigin);
|
||
break;
|
||
}
|
||
case LineElement:
|
||
{
|
||
if (distance > 9)
|
||
XHighlightLine(display,windows->image.id,
|
||
windows->image.highlight_context,&line_info);
|
||
break;
|
||
}
|
||
case RectangleElement:
|
||
case FillRectangleElement:
|
||
{
|
||
if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&rectangle_info);
|
||
break;
|
||
}
|
||
case CircleElement:
|
||
case FillCircleElement:
|
||
case EllipseElement:
|
||
case FillEllipseElement:
|
||
{
|
||
if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
|
||
XHighlightEllipse(display,windows->image.id,
|
||
windows->image.highlight_context,&rectangle_info);
|
||
break;
|
||
}
|
||
case PolygonElement:
|
||
case FillPolygonElement:
|
||
{
|
||
if (number_coordinates > 1)
|
||
(void) XDrawLines(display,windows->image.id,
|
||
windows->image.highlight_context,coordinate_info,
|
||
number_coordinates,CoordModeOrigin);
|
||
if (distance > 9)
|
||
XHighlightLine(display,windows->image.id,
|
||
windows->image.highlight_context,&line_info);
|
||
break;
|
||
}
|
||
}
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
break;
|
||
case ButtonRelease:
|
||
{
|
||
/*
|
||
User has committed to element.
|
||
*/
|
||
line_info.x2=event.xbutton.x;
|
||
line_info.y2=event.xbutton.y;
|
||
rectangle_info.x=(ssize_t) event.xbutton.x;
|
||
rectangle_info.y=(ssize_t) event.xbutton.y;
|
||
coordinate_info[number_coordinates].x=event.xbutton.x;
|
||
coordinate_info[number_coordinates].y=event.xbutton.y;
|
||
if (((element != PolygonElement) &&
|
||
(element != FillPolygonElement)) || (distance <= 9))
|
||
{
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
number_coordinates++;
|
||
if (number_coordinates < (int) max_coordinates)
|
||
{
|
||
line_info.x1=event.xbutton.x;
|
||
line_info.y1=event.xbutton.y;
|
||
break;
|
||
}
|
||
max_coordinates<<=1;
|
||
coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
|
||
max_coordinates,sizeof(*coordinate_info));
|
||
if (coordinate_info == (XPoint *) NULL)
|
||
(void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
|
||
ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
|
||
break;
|
||
}
|
||
case Expose:
|
||
break;
|
||
case MotionNotify:
|
||
{
|
||
if (event.xmotion.window != windows->image.id)
|
||
break;
|
||
if (element != PointElement)
|
||
{
|
||
line_info.x2=event.xmotion.x;
|
||
line_info.y2=event.xmotion.y;
|
||
rectangle_info.x=(ssize_t) event.xmotion.x;
|
||
rectangle_info.y=(ssize_t) event.xmotion.y;
|
||
break;
|
||
}
|
||
coordinate_info[number_coordinates].x=event.xbutton.x;
|
||
coordinate_info[number_coordinates].y=event.xbutton.y;
|
||
number_coordinates++;
|
||
if (number_coordinates < (int) max_coordinates)
|
||
break;
|
||
max_coordinates<<=1;
|
||
coordinate_info=(XPoint *) ResizeQuantumMemory(coordinate_info,
|
||
max_coordinates,sizeof(*coordinate_info));
|
||
if (coordinate_info == (XPoint *) NULL)
|
||
(void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
|
||
ResourceLimitError,"MemoryAllocationFailed","`%s'","...");
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
/*
|
||
Check boundary conditions.
|
||
*/
|
||
if (line_info.x2 < 0)
|
||
line_info.x2=0;
|
||
else
|
||
if (line_info.x2 > (int) windows->image.width)
|
||
line_info.x2=(short) windows->image.width;
|
||
if (line_info.y2 < 0)
|
||
line_info.y2=0;
|
||
else
|
||
if (line_info.y2 > (int) windows->image.height)
|
||
line_info.y2=(short) windows->image.height;
|
||
distance=(unsigned int)
|
||
(((line_info.x2-line_info.x1+1)*(line_info.x2-line_info.x1+1))+
|
||
((line_info.y2-line_info.y1+1)*(line_info.y2-line_info.y1+1)));
|
||
if ((((int) rectangle_info.x != x) && ((int) rectangle_info.y != y)) ||
|
||
((state & ExitState) != 0))
|
||
{
|
||
if (rectangle_info.x < 0)
|
||
rectangle_info.x=0;
|
||
else
|
||
if (rectangle_info.x > (ssize_t) windows->image.width)
|
||
rectangle_info.x=(ssize_t) windows->image.width;
|
||
if ((int) rectangle_info.x < x)
|
||
rectangle_info.width=(unsigned int) (x-rectangle_info.x);
|
||
else
|
||
{
|
||
rectangle_info.width=(unsigned int) (rectangle_info.x-x);
|
||
rectangle_info.x=(ssize_t) x;
|
||
}
|
||
if (rectangle_info.y < 0)
|
||
rectangle_info.y=0;
|
||
else
|
||
if (rectangle_info.y > (ssize_t) windows->image.height)
|
||
rectangle_info.y=(ssize_t) windows->image.height;
|
||
if ((int) rectangle_info.y < y)
|
||
rectangle_info.height=(unsigned int) (y-rectangle_info.y);
|
||
else
|
||
{
|
||
rectangle_info.height=(unsigned int) (rectangle_info.y-y);
|
||
rectangle_info.y=(ssize_t) y;
|
||
}
|
||
}
|
||
} while ((state & ExitState) == 0);
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXcopy);
|
||
if ((element == PointElement) || (element == PolygonElement) ||
|
||
(element == FillPolygonElement))
|
||
{
|
||
/*
|
||
Determine polygon bounding box.
|
||
*/
|
||
rectangle_info.x=(ssize_t) coordinate_info->x;
|
||
rectangle_info.y=(ssize_t) coordinate_info->y;
|
||
x=coordinate_info->x;
|
||
y=coordinate_info->y;
|
||
for (i=1; i < number_coordinates; i++)
|
||
{
|
||
if (coordinate_info[i].x > x)
|
||
x=coordinate_info[i].x;
|
||
if (coordinate_info[i].y > y)
|
||
y=coordinate_info[i].y;
|
||
if ((ssize_t) coordinate_info[i].x < rectangle_info.x)
|
||
rectangle_info.x=MagickMax((ssize_t) coordinate_info[i].x,0);
|
||
if ((ssize_t) coordinate_info[i].y < rectangle_info.y)
|
||
rectangle_info.y=MagickMax((ssize_t) coordinate_info[i].y,0);
|
||
}
|
||
rectangle_info.width=(size_t) (x-rectangle_info.x);
|
||
rectangle_info.height=(size_t) (y-rectangle_info.y);
|
||
for (i=0; i < number_coordinates; i++)
|
||
{
|
||
coordinate_info[i].x-=rectangle_info.x;
|
||
coordinate_info[i].y-=rectangle_info.y;
|
||
}
|
||
}
|
||
else
|
||
if (distance <= 9)
|
||
continue;
|
||
else
|
||
if ((element == RectangleElement) ||
|
||
(element == CircleElement) || (element == EllipseElement))
|
||
{
|
||
rectangle_info.width--;
|
||
rectangle_info.height--;
|
||
}
|
||
/*
|
||
Drawing is relative to image configuration.
|
||
*/
|
||
draw_info.x=(int) rectangle_info.x;
|
||
draw_info.y=(int) rectangle_info.y;
|
||
(void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand,
|
||
image);
|
||
width=(unsigned int) (*image)->columns;
|
||
height=(unsigned int) (*image)->rows;
|
||
x=0;
|
||
y=0;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
|
||
draw_info.x+=windows->image.x-(line_width/2);
|
||
if (draw_info.x < 0)
|
||
draw_info.x=0;
|
||
draw_info.x=(int) (width*draw_info.x/windows->image.ximage->width);
|
||
draw_info.y+=windows->image.y-(line_width/2);
|
||
if (draw_info.y < 0)
|
||
draw_info.y=0;
|
||
draw_info.y=(int) height*draw_info.y/windows->image.ximage->height;
|
||
draw_info.width=(unsigned int) rectangle_info.width+(line_width << 1);
|
||
if (draw_info.width > (unsigned int) (*image)->columns)
|
||
draw_info.width=(unsigned int) (*image)->columns;
|
||
draw_info.height=(unsigned int) rectangle_info.height+(line_width << 1);
|
||
if (draw_info.height > (unsigned int) (*image)->rows)
|
||
draw_info.height=(unsigned int) (*image)->rows;
|
||
(void) FormatLocaleString(draw_info.geometry,MaxTextExtent,"%ux%u%+d%+d",
|
||
width*draw_info.width/windows->image.ximage->width,
|
||
height*draw_info.height/windows->image.ximage->height,
|
||
draw_info.x+x,draw_info.y+y);
|
||
/*
|
||
Initialize drawing attributes.
|
||
*/
|
||
draw_info.degrees=0.0;
|
||
draw_info.element=element;
|
||
draw_info.stipple=stipple;
|
||
draw_info.line_width=line_width;
|
||
draw_info.line_info=line_info;
|
||
if (line_info.x1 > (int) (line_width/2))
|
||
draw_info.line_info.x1=(short) line_width/2;
|
||
if (line_info.y1 > (int) (line_width/2))
|
||
draw_info.line_info.y1=(short) line_width/2;
|
||
draw_info.line_info.x2=(short) (line_info.x2-line_info.x1+(line_width/2));
|
||
draw_info.line_info.y2=(short) (line_info.y2-line_info.y1+(line_width/2));
|
||
if ((draw_info.line_info.x2 < 0) && (draw_info.line_info.y2 < 0))
|
||
{
|
||
draw_info.line_info.x2=(-draw_info.line_info.x2);
|
||
draw_info.line_info.y2=(-draw_info.line_info.y2);
|
||
}
|
||
if (draw_info.line_info.x2 < 0)
|
||
{
|
||
draw_info.line_info.x2=(-draw_info.line_info.x2);
|
||
Swap(draw_info.line_info.x1,draw_info.line_info.x2);
|
||
}
|
||
if (draw_info.line_info.y2 < 0)
|
||
{
|
||
draw_info.line_info.y2=(-draw_info.line_info.y2);
|
||
Swap(draw_info.line_info.y1,draw_info.line_info.y2);
|
||
}
|
||
draw_info.rectangle_info=rectangle_info;
|
||
if (draw_info.rectangle_info.x > (ssize_t) (line_width/2))
|
||
draw_info.rectangle_info.x=(ssize_t) line_width/2;
|
||
if (draw_info.rectangle_info.y > (ssize_t) (line_width/2))
|
||
draw_info.rectangle_info.y=(ssize_t) line_width/2;
|
||
draw_info.number_coordinates=(unsigned int) number_coordinates;
|
||
draw_info.coordinate_info=coordinate_info;
|
||
windows->pixel_info->pen_color=windows->pixel_info->pen_colors[pen_id];
|
||
/*
|
||
Draw element on image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
status=XDrawImage(display,windows->pixel_info,&draw_info,*image);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
/*
|
||
Update image colormap and return to image drawing.
|
||
*/
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
}
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
coordinate_info=(XPoint *) RelinquishMagickMemory(coordinate_info);
|
||
return(status != 0 ? MagickTrue : MagickFalse);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X D r a w P a n R e c t a n g l e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XDrawPanRectangle() draws a rectangle in the pan window. The pan window
|
||
% displays a zoom image and the rectangle shows which portion of the image is
|
||
% displayed in the Image window.
|
||
%
|
||
% The format of the XDrawPanRectangle method is:
|
||
%
|
||
% XDrawPanRectangle(Display *display,XWindows *windows)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
*/
|
||
static void XDrawPanRectangle(Display *display,XWindows *windows)
|
||
{
|
||
MagickRealType
|
||
scale_factor;
|
||
|
||
RectangleInfo
|
||
highlight_info;
|
||
|
||
/*
|
||
Determine dimensions of the panning rectangle.
|
||
*/
|
||
scale_factor=(MagickRealType) windows->pan.width/windows->image.ximage->width;
|
||
highlight_info.x=(ssize_t) (scale_factor*windows->image.x+0.5);
|
||
highlight_info.width=(unsigned int) (scale_factor*windows->image.width+0.5);
|
||
scale_factor=(MagickRealType)
|
||
windows->pan.height/windows->image.ximage->height;
|
||
highlight_info.y=(ssize_t) (scale_factor*windows->image.y+0.5);
|
||
highlight_info.height=(unsigned int) (scale_factor*windows->image.height+0.5);
|
||
/*
|
||
Display the panning rectangle.
|
||
*/
|
||
(void) XClearWindow(display,windows->pan.id);
|
||
XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context,
|
||
&highlight_info);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X I m a g e C a c h e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XImageCache() handles the creation, manipulation, and destruction of the
|
||
% image cache (undo and redo buffers).
|
||
%
|
||
% The format of the XImageCache method is:
|
||
%
|
||
% void XImageCache(Display *display,XResourceInfo *resource_info,
|
||
% XWindows *windows,const CommandType command,Image **image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o command: Specifies a command to perform.
|
||
%
|
||
% o image: the image; XImageCache may transform the image and return a new
|
||
% image pointer.
|
||
%
|
||
*/
|
||
static void XImageCache(Display *display,XResourceInfo *resource_info,
|
||
XWindows *windows,const CommandType command,Image **image)
|
||
{
|
||
Image
|
||
*cache_image;
|
||
|
||
static Image
|
||
*redo_image = (Image *) NULL,
|
||
*undo_image = (Image *) NULL;
|
||
|
||
switch (command)
|
||
{
|
||
case FreeBuffersCommand:
|
||
{
|
||
/*
|
||
Free memory from the undo and redo cache.
|
||
*/
|
||
while (undo_image != (Image *) NULL)
|
||
{
|
||
cache_image=undo_image;
|
||
undo_image=GetPreviousImageInList(undo_image);
|
||
cache_image->list=DestroyImage(cache_image->list);
|
||
cache_image=DestroyImage(cache_image);
|
||
}
|
||
undo_image=NewImageList();
|
||
if (redo_image != (Image *) NULL)
|
||
redo_image=DestroyImage(redo_image);
|
||
redo_image=NewImageList();
|
||
return;
|
||
}
|
||
case UndoCommand:
|
||
{
|
||
char
|
||
image_geometry[MaxTextExtent];
|
||
|
||
/*
|
||
Undo the last image transformation.
|
||
*/
|
||
if (undo_image == (Image *) NULL)
|
||
{
|
||
(void) XBell(display,0);
|
||
return;
|
||
}
|
||
cache_image=undo_image;
|
||
undo_image=GetPreviousImageInList(undo_image);
|
||
windows->image.window_changes.width=(int) cache_image->columns;
|
||
windows->image.window_changes.height=(int) cache_image->rows;
|
||
(void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
|
||
windows->image.ximage->width,windows->image.ximage->height);
|
||
(void) TransformImage(image,windows->image.crop_geometry,image_geometry);
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
windows->image.crop_geometry=(char *)
|
||
RelinquishMagickMemory(windows->image.crop_geometry);
|
||
windows->image.crop_geometry=cache_image->geometry;
|
||
if (redo_image != (Image *) NULL)
|
||
redo_image=DestroyImage(redo_image);
|
||
redo_image=(*image);
|
||
*image=cache_image->list;
|
||
cache_image=DestroyImage(cache_image);
|
||
if (windows->image.orphan != MagickFalse)
|
||
return;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
return;
|
||
}
|
||
case CutCommand:
|
||
case PasteCommand:
|
||
case ApplyCommand:
|
||
case HalfSizeCommand:
|
||
case OriginalSizeCommand:
|
||
case DoubleSizeCommand:
|
||
case ResizeCommand:
|
||
case TrimCommand:
|
||
case CropCommand:
|
||
case ChopCommand:
|
||
case FlipCommand:
|
||
case FlopCommand:
|
||
case RotateRightCommand:
|
||
case RotateLeftCommand:
|
||
case RotateCommand:
|
||
case ShearCommand:
|
||
case RollCommand:
|
||
case NegateCommand:
|
||
case ContrastStretchCommand:
|
||
case SigmoidalContrastCommand:
|
||
case NormalizeCommand:
|
||
case EqualizeCommand:
|
||
case HueCommand:
|
||
case SaturationCommand:
|
||
case BrightnessCommand:
|
||
case GammaCommand:
|
||
case SpiffCommand:
|
||
case DullCommand:
|
||
case GrayscaleCommand:
|
||
case MapCommand:
|
||
case QuantizeCommand:
|
||
case DespeckleCommand:
|
||
case EmbossCommand:
|
||
case ReduceNoiseCommand:
|
||
case AddNoiseCommand:
|
||
case SharpenCommand:
|
||
case BlurCommand:
|
||
case ThresholdCommand:
|
||
case EdgeDetectCommand:
|
||
case SpreadCommand:
|
||
case ShadeCommand:
|
||
case RaiseCommand:
|
||
case SegmentCommand:
|
||
case SolarizeCommand:
|
||
case SepiaToneCommand:
|
||
case SwirlCommand:
|
||
case ImplodeCommand:
|
||
case VignetteCommand:
|
||
case WaveCommand:
|
||
case OilPaintCommand:
|
||
case CharcoalDrawCommand:
|
||
case AnnotateCommand:
|
||
case AddBorderCommand:
|
||
case AddFrameCommand:
|
||
case CompositeCommand:
|
||
case CommentCommand:
|
||
case LaunchCommand:
|
||
case RegionofInterestCommand:
|
||
case SaveToUndoBufferCommand:
|
||
case RedoCommand:
|
||
{
|
||
Image
|
||
*previous_image;
|
||
|
||
ssize_t
|
||
bytes;
|
||
|
||
bytes=(ssize_t) ((*image)->columns*(*image)->rows*sizeof(PixelPacket));
|
||
if (undo_image != (Image *) NULL)
|
||
{
|
||
/*
|
||
Ensure the undo cache has enough memory available.
|
||
*/
|
||
previous_image=undo_image;
|
||
while (previous_image != (Image *) NULL)
|
||
{
|
||
bytes+=previous_image->list->columns*previous_image->list->rows*
|
||
sizeof(PixelPacket);
|
||
if (bytes <= (ssize_t) (resource_info->undo_cache << 20))
|
||
{
|
||
previous_image=GetPreviousImageInList(previous_image);
|
||
continue;
|
||
}
|
||
bytes-=previous_image->list->columns*previous_image->list->rows*
|
||
sizeof(PixelPacket);
|
||
if (previous_image == undo_image)
|
||
undo_image=NewImageList();
|
||
else
|
||
previous_image->next->previous=NewImageList();
|
||
break;
|
||
}
|
||
while (previous_image != (Image *) NULL)
|
||
{
|
||
/*
|
||
Delete any excess memory from undo cache.
|
||
*/
|
||
cache_image=previous_image;
|
||
previous_image=GetPreviousImageInList(previous_image);
|
||
cache_image->list=DestroyImage(cache_image->list);
|
||
cache_image=DestroyImage(cache_image);
|
||
}
|
||
}
|
||
if (bytes > (ssize_t) (resource_info->undo_cache << 20))
|
||
break;
|
||
/*
|
||
Save image before transformations are applied.
|
||
*/
|
||
cache_image=AcquireImage((ImageInfo *) NULL);
|
||
if (cache_image == (Image *) NULL)
|
||
break;
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
cache_image->list=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (cache_image->list == (Image *) NULL)
|
||
{
|
||
cache_image=DestroyImage(cache_image);
|
||
break;
|
||
}
|
||
cache_image->columns=(size_t) windows->image.ximage->width;
|
||
cache_image->rows=(size_t) windows->image.ximage->height;
|
||
cache_image->geometry=windows->image.crop_geometry;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
{
|
||
cache_image->geometry=AcquireString((char *) NULL);
|
||
(void) CopyMagickString(cache_image->geometry,
|
||
windows->image.crop_geometry,MaxTextExtent);
|
||
}
|
||
if (undo_image == (Image *) NULL)
|
||
{
|
||
undo_image=cache_image;
|
||
break;
|
||
}
|
||
undo_image->next=cache_image;
|
||
undo_image->next->previous=undo_image;
|
||
undo_image=undo_image->next;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
if (command == RedoCommand)
|
||
{
|
||
/*
|
||
Redo the last image transformation.
|
||
*/
|
||
if (redo_image == (Image *) NULL)
|
||
{
|
||
(void) XBell(display,0);
|
||
return;
|
||
}
|
||
windows->image.window_changes.width=(int) redo_image->columns;
|
||
windows->image.window_changes.height=(int) redo_image->rows;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
windows->image.crop_geometry=(char *)
|
||
RelinquishMagickMemory(windows->image.crop_geometry);
|
||
windows->image.crop_geometry=redo_image->geometry;
|
||
*image=DestroyImage(*image);
|
||
*image=redo_image;
|
||
redo_image=NewImageList();
|
||
if (windows->image.orphan != MagickFalse)
|
||
return;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
return;
|
||
}
|
||
if (command != InfoCommand)
|
||
return;
|
||
/*
|
||
Display image info.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
XDisplayImageInfo(display,resource_info,windows,undo_image,*image);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X I m a g e W i n d o w C o m m a n d %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XImageWindowCommand() makes a transform to the image or Image window as
|
||
% specified by a user menu button or keyboard command.
|
||
%
|
||
% The format of the XMagickCommand method is:
|
||
%
|
||
% CommandType XImageWindowCommand(Display *display,
|
||
% XResourceInfo *resource_info,XWindows *windows,
|
||
% const MagickStatusType state,KeySym key_symbol,Image **image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o nexus: Method XImageWindowCommand returns an image when the
|
||
% user chooses 'Open Image' from the command menu. Otherwise a null
|
||
% image is returned.
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o state: key mask.
|
||
%
|
||
% o key_symbol: Specifies a command to perform.
|
||
%
|
||
% o image: the image; XImageWIndowCommand
|
||
% may transform the image and return a new image pointer.
|
||
%
|
||
*/
|
||
static CommandType XImageWindowCommand(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows,const MagickStatusType state,
|
||
KeySym key_symbol,Image **image)
|
||
{
|
||
static char
|
||
delta[MaxTextExtent] = "";
|
||
|
||
static const char
|
||
Digits[] = "01234567890";
|
||
|
||
static KeySym
|
||
last_symbol = XK_0;
|
||
|
||
if ((key_symbol >= XK_0) && (key_symbol <= XK_9))
|
||
{
|
||
if (((last_symbol < XK_0) || (last_symbol > XK_9)))
|
||
{
|
||
*delta='\0';
|
||
resource_info->quantum=1;
|
||
}
|
||
last_symbol=key_symbol;
|
||
delta[strlen(delta)+1]='\0';
|
||
delta[strlen(delta)]=Digits[key_symbol-XK_0];
|
||
resource_info->quantum=StringToLong(delta);
|
||
return(NullCommand);
|
||
}
|
||
last_symbol=key_symbol;
|
||
if (resource_info->immutable)
|
||
{
|
||
/*
|
||
Virtual image window has a restricted command set.
|
||
*/
|
||
switch (key_symbol)
|
||
{
|
||
case XK_question:
|
||
return(InfoCommand);
|
||
case XK_p:
|
||
case XK_Print:
|
||
return(PrintCommand);
|
||
case XK_space:
|
||
return(NextCommand);
|
||
case XK_q:
|
||
case XK_Escape:
|
||
return(QuitCommand);
|
||
default:
|
||
break;
|
||
}
|
||
return(NullCommand);
|
||
}
|
||
switch ((int) key_symbol)
|
||
{
|
||
case XK_o:
|
||
{
|
||
if ((state & ControlMask) == 0)
|
||
break;
|
||
return(OpenCommand);
|
||
}
|
||
case XK_space:
|
||
return(NextCommand);
|
||
case XK_BackSpace:
|
||
return(FormerCommand);
|
||
case XK_s:
|
||
{
|
||
if ((state & Mod1Mask) != 0)
|
||
return(SwirlCommand);
|
||
if ((state & ControlMask) == 0)
|
||
return(ShearCommand);
|
||
return(SaveCommand);
|
||
}
|
||
case XK_p:
|
||
case XK_Print:
|
||
{
|
||
if ((state & Mod1Mask) != 0)
|
||
return(OilPaintCommand);
|
||
if ((state & Mod4Mask) != 0)
|
||
return(ColorCommand);
|
||
if ((state & ControlMask) == 0)
|
||
return(NullCommand);
|
||
return(PrintCommand);
|
||
}
|
||
case XK_d:
|
||
{
|
||
if ((state & Mod4Mask) != 0)
|
||
return(DrawCommand);
|
||
if ((state & ControlMask) == 0)
|
||
return(NullCommand);
|
||
return(DeleteCommand);
|
||
}
|
||
case XK_Select:
|
||
{
|
||
if ((state & ControlMask) == 0)
|
||
return(NullCommand);
|
||
return(SelectCommand);
|
||
}
|
||
case XK_n:
|
||
{
|
||
if ((state & ControlMask) == 0)
|
||
return(NullCommand);
|
||
return(NewCommand);
|
||
}
|
||
case XK_q:
|
||
case XK_Escape:
|
||
return(QuitCommand);
|
||
case XK_z:
|
||
case XK_Undo:
|
||
{
|
||
if ((state & ControlMask) == 0)
|
||
return(NullCommand);
|
||
return(UndoCommand);
|
||
}
|
||
case XK_r:
|
||
case XK_Redo:
|
||
{
|
||
if ((state & ControlMask) == 0)
|
||
return(RollCommand);
|
||
return(RedoCommand);
|
||
}
|
||
case XK_x:
|
||
{
|
||
if ((state & ControlMask) == 0)
|
||
return(NullCommand);
|
||
return(CutCommand);
|
||
}
|
||
case XK_c:
|
||
{
|
||
if ((state & Mod1Mask) != 0)
|
||
return(CharcoalDrawCommand);
|
||
if ((state & ControlMask) == 0)
|
||
return(CropCommand);
|
||
return(CopyCommand);
|
||
}
|
||
case XK_v:
|
||
case XK_Insert:
|
||
{
|
||
if ((state & Mod4Mask) != 0)
|
||
return(CompositeCommand);
|
||
if ((state & ControlMask) == 0)
|
||
return(FlipCommand);
|
||
return(PasteCommand);
|
||
}
|
||
case XK_less:
|
||
return(HalfSizeCommand);
|
||
case XK_minus:
|
||
return(OriginalSizeCommand);
|
||
case XK_greater:
|
||
return(DoubleSizeCommand);
|
||
case XK_percent:
|
||
return(ResizeCommand);
|
||
case XK_at:
|
||
return(RefreshCommand);
|
||
case XK_bracketleft:
|
||
return(ChopCommand);
|
||
case XK_h:
|
||
return(FlopCommand);
|
||
case XK_slash:
|
||
return(RotateRightCommand);
|
||
case XK_backslash:
|
||
return(RotateLeftCommand);
|
||
case XK_asterisk:
|
||
return(RotateCommand);
|
||
case XK_t:
|
||
return(TrimCommand);
|
||
case XK_H:
|
||
return(HueCommand);
|
||
case XK_S:
|
||
return(SaturationCommand);
|
||
case XK_L:
|
||
return(BrightnessCommand);
|
||
case XK_G:
|
||
return(GammaCommand);
|
||
case XK_C:
|
||
return(SpiffCommand);
|
||
case XK_Z:
|
||
return(DullCommand);
|
||
case XK_N:
|
||
return(NormalizeCommand);
|
||
case XK_equal:
|
||
return(EqualizeCommand);
|
||
case XK_asciitilde:
|
||
return(NegateCommand);
|
||
case XK_period:
|
||
return(GrayscaleCommand);
|
||
case XK_numbersign:
|
||
return(QuantizeCommand);
|
||
case XK_F2:
|
||
return(DespeckleCommand);
|
||
case XK_F3:
|
||
return(EmbossCommand);
|
||
case XK_F4:
|
||
return(ReduceNoiseCommand);
|
||
case XK_F5:
|
||
return(AddNoiseCommand);
|
||
case XK_F6:
|
||
return(SharpenCommand);
|
||
case XK_F7:
|
||
return(BlurCommand);
|
||
case XK_F8:
|
||
return(ThresholdCommand);
|
||
case XK_F9:
|
||
return(EdgeDetectCommand);
|
||
case XK_F10:
|
||
return(SpreadCommand);
|
||
case XK_F11:
|
||
return(ShadeCommand);
|
||
case XK_F12:
|
||
return(RaiseCommand);
|
||
case XK_F13:
|
||
return(SegmentCommand);
|
||
case XK_i:
|
||
{
|
||
if ((state & Mod1Mask) == 0)
|
||
return(NullCommand);
|
||
return(ImplodeCommand);
|
||
}
|
||
case XK_w:
|
||
{
|
||
if ((state & Mod1Mask) == 0)
|
||
return(NullCommand);
|
||
return(WaveCommand);
|
||
}
|
||
case XK_m:
|
||
{
|
||
if ((state & Mod4Mask) == 0)
|
||
return(NullCommand);
|
||
return(MatteCommand);
|
||
}
|
||
case XK_b:
|
||
{
|
||
if ((state & Mod4Mask) == 0)
|
||
return(NullCommand);
|
||
return(AddBorderCommand);
|
||
}
|
||
case XK_f:
|
||
{
|
||
if ((state & Mod4Mask) == 0)
|
||
return(NullCommand);
|
||
return(AddFrameCommand);
|
||
}
|
||
case XK_exclam:
|
||
{
|
||
if ((state & Mod4Mask) == 0)
|
||
return(NullCommand);
|
||
return(CommentCommand);
|
||
}
|
||
case XK_a:
|
||
{
|
||
if ((state & Mod1Mask) != 0)
|
||
return(ApplyCommand);
|
||
if ((state & Mod4Mask) != 0)
|
||
return(AnnotateCommand);
|
||
if ((state & ControlMask) == 0)
|
||
return(NullCommand);
|
||
return(RegionofInterestCommand);
|
||
}
|
||
case XK_question:
|
||
return(InfoCommand);
|
||
case XK_plus:
|
||
return(ZoomCommand);
|
||
case XK_P:
|
||
{
|
||
if ((state & ShiftMask) == 0)
|
||
return(NullCommand);
|
||
return(ShowPreviewCommand);
|
||
}
|
||
case XK_Execute:
|
||
return(LaunchCommand);
|
||
case XK_F1:
|
||
return(HelpCommand);
|
||
case XK_Find:
|
||
return(BrowseDocumentationCommand);
|
||
case XK_Menu:
|
||
{
|
||
(void) XMapRaised(display,windows->command.id);
|
||
return(NullCommand);
|
||
}
|
||
case XK_Next:
|
||
case XK_Prior:
|
||
case XK_Home:
|
||
case XK_KP_Home:
|
||
{
|
||
XTranslateImage(display,windows,*image,key_symbol);
|
||
return(NullCommand);
|
||
}
|
||
case XK_Up:
|
||
case XK_KP_Up:
|
||
case XK_Down:
|
||
case XK_KP_Down:
|
||
case XK_Left:
|
||
case XK_KP_Left:
|
||
case XK_Right:
|
||
case XK_KP_Right:
|
||
{
|
||
if ((state & Mod1Mask) != 0)
|
||
{
|
||
RectangleInfo
|
||
crop_info;
|
||
|
||
/*
|
||
Trim one pixel from edge of image.
|
||
*/
|
||
crop_info.x=0;
|
||
crop_info.y=0;
|
||
crop_info.width=(size_t) windows->image.ximage->width;
|
||
crop_info.height=(size_t) windows->image.ximage->height;
|
||
if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
|
||
{
|
||
if (resource_info->quantum >= (int) crop_info.height)
|
||
resource_info->quantum=(int) crop_info.height-1;
|
||
crop_info.height-=resource_info->quantum;
|
||
}
|
||
if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
|
||
{
|
||
if (resource_info->quantum >= (int) (crop_info.height-crop_info.y))
|
||
resource_info->quantum=(int) (crop_info.height-crop_info.y-1);
|
||
crop_info.y+=resource_info->quantum;
|
||
crop_info.height-=resource_info->quantum;
|
||
}
|
||
if ((key_symbol == XK_Left) || (key_symbol == XK_KP_Left))
|
||
{
|
||
if (resource_info->quantum >= (int) crop_info.width)
|
||
resource_info->quantum=(int) crop_info.width-1;
|
||
crop_info.width-=resource_info->quantum;
|
||
}
|
||
if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
|
||
{
|
||
if (resource_info->quantum >= (int) (crop_info.width-crop_info.x))
|
||
resource_info->quantum=(int) (crop_info.width-crop_info.x-1);
|
||
crop_info.x+=resource_info->quantum;
|
||
crop_info.width-=resource_info->quantum;
|
||
}
|
||
if ((int) (windows->image.x+windows->image.width) >
|
||
(int) crop_info.width)
|
||
windows->image.x=(int) (crop_info.width-windows->image.width);
|
||
if ((int) (windows->image.y+windows->image.height) >
|
||
(int) crop_info.height)
|
||
windows->image.y=(int) (crop_info.height-windows->image.height);
|
||
XSetCropGeometry(display,windows,&crop_info,*image);
|
||
windows->image.window_changes.width=(int) crop_info.width;
|
||
windows->image.window_changes.height=(int) crop_info.height;
|
||
(void) XSetWindowBackgroundPixmap(display,windows->image.id,None);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
return(NullCommand);
|
||
}
|
||
XTranslateImage(display,windows,*image,key_symbol);
|
||
return(NullCommand);
|
||
}
|
||
default:
|
||
return(NullCommand);
|
||
}
|
||
return(NullCommand);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X M a g i c k C o m m a n d %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XMagickCommand() makes a transform to the image or Image window as
|
||
% specified by a user menu button or keyboard command.
|
||
%
|
||
% The format of the XMagickCommand method is:
|
||
%
|
||
% Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
|
||
% XWindows *windows,const CommandType command,Image **image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o nexus: Method XMagickCommand returns an image when the
|
||
% user chooses 'Load Image' from the command menu. Otherwise a null
|
||
% image is returned.
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o command: Specifies a command to perform.
|
||
%
|
||
% o image: the image; XMagickCommand
|
||
% may transform the image and return a new image pointer.
|
||
%
|
||
*/
|
||
static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
|
||
XWindows *windows,const CommandType command,Image **image)
|
||
{
|
||
char
|
||
filename[MaxTextExtent],
|
||
geometry[MaxTextExtent],
|
||
modulate_factors[MaxTextExtent];
|
||
|
||
GeometryInfo
|
||
geometry_info;
|
||
|
||
Image
|
||
*nexus;
|
||
|
||
ImageInfo
|
||
*image_info;
|
||
|
||
int
|
||
x,
|
||
y;
|
||
|
||
MagickStatusType
|
||
flags,
|
||
status;
|
||
|
||
QuantizeInfo
|
||
quantize_info;
|
||
|
||
RectangleInfo
|
||
page_geometry;
|
||
|
||
register int
|
||
i;
|
||
|
||
static char
|
||
color[MaxTextExtent] = "gray";
|
||
|
||
unsigned int
|
||
height,
|
||
width;
|
||
|
||
/*
|
||
Process user command.
|
||
*/
|
||
XCheckRefreshWindows(display,windows);
|
||
XImageCache(display,resource_info,windows,command,image);
|
||
nexus=NewImageList();
|
||
windows->image.window_changes.width=windows->image.ximage->width;
|
||
windows->image.window_changes.height=windows->image.ximage->height;
|
||
image_info=CloneImageInfo(resource_info->image_info);
|
||
SetGeometryInfo(&geometry_info);
|
||
GetQuantizeInfo(&quantize_info);
|
||
switch (command)
|
||
{
|
||
case OpenCommand:
|
||
{
|
||
/*
|
||
Load image.
|
||
*/
|
||
nexus=XOpenImage(display,resource_info,windows,MagickFalse);
|
||
break;
|
||
}
|
||
case NextCommand:
|
||
{
|
||
/*
|
||
Display next image.
|
||
*/
|
||
for (i=0; i < resource_info->quantum; i++)
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_next_image,CurrentTime);
|
||
break;
|
||
}
|
||
case FormerCommand:
|
||
{
|
||
/*
|
||
Display former image.
|
||
*/
|
||
for (i=0; i < resource_info->quantum; i++)
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_former_image,CurrentTime);
|
||
break;
|
||
}
|
||
case SelectCommand:
|
||
{
|
||
int
|
||
status;
|
||
|
||
/*
|
||
Select image.
|
||
*/
|
||
if (*resource_info->home_directory == '\0')
|
||
(void) CopyMagickString(resource_info->home_directory,".",
|
||
MaxTextExtent);
|
||
status=chdir(resource_info->home_directory);
|
||
if (status == -1)
|
||
(void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
|
||
FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
|
||
nexus=XOpenImage(display,resource_info,windows,MagickTrue);
|
||
break;
|
||
}
|
||
case SaveCommand:
|
||
{
|
||
/*
|
||
Save image.
|
||
*/
|
||
status=XSaveImage(display,resource_info,windows,*image);
|
||
if (status == MagickFalse)
|
||
{
|
||
char
|
||
message[MaxTextExtent];
|
||
|
||
(void) FormatLocaleString(message,MaxTextExtent,"%s:%s",
|
||
(*image)->exception.reason != (char *) NULL ?
|
||
(*image)->exception.reason : "",
|
||
(*image)->exception.description != (char *) NULL ?
|
||
(*image)->exception.description : "");
|
||
XNoticeWidget(display,windows,"Unable to save file:",message);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case PrintCommand:
|
||
{
|
||
/*
|
||
Print image.
|
||
*/
|
||
status=XPrintImage(display,resource_info,windows,*image);
|
||
if (status == MagickFalse)
|
||
{
|
||
char
|
||
message[MaxTextExtent];
|
||
|
||
(void) FormatLocaleString(message,MaxTextExtent,"%s:%s",
|
||
(*image)->exception.reason != (char *) NULL ?
|
||
(*image)->exception.reason : "",
|
||
(*image)->exception.description != (char *) NULL ?
|
||
(*image)->exception.description : "");
|
||
XNoticeWidget(display,windows,"Unable to print file:",message);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case DeleteCommand:
|
||
{
|
||
static char
|
||
filename[MaxTextExtent] = "\0";
|
||
|
||
/*
|
||
Delete image file.
|
||
*/
|
||
XFileBrowserWidget(display,windows,"Delete",filename);
|
||
if (*filename == '\0')
|
||
break;
|
||
status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse;
|
||
if (status != MagickFalse)
|
||
XNoticeWidget(display,windows,"Unable to delete image file:",filename);
|
||
break;
|
||
}
|
||
case NewCommand:
|
||
{
|
||
int
|
||
status;
|
||
|
||
static char
|
||
color[MaxTextExtent] = "gray",
|
||
geometry[MaxTextExtent] = "640x480";
|
||
|
||
static const char
|
||
*format = "gradient";
|
||
|
||
/*
|
||
Query user for canvas geometry.
|
||
*/
|
||
status=XDialogWidget(display,windows,"New","Enter image geometry:",
|
||
geometry);
|
||
if (*geometry == '\0')
|
||
break;
|
||
if (status == 0)
|
||
format="xc";
|
||
XColorBrowserWidget(display,windows,"Select",color);
|
||
if (*color == '\0')
|
||
break;
|
||
/*
|
||
Create canvas.
|
||
*/
|
||
(void) FormatLocaleString(image_info->filename,MaxTextExtent,
|
||
"%s:%s",format,color);
|
||
(void) CloneString(&image_info->size,geometry);
|
||
nexus=ReadImage(image_info,&(*image)->exception);
|
||
CatchException(&(*image)->exception);
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_next_image,CurrentTime);
|
||
break;
|
||
}
|
||
case VisualDirectoryCommand:
|
||
{
|
||
/*
|
||
Visual Image directory.
|
||
*/
|
||
nexus=XVisualDirectoryImage(display,resource_info,windows);
|
||
break;
|
||
}
|
||
case QuitCommand:
|
||
{
|
||
/*
|
||
exit program.
|
||
*/
|
||
if (resource_info->confirm_exit == MagickFalse)
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_exit,CurrentTime);
|
||
else
|
||
{
|
||
int
|
||
status;
|
||
|
||
/*
|
||
Confirm program exit.
|
||
*/
|
||
status=XConfirmWidget(display,windows,"Do you really want to exit",
|
||
resource_info->client_name);
|
||
if (status > 0)
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_exit,CurrentTime);
|
||
}
|
||
break;
|
||
}
|
||
case CutCommand:
|
||
{
|
||
/*
|
||
Cut image.
|
||
*/
|
||
(void) XCropImage(display,resource_info,windows,*image,CutMode);
|
||
break;
|
||
}
|
||
case CopyCommand:
|
||
{
|
||
/*
|
||
Copy image.
|
||
*/
|
||
(void) XCropImage(display,resource_info,windows,*image,CopyMode);
|
||
break;
|
||
}
|
||
case PasteCommand:
|
||
{
|
||
/*
|
||
Paste image.
|
||
*/
|
||
status=XPasteImage(display,resource_info,windows,*image);
|
||
if (status == MagickFalse)
|
||
{
|
||
XNoticeWidget(display,windows,"Unable to paste X image",
|
||
(*image)->filename);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case HalfSizeCommand:
|
||
{
|
||
/*
|
||
Half image size.
|
||
*/
|
||
windows->image.window_changes.width=windows->image.ximage->width/2;
|
||
windows->image.window_changes.height=windows->image.ximage->height/2;
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case OriginalSizeCommand:
|
||
{
|
||
/*
|
||
Original image size.
|
||
*/
|
||
windows->image.window_changes.width=(int) (*image)->columns;
|
||
windows->image.window_changes.height=(int) (*image)->rows;
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case DoubleSizeCommand:
|
||
{
|
||
/*
|
||
Double the image size.
|
||
*/
|
||
windows->image.window_changes.width=windows->image.ximage->width << 1;
|
||
windows->image.window_changes.height=windows->image.ximage->height << 1;
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case ResizeCommand:
|
||
{
|
||
int
|
||
status;
|
||
|
||
size_t
|
||
height,
|
||
width;
|
||
|
||
ssize_t
|
||
x,
|
||
y;
|
||
|
||
/*
|
||
Resize image.
|
||
*/
|
||
width=(size_t) windows->image.ximage->width;
|
||
height=(size_t) windows->image.ximage->height;
|
||
x=0;
|
||
y=0;
|
||
(void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g+0+0",
|
||
(double) width,(double) height);
|
||
status=XDialogWidget(display,windows,"Resize",
|
||
"Enter resize geometry (e.g. 640x480, 200%):",geometry);
|
||
if (*geometry == '\0')
|
||
break;
|
||
if (status == 0)
|
||
(void) ConcatenateMagickString(geometry,"!",MaxTextExtent);
|
||
(void) ParseMetaGeometry(geometry,&x,&y,&width,&height);
|
||
windows->image.window_changes.width=(int) width;
|
||
windows->image.window_changes.height=(int) height;
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case ApplyCommand:
|
||
{
|
||
char
|
||
image_geometry[MaxTextExtent];
|
||
|
||
if ((windows->image.crop_geometry == (char *) NULL) &&
|
||
((int) (*image)->columns == windows->image.ximage->width) &&
|
||
((int) (*image)->rows == windows->image.ximage->height))
|
||
break;
|
||
/*
|
||
Apply size transforms to image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
/*
|
||
Crop and/or scale displayed image.
|
||
*/
|
||
(void) FormatLocaleString(image_geometry,MaxTextExtent,"%dx%d!",
|
||
windows->image.ximage->width,windows->image.ximage->height);
|
||
(void) TransformImage(image,windows->image.crop_geometry,image_geometry);
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
windows->image.crop_geometry=(char *)
|
||
RelinquishMagickMemory(windows->image.crop_geometry);
|
||
windows->image.x=0;
|
||
windows->image.y=0;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case RefreshCommand:
|
||
{
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case RestoreCommand:
|
||
{
|
||
/*
|
||
Restore Image window to its original size.
|
||
*/
|
||
if ((windows->image.width == (unsigned int) (*image)->columns) &&
|
||
(windows->image.height == (unsigned int) (*image)->rows) &&
|
||
(windows->image.crop_geometry == (char *) NULL))
|
||
{
|
||
(void) XBell(display,0);
|
||
break;
|
||
}
|
||
windows->image.window_changes.width=(int) (*image)->columns;
|
||
windows->image.window_changes.height=(int) (*image)->rows;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
{
|
||
windows->image.crop_geometry=(char *)
|
||
RelinquishMagickMemory(windows->image.crop_geometry);
|
||
windows->image.crop_geometry=(char *) NULL;
|
||
windows->image.x=0;
|
||
windows->image.y=0;
|
||
}
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case CropCommand:
|
||
{
|
||
/*
|
||
Crop image.
|
||
*/
|
||
(void) XCropImage(display,resource_info,windows,*image,CropMode);
|
||
break;
|
||
}
|
||
case ChopCommand:
|
||
{
|
||
/*
|
||
Chop image.
|
||
*/
|
||
status=XChopImage(display,resource_info,windows,image);
|
||
if (status == MagickFalse)
|
||
{
|
||
XNoticeWidget(display,windows,"Unable to cut X image",
|
||
(*image)->filename);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case FlopCommand:
|
||
{
|
||
Image
|
||
*flop_image;
|
||
|
||
/*
|
||
Flop image scanlines.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flop_image=FlopImage(*image,&(*image)->exception);
|
||
if (flop_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=flop_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
{
|
||
/*
|
||
Flop crop geometry.
|
||
*/
|
||
width=(unsigned int) (*image)->columns;
|
||
height=(unsigned int) (*image)->rows;
|
||
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,
|
||
&width,&height);
|
||
(void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
|
||
"%ux%u%+d%+d",width,height,(int) (*image)->columns-(int) width-x,y);
|
||
}
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case FlipCommand:
|
||
{
|
||
Image
|
||
*flip_image;
|
||
|
||
/*
|
||
Flip image scanlines.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flip_image=FlipImage(*image,&(*image)->exception);
|
||
if (flip_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=flip_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
{
|
||
/*
|
||
Flip crop geometry.
|
||
*/
|
||
width=(unsigned int) (*image)->columns;
|
||
height=(unsigned int) (*image)->rows;
|
||
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,
|
||
&width,&height);
|
||
(void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
|
||
"%ux%u%+d%+d",width,height,x,(int) (*image)->rows-(int) height-y);
|
||
}
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case RotateRightCommand:
|
||
{
|
||
/*
|
||
Rotate image 90 degrees clockwise.
|
||
*/
|
||
status=XRotateImage(display,resource_info,windows,90.0,image);
|
||
if (status == MagickFalse)
|
||
{
|
||
XNoticeWidget(display,windows,"Unable to rotate X image",
|
||
(*image)->filename);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case RotateLeftCommand:
|
||
{
|
||
/*
|
||
Rotate image 90 degrees counter-clockwise.
|
||
*/
|
||
status=XRotateImage(display,resource_info,windows,-90.0,image);
|
||
if (status == MagickFalse)
|
||
{
|
||
XNoticeWidget(display,windows,"Unable to rotate X image",
|
||
(*image)->filename);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case RotateCommand:
|
||
{
|
||
/*
|
||
Rotate image.
|
||
*/
|
||
status=XRotateImage(display,resource_info,windows,0.0,image);
|
||
if (status == MagickFalse)
|
||
{
|
||
XNoticeWidget(display,windows,"Unable to rotate X image",
|
||
(*image)->filename);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case ShearCommand:
|
||
{
|
||
Image
|
||
*shear_image;
|
||
|
||
static char
|
||
geometry[MaxTextExtent] = "45.0x45.0";
|
||
|
||
/*
|
||
Query user for shear color and geometry.
|
||
*/
|
||
XColorBrowserWidget(display,windows,"Select",color);
|
||
if (*color == '\0')
|
||
break;
|
||
(void) XDialogWidget(display,windows,"Shear","Enter shear geometry:",
|
||
geometry);
|
||
if (*geometry == '\0')
|
||
break;
|
||
/*
|
||
Shear image.
|
||
*/
|
||
(void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) QueryColorDatabase(color,&(*image)->background_color,
|
||
&(*image)->exception);
|
||
flags=ParseGeometry(geometry,&geometry_info);
|
||
if ((flags & SigmaValue) == 0)
|
||
geometry_info.sigma=geometry_info.rho;
|
||
shear_image=ShearImage(*image,geometry_info.rho,geometry_info.sigma,
|
||
&(*image)->exception);
|
||
if (shear_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=shear_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
windows->image.window_changes.width=(int) (*image)->columns;
|
||
windows->image.window_changes.height=(int) (*image)->rows;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case RollCommand:
|
||
{
|
||
Image
|
||
*roll_image;
|
||
|
||
static char
|
||
geometry[MaxTextExtent] = "+2+2";
|
||
|
||
/*
|
||
Query user for the roll geometry.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Roll","Enter roll geometry:",
|
||
geometry);
|
||
if (*geometry == '\0')
|
||
break;
|
||
/*
|
||
Roll image.
|
||
*/
|
||
(void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) ParsePageGeometry(*image,geometry,&page_geometry,
|
||
&(*image)->exception);
|
||
roll_image=RollImage(*image,page_geometry.x,page_geometry.y,
|
||
&(*image)->exception);
|
||
if (roll_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=roll_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
windows->image.window_changes.width=(int) (*image)->columns;
|
||
windows->image.window_changes.height=(int) (*image)->rows;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case TrimCommand:
|
||
{
|
||
static char
|
||
fuzz[MaxTextExtent];
|
||
|
||
/*
|
||
Query user for the fuzz factor.
|
||
*/
|
||
(void) FormatLocaleString(fuzz,MaxTextExtent,"%g%%",100.0*
|
||
(*image)->fuzz/(QuantumRange+1.0));
|
||
(void) XDialogWidget(display,windows,"Trim","Enter fuzz factor:",fuzz);
|
||
if (*fuzz == '\0')
|
||
break;
|
||
(*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+1.0);
|
||
/*
|
||
Trim image.
|
||
*/
|
||
status=XTrimImage(display,resource_info,windows,*image);
|
||
if (status == MagickFalse)
|
||
{
|
||
XNoticeWidget(display,windows,"Unable to trim X image",
|
||
(*image)->filename);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case HueCommand:
|
||
{
|
||
static char
|
||
hue_percent[MaxTextExtent] = "110";
|
||
|
||
/*
|
||
Query user for percent hue change.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Apply",
|
||
"Enter percent change in image hue (0-200):",hue_percent);
|
||
if (*hue_percent == '\0')
|
||
break;
|
||
/*
|
||
Vary the image hue.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) CopyMagickString(modulate_factors,"100.0/100.0/",MaxTextExtent);
|
||
(void) ConcatenateMagickString(modulate_factors,hue_percent,
|
||
MaxTextExtent);
|
||
(void) ModulateImage(*image,modulate_factors);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case SaturationCommand:
|
||
{
|
||
static char
|
||
saturation_percent[MaxTextExtent] = "110";
|
||
|
||
/*
|
||
Query user for percent saturation change.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Apply",
|
||
"Enter percent change in color saturation (0-200):",saturation_percent);
|
||
if (*saturation_percent == '\0')
|
||
break;
|
||
/*
|
||
Vary color saturation.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) CopyMagickString(modulate_factors,"100.0/",MaxTextExtent);
|
||
(void) ConcatenateMagickString(modulate_factors,saturation_percent,
|
||
MaxTextExtent);
|
||
(void) ModulateImage(*image,modulate_factors);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case BrightnessCommand:
|
||
{
|
||
static char
|
||
brightness_percent[MaxTextExtent] = "110";
|
||
|
||
/*
|
||
Query user for percent brightness change.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Apply",
|
||
"Enter percent change in color brightness (0-200):",brightness_percent);
|
||
if (*brightness_percent == '\0')
|
||
break;
|
||
/*
|
||
Vary the color brightness.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) CopyMagickString(modulate_factors,brightness_percent,
|
||
MaxTextExtent);
|
||
(void) ModulateImage(*image,modulate_factors);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case GammaCommand:
|
||
{
|
||
static char
|
||
factor[MaxTextExtent] = "1.6";
|
||
|
||
/*
|
||
Query user for gamma value.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Gamma",
|
||
"Enter gamma value (e.g. 1.0,1.0,1.6):",factor);
|
||
if (*factor == '\0')
|
||
break;
|
||
/*
|
||
Gamma correct image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) GammaImage(*image,factor);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case SpiffCommand:
|
||
{
|
||
/*
|
||
Sharpen the image contrast.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) ContrastImage(*image,MagickTrue);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case DullCommand:
|
||
{
|
||
/*
|
||
Dull the image contrast.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) ContrastImage(*image,MagickFalse);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case ContrastStretchCommand:
|
||
{
|
||
double
|
||
black_point,
|
||
white_point;
|
||
|
||
static char
|
||
levels[MaxTextExtent] = "1%";
|
||
|
||
/*
|
||
Query user for gamma value.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Contrast Stretch",
|
||
"Enter black and white points:",levels);
|
||
if (*levels == '\0')
|
||
break;
|
||
/*
|
||
Contrast stretch image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flags=ParseGeometry(levels,&geometry_info);
|
||
black_point=geometry_info.rho;
|
||
white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma : black_point;
|
||
if ((flags & PercentValue) != 0)
|
||
{
|
||
black_point*=(double) (*image)->columns*(*image)->rows/100.0;
|
||
white_point*=(double) (*image)->columns*(*image)->rows/100.0;
|
||
}
|
||
white_point=(MagickRealType) (*image)->columns*(*image)->rows-white_point;
|
||
(void) ContrastStretchImageChannel(*image,DefaultChannels,black_point,
|
||
white_point);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case SigmoidalContrastCommand:
|
||
{
|
||
static char
|
||
levels[MaxTextExtent] = "3x50%";
|
||
|
||
/*
|
||
Query user for gamma value.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Sigmoidal Contrast",
|
||
"Enter contrast and midpoint:",levels);
|
||
if (*levels == '\0')
|
||
break;
|
||
/*
|
||
Contrast stretch image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) SigmoidalContrastImage(*image,MagickTrue,levels);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case NormalizeCommand:
|
||
{
|
||
/*
|
||
Perform histogram normalization on the image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) NormalizeImage(*image);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case EqualizeCommand:
|
||
{
|
||
/*
|
||
Perform histogram equalization on the image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) EqualizeImage(*image);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case NegateCommand:
|
||
{
|
||
/*
|
||
Negate colors in image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) NegateImage(*image,MagickFalse);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case GrayscaleCommand:
|
||
{
|
||
/*
|
||
Convert image to grayscale.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) SetImageType(*image,(*image)->matte == MagickFalse ?
|
||
GrayscaleType : GrayscaleMatteType);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case MapCommand:
|
||
{
|
||
Image
|
||
*affinity_image;
|
||
|
||
static char
|
||
filename[MaxTextExtent] = "\0";
|
||
|
||
/*
|
||
Request image file name from user.
|
||
*/
|
||
XFileBrowserWidget(display,windows,"Map",filename);
|
||
if (*filename == '\0')
|
||
break;
|
||
/*
|
||
Map image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
|
||
affinity_image=ReadImage(image_info,&(*image)->exception);
|
||
if (affinity_image != (Image *) NULL)
|
||
{
|
||
(void) RemapImage(&quantize_info,*image,affinity_image);
|
||
affinity_image=DestroyImage(affinity_image);
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case QuantizeCommand:
|
||
{
|
||
int
|
||
status;
|
||
|
||
static char
|
||
colors[MaxTextExtent] = "256";
|
||
|
||
/*
|
||
Query user for maximum number of colors.
|
||
*/
|
||
status=XDialogWidget(display,windows,"Quantize",
|
||
"Maximum number of colors:",colors);
|
||
if (*colors == '\0')
|
||
break;
|
||
/*
|
||
Color reduce the image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
quantize_info.number_colors=StringToUnsignedLong(colors);
|
||
quantize_info.dither=status != 0 ? MagickTrue : MagickFalse;
|
||
(void) QuantizeImage(&quantize_info,*image);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case DespeckleCommand:
|
||
{
|
||
Image
|
||
*despeckle_image;
|
||
|
||
/*
|
||
Despeckle image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
despeckle_image=DespeckleImage(*image,&(*image)->exception);
|
||
if (despeckle_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=despeckle_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case EmbossCommand:
|
||
{
|
||
Image
|
||
*emboss_image;
|
||
|
||
static char
|
||
radius[MaxTextExtent] = "0.0x1.0";
|
||
|
||
/*
|
||
Query user for emboss radius.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Emboss",
|
||
"Enter the emboss radius and standard deviation:",radius);
|
||
if (*radius == '\0')
|
||
break;
|
||
/*
|
||
Reduce noise in the image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flags=ParseGeometry(radius,&geometry_info);
|
||
if ((flags & SigmaValue) == 0)
|
||
geometry_info.sigma=1.0;
|
||
emboss_image=EmbossImage(*image,geometry_info.rho,geometry_info.sigma,
|
||
&(*image)->exception);
|
||
if (emboss_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=emboss_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case ReduceNoiseCommand:
|
||
{
|
||
Image
|
||
*noise_image;
|
||
|
||
static char
|
||
radius[MaxTextExtent] = "0";
|
||
|
||
/*
|
||
Query user for noise radius.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Reduce Noise",
|
||
"Enter the noise radius:",radius);
|
||
if (*radius == '\0')
|
||
break;
|
||
/*
|
||
Reduce noise in the image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flags=ParseGeometry(radius,&geometry_info);
|
||
noise_image=StatisticImage(*image,NonpeakStatistic,(size_t)
|
||
geometry_info.rho,(size_t) geometry_info.rho,&(*image)->exception);
|
||
if (noise_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=noise_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case AddNoiseCommand:
|
||
{
|
||
char
|
||
**noises;
|
||
|
||
Image
|
||
*noise_image;
|
||
|
||
static char
|
||
noise_type[MaxTextExtent] = "Gaussian";
|
||
|
||
/*
|
||
Add noise to the image.
|
||
*/
|
||
noises=GetCommandOptions(MagickNoiseOptions);
|
||
if (noises == (char **) NULL)
|
||
break;
|
||
XListBrowserWidget(display,windows,&windows->widget,
|
||
(const char **) noises,"Add Noise",
|
||
"Select a type of noise to add to your image:",noise_type);
|
||
noises=DestroyStringList(noises);
|
||
if (*noise_type == '\0')
|
||
break;
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
noise_image=AddNoiseImage(*image,(NoiseType) ParseCommandOption(
|
||
MagickNoiseOptions,MagickFalse,noise_type),&(*image)->exception);
|
||
if (noise_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=noise_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case SharpenCommand:
|
||
{
|
||
Image
|
||
*sharp_image;
|
||
|
||
static char
|
||
radius[MaxTextExtent] = "0.0x1.0";
|
||
|
||
/*
|
||
Query user for sharpen radius.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Sharpen",
|
||
"Enter the sharpen radius and standard deviation:",radius);
|
||
if (*radius == '\0')
|
||
break;
|
||
/*
|
||
Sharpen image scanlines.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flags=ParseGeometry(radius,&geometry_info);
|
||
sharp_image=SharpenImage(*image,geometry_info.rho,geometry_info.sigma,
|
||
&(*image)->exception);
|
||
if (sharp_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=sharp_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case BlurCommand:
|
||
{
|
||
Image
|
||
*blur_image;
|
||
|
||
static char
|
||
radius[MaxTextExtent] = "0.0x1.0";
|
||
|
||
/*
|
||
Query user for blur radius.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Blur",
|
||
"Enter the blur radius and standard deviation:",radius);
|
||
if (*radius == '\0')
|
||
break;
|
||
/*
|
||
Blur an image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flags=ParseGeometry(radius,&geometry_info);
|
||
blur_image=BlurImage(*image,geometry_info.rho,geometry_info.sigma,
|
||
&(*image)->exception);
|
||
if (blur_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=blur_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case ThresholdCommand:
|
||
{
|
||
double
|
||
threshold;
|
||
|
||
static char
|
||
factor[MaxTextExtent] = "128";
|
||
|
||
/*
|
||
Query user for threshold value.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Threshold",
|
||
"Enter threshold value:",factor);
|
||
if (*factor == '\0')
|
||
break;
|
||
/*
|
||
Gamma correct image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
|
||
(void) BilevelImage(*image,threshold);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case EdgeDetectCommand:
|
||
{
|
||
Image
|
||
*edge_image;
|
||
|
||
static char
|
||
radius[MaxTextExtent] = "0";
|
||
|
||
/*
|
||
Query user for edge factor.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Detect Edges",
|
||
"Enter the edge detect radius:",radius);
|
||
if (*radius == '\0')
|
||
break;
|
||
/*
|
||
Detect edge in image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flags=ParseGeometry(radius,&geometry_info);
|
||
edge_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
|
||
if (edge_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=edge_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case SpreadCommand:
|
||
{
|
||
Image
|
||
*spread_image;
|
||
|
||
static char
|
||
amount[MaxTextExtent] = "2";
|
||
|
||
/*
|
||
Query user for spread amount.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Spread",
|
||
"Enter the displacement amount:",amount);
|
||
if (*amount == '\0')
|
||
break;
|
||
/*
|
||
Displace image pixels by a random amount.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flags=ParseGeometry(amount,&geometry_info);
|
||
spread_image=EdgeImage(*image,geometry_info.rho,&(*image)->exception);
|
||
if (spread_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=spread_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case ShadeCommand:
|
||
{
|
||
Image
|
||
*shade_image;
|
||
|
||
int
|
||
status;
|
||
|
||
static char
|
||
geometry[MaxTextExtent] = "30x30";
|
||
|
||
/*
|
||
Query user for the shade geometry.
|
||
*/
|
||
status=XDialogWidget(display,windows,"Shade",
|
||
"Enter the azimuth and elevation of the light source:",geometry);
|
||
if (*geometry == '\0')
|
||
break;
|
||
/*
|
||
Shade image pixels.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flags=ParseGeometry(geometry,&geometry_info);
|
||
if ((flags & SigmaValue) == 0)
|
||
geometry_info.sigma=1.0;
|
||
shade_image=ShadeImage(*image,status != 0 ? MagickFalse : MagickTrue,
|
||
geometry_info.rho,geometry_info.sigma,&(*image)->exception);
|
||
if (shade_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=shade_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case RaiseCommand:
|
||
{
|
||
static char
|
||
bevel_width[MaxTextExtent] = "10";
|
||
|
||
/*
|
||
Query user for bevel width.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Raise","Bevel width:",bevel_width);
|
||
if (*bevel_width == '\0')
|
||
break;
|
||
/*
|
||
Raise an image.
|
||
*/
|
||
(void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) ParsePageGeometry(*image,bevel_width,&page_geometry,
|
||
&(*image)->exception);
|
||
(void) RaiseImage(*image,&page_geometry,MagickTrue);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case SegmentCommand:
|
||
{
|
||
static char
|
||
threshold[MaxTextExtent] = "1.0x1.5";
|
||
|
||
/*
|
||
Query user for smoothing threshold.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Segment","Smooth threshold:",
|
||
threshold);
|
||
if (*threshold == '\0')
|
||
break;
|
||
/*
|
||
Segment an image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flags=ParseGeometry(threshold,&geometry_info);
|
||
if ((flags & SigmaValue) == 0)
|
||
geometry_info.sigma=1.0;
|
||
(void) SegmentImage(*image,sRGBColorspace,MagickFalse,geometry_info.rho,
|
||
geometry_info.sigma);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case SepiaToneCommand:
|
||
{
|
||
double
|
||
threshold;
|
||
|
||
Image
|
||
*sepia_image;
|
||
|
||
static char
|
||
factor[MaxTextExtent] = "80%";
|
||
|
||
/*
|
||
Query user for sepia-tone factor.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Sepia Tone",
|
||
"Enter the sepia tone factor (0 - 99.9%):",factor);
|
||
if (*factor == '\0')
|
||
break;
|
||
/*
|
||
Sepia tone image pixels.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
|
||
sepia_image=SepiaToneImage(*image,threshold,&(*image)->exception);
|
||
if (sepia_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=sepia_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case SolarizeCommand:
|
||
{
|
||
double
|
||
threshold;
|
||
|
||
static char
|
||
factor[MaxTextExtent] = "60%";
|
||
|
||
/*
|
||
Query user for solarize factor.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Solarize",
|
||
"Enter the solarize factor (0 - 99.9%):",factor);
|
||
if (*factor == '\0')
|
||
break;
|
||
/*
|
||
Solarize image pixels.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
threshold=StringToDoubleInterval(factor,(double) QuantumRange+1.0);
|
||
(void) SolarizeImage(*image,threshold);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case SwirlCommand:
|
||
{
|
||
Image
|
||
*swirl_image;
|
||
|
||
static char
|
||
degrees[MaxTextExtent] = "60";
|
||
|
||
/*
|
||
Query user for swirl angle.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Swirl","Enter the swirl angle:",
|
||
degrees);
|
||
if (*degrees == '\0')
|
||
break;
|
||
/*
|
||
Swirl image pixels about the center.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flags=ParseGeometry(degrees,&geometry_info);
|
||
swirl_image=SwirlImage(*image,geometry_info.rho,&(*image)->exception);
|
||
if (swirl_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=swirl_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case ImplodeCommand:
|
||
{
|
||
Image
|
||
*implode_image;
|
||
|
||
static char
|
||
factor[MaxTextExtent] = "0.3";
|
||
|
||
/*
|
||
Query user for implode factor.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Implode",
|
||
"Enter the implosion/explosion factor (-1.0 - 1.0):",factor);
|
||
if (*factor == '\0')
|
||
break;
|
||
/*
|
||
Implode image pixels about the center.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flags=ParseGeometry(factor,&geometry_info);
|
||
implode_image=ImplodeImage(*image,geometry_info.rho,&(*image)->exception);
|
||
if (implode_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=implode_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case VignetteCommand:
|
||
{
|
||
Image
|
||
*vignette_image;
|
||
|
||
static char
|
||
geometry[MaxTextExtent] = "0x20";
|
||
|
||
/*
|
||
Query user for the vignette geometry.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Vignette",
|
||
"Enter the radius, sigma, and x and y offsets:",geometry);
|
||
if (*geometry == '\0')
|
||
break;
|
||
/*
|
||
Soften the edges of the image in vignette style
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flags=ParseGeometry(geometry,&geometry_info);
|
||
if ((flags & SigmaValue) == 0)
|
||
geometry_info.sigma=1.0;
|
||
if ((flags & XiValue) == 0)
|
||
geometry_info.xi=0.1*(*image)->columns;
|
||
if ((flags & PsiValue) == 0)
|
||
geometry_info.psi=0.1*(*image)->rows;
|
||
vignette_image=VignetteImage(*image,geometry_info.rho,geometry_info.sigma,
|
||
(ssize_t) ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-
|
||
0.5),&(*image)->exception);
|
||
if (vignette_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=vignette_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case WaveCommand:
|
||
{
|
||
Image
|
||
*wave_image;
|
||
|
||
static char
|
||
geometry[MaxTextExtent] = "25x150";
|
||
|
||
/*
|
||
Query user for the wave geometry.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Wave",
|
||
"Enter the amplitude and length of the wave:",geometry);
|
||
if (*geometry == '\0')
|
||
break;
|
||
/*
|
||
Alter an image along a sine wave.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flags=ParseGeometry(geometry,&geometry_info);
|
||
if ((flags & SigmaValue) == 0)
|
||
geometry_info.sigma=1.0;
|
||
wave_image=WaveImage(*image,geometry_info.rho,geometry_info.sigma,
|
||
&(*image)->exception);
|
||
if (wave_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=wave_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case OilPaintCommand:
|
||
{
|
||
Image
|
||
*paint_image;
|
||
|
||
static char
|
||
radius[MaxTextExtent] = "0";
|
||
|
||
/*
|
||
Query user for circular neighborhood radius.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Oil Paint",
|
||
"Enter the mask radius:",radius);
|
||
if (*radius == '\0')
|
||
break;
|
||
/*
|
||
OilPaint image scanlines.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flags=ParseGeometry(radius,&geometry_info);
|
||
paint_image=OilPaintImage(*image,geometry_info.rho,&(*image)->exception);
|
||
if (paint_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=paint_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case CharcoalDrawCommand:
|
||
{
|
||
Image
|
||
*charcoal_image;
|
||
|
||
static char
|
||
radius[MaxTextExtent] = "0x1";
|
||
|
||
/*
|
||
Query user for charcoal radius.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Charcoal Draw",
|
||
"Enter the charcoal radius and sigma:",radius);
|
||
if (*radius == '\0')
|
||
break;
|
||
/*
|
||
Charcoal the image.
|
||
*/
|
||
(void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
flags=ParseGeometry(radius,&geometry_info);
|
||
if ((flags & SigmaValue) == 0)
|
||
geometry_info.sigma=geometry_info.rho;
|
||
charcoal_image=CharcoalImage(*image,geometry_info.rho,geometry_info.sigma,
|
||
&(*image)->exception);
|
||
if (charcoal_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=charcoal_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case AnnotateCommand:
|
||
{
|
||
/*
|
||
Annotate the image with text.
|
||
*/
|
||
status=XAnnotateEditImage(display,resource_info,windows,*image);
|
||
if (status == MagickFalse)
|
||
{
|
||
XNoticeWidget(display,windows,"Unable to annotate X image",
|
||
(*image)->filename);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case DrawCommand:
|
||
{
|
||
/*
|
||
Draw image.
|
||
*/
|
||
status=XDrawEditImage(display,resource_info,windows,image);
|
||
if (status == MagickFalse)
|
||
{
|
||
XNoticeWidget(display,windows,"Unable to draw on the X image",
|
||
(*image)->filename);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case ColorCommand:
|
||
{
|
||
/*
|
||
Color edit.
|
||
*/
|
||
status=XColorEditImage(display,resource_info,windows,image);
|
||
if (status == MagickFalse)
|
||
{
|
||
XNoticeWidget(display,windows,"Unable to pixel edit X image",
|
||
(*image)->filename);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case MatteCommand:
|
||
{
|
||
/*
|
||
Matte edit.
|
||
*/
|
||
status=XMatteEditImage(display,resource_info,windows,image);
|
||
if (status == MagickFalse)
|
||
{
|
||
XNoticeWidget(display,windows,"Unable to matte edit X image",
|
||
(*image)->filename);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case CompositeCommand:
|
||
{
|
||
/*
|
||
Composite image.
|
||
*/
|
||
status=XCompositeImage(display,resource_info,windows,*image);
|
||
if (status == MagickFalse)
|
||
{
|
||
XNoticeWidget(display,windows,"Unable to composite X image",
|
||
(*image)->filename);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case AddBorderCommand:
|
||
{
|
||
Image
|
||
*border_image;
|
||
|
||
static char
|
||
geometry[MaxTextExtent] = "6x6";
|
||
|
||
/*
|
||
Query user for border color and geometry.
|
||
*/
|
||
XColorBrowserWidget(display,windows,"Select",color);
|
||
if (*color == '\0')
|
||
break;
|
||
(void) XDialogWidget(display,windows,"Add Border",
|
||
"Enter border geometry:",geometry);
|
||
if (*geometry == '\0')
|
||
break;
|
||
/*
|
||
Add a border to the image.
|
||
*/
|
||
(void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) QueryColorDatabase(color,&(*image)->border_color,
|
||
&(*image)->exception);
|
||
(void) ParsePageGeometry(*image,geometry,&page_geometry,
|
||
&(*image)->exception);
|
||
border_image=BorderImage(*image,&page_geometry,&(*image)->exception);
|
||
if (border_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=border_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
windows->image.window_changes.width=(int) (*image)->columns;
|
||
windows->image.window_changes.height=(int) (*image)->rows;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case AddFrameCommand:
|
||
{
|
||
FrameInfo
|
||
frame_info;
|
||
|
||
Image
|
||
*frame_image;
|
||
|
||
static char
|
||
geometry[MaxTextExtent] = "6x6";
|
||
|
||
/*
|
||
Query user for frame color and geometry.
|
||
*/
|
||
XColorBrowserWidget(display,windows,"Select",color);
|
||
if (*color == '\0')
|
||
break;
|
||
(void) XDialogWidget(display,windows,"Add Frame","Enter frame geometry:",
|
||
geometry);
|
||
if (*geometry == '\0')
|
||
break;
|
||
/*
|
||
Surround image with an ornamental border.
|
||
*/
|
||
(void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) QueryColorDatabase(color,&(*image)->matte_color,
|
||
&(*image)->exception);
|
||
(void) ParsePageGeometry(*image,geometry,&page_geometry,
|
||
&(*image)->exception);
|
||
frame_info.width=page_geometry.width;
|
||
frame_info.height=page_geometry.height;
|
||
frame_info.outer_bevel=page_geometry.x;
|
||
frame_info.inner_bevel=page_geometry.y;
|
||
frame_info.x=(ssize_t) frame_info.width;
|
||
frame_info.y=(ssize_t) frame_info.height;
|
||
frame_info.width=(*image)->columns+2*frame_info.width;
|
||
frame_info.height=(*image)->rows+2*frame_info.height;
|
||
frame_image=FrameImage(*image,&frame_info,&(*image)->exception);
|
||
if (frame_image != (Image *) NULL)
|
||
{
|
||
*image=DestroyImage(*image);
|
||
*image=frame_image;
|
||
}
|
||
CatchException(&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (windows->image.orphan != MagickFalse)
|
||
break;
|
||
windows->image.window_changes.width=(int) (*image)->columns;
|
||
windows->image.window_changes.height=(int) (*image)->rows;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
break;
|
||
}
|
||
case CommentCommand:
|
||
{
|
||
const char
|
||
*value;
|
||
|
||
FILE
|
||
*file;
|
||
|
||
int
|
||
unique_file;
|
||
|
||
/*
|
||
Edit image comment.
|
||
*/
|
||
unique_file=AcquireUniqueFileResource(image_info->filename);
|
||
if (unique_file == -1)
|
||
XNoticeWidget(display,windows,"Unable to edit image comment",
|
||
image_info->filename);
|
||
value=GetImageProperty(*image,"comment");
|
||
if (value == (char *) NULL)
|
||
unique_file=close(unique_file)-1;
|
||
else
|
||
{
|
||
register const char
|
||
*p;
|
||
|
||
file=fdopen(unique_file,"w");
|
||
if (file == (FILE *) NULL)
|
||
{
|
||
XNoticeWidget(display,windows,"Unable to edit image comment",
|
||
image_info->filename);
|
||
break;
|
||
}
|
||
for (p=value; *p != '\0'; p++)
|
||
(void) fputc((int) *p,file);
|
||
(void) fputc('\n',file);
|
||
(void) fclose(file);
|
||
}
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
status=InvokeDelegate(image_info,*image,"edit",(char *) NULL,
|
||
&(*image)->exception);
|
||
if (status == MagickFalse)
|
||
XNoticeWidget(display,windows,"Unable to edit image comment",
|
||
(char *) NULL);
|
||
else
|
||
{
|
||
char
|
||
*comment;
|
||
|
||
comment=FileToString(image_info->filename,~0UL,&(*image)->exception);
|
||
if (comment != (char *) NULL)
|
||
{
|
||
(void) SetImageProperty(*image,"comment",comment);
|
||
(*image)->taint=MagickTrue;
|
||
}
|
||
}
|
||
(void) RelinquishUniqueFileResource(image_info->filename);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
break;
|
||
}
|
||
case LaunchCommand:
|
||
{
|
||
/*
|
||
Launch program.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) AcquireUniqueFilename(filename);
|
||
(void) FormatLocaleString((*image)->filename,MaxTextExtent,"launch:%s",
|
||
filename);
|
||
status=WriteImage(image_info,*image);
|
||
if (status == MagickFalse)
|
||
XNoticeWidget(display,windows,"Unable to launch image editor",
|
||
(char *) NULL);
|
||
else
|
||
{
|
||
nexus=ReadImage(resource_info->image_info,&(*image)->exception);
|
||
CatchException(&(*image)->exception);
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_next_image,CurrentTime);
|
||
}
|
||
(void) RelinquishUniqueFileResource(filename);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
break;
|
||
}
|
||
case RegionofInterestCommand:
|
||
{
|
||
/*
|
||
Apply an image processing technique to a region of interest.
|
||
*/
|
||
(void) XROIImage(display,resource_info,windows,image);
|
||
break;
|
||
}
|
||
case InfoCommand:
|
||
break;
|
||
case ZoomCommand:
|
||
{
|
||
/*
|
||
Zoom image.
|
||
*/
|
||
if (windows->magnify.mapped != MagickFalse)
|
||
(void) XRaiseWindow(display,windows->magnify.id);
|
||
else
|
||
{
|
||
/*
|
||
Make magnify image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
(void) XMapRaised(display,windows->magnify.id);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
}
|
||
break;
|
||
}
|
||
case ShowPreviewCommand:
|
||
{
|
||
char
|
||
**previews;
|
||
|
||
Image
|
||
*preview_image;
|
||
|
||
static char
|
||
preview_type[MaxTextExtent] = "Gamma";
|
||
|
||
/*
|
||
Select preview type from menu.
|
||
*/
|
||
previews=GetCommandOptions(MagickPreviewOptions);
|
||
if (previews == (char **) NULL)
|
||
break;
|
||
XListBrowserWidget(display,windows,&windows->widget,
|
||
(const char **) previews,"Preview",
|
||
"Select an enhancement, effect, or F/X:",preview_type);
|
||
previews=DestroyStringList(previews);
|
||
if (*preview_type == '\0')
|
||
break;
|
||
/*
|
||
Show image preview.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
image_info->preview_type=(PreviewType)
|
||
ParseCommandOption(MagickPreviewOptions,MagickFalse,preview_type);
|
||
image_info->group=(ssize_t) windows->image.id;
|
||
(void) DeleteImageProperty(*image,"label");
|
||
(void) SetImageProperty(*image,"label","Preview");
|
||
(void) AcquireUniqueFilename(filename);
|
||
(void) FormatLocaleString((*image)->filename,MaxTextExtent,"preview:%s",
|
||
filename);
|
||
status=WriteImage(image_info,*image);
|
||
(void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
|
||
preview_image=ReadImage(image_info,&(*image)->exception);
|
||
(void) RelinquishUniqueFileResource(filename);
|
||
if (preview_image == (Image *) NULL)
|
||
break;
|
||
(void) FormatLocaleString(preview_image->filename,MaxTextExtent,"show:%s",
|
||
filename);
|
||
status=WriteImage(image_info,preview_image);
|
||
preview_image=DestroyImage(preview_image);
|
||
if (status == MagickFalse)
|
||
XNoticeWidget(display,windows,"Unable to show image preview",
|
||
(*image)->filename);
|
||
XDelay(display,1500);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
break;
|
||
}
|
||
case ShowHistogramCommand:
|
||
{
|
||
Image
|
||
*histogram_image;
|
||
|
||
/*
|
||
Show image histogram.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
image_info->group=(ssize_t) windows->image.id;
|
||
(void) DeleteImageProperty(*image,"label");
|
||
(void) SetImageProperty(*image,"label","Histogram");
|
||
(void) AcquireUniqueFilename(filename);
|
||
(void) FormatLocaleString((*image)->filename,MaxTextExtent,"histogram:%s",
|
||
filename);
|
||
status=WriteImage(image_info,*image);
|
||
(void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
|
||
histogram_image=ReadImage(image_info,&(*image)->exception);
|
||
(void) RelinquishUniqueFileResource(filename);
|
||
if (histogram_image == (Image *) NULL)
|
||
break;
|
||
(void) FormatLocaleString(histogram_image->filename,MaxTextExtent,
|
||
"show:%s",filename);
|
||
status=WriteImage(image_info,histogram_image);
|
||
histogram_image=DestroyImage(histogram_image);
|
||
if (status == MagickFalse)
|
||
XNoticeWidget(display,windows,"Unable to show histogram",
|
||
(*image)->filename);
|
||
XDelay(display,1500);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
break;
|
||
}
|
||
case ShowMatteCommand:
|
||
{
|
||
Image
|
||
*matte_image;
|
||
|
||
if ((*image)->matte == MagickFalse)
|
||
{
|
||
XNoticeWidget(display,windows,
|
||
"Image does not have any matte information",(*image)->filename);
|
||
break;
|
||
}
|
||
/*
|
||
Show image matte.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
image_info->group=(ssize_t) windows->image.id;
|
||
(void) DeleteImageProperty(*image,"label");
|
||
(void) SetImageProperty(*image,"label","Matte");
|
||
(void) AcquireUniqueFilename(filename);
|
||
(void) FormatLocaleString((*image)->filename,MaxTextExtent,"matte:%s",
|
||
filename);
|
||
status=WriteImage(image_info,*image);
|
||
(void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
|
||
matte_image=ReadImage(image_info,&(*image)->exception);
|
||
(void) RelinquishUniqueFileResource(filename);
|
||
if (matte_image == (Image *) NULL)
|
||
break;
|
||
(void) FormatLocaleString(matte_image->filename,MaxTextExtent,"show:%s",
|
||
filename);
|
||
status=WriteImage(image_info,matte_image);
|
||
matte_image=DestroyImage(matte_image);
|
||
if (status == MagickFalse)
|
||
XNoticeWidget(display,windows,"Unable to show matte",
|
||
(*image)->filename);
|
||
XDelay(display,1500);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
break;
|
||
}
|
||
case BackgroundCommand:
|
||
{
|
||
/*
|
||
Background image.
|
||
*/
|
||
status=XBackgroundImage(display,resource_info,windows,image);
|
||
if (status == MagickFalse)
|
||
break;
|
||
nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
|
||
if (nexus != (Image *) NULL)
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_next_image,CurrentTime);
|
||
break;
|
||
}
|
||
case SlideShowCommand:
|
||
{
|
||
static char
|
||
delay[MaxTextExtent] = "5";
|
||
|
||
/*
|
||
Display next image after pausing.
|
||
*/
|
||
(void) XDialogWidget(display,windows,"Slide Show",
|
||
"Pause how many 1/100ths of a second between images:",delay);
|
||
if (*delay == '\0')
|
||
break;
|
||
resource_info->delay=StringToUnsignedLong(delay);
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_next_image,CurrentTime);
|
||
break;
|
||
}
|
||
case PreferencesCommand:
|
||
{
|
||
/*
|
||
Set user preferences.
|
||
*/
|
||
status=XPreferencesWidget(display,resource_info,windows);
|
||
if (status == MagickFalse)
|
||
break;
|
||
nexus=CloneImage(*image,0,0,MagickTrue,&(*image)->exception);
|
||
if (nexus != (Image *) NULL)
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_next_image,CurrentTime);
|
||
break;
|
||
}
|
||
case HelpCommand:
|
||
{
|
||
/*
|
||
User requested help.
|
||
*/
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Display",DisplayHelp);
|
||
break;
|
||
}
|
||
case BrowseDocumentationCommand:
|
||
{
|
||
Atom
|
||
mozilla_atom;
|
||
|
||
Window
|
||
mozilla_window,
|
||
root_window;
|
||
|
||
/*
|
||
Browse the ImageMagick documentation.
|
||
*/
|
||
root_window=XRootWindow(display,XDefaultScreen(display));
|
||
mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
|
||
mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
|
||
if (mozilla_window != (Window) NULL)
|
||
{
|
||
char
|
||
command[MaxTextExtent],
|
||
*url;
|
||
|
||
/*
|
||
Display documentation using Netscape remote control.
|
||
*/
|
||
url=GetMagickHomeURL();
|
||
(void) FormatLocaleString(command,MaxTextExtent,
|
||
"openurl(%s,new-tab)",url);
|
||
url=DestroyString(url);
|
||
mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
|
||
(void) XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,
|
||
8,PropModeReplace,(unsigned char *) command,(int) strlen(command));
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
break;
|
||
}
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
status=InvokeDelegate(image_info,*image,"browse",(char *) NULL,
|
||
&(*image)->exception);
|
||
if (status == MagickFalse)
|
||
XNoticeWidget(display,windows,"Unable to browse documentation",
|
||
(char *) NULL);
|
||
XDelay(display,1500);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
break;
|
||
}
|
||
case VersionCommand:
|
||
{
|
||
XNoticeWidget(display,windows,GetMagickVersion((size_t *) NULL),
|
||
GetMagickCopyright());
|
||
break;
|
||
}
|
||
case SaveToUndoBufferCommand:
|
||
break;
|
||
default:
|
||
{
|
||
(void) XBell(display,0);
|
||
break;
|
||
}
|
||
}
|
||
image_info=DestroyImageInfo(image_info);
|
||
return(nexus);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X M a g n i f y I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XMagnifyImage() magnifies portions of the image as indicated by the pointer.
|
||
% The magnified portion is displayed in a separate window.
|
||
%
|
||
% The format of the XMagnifyImage method is:
|
||
%
|
||
% void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o event: Specifies a pointer to a XEvent structure. If it is NULL,
|
||
% the entire image is refreshed.
|
||
%
|
||
*/
|
||
static void XMagnifyImage(Display *display,XWindows *windows,XEvent *event)
|
||
{
|
||
char
|
||
text[MaxTextExtent];
|
||
|
||
register int
|
||
x,
|
||
y;
|
||
|
||
size_t
|
||
state;
|
||
|
||
/*
|
||
Update magnified image until the mouse button is released.
|
||
*/
|
||
(void) XCheckDefineCursor(display,windows->image.id,windows->magnify.cursor);
|
||
state=DefaultState;
|
||
x=event->xbutton.x;
|
||
y=event->xbutton.y;
|
||
windows->magnify.x=(int) windows->image.x+x;
|
||
windows->magnify.y=(int) windows->image.y+y;
|
||
do
|
||
{
|
||
/*
|
||
Map and unmap Info widget as text cursor crosses its boundaries.
|
||
*/
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
if ((x < (int) (windows->info.x+windows->info.width)) &&
|
||
(y < (int) (windows->info.y+windows->info.height)))
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
}
|
||
else
|
||
if ((x > (int) (windows->info.x+windows->info.width)) ||
|
||
(y > (int) (windows->info.y+windows->info.height)))
|
||
(void) XMapWindow(display,windows->info.id);
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
/*
|
||
Display pointer position.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
|
||
windows->magnify.x,windows->magnify.y);
|
||
XInfoWidget(display,windows,text);
|
||
}
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,event);
|
||
switch (event->type)
|
||
{
|
||
case ButtonPress:
|
||
break;
|
||
case ButtonRelease:
|
||
{
|
||
/*
|
||
User has finished magnifying image.
|
||
*/
|
||
x=event->xbutton.x;
|
||
y=event->xbutton.y;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case Expose:
|
||
break;
|
||
case MotionNotify:
|
||
{
|
||
x=event->xmotion.x;
|
||
y=event->xmotion.y;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
/*
|
||
Check boundary conditions.
|
||
*/
|
||
if (x < 0)
|
||
x=0;
|
||
else
|
||
if (x >= (int) windows->image.width)
|
||
x=(int) windows->image.width-1;
|
||
if (y < 0)
|
||
y=0;
|
||
else
|
||
if (y >= (int) windows->image.height)
|
||
y=(int) windows->image.height-1;
|
||
} while ((state & ExitState) == 0);
|
||
/*
|
||
Display magnified image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X M a g n i f y W i n d o w C o m m a n d %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XMagnifyWindowCommand() moves the image within an Magnify window by one
|
||
% pixel as specified by the key symbol.
|
||
%
|
||
% The format of the XMagnifyWindowCommand method is:
|
||
%
|
||
% void XMagnifyWindowCommand(Display *display,XWindows *windows,
|
||
% const MagickStatusType state,const KeySym key_symbol)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o state: key mask.
|
||
%
|
||
% o key_symbol: Specifies a KeySym which indicates which side of the image
|
||
% to trim.
|
||
%
|
||
*/
|
||
static void XMagnifyWindowCommand(Display *display,XWindows *windows,
|
||
const MagickStatusType state,const KeySym key_symbol)
|
||
{
|
||
unsigned int
|
||
quantum;
|
||
|
||
/*
|
||
User specified a magnify factor or position.
|
||
*/
|
||
quantum=1;
|
||
if ((state & Mod1Mask) != 0)
|
||
quantum=10;
|
||
switch ((int) key_symbol)
|
||
{
|
||
case QuitCommand:
|
||
{
|
||
(void) XWithdrawWindow(display,windows->magnify.id,
|
||
windows->magnify.screen);
|
||
break;
|
||
}
|
||
case XK_Home:
|
||
case XK_KP_Home:
|
||
{
|
||
windows->magnify.x=(int) windows->image.width/2;
|
||
windows->magnify.y=(int) windows->image.height/2;
|
||
break;
|
||
}
|
||
case XK_Left:
|
||
case XK_KP_Left:
|
||
{
|
||
if (windows->magnify.x > 0)
|
||
windows->magnify.x-=quantum;
|
||
break;
|
||
}
|
||
case XK_Up:
|
||
case XK_KP_Up:
|
||
{
|
||
if (windows->magnify.y > 0)
|
||
windows->magnify.y-=quantum;
|
||
break;
|
||
}
|
||
case XK_Right:
|
||
case XK_KP_Right:
|
||
{
|
||
if (windows->magnify.x < (int) (windows->image.ximage->width-1))
|
||
windows->magnify.x+=quantum;
|
||
break;
|
||
}
|
||
case XK_Down:
|
||
case XK_KP_Down:
|
||
{
|
||
if (windows->magnify.y < (int) (windows->image.ximage->height-1))
|
||
windows->magnify.y+=quantum;
|
||
break;
|
||
}
|
||
case XK_0:
|
||
case XK_1:
|
||
case XK_2:
|
||
case XK_3:
|
||
case XK_4:
|
||
case XK_5:
|
||
case XK_6:
|
||
case XK_7:
|
||
case XK_8:
|
||
case XK_9:
|
||
{
|
||
windows->magnify.data=(key_symbol-XK_0);
|
||
break;
|
||
}
|
||
case XK_KP_0:
|
||
case XK_KP_1:
|
||
case XK_KP_2:
|
||
case XK_KP_3:
|
||
case XK_KP_4:
|
||
case XK_KP_5:
|
||
case XK_KP_6:
|
||
case XK_KP_7:
|
||
case XK_KP_8:
|
||
case XK_KP_9:
|
||
{
|
||
windows->magnify.data=(key_symbol-XK_KP_0);
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
XMakeMagnifyImage(display,windows);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X M a k e P a n I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XMakePanImage() creates a thumbnail of the image and displays it in the Pan
|
||
% icon window.
|
||
%
|
||
% The format of the XMakePanImage method is:
|
||
%
|
||
% void XMakePanImage(Display *display,XResourceInfo *resource_info,
|
||
% XWindows *windows,Image *image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image.
|
||
%
|
||
*/
|
||
static void XMakePanImage(Display *display,XResourceInfo *resource_info,
|
||
XWindows *windows,Image *image)
|
||
{
|
||
MagickStatusType
|
||
status;
|
||
|
||
/*
|
||
Create and display image for panning icon.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
windows->pan.x=(int) windows->image.x;
|
||
windows->pan.y=(int) windows->image.y;
|
||
status=XMakeImage(display,resource_info,&windows->pan,image,
|
||
windows->pan.width,windows->pan.height);
|
||
if (status == MagickFalse)
|
||
ThrowXWindowFatalException(XServerError,image->exception.reason,
|
||
image->exception.description);
|
||
(void) XSetWindowBackgroundPixmap(display,windows->pan.id,
|
||
windows->pan.pixmap);
|
||
(void) XClearWindow(display,windows->pan.id);
|
||
XDrawPanRectangle(display,windows);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X M a t t a E d i t I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XMatteEditImage() allows the user to interactively change the Matte channel
|
||
% of an image. If the image is PseudoClass it is promoted to DirectClass
|
||
% before the matte information is stored.
|
||
%
|
||
% The format of the XMatteEditImage method is:
|
||
%
|
||
% MagickBooleanType XMatteEditImage(Display *display,
|
||
% XResourceInfo *resource_info,XWindows *windows,Image **image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image; returned from ReadImage.
|
||
%
|
||
*/
|
||
static MagickBooleanType XMatteEditImage(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows,Image **image)
|
||
{
|
||
static char
|
||
matte[MaxTextExtent] = "0";
|
||
|
||
static const char
|
||
*MatteEditMenu[] =
|
||
{
|
||
"Method",
|
||
"Border Color",
|
||
"Fuzz",
|
||
"Matte Value",
|
||
"Undo",
|
||
"Help",
|
||
"Dismiss",
|
||
(char *) NULL
|
||
};
|
||
|
||
static const ModeType
|
||
MatteEditCommands[] =
|
||
{
|
||
MatteEditMethod,
|
||
MatteEditBorderCommand,
|
||
MatteEditFuzzCommand,
|
||
MatteEditValueCommand,
|
||
MatteEditUndoCommand,
|
||
MatteEditHelpCommand,
|
||
MatteEditDismissCommand
|
||
};
|
||
|
||
static PaintMethod
|
||
method = PointMethod;
|
||
|
||
static XColor
|
||
border_color = { 0, 0, 0, 0, 0, 0 };
|
||
|
||
char
|
||
command[MaxTextExtent],
|
||
text[MaxTextExtent];
|
||
|
||
Cursor
|
||
cursor;
|
||
|
||
int
|
||
entry,
|
||
id,
|
||
x,
|
||
x_offset,
|
||
y,
|
||
y_offset;
|
||
|
||
register int
|
||
i;
|
||
|
||
register PixelPacket
|
||
*q;
|
||
|
||
unsigned int
|
||
height,
|
||
width;
|
||
|
||
size_t
|
||
state;
|
||
|
||
XEvent
|
||
event;
|
||
|
||
/*
|
||
Map Command widget.
|
||
*/
|
||
(void) CloneString(&windows->command.name,"Matte Edit");
|
||
windows->command.data=4;
|
||
(void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
|
||
(void) XMapRaised(display,windows->command.id);
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_update_widget,CurrentTime);
|
||
/*
|
||
Make cursor.
|
||
*/
|
||
cursor=XMakeCursor(display,windows->image.id,windows->map_info->colormap,
|
||
resource_info->background_color,resource_info->foreground_color);
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
/*
|
||
Track pointer until button 1 is pressed.
|
||
*/
|
||
XQueryPosition(display,windows->image.id,&x,&y);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask | PointerMotionMask);
|
||
state=DefaultState;
|
||
do
|
||
{
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
/*
|
||
Display pointer position.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent," %+d%+d ",
|
||
x+windows->image.x,y+windows->image.y);
|
||
XInfoWidget(display,windows,text);
|
||
}
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,&event);
|
||
if (event.xany.window == windows->command.id)
|
||
{
|
||
/*
|
||
Select a command from the Command widget.
|
||
*/
|
||
id=XCommandWidget(display,windows,MatteEditMenu,&event);
|
||
if (id < 0)
|
||
{
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
continue;
|
||
}
|
||
switch (MatteEditCommands[id])
|
||
{
|
||
case MatteEditMethod:
|
||
{
|
||
char
|
||
**methods;
|
||
|
||
/*
|
||
Select a method from the pop-up menu.
|
||
*/
|
||
methods=GetCommandOptions(MagickMethodOptions);
|
||
if (methods == (char **) NULL)
|
||
break;
|
||
entry=XMenuWidget(display,windows,MatteEditMenu[id],
|
||
(const char **) methods,command);
|
||
if (entry >= 0)
|
||
method=(PaintMethod) ParseCommandOption(MagickMethodOptions,
|
||
MagickFalse,methods[entry]);
|
||
methods=DestroyStringList(methods);
|
||
break;
|
||
}
|
||
case MatteEditBorderCommand:
|
||
{
|
||
const char
|
||
*ColorMenu[MaxNumberPens];
|
||
|
||
int
|
||
pen_number;
|
||
|
||
/*
|
||
Initialize menu selections.
|
||
*/
|
||
for (i=0; i < (int) (MaxNumberPens-2); i++)
|
||
ColorMenu[i]=resource_info->pen_colors[i];
|
||
ColorMenu[MaxNumberPens-2]="Browser...";
|
||
ColorMenu[MaxNumberPens-1]=(const char *) NULL;
|
||
/*
|
||
Select a pen color from the pop-up menu.
|
||
*/
|
||
pen_number=XMenuWidget(display,windows,MatteEditMenu[id],
|
||
(const char **) ColorMenu,command);
|
||
if (pen_number < 0)
|
||
break;
|
||
if (pen_number == (MaxNumberPens-2))
|
||
{
|
||
static char
|
||
color_name[MaxTextExtent] = "gray";
|
||
|
||
/*
|
||
Select a pen color from a dialog.
|
||
*/
|
||
resource_info->pen_colors[pen_number]=color_name;
|
||
XColorBrowserWidget(display,windows,"Select",color_name);
|
||
if (*color_name == '\0')
|
||
break;
|
||
}
|
||
/*
|
||
Set border color.
|
||
*/
|
||
(void) XParseColor(display,windows->map_info->colormap,
|
||
resource_info->pen_colors[pen_number],&border_color);
|
||
break;
|
||
}
|
||
case MatteEditFuzzCommand:
|
||
{
|
||
static char
|
||
fuzz[MaxTextExtent];
|
||
|
||
static const char
|
||
*FuzzMenu[] =
|
||
{
|
||
"0%",
|
||
"2%",
|
||
"5%",
|
||
"10%",
|
||
"15%",
|
||
"Dialog...",
|
||
(char *) NULL,
|
||
};
|
||
|
||
/*
|
||
Select a command from the pop-up menu.
|
||
*/
|
||
entry=XMenuWidget(display,windows,MatteEditMenu[id],FuzzMenu,
|
||
command);
|
||
if (entry < 0)
|
||
break;
|
||
if (entry != 5)
|
||
{
|
||
(*image)->fuzz=StringToDoubleInterval(FuzzMenu[entry],(double)
|
||
QuantumRange+1.0);
|
||
break;
|
||
}
|
||
(void) CopyMagickString(fuzz,"20%",MaxTextExtent);
|
||
(void) XDialogWidget(display,windows,"Ok",
|
||
"Enter fuzz factor (0.0 - 99.9%):",fuzz);
|
||
if (*fuzz == '\0')
|
||
break;
|
||
(void) ConcatenateMagickString(fuzz,"%",MaxTextExtent);
|
||
(*image)->fuzz=StringToDoubleInterval(fuzz,(double) QuantumRange+
|
||
1.0);
|
||
break;
|
||
}
|
||
case MatteEditValueCommand:
|
||
{
|
||
static char
|
||
message[MaxTextExtent];
|
||
|
||
static const char
|
||
*MatteMenu[] =
|
||
{
|
||
"Opaque",
|
||
"Transparent",
|
||
"Dialog...",
|
||
(char *) NULL,
|
||
};
|
||
|
||
/*
|
||
Select a command from the pop-up menu.
|
||
*/
|
||
entry=XMenuWidget(display,windows,MatteEditMenu[id],MatteMenu,
|
||
command);
|
||
if (entry < 0)
|
||
break;
|
||
if (entry != 2)
|
||
{
|
||
(void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
|
||
OpaqueOpacity);
|
||
if (LocaleCompare(MatteMenu[entry],"Transparent") == 0)
|
||
(void) FormatLocaleString(matte,MaxTextExtent,QuantumFormat,
|
||
(Quantum) TransparentOpacity);
|
||
break;
|
||
}
|
||
(void) FormatLocaleString(message,MaxTextExtent,
|
||
"Enter matte value (0 - " QuantumFormat "):",(Quantum)
|
||
QuantumRange);
|
||
(void) XDialogWidget(display,windows,"Matte",message,matte);
|
||
if (*matte == '\0')
|
||
break;
|
||
break;
|
||
}
|
||
case MatteEditUndoCommand:
|
||
{
|
||
(void) XMagickCommand(display,resource_info,windows,UndoCommand,
|
||
image);
|
||
break;
|
||
}
|
||
case MatteEditHelpCommand:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Matte Edit",ImageMatteEditHelp);
|
||
break;
|
||
}
|
||
case MatteEditDismissCommand:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
continue;
|
||
}
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
if (event.xbutton.button != Button1)
|
||
break;
|
||
if ((event.xbutton.window != windows->image.id) &&
|
||
(event.xbutton.window != windows->magnify.id))
|
||
break;
|
||
/*
|
||
Update matte data.
|
||
*/
|
||
x=event.xbutton.x;
|
||
y=event.xbutton.y;
|
||
(void) XMagickCommand(display,resource_info,windows,
|
||
SaveToUndoBufferCommand,image);
|
||
state|=UpdateConfigurationState;
|
||
break;
|
||
}
|
||
case ButtonRelease:
|
||
{
|
||
if (event.xbutton.button != Button1)
|
||
break;
|
||
if ((event.xbutton.window != windows->image.id) &&
|
||
(event.xbutton.window != windows->magnify.id))
|
||
break;
|
||
/*
|
||
Update colormap information.
|
||
*/
|
||
x=event.xbutton.x;
|
||
y=event.xbutton.y;
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
XInfoWidget(display,windows,text);
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
state&=(~UpdateConfigurationState);
|
||
break;
|
||
}
|
||
case Expose:
|
||
break;
|
||
case KeyPress:
|
||
{
|
||
char
|
||
command[MaxTextExtent];
|
||
|
||
KeySym
|
||
key_symbol;
|
||
|
||
if (event.xkey.window == windows->magnify.id)
|
||
{
|
||
Window
|
||
window;
|
||
|
||
window=windows->magnify.id;
|
||
while (XCheckWindowEvent(display,window,KeyPressMask,&event)) ;
|
||
}
|
||
if (event.xkey.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Respond to a user key press.
|
||
*/
|
||
(void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
switch ((int) key_symbol)
|
||
{
|
||
case XK_Escape:
|
||
case XK_F20:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case XK_F1:
|
||
case XK_Help:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Matte Edit",ImageMatteEditHelp);
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
(void) XBell(display,0);
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case MotionNotify:
|
||
{
|
||
/*
|
||
Map and unmap Info widget as cursor crosses its boundaries.
|
||
*/
|
||
x=event.xmotion.x;
|
||
y=event.xmotion.y;
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
if ((x < (int) (windows->info.x+windows->info.width)) &&
|
||
(y < (int) (windows->info.y+windows->info.height)))
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
}
|
||
else
|
||
if ((x > (int) (windows->info.x+windows->info.width)) ||
|
||
(y > (int) (windows->info.y+windows->info.height)))
|
||
(void) XMapWindow(display,windows->info.id);
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
if (event.xany.window == windows->magnify.id)
|
||
{
|
||
x=windows->magnify.x-windows->image.x;
|
||
y=windows->magnify.y-windows->image.y;
|
||
}
|
||
x_offset=x;
|
||
y_offset=y;
|
||
if ((state & UpdateConfigurationState) != 0)
|
||
{
|
||
CacheView
|
||
*image_view;
|
||
|
||
ExceptionInfo
|
||
*exception;
|
||
|
||
int
|
||
x,
|
||
y;
|
||
|
||
/*
|
||
Matte edit is relative to image configuration.
|
||
*/
|
||
(void) XClearArea(display,windows->image.id,x_offset,y_offset,1,1,
|
||
MagickTrue);
|
||
XPutPixel(windows->image.ximage,x_offset,y_offset,
|
||
windows->pixel_info->background_color.pixel);
|
||
width=(unsigned int) (*image)->columns;
|
||
height=(unsigned int) (*image)->rows;
|
||
x=0;
|
||
y=0;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,
|
||
&width,&height);
|
||
x_offset=(int)
|
||
(width*(windows->image.x+x_offset)/windows->image.ximage->width+x);
|
||
y_offset=(int)
|
||
(height*(windows->image.y+y_offset)/windows->image.ximage->height+y);
|
||
if ((x_offset < 0) || (y_offset < 0))
|
||
continue;
|
||
if ((x_offset >= (int) (*image)->columns) ||
|
||
(y_offset >= (int) (*image)->rows))
|
||
continue;
|
||
if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
|
||
return(MagickFalse);
|
||
(*image)->matte=MagickTrue;
|
||
exception=(&(*image)->exception);
|
||
image_view=AcquireAuthenticCacheView(*image,exception);
|
||
switch (method)
|
||
{
|
||
case PointMethod:
|
||
default:
|
||
{
|
||
/*
|
||
Update matte information using point algorithm.
|
||
*/
|
||
q=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,
|
||
(ssize_t) y_offset,1,1,exception);
|
||
if (q == (PixelPacket *) NULL)
|
||
break;
|
||
q->opacity=(Quantum) StringToLong(matte);
|
||
(void) SyncCacheViewAuthenticPixels(image_view,exception);
|
||
break;
|
||
}
|
||
case ReplaceMethod:
|
||
{
|
||
PixelPacket
|
||
target;
|
||
|
||
/*
|
||
Update matte information using replace algorithm.
|
||
*/
|
||
(void) GetOneCacheViewVirtualPixel(image_view,(ssize_t) x_offset,
|
||
(ssize_t) y_offset,&target,exception);
|
||
for (y=0; y < (int) (*image)->rows; y++)
|
||
{
|
||
q=GetCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
|
||
(*image)->columns,1,&(*image)->exception);
|
||
if (q == (PixelPacket *) NULL)
|
||
break;
|
||
for (x=0; x < (int) (*image)->columns; x++)
|
||
{
|
||
if (IsColorSimilar(*image,q,&target))
|
||
q->opacity=(Quantum) StringToLong(matte);
|
||
q++;
|
||
}
|
||
if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case FloodfillMethod:
|
||
case FillToBorderMethod:
|
||
{
|
||
DrawInfo
|
||
*draw_info;
|
||
|
||
MagickPixelPacket
|
||
target;
|
||
|
||
/*
|
||
Update matte information using floodfill algorithm.
|
||
*/
|
||
(void) GetOneVirtualMagickPixel(*image,(ssize_t) x_offset,
|
||
(ssize_t) y_offset,&target,exception);
|
||
if (method == FillToBorderMethod)
|
||
{
|
||
target.red=(MagickRealType)
|
||
ScaleShortToQuantum(border_color.red);
|
||
target.green=(MagickRealType)
|
||
ScaleShortToQuantum(border_color.green);
|
||
target.blue=(MagickRealType)
|
||
ScaleShortToQuantum(border_color.blue);
|
||
}
|
||
draw_info=CloneDrawInfo(resource_info->image_info,
|
||
(DrawInfo *) NULL);
|
||
draw_info->fill.opacity=ClampToQuantum(StringToDouble(matte,
|
||
(char **) NULL));
|
||
(void) FloodfillPaintImage(*image,OpacityChannel,draw_info,&target,
|
||
(ssize_t) x_offset,(ssize_t) y_offset,
|
||
method == FloodfillMethod ? MagickFalse : MagickTrue);
|
||
draw_info=DestroyDrawInfo(draw_info);
|
||
break;
|
||
}
|
||
case ResetMethod:
|
||
{
|
||
/*
|
||
Update matte information using reset algorithm.
|
||
*/
|
||
if (SetImageStorageClass(*image,DirectClass) == MagickFalse)
|
||
return(MagickFalse);
|
||
for (y=0; y < (int) (*image)->rows; y++)
|
||
{
|
||
q=QueueCacheViewAuthenticPixels(image_view,0,(ssize_t) y,
|
||
(*image)->columns,1,exception);
|
||
if (q == (PixelPacket *) NULL)
|
||
break;
|
||
for (x=0; x < (int) (*image)->columns; x++)
|
||
{
|
||
q->opacity=(Quantum) StringToLong(matte);
|
||
q++;
|
||
}
|
||
if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
|
||
break;
|
||
}
|
||
if (StringToLong(matte) == OpaqueOpacity)
|
||
(*image)->matte=MagickFalse;
|
||
break;
|
||
}
|
||
}
|
||
image_view=DestroyCacheView(image_view);
|
||
state&=(~UpdateConfigurationState);
|
||
}
|
||
} while ((state & ExitState) == 0);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
(void) XFreeCursor(display,cursor);
|
||
return(MagickTrue);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X O p e n I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XOpenImage() loads an image from a file.
|
||
%
|
||
% The format of the XOpenImage method is:
|
||
%
|
||
% Image *XOpenImage(Display *display,XResourceInfo *resource_info,
|
||
% XWindows *windows,const unsigned int command)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o command: A value other than zero indicates that the file is selected
|
||
% from the command line argument list.
|
||
%
|
||
*/
|
||
static Image *XOpenImage(Display *display,XResourceInfo *resource_info,
|
||
XWindows *windows,const MagickBooleanType command)
|
||
{
|
||
const MagickInfo
|
||
*magick_info;
|
||
|
||
ExceptionInfo
|
||
*exception;
|
||
|
||
Image
|
||
*nexus;
|
||
|
||
ImageInfo
|
||
*image_info;
|
||
|
||
static char
|
||
filename[MaxTextExtent] = "\0";
|
||
|
||
/*
|
||
Request file name from user.
|
||
*/
|
||
if (command == MagickFalse)
|
||
XFileBrowserWidget(display,windows,"Open",filename);
|
||
else
|
||
{
|
||
char
|
||
**filelist,
|
||
**files;
|
||
|
||
int
|
||
count,
|
||
status;
|
||
|
||
register int
|
||
i,
|
||
j;
|
||
|
||
/*
|
||
Select next image from the command line.
|
||
*/
|
||
status=XGetCommand(display,windows->image.id,&files,&count);
|
||
if (status == 0)
|
||
{
|
||
ThrowXWindowFatalException(XServerError,"UnableToGetProperty","...");
|
||
return((Image *) NULL);
|
||
}
|
||
filelist=(char **) AcquireQuantumMemory((size_t) count,sizeof(*filelist));
|
||
if (filelist == (char **) NULL)
|
||
{
|
||
ThrowXWindowFatalException(ResourceLimitError,
|
||
"MemoryAllocationFailed","...");
|
||
(void) XFreeStringList(files);
|
||
return((Image *) NULL);
|
||
}
|
||
j=0;
|
||
for (i=1; i < count; i++)
|
||
if (*files[i] != '-')
|
||
filelist[j++]=files[i];
|
||
filelist[j]=(char *) NULL;
|
||
XListBrowserWidget(display,windows,&windows->widget,
|
||
(const char **) filelist,"Load","Select Image to Load:",filename);
|
||
filelist=(char **) RelinquishMagickMemory(filelist);
|
||
(void) XFreeStringList(files);
|
||
}
|
||
if (*filename == '\0')
|
||
return((Image *) NULL);
|
||
image_info=CloneImageInfo(resource_info->image_info);
|
||
(void) SetImageInfoProgressMonitor(image_info,(MagickProgressMonitor) NULL,
|
||
(void *) NULL);
|
||
(void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
|
||
exception=AcquireExceptionInfo();
|
||
(void) SetImageInfo(image_info,0,exception);
|
||
if (LocaleCompare(image_info->magick,"X") == 0)
|
||
{
|
||
char
|
||
seconds[MaxTextExtent];
|
||
|
||
/*
|
||
User may want to delay the X server screen grab.
|
||
*/
|
||
(void) CopyMagickString(seconds,"0",MaxTextExtent);
|
||
(void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
|
||
seconds);
|
||
if (*seconds == '\0')
|
||
return((Image *) NULL);
|
||
XDelay(display,(size_t) (1000*StringToLong(seconds)));
|
||
}
|
||
magick_info=GetMagickInfo(image_info->magick,exception);
|
||
if ((magick_info != (const MagickInfo *) NULL) &&
|
||
(magick_info->raw != MagickFalse))
|
||
{
|
||
char
|
||
geometry[MaxTextExtent];
|
||
|
||
/*
|
||
Request image size from the user.
|
||
*/
|
||
(void) CopyMagickString(geometry,"512x512",MaxTextExtent);
|
||
if (image_info->size != (char *) NULL)
|
||
(void) CopyMagickString(geometry,image_info->size,MaxTextExtent);
|
||
(void) XDialogWidget(display,windows,"Load","Enter the image geometry:",
|
||
geometry);
|
||
(void) CloneString(&image_info->size,geometry);
|
||
}
|
||
/*
|
||
Load the image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
|
||
nexus=ReadImage(image_info,exception);
|
||
CatchException(exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (nexus != (Image *) NULL)
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_next_image,CurrentTime);
|
||
else
|
||
{
|
||
char
|
||
*text,
|
||
**textlist;
|
||
|
||
/*
|
||
Unknown image format.
|
||
*/
|
||
text=FileToString(filename,~0,exception);
|
||
if (text == (char *) NULL)
|
||
return((Image *) NULL);
|
||
textlist=StringToList(text);
|
||
if (textlist != (char **) NULL)
|
||
{
|
||
char
|
||
title[MaxTextExtent];
|
||
|
||
register int
|
||
i;
|
||
|
||
(void) FormatLocaleString(title,MaxTextExtent,
|
||
"Unknown format: %s",filename);
|
||
XTextViewWidget(display,resource_info,windows,MagickTrue,title,
|
||
(const char **) textlist);
|
||
for (i=0; textlist[i] != (char *) NULL; i++)
|
||
textlist[i]=DestroyString(textlist[i]);
|
||
textlist=(char **) RelinquishMagickMemory(textlist);
|
||
}
|
||
text=DestroyString(text);
|
||
}
|
||
exception=DestroyExceptionInfo(exception);
|
||
image_info=DestroyImageInfo(image_info);
|
||
return(nexus);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X P a n I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XPanImage() pans the image until the mouse button is released.
|
||
%
|
||
% The format of the XPanImage method is:
|
||
%
|
||
% void XPanImage(Display *display,XWindows *windows,XEvent *event)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o event: Specifies a pointer to a XEvent structure. If it is NULL,
|
||
% the entire image is refreshed.
|
||
%
|
||
*/
|
||
static void XPanImage(Display *display,XWindows *windows,XEvent *event)
|
||
{
|
||
char
|
||
text[MaxTextExtent];
|
||
|
||
Cursor
|
||
cursor;
|
||
|
||
MagickRealType
|
||
x_factor,
|
||
y_factor;
|
||
|
||
RectangleInfo
|
||
pan_info;
|
||
|
||
size_t
|
||
state;
|
||
|
||
/*
|
||
Define cursor.
|
||
*/
|
||
if ((windows->image.ximage->width > (int) windows->image.width) &&
|
||
(windows->image.ximage->height > (int) windows->image.height))
|
||
cursor=XCreateFontCursor(display,XC_fleur);
|
||
else
|
||
if (windows->image.ximage->width > (int) windows->image.width)
|
||
cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
|
||
else
|
||
if (windows->image.ximage->height > (int) windows->image.height)
|
||
cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
|
||
else
|
||
cursor=XCreateFontCursor(display,XC_arrow);
|
||
(void) XCheckDefineCursor(display,windows->pan.id,cursor);
|
||
/*
|
||
Pan image as pointer moves until the mouse button is released.
|
||
*/
|
||
x_factor=(MagickRealType) windows->image.ximage->width/windows->pan.width;
|
||
y_factor=(MagickRealType) windows->image.ximage->height/windows->pan.height;
|
||
pan_info.width=windows->pan.width*windows->image.width/
|
||
windows->image.ximage->width;
|
||
pan_info.height=windows->pan.height*windows->image.height/
|
||
windows->image.ximage->height;
|
||
pan_info.x=0;
|
||
pan_info.y=0;
|
||
state=UpdateConfigurationState;
|
||
do
|
||
{
|
||
switch (event->type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
/*
|
||
User choose an initial pan location.
|
||
*/
|
||
pan_info.x=(ssize_t) event->xbutton.x;
|
||
pan_info.y=(ssize_t) event->xbutton.y;
|
||
state|=UpdateConfigurationState;
|
||
break;
|
||
}
|
||
case ButtonRelease:
|
||
{
|
||
/*
|
||
User has finished panning the image.
|
||
*/
|
||
pan_info.x=(ssize_t) event->xbutton.x;
|
||
pan_info.y=(ssize_t) event->xbutton.y;
|
||
state|=UpdateConfigurationState | ExitState;
|
||
break;
|
||
}
|
||
case MotionNotify:
|
||
{
|
||
pan_info.x=(ssize_t) event->xmotion.x;
|
||
pan_info.y=(ssize_t) event->xmotion.y;
|
||
state|=UpdateConfigurationState;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
if ((state & UpdateConfigurationState) != 0)
|
||
{
|
||
/*
|
||
Check boundary conditions.
|
||
*/
|
||
if (pan_info.x < (ssize_t) (pan_info.width/2))
|
||
pan_info.x=0;
|
||
else
|
||
pan_info.x=(ssize_t) (x_factor*(pan_info.x-(pan_info.width/2)));
|
||
if (pan_info.x < 0)
|
||
pan_info.x=0;
|
||
else
|
||
if ((int) (pan_info.x+windows->image.width) >
|
||
windows->image.ximage->width)
|
||
pan_info.x=(ssize_t)
|
||
(windows->image.ximage->width-windows->image.width);
|
||
if (pan_info.y < (ssize_t) (pan_info.height/2))
|
||
pan_info.y=0;
|
||
else
|
||
pan_info.y=(ssize_t) (y_factor*(pan_info.y-(pan_info.height/2)));
|
||
if (pan_info.y < 0)
|
||
pan_info.y=0;
|
||
else
|
||
if ((int) (pan_info.y+windows->image.height) >
|
||
windows->image.ximage->height)
|
||
pan_info.y=(ssize_t)
|
||
(windows->image.ximage->height-windows->image.height);
|
||
if ((windows->image.x != (int) pan_info.x) ||
|
||
(windows->image.y != (int) pan_info.y))
|
||
{
|
||
/*
|
||
Display image pan offset.
|
||
*/
|
||
windows->image.x=(int) pan_info.x;
|
||
windows->image.y=(int) pan_info.y;
|
||
(void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
|
||
windows->image.width,windows->image.height,windows->image.x,
|
||
windows->image.y);
|
||
XInfoWidget(display,windows,text);
|
||
/*
|
||
Refresh Image window.
|
||
*/
|
||
XDrawPanRectangle(display,windows);
|
||
XRefreshWindow(display,&windows->image,(XEvent *) NULL);
|
||
}
|
||
state&=(~UpdateConfigurationState);
|
||
}
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
if ((state & ExitState) == 0)
|
||
XScreenEvent(display,windows,event);
|
||
} while ((state & ExitState) == 0);
|
||
/*
|
||
Restore cursor.
|
||
*/
|
||
(void) XCheckDefineCursor(display,windows->pan.id,windows->pan.cursor);
|
||
(void) XFreeCursor(display,cursor);
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X P a s t e I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XPasteImage() pastes an image previously saved with XCropImage in the X
|
||
% window image at a location the user chooses with the pointer.
|
||
%
|
||
% The format of the XPasteImage method is:
|
||
%
|
||
% MagickBooleanType XPasteImage(Display *display,
|
||
% XResourceInfo *resource_info,XWindows *windows,Image *image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image; returned from ReadImage.
|
||
%
|
||
*/
|
||
static MagickBooleanType XPasteImage(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows,Image *image)
|
||
{
|
||
static const char
|
||
*PasteMenu[] =
|
||
{
|
||
"Operator",
|
||
"Help",
|
||
"Dismiss",
|
||
(char *) NULL
|
||
};
|
||
|
||
static const ModeType
|
||
PasteCommands[] =
|
||
{
|
||
PasteOperatorsCommand,
|
||
PasteHelpCommand,
|
||
PasteDismissCommand
|
||
};
|
||
|
||
static CompositeOperator
|
||
compose = CopyCompositeOp;
|
||
|
||
char
|
||
text[MaxTextExtent];
|
||
|
||
Cursor
|
||
cursor;
|
||
|
||
Image
|
||
*paste_image;
|
||
|
||
int
|
||
entry,
|
||
id,
|
||
x,
|
||
y;
|
||
|
||
MagickRealType
|
||
scale_factor;
|
||
|
||
RectangleInfo
|
||
highlight_info,
|
||
paste_info;
|
||
|
||
unsigned int
|
||
height,
|
||
width;
|
||
|
||
size_t
|
||
state;
|
||
|
||
XEvent
|
||
event;
|
||
|
||
/*
|
||
Copy image.
|
||
*/
|
||
if (resource_info->copy_image == (Image *) NULL)
|
||
return(MagickFalse);
|
||
paste_image=CloneImage(resource_info->copy_image,0,0,MagickTrue,
|
||
&image->exception);
|
||
/*
|
||
Map Command widget.
|
||
*/
|
||
(void) CloneString(&windows->command.name,"Paste");
|
||
windows->command.data=1;
|
||
(void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
|
||
(void) XMapRaised(display,windows->command.id);
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_update_widget,CurrentTime);
|
||
/*
|
||
Track pointer until button 1 is pressed.
|
||
*/
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
XQueryPosition(display,windows->image.id,&x,&y);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask | PointerMotionMask);
|
||
paste_info.x=(ssize_t) windows->image.x+x;
|
||
paste_info.y=(ssize_t) windows->image.y+y;
|
||
paste_info.width=0;
|
||
paste_info.height=0;
|
||
cursor=XCreateFontCursor(display,XC_ul_angle);
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXinvert);
|
||
state=DefaultState;
|
||
do
|
||
{
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
/*
|
||
Display pointer position.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
|
||
(long) paste_info.x,(long) paste_info.y);
|
||
XInfoWidget(display,windows,text);
|
||
}
|
||
highlight_info=paste_info;
|
||
highlight_info.x=paste_info.x-windows->image.x;
|
||
highlight_info.y=paste_info.y-windows->image.y;
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&highlight_info);
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,&event);
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&highlight_info);
|
||
if (event.xany.window == windows->command.id)
|
||
{
|
||
/*
|
||
Select a command from the Command widget.
|
||
*/
|
||
id=XCommandWidget(display,windows,PasteMenu,&event);
|
||
if (id < 0)
|
||
continue;
|
||
switch (PasteCommands[id])
|
||
{
|
||
case PasteOperatorsCommand:
|
||
{
|
||
char
|
||
command[MaxTextExtent],
|
||
**operators;
|
||
|
||
/*
|
||
Select a command from the pop-up menu.
|
||
*/
|
||
operators=GetCommandOptions(MagickComposeOptions);
|
||
if (operators == (char **) NULL)
|
||
break;
|
||
entry=XMenuWidget(display,windows,PasteMenu[id],
|
||
(const char **) operators,command);
|
||
if (entry >= 0)
|
||
compose=(CompositeOperator) ParseCommandOption(
|
||
MagickComposeOptions,MagickFalse,operators[entry]);
|
||
operators=DestroyStringList(operators);
|
||
break;
|
||
}
|
||
case PasteHelpCommand:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Composite",ImagePasteHelp);
|
||
break;
|
||
}
|
||
case PasteDismissCommand:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
continue;
|
||
}
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
if (image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
|
||
event.xbutton.button,event.xbutton.x,event.xbutton.y);
|
||
if (event.xbutton.button != Button1)
|
||
break;
|
||
if (event.xbutton.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Paste rectangle is relative to image configuration.
|
||
*/
|
||
width=(unsigned int) image->columns;
|
||
height=(unsigned int) image->rows;
|
||
x=0;
|
||
y=0;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,
|
||
&width,&height);
|
||
scale_factor=(MagickRealType) windows->image.ximage->width/width;
|
||
paste_info.width=(unsigned int) (scale_factor*paste_image->columns+0.5);
|
||
scale_factor=(MagickRealType) windows->image.ximage->height/height;
|
||
paste_info.height=(unsigned int) (scale_factor*paste_image->rows+0.5);
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
|
||
paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
|
||
break;
|
||
}
|
||
case ButtonRelease:
|
||
{
|
||
if (image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
|
||
event.xbutton.button,event.xbutton.x,event.xbutton.y);
|
||
if (event.xbutton.button != Button1)
|
||
break;
|
||
if (event.xbutton.window != windows->image.id)
|
||
break;
|
||
if ((paste_info.width != 0) && (paste_info.height != 0))
|
||
{
|
||
/*
|
||
User has selected the location of the paste image.
|
||
*/
|
||
paste_info.x=(ssize_t) windows->image.x+event.xbutton.x;
|
||
paste_info.y=(ssize_t) windows->image.y+event.xbutton.y;
|
||
state|=ExitState;
|
||
}
|
||
break;
|
||
}
|
||
case Expose:
|
||
break;
|
||
case KeyPress:
|
||
{
|
||
char
|
||
command[MaxTextExtent];
|
||
|
||
KeySym
|
||
key_symbol;
|
||
|
||
int
|
||
length;
|
||
|
||
if (event.xkey.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Respond to a user key press.
|
||
*/
|
||
length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
*(command+length)='\0';
|
||
if (image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Key press: 0x%lx (%s)",(long) key_symbol,command);
|
||
switch ((int) key_symbol)
|
||
{
|
||
case XK_Escape:
|
||
case XK_F20:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
paste_image=DestroyImage(paste_image);
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case XK_F1:
|
||
case XK_Help:
|
||
{
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXcopy);
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Composite",ImagePasteHelp);
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXinvert);
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
(void) XBell(display,0);
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case MotionNotify:
|
||
{
|
||
/*
|
||
Map and unmap Info widget as text cursor crosses its boundaries.
|
||
*/
|
||
x=event.xmotion.x;
|
||
y=event.xmotion.y;
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
if ((x < (int) (windows->info.x+windows->info.width)) &&
|
||
(y < (int) (windows->info.y+windows->info.height)))
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
}
|
||
else
|
||
if ((x > (int) (windows->info.x+windows->info.width)) ||
|
||
(y > (int) (windows->info.y+windows->info.height)))
|
||
(void) XMapWindow(display,windows->info.id);
|
||
paste_info.x=(ssize_t) windows->image.x+x;
|
||
paste_info.y=(ssize_t) windows->image.y+y;
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
if (image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
|
||
event.type);
|
||
break;
|
||
}
|
||
}
|
||
} while ((state & ExitState) == 0);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask);
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXcopy);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
(void) XFreeCursor(display,cursor);
|
||
if ((state & EscapeState) != 0)
|
||
return(MagickTrue);
|
||
/*
|
||
Image pasting is relative to image configuration.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
width=(unsigned int) image->columns;
|
||
height=(unsigned int) image->rows;
|
||
x=0;
|
||
y=0;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
|
||
scale_factor=(MagickRealType) width/windows->image.ximage->width;
|
||
paste_info.x+=x;
|
||
paste_info.x=(ssize_t) (scale_factor*paste_info.x+0.5);
|
||
paste_info.width=(unsigned int) (scale_factor*paste_info.width+0.5);
|
||
scale_factor=(MagickRealType) height/windows->image.ximage->height;
|
||
paste_info.y+=y;
|
||
paste_info.y=(ssize_t) (scale_factor*paste_info.y*scale_factor+0.5);
|
||
paste_info.height=(unsigned int) (scale_factor*paste_info.height+0.5);
|
||
/*
|
||
Paste image with X Image window.
|
||
*/
|
||
(void) CompositeImage(image,compose,paste_image,paste_info.x,paste_info.y);
|
||
paste_image=DestroyImage(paste_image);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
/*
|
||
Update image colormap.
|
||
*/
|
||
XConfigureImageColormap(display,resource_info,windows,image);
|
||
(void) XConfigureImage(display,resource_info,windows,image);
|
||
return(MagickTrue);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X P r i n t I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XPrintImage() prints an image to a Postscript printer.
|
||
%
|
||
% The format of the XPrintImage method is:
|
||
%
|
||
% MagickBooleanType XPrintImage(Display *display,
|
||
% XResourceInfo *resource_info,XWindows *windows,Image *image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image.
|
||
%
|
||
*/
|
||
static MagickBooleanType XPrintImage(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows,Image *image)
|
||
{
|
||
char
|
||
filename[MaxTextExtent],
|
||
geometry[MaxTextExtent];
|
||
|
||
Image
|
||
*print_image;
|
||
|
||
ImageInfo
|
||
*image_info;
|
||
|
||
MagickStatusType
|
||
status;
|
||
|
||
/*
|
||
Request Postscript page geometry from user.
|
||
*/
|
||
image_info=CloneImageInfo(resource_info->image_info);
|
||
(void) FormatLocaleString(geometry,MaxTextExtent,"Letter");
|
||
if (image_info->page != (char *) NULL)
|
||
(void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
|
||
XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
|
||
"Select Postscript Page Geometry:",geometry);
|
||
if (*geometry == '\0')
|
||
return(MagickTrue);
|
||
image_info->page=GetPageGeometry(geometry);
|
||
/*
|
||
Apply image transforms.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
print_image=CloneImage(image,0,0,MagickTrue,&image->exception);
|
||
if (print_image == (Image *) NULL)
|
||
return(MagickFalse);
|
||
(void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
|
||
windows->image.ximage->width,windows->image.ximage->height);
|
||
(void) TransformImage(&print_image,windows->image.crop_geometry,geometry);
|
||
/*
|
||
Print image.
|
||
*/
|
||
(void) AcquireUniqueFilename(filename);
|
||
(void) FormatLocaleString(print_image->filename,MaxTextExtent,"print:%s",
|
||
filename);
|
||
status=WriteImage(image_info,print_image);
|
||
(void) RelinquishUniqueFileResource(filename);
|
||
print_image=DestroyImage(print_image);
|
||
image_info=DestroyImageInfo(image_info);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
return(status != 0 ? MagickTrue : MagickFalse);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X R O I I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XROIImage() applies an image processing technique to a region of interest.
|
||
%
|
||
% The format of the XROIImage method is:
|
||
%
|
||
% MagickBooleanType XROIImage(Display *display,
|
||
% XResourceInfo *resource_info,XWindows *windows,Image **image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image; returned from ReadImage.
|
||
%
|
||
*/
|
||
static MagickBooleanType XROIImage(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows,Image **image)
|
||
{
|
||
#define ApplyMenus 7
|
||
|
||
static const char
|
||
*ROIMenu[] =
|
||
{
|
||
"Help",
|
||
"Dismiss",
|
||
(char *) NULL
|
||
},
|
||
*ApplyMenu[] =
|
||
{
|
||
"File",
|
||
"Edit",
|
||
"Transform",
|
||
"Enhance",
|
||
"Effects",
|
||
"F/X",
|
||
"Miscellany",
|
||
"Help",
|
||
"Dismiss",
|
||
(char *) NULL
|
||
},
|
||
*FileMenu[] =
|
||
{
|
||
"Save...",
|
||
"Print...",
|
||
(char *) NULL
|
||
},
|
||
*EditMenu[] =
|
||
{
|
||
"Undo",
|
||
"Redo",
|
||
(char *) NULL
|
||
},
|
||
*TransformMenu[] =
|
||
{
|
||
"Flop",
|
||
"Flip",
|
||
"Rotate Right",
|
||
"Rotate Left",
|
||
(char *) NULL
|
||
},
|
||
*EnhanceMenu[] =
|
||
{
|
||
"Hue...",
|
||
"Saturation...",
|
||
"Brightness...",
|
||
"Gamma...",
|
||
"Spiff",
|
||
"Dull",
|
||
"Contrast Stretch...",
|
||
"Sigmoidal Contrast...",
|
||
"Normalize",
|
||
"Equalize",
|
||
"Negate",
|
||
"Grayscale",
|
||
"Map...",
|
||
"Quantize...",
|
||
(char *) NULL
|
||
},
|
||
*EffectsMenu[] =
|
||
{
|
||
"Despeckle",
|
||
"Emboss",
|
||
"Reduce Noise",
|
||
"Add Noise",
|
||
"Sharpen...",
|
||
"Blur...",
|
||
"Threshold...",
|
||
"Edge Detect...",
|
||
"Spread...",
|
||
"Shade...",
|
||
"Raise...",
|
||
"Segment...",
|
||
(char *) NULL
|
||
},
|
||
*FXMenu[] =
|
||
{
|
||
"Solarize...",
|
||
"Sepia Tone...",
|
||
"Swirl...",
|
||
"Implode...",
|
||
"Vignette...",
|
||
"Wave...",
|
||
"Oil Paint...",
|
||
"Charcoal Draw...",
|
||
(char *) NULL
|
||
},
|
||
*MiscellanyMenu[] =
|
||
{
|
||
"Image Info",
|
||
"Zoom Image",
|
||
"Show Preview...",
|
||
"Show Histogram",
|
||
"Show Matte",
|
||
(char *) NULL
|
||
};
|
||
|
||
static const char
|
||
**Menus[ApplyMenus] =
|
||
{
|
||
FileMenu,
|
||
EditMenu,
|
||
TransformMenu,
|
||
EnhanceMenu,
|
||
EffectsMenu,
|
||
FXMenu,
|
||
MiscellanyMenu
|
||
};
|
||
|
||
static const CommandType
|
||
ApplyCommands[] =
|
||
{
|
||
NullCommand,
|
||
NullCommand,
|
||
NullCommand,
|
||
NullCommand,
|
||
NullCommand,
|
||
NullCommand,
|
||
NullCommand,
|
||
HelpCommand,
|
||
QuitCommand
|
||
},
|
||
FileCommands[] =
|
||
{
|
||
SaveCommand,
|
||
PrintCommand
|
||
},
|
||
EditCommands[] =
|
||
{
|
||
UndoCommand,
|
||
RedoCommand
|
||
},
|
||
TransformCommands[] =
|
||
{
|
||
FlopCommand,
|
||
FlipCommand,
|
||
RotateRightCommand,
|
||
RotateLeftCommand
|
||
},
|
||
EnhanceCommands[] =
|
||
{
|
||
HueCommand,
|
||
SaturationCommand,
|
||
BrightnessCommand,
|
||
GammaCommand,
|
||
SpiffCommand,
|
||
DullCommand,
|
||
ContrastStretchCommand,
|
||
SigmoidalContrastCommand,
|
||
NormalizeCommand,
|
||
EqualizeCommand,
|
||
NegateCommand,
|
||
GrayscaleCommand,
|
||
MapCommand,
|
||
QuantizeCommand
|
||
},
|
||
EffectsCommands[] =
|
||
{
|
||
DespeckleCommand,
|
||
EmbossCommand,
|
||
ReduceNoiseCommand,
|
||
AddNoiseCommand,
|
||
SharpenCommand,
|
||
BlurCommand,
|
||
EdgeDetectCommand,
|
||
SpreadCommand,
|
||
ShadeCommand,
|
||
RaiseCommand,
|
||
SegmentCommand
|
||
},
|
||
FXCommands[] =
|
||
{
|
||
SolarizeCommand,
|
||
SepiaToneCommand,
|
||
SwirlCommand,
|
||
ImplodeCommand,
|
||
VignetteCommand,
|
||
WaveCommand,
|
||
OilPaintCommand,
|
||
CharcoalDrawCommand
|
||
},
|
||
MiscellanyCommands[] =
|
||
{
|
||
InfoCommand,
|
||
ZoomCommand,
|
||
ShowPreviewCommand,
|
||
ShowHistogramCommand,
|
||
ShowMatteCommand
|
||
},
|
||
ROICommands[] =
|
||
{
|
||
ROIHelpCommand,
|
||
ROIDismissCommand
|
||
};
|
||
|
||
static const CommandType
|
||
*Commands[ApplyMenus] =
|
||
{
|
||
FileCommands,
|
||
EditCommands,
|
||
TransformCommands,
|
||
EnhanceCommands,
|
||
EffectsCommands,
|
||
FXCommands,
|
||
MiscellanyCommands
|
||
};
|
||
|
||
char
|
||
command[MaxTextExtent],
|
||
text[MaxTextExtent];
|
||
|
||
CommandType
|
||
command_type;
|
||
|
||
Cursor
|
||
cursor;
|
||
|
||
Image
|
||
*roi_image;
|
||
|
||
int
|
||
entry,
|
||
id,
|
||
x,
|
||
y;
|
||
|
||
MagickRealType
|
||
scale_factor;
|
||
|
||
MagickProgressMonitor
|
||
progress_monitor;
|
||
|
||
RectangleInfo
|
||
crop_info,
|
||
highlight_info,
|
||
roi_info;
|
||
|
||
unsigned int
|
||
height,
|
||
width;
|
||
|
||
size_t
|
||
state;
|
||
|
||
XEvent
|
||
event;
|
||
|
||
/*
|
||
Map Command widget.
|
||
*/
|
||
(void) CloneString(&windows->command.name,"ROI");
|
||
windows->command.data=0;
|
||
(void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
|
||
(void) XMapRaised(display,windows->command.id);
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_update_widget,CurrentTime);
|
||
/*
|
||
Track pointer until button 1 is pressed.
|
||
*/
|
||
XQueryPosition(display,windows->image.id,&x,&y);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask | PointerMotionMask);
|
||
roi_info.x=(ssize_t) windows->image.x+x;
|
||
roi_info.y=(ssize_t) windows->image.y+y;
|
||
roi_info.width=0;
|
||
roi_info.height=0;
|
||
cursor=XCreateFontCursor(display,XC_fleur);
|
||
state=DefaultState;
|
||
do
|
||
{
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
/*
|
||
Display pointer position.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent," %+ld%+ld ",
|
||
(long) roi_info.x,(long) roi_info.y);
|
||
XInfoWidget(display,windows,text);
|
||
}
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,&event);
|
||
if (event.xany.window == windows->command.id)
|
||
{
|
||
/*
|
||
Select a command from the Command widget.
|
||
*/
|
||
id=XCommandWidget(display,windows,ROIMenu,&event);
|
||
if (id < 0)
|
||
continue;
|
||
switch (ROICommands[id])
|
||
{
|
||
case ROIHelpCommand:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Region of Interest",ImageROIHelp);
|
||
break;
|
||
}
|
||
case ROIDismissCommand:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
continue;
|
||
}
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
if (event.xbutton.button != Button1)
|
||
break;
|
||
if (event.xbutton.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Note first corner of region of interest rectangle-- exit loop.
|
||
*/
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
|
||
roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case ButtonRelease:
|
||
break;
|
||
case Expose:
|
||
break;
|
||
case KeyPress:
|
||
{
|
||
KeySym
|
||
key_symbol;
|
||
|
||
if (event.xkey.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Respond to a user key press.
|
||
*/
|
||
(void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
switch ((int) key_symbol)
|
||
{
|
||
case XK_Escape:
|
||
case XK_F20:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case XK_F1:
|
||
case XK_Help:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Region of Interest",ImageROIHelp);
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
(void) XBell(display,0);
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case MotionNotify:
|
||
{
|
||
/*
|
||
Map and unmap Info widget as text cursor crosses its boundaries.
|
||
*/
|
||
x=event.xmotion.x;
|
||
y=event.xmotion.y;
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
if ((x < (int) (windows->info.x+windows->info.width)) &&
|
||
(y < (int) (windows->info.y+windows->info.height)))
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
}
|
||
else
|
||
if ((x > (int) (windows->info.x+windows->info.width)) ||
|
||
(y > (int) (windows->info.y+windows->info.height)))
|
||
(void) XMapWindow(display,windows->info.id);
|
||
roi_info.x=(ssize_t) windows->image.x+x;
|
||
roi_info.y=(ssize_t) windows->image.y+y;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
} while ((state & ExitState) == 0);
|
||
(void) XSelectInput(display,windows->image.id,
|
||
windows->image.attributes.event_mask);
|
||
if ((state & EscapeState) != 0)
|
||
{
|
||
/*
|
||
User want to exit without region of interest.
|
||
*/
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
(void) XFreeCursor(display,cursor);
|
||
return(MagickTrue);
|
||
}
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXinvert);
|
||
do
|
||
{
|
||
/*
|
||
Size rectangle as pointer moves until the mouse button is released.
|
||
*/
|
||
x=(int) roi_info.x;
|
||
y=(int) roi_info.y;
|
||
roi_info.width=0;
|
||
roi_info.height=0;
|
||
state=DefaultState;
|
||
do
|
||
{
|
||
highlight_info=roi_info;
|
||
highlight_info.x=roi_info.x-windows->image.x;
|
||
highlight_info.y=roi_info.y-windows->image.y;
|
||
if ((highlight_info.width > 3) && (highlight_info.height > 3))
|
||
{
|
||
/*
|
||
Display info and draw region of interest rectangle.
|
||
*/
|
||
if (windows->info.mapped == MagickFalse)
|
||
(void) XMapWindow(display,windows->info.id);
|
||
(void) FormatLocaleString(text,MaxTextExtent,
|
||
" %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
|
||
roi_info.height,(double) roi_info.x,(double) roi_info.y);
|
||
XInfoWidget(display,windows,text);
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&highlight_info);
|
||
}
|
||
else
|
||
if (windows->info.mapped != MagickFalse)
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,&event);
|
||
if ((highlight_info.width > 3) && (highlight_info.height > 3))
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&highlight_info);
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
|
||
roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
|
||
break;
|
||
}
|
||
case ButtonRelease:
|
||
{
|
||
/*
|
||
User has committed to region of interest rectangle.
|
||
*/
|
||
roi_info.x=(ssize_t) windows->image.x+event.xbutton.x;
|
||
roi_info.y=(ssize_t) windows->image.y+event.xbutton.y;
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
state|=ExitState;
|
||
if (LocaleCompare(windows->command.name,"Apply") == 0)
|
||
break;
|
||
(void) CloneString(&windows->command.name,"Apply");
|
||
windows->command.data=ApplyMenus;
|
||
(void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
|
||
break;
|
||
}
|
||
case Expose:
|
||
break;
|
||
case MotionNotify:
|
||
{
|
||
roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
|
||
roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
if ((((int) roi_info.x != x) && ((int) roi_info.y != y)) ||
|
||
((state & ExitState) != 0))
|
||
{
|
||
/*
|
||
Check boundary conditions.
|
||
*/
|
||
if (roi_info.x < 0)
|
||
roi_info.x=0;
|
||
else
|
||
if (roi_info.x > (ssize_t) windows->image.ximage->width)
|
||
roi_info.x=(ssize_t) windows->image.ximage->width;
|
||
if ((int) roi_info.x < x)
|
||
roi_info.width=(unsigned int) (x-roi_info.x);
|
||
else
|
||
{
|
||
roi_info.width=(unsigned int) (roi_info.x-x);
|
||
roi_info.x=(ssize_t) x;
|
||
}
|
||
if (roi_info.y < 0)
|
||
roi_info.y=0;
|
||
else
|
||
if (roi_info.y > (ssize_t) windows->image.ximage->height)
|
||
roi_info.y=(ssize_t) windows->image.ximage->height;
|
||
if ((int) roi_info.y < y)
|
||
roi_info.height=(unsigned int) (y-roi_info.y);
|
||
else
|
||
{
|
||
roi_info.height=(unsigned int) (roi_info.y-y);
|
||
roi_info.y=(ssize_t) y;
|
||
}
|
||
}
|
||
} while ((state & ExitState) == 0);
|
||
/*
|
||
Wait for user to grab a corner of the rectangle or press return.
|
||
*/
|
||
state=DefaultState;
|
||
command_type=NullCommand;
|
||
(void) XMapWindow(display,windows->info.id);
|
||
do
|
||
{
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
/*
|
||
Display pointer position.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent,
|
||
" %.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
|
||
roi_info.height,(double) roi_info.x,(double) roi_info.y);
|
||
XInfoWidget(display,windows,text);
|
||
}
|
||
highlight_info=roi_info;
|
||
highlight_info.x=roi_info.x-windows->image.x;
|
||
highlight_info.y=roi_info.y-windows->image.y;
|
||
if ((highlight_info.width <= 3) || (highlight_info.height <= 3))
|
||
{
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
if ((state & UpdateRegionState) != 0)
|
||
{
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXcopy);
|
||
switch (command_type)
|
||
{
|
||
case UndoCommand:
|
||
case RedoCommand:
|
||
{
|
||
(void) XMagickCommand(display,resource_info,windows,command_type,
|
||
image);
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
/*
|
||
Region of interest is relative to image configuration.
|
||
*/
|
||
progress_monitor=SetImageProgressMonitor(*image,
|
||
(MagickProgressMonitor) NULL,(*image)->client_data);
|
||
crop_info=roi_info;
|
||
width=(unsigned int) (*image)->columns;
|
||
height=(unsigned int) (*image)->rows;
|
||
x=0;
|
||
y=0;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,
|
||
&width,&height);
|
||
scale_factor=(MagickRealType) width/windows->image.ximage->width;
|
||
crop_info.x+=x;
|
||
crop_info.x=(ssize_t) (scale_factor*crop_info.x+0.5);
|
||
crop_info.width=(unsigned int) (scale_factor*crop_info.width+0.5);
|
||
scale_factor=(MagickRealType)
|
||
height/windows->image.ximage->height;
|
||
crop_info.y+=y;
|
||
crop_info.y=(ssize_t) (scale_factor*crop_info.y+0.5);
|
||
crop_info.height=(unsigned int)
|
||
(scale_factor*crop_info.height+0.5);
|
||
roi_image=CropImage(*image,&crop_info,&(*image)->exception);
|
||
(void) SetImageProgressMonitor(*image,progress_monitor,
|
||
(*image)->client_data);
|
||
if (roi_image == (Image *) NULL)
|
||
continue;
|
||
/*
|
||
Apply image processing technique to the region of interest.
|
||
*/
|
||
windows->image.orphan=MagickTrue;
|
||
(void) XMagickCommand(display,resource_info,windows,command_type,
|
||
&roi_image);
|
||
progress_monitor=SetImageProgressMonitor(*image,
|
||
(MagickProgressMonitor) NULL,(*image)->client_data);
|
||
(void) XMagickCommand(display,resource_info,windows,
|
||
SaveToUndoBufferCommand,image);
|
||
windows->image.orphan=MagickFalse;
|
||
(void) CompositeImage(*image,CopyCompositeOp,roi_image,
|
||
crop_info.x,crop_info.y);
|
||
roi_image=DestroyImage(roi_image);
|
||
(void) SetImageProgressMonitor(*image,progress_monitor,
|
||
(*image)->client_data);
|
||
break;
|
||
}
|
||
}
|
||
if (command_type != InfoCommand)
|
||
{
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
}
|
||
XCheckRefreshWindows(display,windows);
|
||
XInfoWidget(display,windows,text);
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXinvert);
|
||
state&=(~UpdateRegionState);
|
||
}
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&highlight_info);
|
||
XScreenEvent(display,windows,&event);
|
||
if (event.xany.window == windows->command.id)
|
||
{
|
||
/*
|
||
Select a command from the Command widget.
|
||
*/
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXcopy);
|
||
command_type=NullCommand;
|
||
id=XCommandWidget(display,windows,ApplyMenu,&event);
|
||
if (id >= 0)
|
||
{
|
||
(void) CopyMagickString(command,ApplyMenu[id],MaxTextExtent);
|
||
command_type=ApplyCommands[id];
|
||
if (id < ApplyMenus)
|
||
{
|
||
/*
|
||
Select a command from a pop-up menu.
|
||
*/
|
||
entry=XMenuWidget(display,windows,ApplyMenu[id],
|
||
(const char **) Menus[id],command);
|
||
if (entry >= 0)
|
||
{
|
||
(void) CopyMagickString(command,Menus[id][entry],
|
||
MaxTextExtent);
|
||
command_type=Commands[id][entry];
|
||
}
|
||
}
|
||
}
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXinvert);
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&highlight_info);
|
||
if (command_type == HelpCommand)
|
||
{
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXcopy);
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Region of Interest",ImageROIHelp);
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXinvert);
|
||
continue;
|
||
}
|
||
if (command_type == QuitCommand)
|
||
{
|
||
/*
|
||
exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
continue;
|
||
}
|
||
if (command_type != NullCommand)
|
||
state|=UpdateRegionState;
|
||
continue;
|
||
}
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&highlight_info);
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
x=windows->image.x;
|
||
y=windows->image.y;
|
||
if (event.xbutton.button != Button1)
|
||
break;
|
||
if (event.xbutton.window != windows->image.id)
|
||
break;
|
||
x=windows->image.x+event.xbutton.x;
|
||
y=windows->image.y+event.xbutton.y;
|
||
if ((x < (int) (roi_info.x+RoiDelta)) &&
|
||
(x > (int) (roi_info.x-RoiDelta)) &&
|
||
(y < (int) (roi_info.y+RoiDelta)) &&
|
||
(y > (int) (roi_info.y-RoiDelta)))
|
||
{
|
||
roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
|
||
roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
|
||
state|=UpdateConfigurationState;
|
||
break;
|
||
}
|
||
if ((x < (int) (roi_info.x+RoiDelta)) &&
|
||
(x > (int) (roi_info.x-RoiDelta)) &&
|
||
(y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
|
||
(y > (int) (roi_info.y+roi_info.height-RoiDelta)))
|
||
{
|
||
roi_info.x=(ssize_t) (roi_info.x+roi_info.width);
|
||
state|=UpdateConfigurationState;
|
||
break;
|
||
}
|
||
if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
|
||
(x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
|
||
(y < (int) (roi_info.y+RoiDelta)) &&
|
||
(y > (int) (roi_info.y-RoiDelta)))
|
||
{
|
||
roi_info.y=(ssize_t) (roi_info.y+roi_info.height);
|
||
state|=UpdateConfigurationState;
|
||
break;
|
||
}
|
||
if ((x < (int) (roi_info.x+roi_info.width+RoiDelta)) &&
|
||
(x > (int) (roi_info.x+roi_info.width-RoiDelta)) &&
|
||
(y < (int) (roi_info.y+roi_info.height+RoiDelta)) &&
|
||
(y > (int) (roi_info.y+roi_info.height-RoiDelta)))
|
||
{
|
||
state|=UpdateConfigurationState;
|
||
break;
|
||
}
|
||
}
|
||
case ButtonRelease:
|
||
{
|
||
if (event.xbutton.window == windows->pan.id)
|
||
if ((highlight_info.x != crop_info.x-windows->image.x) ||
|
||
(highlight_info.y != crop_info.y-windows->image.y))
|
||
XHighlightRectangle(display,windows->image.id,
|
||
windows->image.highlight_context,&highlight_info);
|
||
(void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
|
||
event.xbutton.time);
|
||
break;
|
||
}
|
||
case Expose:
|
||
{
|
||
if (event.xexpose.window == windows->image.id)
|
||
if (event.xexpose.count == 0)
|
||
{
|
||
event.xexpose.x=(int) highlight_info.x;
|
||
event.xexpose.y=(int) highlight_info.y;
|
||
event.xexpose.width=(int) highlight_info.width;
|
||
event.xexpose.height=(int) highlight_info.height;
|
||
XRefreshWindow(display,&windows->image,&event);
|
||
}
|
||
if (event.xexpose.window == windows->info.id)
|
||
if (event.xexpose.count == 0)
|
||
XInfoWidget(display,windows,text);
|
||
break;
|
||
}
|
||
case KeyPress:
|
||
{
|
||
KeySym
|
||
key_symbol;
|
||
|
||
if (event.xkey.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Respond to a user key press.
|
||
*/
|
||
(void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
switch ((int) key_symbol)
|
||
{
|
||
case XK_Shift_L:
|
||
case XK_Shift_R:
|
||
break;
|
||
case XK_Escape:
|
||
case XK_F20:
|
||
state|=EscapeState;
|
||
case XK_Return:
|
||
{
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case XK_Home:
|
||
case XK_KP_Home:
|
||
{
|
||
roi_info.x=(ssize_t) (windows->image.width/2L-roi_info.width/2L);
|
||
roi_info.y=(ssize_t) (windows->image.height/2L-
|
||
roi_info.height/2L);
|
||
break;
|
||
}
|
||
case XK_Left:
|
||
case XK_KP_Left:
|
||
{
|
||
roi_info.x--;
|
||
break;
|
||
}
|
||
case XK_Up:
|
||
case XK_KP_Up:
|
||
case XK_Next:
|
||
{
|
||
roi_info.y--;
|
||
break;
|
||
}
|
||
case XK_Right:
|
||
case XK_KP_Right:
|
||
{
|
||
roi_info.x++;
|
||
break;
|
||
}
|
||
case XK_Prior:
|
||
case XK_Down:
|
||
case XK_KP_Down:
|
||
{
|
||
roi_info.y++;
|
||
break;
|
||
}
|
||
case XK_F1:
|
||
case XK_Help:
|
||
{
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXcopy);
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Region of Interest",ImageROIHelp);
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXinvert);
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
command_type=XImageWindowCommand(display,resource_info,windows,
|
||
event.xkey.state,key_symbol,image);
|
||
if (command_type != NullCommand)
|
||
state|=UpdateRegionState;
|
||
break;
|
||
}
|
||
}
|
||
(void) XSetSelectionOwner(display,XA_PRIMARY,windows->image.id,
|
||
event.xkey.time);
|
||
break;
|
||
}
|
||
case KeyRelease:
|
||
break;
|
||
case MotionNotify:
|
||
{
|
||
if (event.xbutton.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Map and unmap Info widget as text cursor crosses its boundaries.
|
||
*/
|
||
x=event.xmotion.x;
|
||
y=event.xmotion.y;
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
if ((x < (int) (windows->info.x+windows->info.width)) &&
|
||
(y < (int) (windows->info.y+windows->info.height)))
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
}
|
||
else
|
||
if ((x > (int) (windows->info.x+windows->info.width)) ||
|
||
(y > (int) (windows->info.y+windows->info.height)))
|
||
(void) XMapWindow(display,windows->info.id);
|
||
roi_info.x=(ssize_t) windows->image.x+event.xmotion.x;
|
||
roi_info.y=(ssize_t) windows->image.y+event.xmotion.y;
|
||
break;
|
||
}
|
||
case SelectionRequest:
|
||
{
|
||
XSelectionEvent
|
||
notify;
|
||
|
||
XSelectionRequestEvent
|
||
*request;
|
||
|
||
/*
|
||
Set primary selection.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent,
|
||
"%.20gx%.20g%+.20g%+.20g",(double) roi_info.width,(double)
|
||
roi_info.height,(double) roi_info.x,(double) roi_info.y);
|
||
request=(&(event.xselectionrequest));
|
||
(void) XChangeProperty(request->display,request->requestor,
|
||
request->property,request->target,8,PropModeReplace,
|
||
(unsigned char *) text,(int) strlen(text));
|
||
notify.type=SelectionNotify;
|
||
notify.display=request->display;
|
||
notify.requestor=request->requestor;
|
||
notify.selection=request->selection;
|
||
notify.target=request->target;
|
||
notify.time=request->time;
|
||
if (request->property == None)
|
||
notify.property=request->target;
|
||
else
|
||
notify.property=request->property;
|
||
(void) XSendEvent(request->display,request->requestor,False,0,
|
||
(XEvent *) ¬ify);
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
if ((state & UpdateConfigurationState) != 0)
|
||
{
|
||
(void) XPutBackEvent(display,&event);
|
||
(void) XCheckDefineCursor(display,windows->image.id,cursor);
|
||
break;
|
||
}
|
||
} while ((state & ExitState) == 0);
|
||
} while ((state & ExitState) == 0);
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXcopy);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if ((state & EscapeState) != 0)
|
||
return(MagickTrue);
|
||
return(MagickTrue);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X R o t a t e I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XRotateImage() rotates the X image. If the degrees parameter if zero, the
|
||
% rotation angle is computed from the slope of a line drawn by the user.
|
||
%
|
||
% The format of the XRotateImage method is:
|
||
%
|
||
% MagickBooleanType XRotateImage(Display *display,
|
||
% XResourceInfo *resource_info,XWindows *windows,double degrees,
|
||
% Image **image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o degrees: Specifies the number of degrees to rotate the image.
|
||
%
|
||
% o image: the image.
|
||
%
|
||
*/
|
||
static MagickBooleanType XRotateImage(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows,double degrees,Image **image)
|
||
{
|
||
static const char
|
||
*RotateMenu[] =
|
||
{
|
||
"Pixel Color",
|
||
"Direction",
|
||
"Help",
|
||
"Dismiss",
|
||
(char *) NULL
|
||
};
|
||
|
||
static ModeType
|
||
direction = HorizontalRotateCommand;
|
||
|
||
static const ModeType
|
||
DirectionCommands[] =
|
||
{
|
||
HorizontalRotateCommand,
|
||
VerticalRotateCommand
|
||
},
|
||
RotateCommands[] =
|
||
{
|
||
RotateColorCommand,
|
||
RotateDirectionCommand,
|
||
RotateHelpCommand,
|
||
RotateDismissCommand
|
||
};
|
||
|
||
static unsigned int
|
||
pen_id = 0;
|
||
|
||
char
|
||
command[MaxTextExtent],
|
||
text[MaxTextExtent];
|
||
|
||
Image
|
||
*rotate_image;
|
||
|
||
int
|
||
id,
|
||
x,
|
||
y;
|
||
|
||
MagickRealType
|
||
normalized_degrees;
|
||
|
||
register int
|
||
i;
|
||
|
||
unsigned int
|
||
height,
|
||
rotations,
|
||
width;
|
||
|
||
if (degrees == 0.0)
|
||
{
|
||
unsigned int
|
||
distance;
|
||
|
||
size_t
|
||
state;
|
||
|
||
XEvent
|
||
event;
|
||
|
||
XSegment
|
||
rotate_info;
|
||
|
||
/*
|
||
Map Command widget.
|
||
*/
|
||
(void) CloneString(&windows->command.name,"Rotate");
|
||
windows->command.data=2;
|
||
(void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
|
||
(void) XMapRaised(display,windows->command.id);
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_update_widget,CurrentTime);
|
||
/*
|
||
Wait for first button press.
|
||
*/
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXinvert);
|
||
XQueryPosition(display,windows->image.id,&x,&y);
|
||
rotate_info.x1=x;
|
||
rotate_info.y1=y;
|
||
rotate_info.x2=x;
|
||
rotate_info.y2=y;
|
||
state=DefaultState;
|
||
do
|
||
{
|
||
XHighlightLine(display,windows->image.id,
|
||
windows->image.highlight_context,&rotate_info);
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,&event);
|
||
XHighlightLine(display,windows->image.id,
|
||
windows->image.highlight_context,&rotate_info);
|
||
if (event.xany.window == windows->command.id)
|
||
{
|
||
/*
|
||
Select a command from the Command widget.
|
||
*/
|
||
id=XCommandWidget(display,windows,RotateMenu,&event);
|
||
if (id < 0)
|
||
continue;
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXcopy);
|
||
switch (RotateCommands[id])
|
||
{
|
||
case RotateColorCommand:
|
||
{
|
||
const char
|
||
*ColorMenu[MaxNumberPens];
|
||
|
||
int
|
||
pen_number;
|
||
|
||
XColor
|
||
color;
|
||
|
||
/*
|
||
Initialize menu selections.
|
||
*/
|
||
for (i=0; i < (int) (MaxNumberPens-2); i++)
|
||
ColorMenu[i]=resource_info->pen_colors[i];
|
||
ColorMenu[MaxNumberPens-2]="Browser...";
|
||
ColorMenu[MaxNumberPens-1]=(const char *) NULL;
|
||
/*
|
||
Select a pen color from the pop-up menu.
|
||
*/
|
||
pen_number=XMenuWidget(display,windows,RotateMenu[id],
|
||
(const char **) ColorMenu,command);
|
||
if (pen_number < 0)
|
||
break;
|
||
if (pen_number == (MaxNumberPens-2))
|
||
{
|
||
static char
|
||
color_name[MaxTextExtent] = "gray";
|
||
|
||
/*
|
||
Select a pen color from a dialog.
|
||
*/
|
||
resource_info->pen_colors[pen_number]=color_name;
|
||
XColorBrowserWidget(display,windows,"Select",color_name);
|
||
if (*color_name == '\0')
|
||
break;
|
||
}
|
||
/*
|
||
Set pen color.
|
||
*/
|
||
(void) XParseColor(display,windows->map_info->colormap,
|
||
resource_info->pen_colors[pen_number],&color);
|
||
XBestPixel(display,windows->map_info->colormap,(XColor *) NULL,
|
||
(unsigned int) MaxColors,&color);
|
||
windows->pixel_info->pen_colors[pen_number]=color;
|
||
pen_id=(unsigned int) pen_number;
|
||
break;
|
||
}
|
||
case RotateDirectionCommand:
|
||
{
|
||
static const char
|
||
*Directions[] =
|
||
{
|
||
"horizontal",
|
||
"vertical",
|
||
(char *) NULL,
|
||
};
|
||
|
||
/*
|
||
Select a command from the pop-up menu.
|
||
*/
|
||
id=XMenuWidget(display,windows,RotateMenu[id],
|
||
Directions,command);
|
||
if (id >= 0)
|
||
direction=DirectionCommands[id];
|
||
break;
|
||
}
|
||
case RotateHelpCommand:
|
||
{
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Rotation",ImageRotateHelp);
|
||
break;
|
||
}
|
||
case RotateDismissCommand:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXinvert);
|
||
continue;
|
||
}
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
if (event.xbutton.button != Button1)
|
||
break;
|
||
if (event.xbutton.window != windows->image.id)
|
||
break;
|
||
/*
|
||
exit loop.
|
||
*/
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXcopy);
|
||
rotate_info.x1=event.xbutton.x;
|
||
rotate_info.y1=event.xbutton.y;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case ButtonRelease:
|
||
break;
|
||
case Expose:
|
||
break;
|
||
case KeyPress:
|
||
{
|
||
char
|
||
command[MaxTextExtent];
|
||
|
||
KeySym
|
||
key_symbol;
|
||
|
||
if (event.xkey.window != windows->image.id)
|
||
break;
|
||
/*
|
||
Respond to a user key press.
|
||
*/
|
||
(void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
switch ((int) key_symbol)
|
||
{
|
||
case XK_Escape:
|
||
case XK_F20:
|
||
{
|
||
/*
|
||
Prematurely exit.
|
||
*/
|
||
state|=EscapeState;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case XK_F1:
|
||
case XK_Help:
|
||
{
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXcopy);
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Rotation",ImageRotateHelp);
|
||
(void) XSetFunction(display,windows->image.highlight_context,
|
||
GXinvert);
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
(void) XBell(display,0);
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case MotionNotify:
|
||
{
|
||
rotate_info.x1=event.xmotion.x;
|
||
rotate_info.y1=event.xmotion.y;
|
||
}
|
||
}
|
||
rotate_info.x2=rotate_info.x1;
|
||
rotate_info.y2=rotate_info.y1;
|
||
if (direction == HorizontalRotateCommand)
|
||
rotate_info.x2+=32;
|
||
else
|
||
rotate_info.y2-=32;
|
||
} while ((state & ExitState) == 0);
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXcopy);
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
if ((state & EscapeState) != 0)
|
||
return(MagickTrue);
|
||
/*
|
||
Draw line as pointer moves until the mouse button is released.
|
||
*/
|
||
distance=0;
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXinvert);
|
||
state=DefaultState;
|
||
do
|
||
{
|
||
if (distance > 9)
|
||
{
|
||
/*
|
||
Display info and draw rotation line.
|
||
*/
|
||
if (windows->info.mapped == MagickFalse)
|
||
(void) XMapWindow(display,windows->info.id);
|
||
(void) FormatLocaleString(text,MaxTextExtent," %g",
|
||
direction == VerticalRotateCommand ? degrees-90.0 : degrees);
|
||
XInfoWidget(display,windows,text);
|
||
XHighlightLine(display,windows->image.id,
|
||
windows->image.highlight_context,&rotate_info);
|
||
}
|
||
else
|
||
if (windows->info.mapped != MagickFalse)
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
/*
|
||
Wait for next event.
|
||
*/
|
||
XScreenEvent(display,windows,&event);
|
||
if (distance > 9)
|
||
XHighlightLine(display,windows->image.id,
|
||
windows->image.highlight_context,&rotate_info);
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
break;
|
||
case ButtonRelease:
|
||
{
|
||
/*
|
||
User has committed to rotation line.
|
||
*/
|
||
rotate_info.x2=event.xbutton.x;
|
||
rotate_info.y2=event.xbutton.y;
|
||
state|=ExitState;
|
||
break;
|
||
}
|
||
case Expose:
|
||
break;
|
||
case MotionNotify:
|
||
{
|
||
rotate_info.x2=event.xmotion.x;
|
||
rotate_info.y2=event.xmotion.y;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
/*
|
||
Check boundary conditions.
|
||
*/
|
||
if (rotate_info.x2 < 0)
|
||
rotate_info.x2=0;
|
||
else
|
||
if (rotate_info.x2 > (int) windows->image.width)
|
||
rotate_info.x2=(short) windows->image.width;
|
||
if (rotate_info.y2 < 0)
|
||
rotate_info.y2=0;
|
||
else
|
||
if (rotate_info.y2 > (int) windows->image.height)
|
||
rotate_info.y2=(short) windows->image.height;
|
||
/*
|
||
Compute rotation angle from the slope of the line.
|
||
*/
|
||
degrees=0.0;
|
||
distance=(unsigned int)
|
||
((rotate_info.x2-rotate_info.x1+1)*(rotate_info.x2-rotate_info.x1+1))+
|
||
((rotate_info.y2-rotate_info.y1+1)*(rotate_info.y2-rotate_info.y1+1));
|
||
if (distance > 9)
|
||
degrees=RadiansToDegrees(-atan2((double) (rotate_info.y2-
|
||
rotate_info.y1),(double) (rotate_info.x2-rotate_info.x1)));
|
||
} while ((state & ExitState) == 0);
|
||
(void) XSetFunction(display,windows->image.highlight_context,GXcopy);
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
if (distance <= 9)
|
||
return(MagickTrue);
|
||
}
|
||
if (direction == VerticalRotateCommand)
|
||
degrees-=90.0;
|
||
if (degrees == 0.0)
|
||
return(MagickTrue);
|
||
/*
|
||
Rotate image.
|
||
*/
|
||
normalized_degrees=degrees;
|
||
while (normalized_degrees < -45.0)
|
||
normalized_degrees+=360.0;
|
||
for (rotations=0; normalized_degrees > 45.0; rotations++)
|
||
normalized_degrees-=90.0;
|
||
if (normalized_degrees != 0.0)
|
||
(void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
(*image)->background_color.red=ScaleShortToQuantum(
|
||
windows->pixel_info->pen_colors[pen_id].red);
|
||
(*image)->background_color.green=ScaleShortToQuantum(
|
||
windows->pixel_info->pen_colors[pen_id].green);
|
||
(*image)->background_color.blue=ScaleShortToQuantum(
|
||
windows->pixel_info->pen_colors[pen_id].blue);
|
||
rotate_image=RotateImage(*image,degrees,&(*image)->exception);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (rotate_image == (Image *) NULL)
|
||
return(MagickFalse);
|
||
*image=DestroyImage(*image);
|
||
*image=rotate_image;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
{
|
||
/*
|
||
Rotate crop geometry.
|
||
*/
|
||
width=(unsigned int) (*image)->columns;
|
||
height=(unsigned int) (*image)->rows;
|
||
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
|
||
switch (rotations % 4)
|
||
{
|
||
default:
|
||
case 0:
|
||
break;
|
||
case 1:
|
||
{
|
||
/*
|
||
Rotate 90 degrees.
|
||
*/
|
||
(void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
|
||
"%ux%u%+d%+d",height,width,(int) (*image)->columns-
|
||
(int) height-y,x);
|
||
break;
|
||
}
|
||
case 2:
|
||
{
|
||
/*
|
||
Rotate 180 degrees.
|
||
*/
|
||
(void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
|
||
"%ux%u%+d%+d",width,height,(int) width-x,(int) height-y);
|
||
break;
|
||
}
|
||
case 3:
|
||
{
|
||
/*
|
||
Rotate 270 degrees.
|
||
*/
|
||
(void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
|
||
"%ux%u%+d%+d",height,width,y,(int) (*image)->rows-(int) width-x);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (windows->image.orphan != MagickFalse)
|
||
return(MagickTrue);
|
||
if (normalized_degrees != 0.0)
|
||
{
|
||
/*
|
||
Update image colormap.
|
||
*/
|
||
windows->image.window_changes.width=(int) (*image)->columns;
|
||
windows->image.window_changes.height=(int) (*image)->rows;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
{
|
||
/*
|
||
Obtain dimensions of image from crop geometry.
|
||
*/
|
||
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,
|
||
&width,&height);
|
||
windows->image.window_changes.width=(int) width;
|
||
windows->image.window_changes.height=(int) height;
|
||
}
|
||
XConfigureImageColormap(display,resource_info,windows,*image);
|
||
}
|
||
else
|
||
if (((rotations % 4) == 1) || ((rotations % 4) == 3))
|
||
{
|
||
windows->image.window_changes.width=windows->image.ximage->height;
|
||
windows->image.window_changes.height=windows->image.ximage->width;
|
||
}
|
||
/*
|
||
Update image configuration.
|
||
*/
|
||
(void) XConfigureImage(display,resource_info,windows,*image);
|
||
return(MagickTrue);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X S a v e I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XSaveImage() saves an image to a file.
|
||
%
|
||
% The format of the XSaveImage method is:
|
||
%
|
||
% MagickBooleanType XSaveImage(Display *display,
|
||
% XResourceInfo *resource_info,XWindows *windows,Image *image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image.
|
||
%
|
||
*/
|
||
static MagickBooleanType XSaveImage(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows,Image *image)
|
||
{
|
||
char
|
||
filename[MaxTextExtent],
|
||
geometry[MaxTextExtent];
|
||
|
||
Image
|
||
*save_image;
|
||
|
||
ImageInfo
|
||
*image_info;
|
||
|
||
MagickStatusType
|
||
status;
|
||
|
||
/*
|
||
Request file name from user.
|
||
*/
|
||
if (resource_info->write_filename != (char *) NULL)
|
||
(void) CopyMagickString(filename,resource_info->write_filename,
|
||
MaxTextExtent);
|
||
else
|
||
{
|
||
char
|
||
path[MaxTextExtent];
|
||
|
||
int
|
||
status;
|
||
|
||
GetPathComponent(image->filename,HeadPath,path);
|
||
GetPathComponent(image->filename,TailPath,filename);
|
||
if (*path != '\0')
|
||
{
|
||
status=chdir(path);
|
||
if (status == -1)
|
||
(void) ThrowMagickException(&image->exception,GetMagickModule(),
|
||
FileOpenError,"UnableToOpenFile","%s",path);
|
||
}
|
||
}
|
||
XFileBrowserWidget(display,windows,"Save",filename);
|
||
if (*filename == '\0')
|
||
return(MagickTrue);
|
||
if (IsPathAccessible(filename) != MagickFalse)
|
||
{
|
||
int
|
||
status;
|
||
|
||
/*
|
||
File exists-- seek user's permission before overwriting.
|
||
*/
|
||
status=XConfirmWidget(display,windows,"Overwrite",filename);
|
||
if (status <= 0)
|
||
return(MagickTrue);
|
||
}
|
||
image_info=CloneImageInfo(resource_info->image_info);
|
||
(void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
|
||
(void) SetImageInfo(image_info,1,&image->exception);
|
||
if ((LocaleCompare(image_info->magick,"JPEG") == 0) ||
|
||
(LocaleCompare(image_info->magick,"JPG") == 0))
|
||
{
|
||
char
|
||
quality[MaxTextExtent];
|
||
|
||
int
|
||
status;
|
||
|
||
/*
|
||
Request JPEG quality from user.
|
||
*/
|
||
(void) FormatLocaleString(quality,MaxTextExtent,"%.20g",(double)
|
||
image->quality);
|
||
status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
|
||
quality);
|
||
if (*quality == '\0')
|
||
return(MagickTrue);
|
||
image->quality=StringToUnsignedLong(quality);
|
||
image_info->interlace=status != 0 ? NoInterlace : PlaneInterlace;
|
||
}
|
||
if ((LocaleCompare(image_info->magick,"EPS") == 0) ||
|
||
(LocaleCompare(image_info->magick,"PDF") == 0) ||
|
||
(LocaleCompare(image_info->magick,"PS") == 0) ||
|
||
(LocaleCompare(image_info->magick,"PS2") == 0))
|
||
{
|
||
char
|
||
geometry[MaxTextExtent];
|
||
|
||
/*
|
||
Request page geometry from user.
|
||
*/
|
||
(void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
|
||
if (LocaleCompare(image_info->magick,"PDF") == 0)
|
||
(void) CopyMagickString(geometry,PSPageGeometry,MaxTextExtent);
|
||
if (image_info->page != (char *) NULL)
|
||
(void) CopyMagickString(geometry,image_info->page,MaxTextExtent);
|
||
XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
|
||
"Select page geometry:",geometry);
|
||
if (*geometry != '\0')
|
||
image_info->page=GetPageGeometry(geometry);
|
||
}
|
||
/*
|
||
Apply image transforms.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
save_image=CloneImage(image,0,0,MagickTrue,&image->exception);
|
||
if (save_image == (Image *) NULL)
|
||
return(MagickFalse);
|
||
(void) FormatLocaleString(geometry,MaxTextExtent,"%dx%d!",
|
||
windows->image.ximage->width,windows->image.ximage->height);
|
||
(void) TransformImage(&save_image,windows->image.crop_geometry,geometry);
|
||
/*
|
||
Write image.
|
||
*/
|
||
(void) CopyMagickString(save_image->filename,filename,MaxTextExtent);
|
||
status=WriteImage(image_info,save_image);
|
||
if (status != MagickFalse)
|
||
image->taint=MagickFalse;
|
||
save_image=DestroyImage(save_image);
|
||
image_info=DestroyImageInfo(image_info);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
return(status != 0 ? MagickTrue : MagickFalse);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X S c r e e n E v e n t %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XScreenEvent() handles global events associated with the Pan and Magnify
|
||
% windows.
|
||
%
|
||
% The format of the XScreenEvent function is:
|
||
%
|
||
% void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a pointer to the Display structure; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o event: Specifies a pointer to a X11 XEvent structure.
|
||
%
|
||
%
|
||
*/
|
||
|
||
#if defined(__cplusplus) || defined(c_plusplus)
|
||
extern "C" {
|
||
#endif
|
||
|
||
static int XPredicate(Display *magick_unused(display),XEvent *event,char *data)
|
||
{
|
||
register XWindows
|
||
*windows;
|
||
|
||
windows=(XWindows *) data;
|
||
if ((event->type == ClientMessage) &&
|
||
(event->xclient.window == windows->image.id))
|
||
return(MagickFalse);
|
||
return(MagickTrue);
|
||
}
|
||
|
||
#if defined(__cplusplus) || defined(c_plusplus)
|
||
}
|
||
#endif
|
||
|
||
static void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
|
||
{
|
||
register int
|
||
x,
|
||
y;
|
||
|
||
(void) XIfEvent(display,event,XPredicate,(char *) windows);
|
||
if (event->xany.window == windows->command.id)
|
||
return;
|
||
switch (event->type)
|
||
{
|
||
case ButtonPress:
|
||
case ButtonRelease:
|
||
{
|
||
if ((event->xbutton.button == Button3) &&
|
||
(event->xbutton.state & Mod1Mask))
|
||
{
|
||
/*
|
||
Convert Alt-Button3 to Button2.
|
||
*/
|
||
event->xbutton.button=Button2;
|
||
event->xbutton.state&=(~Mod1Mask);
|
||
}
|
||
if (event->xbutton.window == windows->backdrop.id)
|
||
{
|
||
(void) XSetInputFocus(display,event->xbutton.window,RevertToParent,
|
||
event->xbutton.time);
|
||
break;
|
||
}
|
||
if (event->xbutton.window == windows->pan.id)
|
||
{
|
||
XPanImage(display,windows,event);
|
||
break;
|
||
}
|
||
if (event->xbutton.window == windows->image.id)
|
||
if (event->xbutton.button == Button2)
|
||
{
|
||
/*
|
||
Update magnified image.
|
||
*/
|
||
x=event->xbutton.x;
|
||
y=event->xbutton.y;
|
||
if (x < 0)
|
||
x=0;
|
||
else
|
||
if (x >= (int) windows->image.width)
|
||
x=(int) (windows->image.width-1);
|
||
windows->magnify.x=(int) windows->image.x+x;
|
||
if (y < 0)
|
||
y=0;
|
||
else
|
||
if (y >= (int) windows->image.height)
|
||
y=(int) (windows->image.height-1);
|
||
windows->magnify.y=windows->image.y+y;
|
||
if (windows->magnify.mapped == MagickFalse)
|
||
(void) XMapRaised(display,windows->magnify.id);
|
||
XMakeMagnifyImage(display,windows);
|
||
if (event->type == ButtonRelease)
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case ClientMessage:
|
||
{
|
||
/*
|
||
If client window delete message, exit.
|
||
*/
|
||
if (event->xclient.message_type != windows->wm_protocols)
|
||
break;
|
||
if (*event->xclient.data.l != (long) windows->wm_delete_window)
|
||
break;
|
||
if (event->xclient.window == windows->magnify.id)
|
||
{
|
||
(void) XWithdrawWindow(display,windows->magnify.id,
|
||
windows->magnify.screen);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case ConfigureNotify:
|
||
{
|
||
if (event->xconfigure.window == windows->magnify.id)
|
||
{
|
||
unsigned int
|
||
magnify;
|
||
|
||
/*
|
||
Magnify window has a new configuration.
|
||
*/
|
||
windows->magnify.width=(unsigned int) event->xconfigure.width;
|
||
windows->magnify.height=(unsigned int) event->xconfigure.height;
|
||
if (windows->magnify.mapped == MagickFalse)
|
||
break;
|
||
magnify=1;
|
||
while ((int) magnify <= event->xconfigure.width)
|
||
magnify<<=1;
|
||
while ((int) magnify <= event->xconfigure.height)
|
||
magnify<<=1;
|
||
magnify>>=1;
|
||
if (((int) magnify != event->xconfigure.width) ||
|
||
((int) magnify != event->xconfigure.height))
|
||
{
|
||
XWindowChanges
|
||
window_changes;
|
||
|
||
window_changes.width=(int) magnify;
|
||
window_changes.height=(int) magnify;
|
||
(void) XReconfigureWMWindow(display,windows->magnify.id,
|
||
windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
|
||
&window_changes);
|
||
break;
|
||
}
|
||
XMakeMagnifyImage(display,windows);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case Expose:
|
||
{
|
||
if (event->xexpose.window == windows->image.id)
|
||
{
|
||
XRefreshWindow(display,&windows->image,event);
|
||
break;
|
||
}
|
||
if (event->xexpose.window == windows->pan.id)
|
||
if (event->xexpose.count == 0)
|
||
{
|
||
XDrawPanRectangle(display,windows);
|
||
break;
|
||
}
|
||
if (event->xexpose.window == windows->magnify.id)
|
||
if (event->xexpose.count == 0)
|
||
{
|
||
XMakeMagnifyImage(display,windows);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case KeyPress:
|
||
{
|
||
char
|
||
command[MaxTextExtent];
|
||
|
||
KeySym
|
||
key_symbol;
|
||
|
||
if (event->xkey.window != windows->magnify.id)
|
||
break;
|
||
/*
|
||
Respond to a user key press.
|
||
*/
|
||
(void) XLookupString((XKeyEvent *) &event->xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
XMagnifyWindowCommand(display,windows,event->xkey.state,key_symbol);
|
||
break;
|
||
}
|
||
case MapNotify:
|
||
{
|
||
if (event->xmap.window == windows->magnify.id)
|
||
{
|
||
windows->magnify.mapped=MagickTrue;
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
break;
|
||
}
|
||
if (event->xmap.window == windows->info.id)
|
||
{
|
||
windows->info.mapped=MagickTrue;
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case MotionNotify:
|
||
{
|
||
while (XCheckMaskEvent(display,ButtonMotionMask,event)) ;
|
||
if (event->xmotion.window == windows->image.id)
|
||
if (windows->magnify.mapped != MagickFalse)
|
||
{
|
||
/*
|
||
Update magnified image.
|
||
*/
|
||
x=event->xmotion.x;
|
||
y=event->xmotion.y;
|
||
if (x < 0)
|
||
x=0;
|
||
else
|
||
if (x >= (int) windows->image.width)
|
||
x=(int) (windows->image.width-1);
|
||
windows->magnify.x=(int) windows->image.x+x;
|
||
if (y < 0)
|
||
y=0;
|
||
else
|
||
if (y >= (int) windows->image.height)
|
||
y=(int) (windows->image.height-1);
|
||
windows->magnify.y=windows->image.y+y;
|
||
XMakeMagnifyImage(display,windows);
|
||
}
|
||
break;
|
||
}
|
||
case UnmapNotify:
|
||
{
|
||
if (event->xunmap.window == windows->magnify.id)
|
||
{
|
||
windows->magnify.mapped=MagickFalse;
|
||
break;
|
||
}
|
||
if (event->xunmap.window == windows->info.id)
|
||
{
|
||
windows->info.mapped=MagickFalse;
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X S e t C r o p G e o m e t r y %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XSetCropGeometry() accepts a cropping geometry relative to the Image window
|
||
% and translates it to a cropping geometry relative to the image.
|
||
%
|
||
% The format of the XSetCropGeometry method is:
|
||
%
|
||
% void XSetCropGeometry(Display *display,XWindows *windows,
|
||
% RectangleInfo *crop_info,Image *image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o crop_info: A pointer to a RectangleInfo that defines a region of the
|
||
% Image window to crop.
|
||
%
|
||
% o image: the image.
|
||
%
|
||
*/
|
||
static void XSetCropGeometry(Display *display,XWindows *windows,
|
||
RectangleInfo *crop_info,Image *image)
|
||
{
|
||
char
|
||
text[MaxTextExtent];
|
||
|
||
int
|
||
x,
|
||
y;
|
||
|
||
MagickRealType
|
||
scale_factor;
|
||
|
||
unsigned int
|
||
height,
|
||
width;
|
||
|
||
if (windows->info.mapped != MagickFalse)
|
||
{
|
||
/*
|
||
Display info on cropping rectangle.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent," %.20gx%.20g%+.20g%+.20g",
|
||
(double) crop_info->width,(double) crop_info->height,(double)
|
||
crop_info->x,(double) crop_info->y);
|
||
XInfoWidget(display,windows,text);
|
||
}
|
||
/*
|
||
Cropping geometry is relative to any previous crop geometry.
|
||
*/
|
||
x=0;
|
||
y=0;
|
||
width=(unsigned int) image->columns;
|
||
height=(unsigned int) image->rows;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
|
||
else
|
||
windows->image.crop_geometry=AcquireString((char *) NULL);
|
||
/*
|
||
Define the crop geometry string from the cropping rectangle.
|
||
*/
|
||
scale_factor=(MagickRealType) width/windows->image.ximage->width;
|
||
if (crop_info->x > 0)
|
||
x+=(int) (scale_factor*crop_info->x+0.5);
|
||
width=(unsigned int) (scale_factor*crop_info->width+0.5);
|
||
if (width == 0)
|
||
width=1;
|
||
scale_factor=(MagickRealType) height/windows->image.ximage->height;
|
||
if (crop_info->y > 0)
|
||
y+=(int) (scale_factor*crop_info->y+0.5);
|
||
height=(unsigned int) (scale_factor*crop_info->height+0.5);
|
||
if (height == 0)
|
||
height=1;
|
||
(void) FormatLocaleString(windows->image.crop_geometry,MaxTextExtent,
|
||
"%ux%u%+d%+d",width,height,x,y);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X T i l e I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XTileImage() loads or deletes a selected tile from a visual image directory.
|
||
% The load or delete command is chosen from a menu.
|
||
%
|
||
% The format of the XTileImage method is:
|
||
%
|
||
% Image *XTileImage(Display *display,XResourceInfo *resource_info,
|
||
% XWindows *windows,Image *image,XEvent *event)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o tile_image: XTileImage reads or deletes the tile image
|
||
% and returns it. A null image is returned if an error occurs.
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image; returned from ReadImage.
|
||
%
|
||
% o event: Specifies a pointer to a XEvent structure. If it is NULL,
|
||
% the entire image is refreshed.
|
||
%
|
||
*/
|
||
static Image *XTileImage(Display *display,XResourceInfo *resource_info,
|
||
XWindows *windows,Image *image,XEvent *event)
|
||
{
|
||
static const char
|
||
*VerbMenu[] =
|
||
{
|
||
"Load",
|
||
"Next",
|
||
"Former",
|
||
"Delete",
|
||
"Update",
|
||
(char *) NULL,
|
||
};
|
||
|
||
static const ModeType
|
||
TileCommands[] =
|
||
{
|
||
TileLoadCommand,
|
||
TileNextCommand,
|
||
TileFormerCommand,
|
||
TileDeleteCommand,
|
||
TileUpdateCommand
|
||
};
|
||
|
||
char
|
||
command[MaxTextExtent],
|
||
filename[MaxTextExtent];
|
||
|
||
Image
|
||
*tile_image;
|
||
|
||
int
|
||
id,
|
||
status,
|
||
tile,
|
||
x,
|
||
y;
|
||
|
||
MagickRealType
|
||
scale_factor;
|
||
|
||
register char
|
||
*p,
|
||
*q;
|
||
|
||
register int
|
||
i;
|
||
|
||
unsigned int
|
||
height,
|
||
width;
|
||
|
||
/*
|
||
Tile image is relative to montage image configuration.
|
||
*/
|
||
x=0;
|
||
y=0;
|
||
width=(unsigned int) image->columns;
|
||
height=(unsigned int) image->rows;
|
||
if (windows->image.crop_geometry != (char *) NULL)
|
||
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
|
||
scale_factor=(MagickRealType) width/windows->image.ximage->width;
|
||
event->xbutton.x+=windows->image.x;
|
||
event->xbutton.x=(int) (scale_factor*event->xbutton.x+x+0.5);
|
||
scale_factor=(MagickRealType) height/windows->image.ximage->height;
|
||
event->xbutton.y+=windows->image.y;
|
||
event->xbutton.y=(int) (scale_factor*event->xbutton.y+y+0.5);
|
||
/*
|
||
Determine size and location of each tile in the visual image directory.
|
||
*/
|
||
width=(unsigned int) image->columns;
|
||
height=(unsigned int) image->rows;
|
||
x=0;
|
||
y=0;
|
||
(void) XParseGeometry(image->montage,&x,&y,&width,&height);
|
||
tile=((event->xbutton.y-y)/height)*(((int) image->columns-x)/width)+
|
||
(event->xbutton.x-x)/width;
|
||
if (tile < 0)
|
||
{
|
||
/*
|
||
Button press is outside any tile.
|
||
*/
|
||
(void) XBell(display,0);
|
||
return((Image *) NULL);
|
||
}
|
||
/*
|
||
Determine file name from the tile directory.
|
||
*/
|
||
p=image->directory;
|
||
for (i=tile; (i != 0) && (*p != '\0'); )
|
||
{
|
||
if (*p == '\n')
|
||
i--;
|
||
p++;
|
||
}
|
||
if (*p == '\0')
|
||
{
|
||
/*
|
||
Button press is outside any tile.
|
||
*/
|
||
(void) XBell(display,0);
|
||
return((Image *) NULL);
|
||
}
|
||
/*
|
||
Select a command from the pop-up menu.
|
||
*/
|
||
id=XMenuWidget(display,windows,"Tile Verb",VerbMenu,command);
|
||
if (id < 0)
|
||
return((Image *) NULL);
|
||
q=p;
|
||
while ((*q != '\n') && (*q != '\0'))
|
||
q++;
|
||
(void) CopyMagickString(filename,p,(size_t) (q-p+1));
|
||
/*
|
||
Perform command for the selected tile.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
tile_image=NewImageList();
|
||
switch (TileCommands[id])
|
||
{
|
||
case TileLoadCommand:
|
||
{
|
||
/*
|
||
Load tile image.
|
||
*/
|
||
XCheckRefreshWindows(display,windows);
|
||
(void) CopyMagickString(resource_info->image_info->magick,"MIFF",
|
||
MaxTextExtent);
|
||
(void) CopyMagickString(resource_info->image_info->filename,filename,
|
||
MaxTextExtent);
|
||
tile_image=ReadImage(resource_info->image_info,&image->exception);
|
||
CatchException(&image->exception);
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
break;
|
||
}
|
||
case TileNextCommand:
|
||
{
|
||
/*
|
||
Display next image.
|
||
*/
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_next_image,CurrentTime);
|
||
break;
|
||
}
|
||
case TileFormerCommand:
|
||
{
|
||
/*
|
||
Display former image.
|
||
*/
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_former_image,CurrentTime);
|
||
break;
|
||
}
|
||
case TileDeleteCommand:
|
||
{
|
||
/*
|
||
Delete tile image.
|
||
*/
|
||
if (IsPathAccessible(filename) == MagickFalse)
|
||
{
|
||
XNoticeWidget(display,windows,"Image file does not exist:",filename);
|
||
break;
|
||
}
|
||
status=XConfirmWidget(display,windows,"Really delete tile",filename);
|
||
if (status <= 0)
|
||
break;
|
||
status=remove_utf8(filename) != 0 ? MagickTrue : MagickFalse;
|
||
if (status != MagickFalse)
|
||
{
|
||
XNoticeWidget(display,windows,"Unable to delete image file:",
|
||
filename);
|
||
break;
|
||
}
|
||
}
|
||
case TileUpdateCommand:
|
||
{
|
||
ExceptionInfo
|
||
*exception;
|
||
|
||
int
|
||
x_offset,
|
||
y_offset;
|
||
|
||
PixelPacket
|
||
pixel;
|
||
|
||
register int
|
||
j;
|
||
|
||
register PixelPacket
|
||
*s;
|
||
|
||
/*
|
||
Ensure all the images exist.
|
||
*/
|
||
tile=0;
|
||
for (p=image->directory; *p != '\0'; p++)
|
||
{
|
||
CacheView
|
||
*image_view;
|
||
|
||
q=p;
|
||
while ((*q != '\n') && (*q != '\0'))
|
||
q++;
|
||
(void) CopyMagickString(filename,p,(size_t) (q-p+1));
|
||
p=q;
|
||
if (IsPathAccessible(filename) != MagickFalse)
|
||
{
|
||
tile++;
|
||
continue;
|
||
}
|
||
/*
|
||
Overwrite tile with background color.
|
||
*/
|
||
x_offset=(int) (width*(tile % (((int) image->columns-x)/width))+x);
|
||
y_offset=(int) (height*(tile/(((int) image->columns-x)/width))+y);
|
||
exception=(&image->exception);
|
||
image_view=AcquireAuthenticCacheView(image,exception);
|
||
(void) GetOneCacheViewVirtualPixel(image_view,0,0,&pixel,exception);
|
||
for (i=0; i < (int) height; i++)
|
||
{
|
||
s=GetCacheViewAuthenticPixels(image_view,(ssize_t) x_offset,(ssize_t)
|
||
y_offset+i,width,1,exception);
|
||
if (s == (PixelPacket *) NULL)
|
||
break;
|
||
for (j=0; j < (int) width; j++)
|
||
*s++=pixel;
|
||
if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
|
||
break;
|
||
}
|
||
image_view=DestroyCacheView(image_view);
|
||
tile++;
|
||
}
|
||
windows->image.window_changes.width=(int) image->columns;
|
||
windows->image.window_changes.height=(int) image->rows;
|
||
XConfigureImageColormap(display,resource_info,windows,image);
|
||
(void) XConfigureImage(display,resource_info,windows,image);
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
return(tile_image);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X T r a n s l a t e I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XTranslateImage() translates the image within an Image window by one pixel
|
||
% as specified by the key symbol. If the image has a `montage string the
|
||
% translation is respect to the width and height contained within the string.
|
||
%
|
||
% The format of the XTranslateImage method is:
|
||
%
|
||
% void XTranslateImage(Display *display,XWindows *windows,
|
||
% Image *image,const KeySym key_symbol)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image.
|
||
%
|
||
% o key_symbol: Specifies a KeySym which indicates which side of the image
|
||
% to trim.
|
||
%
|
||
*/
|
||
static void XTranslateImage(Display *display,XWindows *windows,
|
||
Image *image,const KeySym key_symbol)
|
||
{
|
||
char
|
||
text[MaxTextExtent];
|
||
|
||
int
|
||
x,
|
||
y;
|
||
|
||
unsigned int
|
||
x_offset,
|
||
y_offset;
|
||
|
||
/*
|
||
User specified a pan position offset.
|
||
*/
|
||
x_offset=windows->image.width;
|
||
y_offset=windows->image.height;
|
||
if (image->montage != (char *) NULL)
|
||
(void) XParseGeometry(image->montage,&x,&y,&x_offset,&y_offset);
|
||
switch ((int) key_symbol)
|
||
{
|
||
case XK_Home:
|
||
case XK_KP_Home:
|
||
{
|
||
windows->image.x=(int) windows->image.width/2;
|
||
windows->image.y=(int) windows->image.height/2;
|
||
break;
|
||
}
|
||
case XK_Left:
|
||
case XK_KP_Left:
|
||
{
|
||
windows->image.x-=x_offset;
|
||
break;
|
||
}
|
||
case XK_Next:
|
||
case XK_Up:
|
||
case XK_KP_Up:
|
||
{
|
||
windows->image.y-=y_offset;
|
||
break;
|
||
}
|
||
case XK_Right:
|
||
case XK_KP_Right:
|
||
{
|
||
windows->image.x+=x_offset;
|
||
break;
|
||
}
|
||
case XK_Prior:
|
||
case XK_Down:
|
||
case XK_KP_Down:
|
||
{
|
||
windows->image.y+=y_offset;
|
||
break;
|
||
}
|
||
default:
|
||
return;
|
||
}
|
||
/*
|
||
Check boundary conditions.
|
||
*/
|
||
if (windows->image.x < 0)
|
||
windows->image.x=0;
|
||
else
|
||
if ((int) (windows->image.x+windows->image.width) >
|
||
windows->image.ximage->width)
|
||
windows->image.x=(int) windows->image.ximage->width-windows->image.width;
|
||
if (windows->image.y < 0)
|
||
windows->image.y=0;
|
||
else
|
||
if ((int) (windows->image.y+windows->image.height) >
|
||
windows->image.ximage->height)
|
||
windows->image.y=(int) windows->image.ximage->height-windows->image.height;
|
||
/*
|
||
Refresh Image window.
|
||
*/
|
||
(void) FormatLocaleString(text,MaxTextExtent," %ux%u%+d%+d ",
|
||
windows->image.width,windows->image.height,windows->image.x,
|
||
windows->image.y);
|
||
XInfoWidget(display,windows,text);
|
||
XCheckRefreshWindows(display,windows);
|
||
XDrawPanRectangle(display,windows);
|
||
XRefreshWindow(display,&windows->image,(XEvent *) NULL);
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X T r i m I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XTrimImage() trims the edges from the Image window.
|
||
%
|
||
% The format of the XTrimImage method is:
|
||
%
|
||
% MagickBooleanType XTrimImage(Display *display,
|
||
% XResourceInfo *resource_info,XWindows *windows,Image *image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
% o image: the image.
|
||
%
|
||
*/
|
||
static MagickBooleanType XTrimImage(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows,Image *image)
|
||
{
|
||
RectangleInfo
|
||
trim_info;
|
||
|
||
register int
|
||
x,
|
||
y;
|
||
|
||
size_t
|
||
background,
|
||
pixel;
|
||
|
||
/*
|
||
Trim edges from image.
|
||
*/
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
/*
|
||
Crop the left edge.
|
||
*/
|
||
background=XGetPixel(windows->image.ximage,0,0);
|
||
trim_info.width=(size_t) windows->image.ximage->width;
|
||
for (x=0; x < windows->image.ximage->width; x++)
|
||
{
|
||
for (y=0; y < windows->image.ximage->height; y++)
|
||
{
|
||
pixel=XGetPixel(windows->image.ximage,x,y);
|
||
if (pixel != background)
|
||
break;
|
||
}
|
||
if (y < windows->image.ximage->height)
|
||
break;
|
||
}
|
||
trim_info.x=(ssize_t) x;
|
||
if (trim_info.x == (ssize_t) windows->image.ximage->width)
|
||
{
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
return(MagickFalse);
|
||
}
|
||
/*
|
||
Crop the right edge.
|
||
*/
|
||
background=XGetPixel(windows->image.ximage,windows->image.ximage->width-1,0);
|
||
for (x=windows->image.ximage->width-1; x != 0; x--)
|
||
{
|
||
for (y=0; y < windows->image.ximage->height; y++)
|
||
{
|
||
pixel=XGetPixel(windows->image.ximage,x,y);
|
||
if (pixel != background)
|
||
break;
|
||
}
|
||
if (y < windows->image.ximage->height)
|
||
break;
|
||
}
|
||
trim_info.width=(size_t) (x-trim_info.x+1);
|
||
/*
|
||
Crop the top edge.
|
||
*/
|
||
background=XGetPixel(windows->image.ximage,0,0);
|
||
trim_info.height=(size_t) windows->image.ximage->height;
|
||
for (y=0; y < windows->image.ximage->height; y++)
|
||
{
|
||
for (x=0; x < windows->image.ximage->width; x++)
|
||
{
|
||
pixel=XGetPixel(windows->image.ximage,x,y);
|
||
if (pixel != background)
|
||
break;
|
||
}
|
||
if (x < windows->image.ximage->width)
|
||
break;
|
||
}
|
||
trim_info.y=(ssize_t) y;
|
||
/*
|
||
Crop the bottom edge.
|
||
*/
|
||
background=XGetPixel(windows->image.ximage,0,windows->image.ximage->height-1);
|
||
for (y=windows->image.ximage->height-1; y != 0; y--)
|
||
{
|
||
for (x=0; x < windows->image.ximage->width; x++)
|
||
{
|
||
pixel=XGetPixel(windows->image.ximage,x,y);
|
||
if (pixel != background)
|
||
break;
|
||
}
|
||
if (x < windows->image.ximage->width)
|
||
break;
|
||
}
|
||
trim_info.height=(size_t) y-trim_info.y+1;
|
||
if (((unsigned int) trim_info.width != windows->image.width) ||
|
||
((unsigned int) trim_info.height != windows->image.height))
|
||
{
|
||
/*
|
||
Reconfigure Image window as defined by the trimming rectangle.
|
||
*/
|
||
XSetCropGeometry(display,windows,&trim_info,image);
|
||
windows->image.window_changes.width=(int) trim_info.width;
|
||
windows->image.window_changes.height=(int) trim_info.height;
|
||
(void) XConfigureImage(display,resource_info,windows,image);
|
||
}
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
return(MagickTrue);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X V i s u a l D i r e c t o r y I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XVisualDirectoryImage() creates a Visual Image Directory.
|
||
%
|
||
% The format of the XVisualDirectoryImage method is:
|
||
%
|
||
% Image *XVisualDirectoryImage(Display *display,
|
||
% XResourceInfo *resource_info,XWindows *windows)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o nexus: Method XVisualDirectoryImage returns a visual image
|
||
% directory if it can be created successfully. Otherwise a null image
|
||
% is returned.
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o windows: Specifies a pointer to a XWindows structure.
|
||
%
|
||
*/
|
||
static Image *XVisualDirectoryImage(Display *display,
|
||
XResourceInfo *resource_info,XWindows *windows)
|
||
{
|
||
#define TileImageTag "Scale/Image"
|
||
#define XClientName "montage"
|
||
|
||
char
|
||
**filelist;
|
||
|
||
ExceptionInfo
|
||
*exception;
|
||
|
||
Image
|
||
*images,
|
||
*montage_image,
|
||
*next_image,
|
||
*thumbnail_image;
|
||
|
||
ImageInfo
|
||
*read_info;
|
||
|
||
int
|
||
number_files;
|
||
|
||
MagickBooleanType
|
||
backdrop;
|
||
|
||
MagickStatusType
|
||
status;
|
||
|
||
MontageInfo
|
||
*montage_info;
|
||
|
||
RectangleInfo
|
||
geometry;
|
||
|
||
register int
|
||
i;
|
||
|
||
static char
|
||
filename[MaxTextExtent] = "\0",
|
||
filenames[MaxTextExtent] = "*";
|
||
|
||
XResourceInfo
|
||
background_resources;
|
||
|
||
/*
|
||
Request file name from user.
|
||
*/
|
||
XFileBrowserWidget(display,windows,"Directory",filenames);
|
||
if (*filenames == '\0')
|
||
return((Image *) NULL);
|
||
/*
|
||
Expand the filenames.
|
||
*/
|
||
filelist=(char **) AcquireMagickMemory(sizeof(*filelist));
|
||
if (filelist == (char **) NULL)
|
||
{
|
||
ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
|
||
filenames);
|
||
return((Image *) NULL);
|
||
}
|
||
number_files=1;
|
||
filelist[0]=filenames;
|
||
status=ExpandFilenames(&number_files,&filelist);
|
||
if ((status == MagickFalse) || (number_files == 0))
|
||
{
|
||
if (number_files == 0)
|
||
ThrowXWindowFatalException(ImageError,"NoImagesWereFound",filenames)
|
||
else
|
||
ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
|
||
filenames);
|
||
return((Image *) NULL);
|
||
}
|
||
/*
|
||
Set image background resources.
|
||
*/
|
||
background_resources=(*resource_info);
|
||
background_resources.window_id=AcquireString("");
|
||
(void) FormatLocaleString(background_resources.window_id,MaxTextExtent,
|
||
"0x%lx",windows->image.id);
|
||
background_resources.backdrop=MagickTrue;
|
||
/*
|
||
Read each image and convert them to a tile.
|
||
*/
|
||
backdrop=(windows->visual_info->klass == TrueColor) ||
|
||
(windows->visual_info->klass == DirectColor) ? MagickTrue : MagickFalse;
|
||
read_info=CloneImageInfo(resource_info->image_info);
|
||
(void) SetImageOption(read_info,"jpeg:size","120x120");
|
||
(void) CloneString(&read_info->size,DefaultTileGeometry);
|
||
(void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
|
||
(void *) NULL);
|
||
images=NewImageList();
|
||
exception=AcquireExceptionInfo();
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
for (i=0; i < (int) number_files; i++)
|
||
{
|
||
(void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
|
||
filelist[i]=DestroyString(filelist[i]);
|
||
*read_info->magick='\0';
|
||
next_image=ReadImage(read_info,exception);
|
||
CatchException(exception);
|
||
if (next_image != (Image *) NULL)
|
||
{
|
||
(void) DeleteImageProperty(next_image,"label");
|
||
(void) SetImageProperty(next_image,"label",InterpretImageProperties(
|
||
read_info,next_image,DefaultTileLabel));
|
||
(void) ParseRegionGeometry(next_image,read_info->size,&geometry,
|
||
exception);
|
||
thumbnail_image=ThumbnailImage(next_image,geometry.width,
|
||
geometry.height,exception);
|
||
if (thumbnail_image != (Image *) NULL)
|
||
{
|
||
next_image=DestroyImage(next_image);
|
||
next_image=thumbnail_image;
|
||
}
|
||
if (backdrop)
|
||
{
|
||
(void) XDisplayBackgroundImage(display,&background_resources,
|
||
next_image);
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
}
|
||
AppendImageToList(&images,next_image);
|
||
if (images->progress_monitor != (MagickProgressMonitor) NULL)
|
||
{
|
||
MagickBooleanType
|
||
proceed;
|
||
|
||
proceed=SetImageProgress(images,LoadImageTag,(MagickOffsetType) i,
|
||
(MagickSizeType) number_files);
|
||
if (proceed == MagickFalse)
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
exception=DestroyExceptionInfo(exception);
|
||
filelist=(char **) RelinquishMagickMemory(filelist);
|
||
if (images == (Image *) NULL)
|
||
{
|
||
read_info=DestroyImageInfo(read_info);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
ThrowXWindowFatalException(ImageError,"NoImagesWereLoaded",filenames);
|
||
return((Image *) NULL);
|
||
}
|
||
/*
|
||
Create the Visual Image Directory.
|
||
*/
|
||
montage_info=CloneMontageInfo(read_info,(MontageInfo *) NULL);
|
||
montage_info->pointsize=10;
|
||
if (resource_info->font != (char *) NULL)
|
||
(void) CloneString(&montage_info->font,resource_info->font);
|
||
(void) CopyMagickString(montage_info->filename,filename,MaxTextExtent);
|
||
montage_image=MontageImageList(read_info,montage_info,GetFirstImageInList(
|
||
images),&images->exception);
|
||
images=DestroyImageList(images);
|
||
montage_info=DestroyMontageInfo(montage_info);
|
||
read_info=DestroyImageInfo(read_info);
|
||
XSetCursorState(display,windows,MagickFalse);
|
||
if (montage_image == (Image *) NULL)
|
||
return(montage_image);
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_next_image,CurrentTime);
|
||
return(montage_image);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
% X D i s p l a y B a c k g r o u n d I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XDisplayBackgroundImage() displays an image in the background of a window.
|
||
%
|
||
% The format of the XDisplayBackgroundImage method is:
|
||
%
|
||
% MagickBooleanType XDisplayBackgroundImage(Display *display,
|
||
% XResourceInfo *resource_info,Image *image)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o image: the image.
|
||
%
|
||
*/
|
||
MagickExport MagickBooleanType XDisplayBackgroundImage(Display *display,
|
||
XResourceInfo *resource_info,Image *image)
|
||
{
|
||
char
|
||
geometry[MaxTextExtent],
|
||
visual_type[MaxTextExtent];
|
||
|
||
int
|
||
height,
|
||
status,
|
||
width;
|
||
|
||
RectangleInfo
|
||
geometry_info;
|
||
|
||
static XPixelInfo
|
||
pixel;
|
||
|
||
static XStandardColormap
|
||
*map_info;
|
||
|
||
static XVisualInfo
|
||
*visual_info = (XVisualInfo *) NULL;
|
||
|
||
static XWindowInfo
|
||
window_info;
|
||
|
||
size_t
|
||
delay;
|
||
|
||
Window
|
||
root_window;
|
||
|
||
XGCValues
|
||
context_values;
|
||
|
||
XResourceInfo
|
||
resources;
|
||
|
||
XWindowAttributes
|
||
window_attributes;
|
||
|
||
/*
|
||
Determine target window.
|
||
*/
|
||
assert(image != (Image *) NULL);
|
||
assert(image->signature == MagickSignature);
|
||
if (image->debug != MagickFalse)
|
||
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
|
||
resources=(*resource_info);
|
||
window_info.id=(Window) NULL;
|
||
root_window=XRootWindow(display,XDefaultScreen(display));
|
||
if (LocaleCompare(resources.window_id,"root") == 0)
|
||
window_info.id=root_window;
|
||
else
|
||
{
|
||
if (isdigit((unsigned char) *resources.window_id) != 0)
|
||
window_info.id=XWindowByID(display,root_window,
|
||
(Window) strtol((char *) resources.window_id,(char **) NULL,0));
|
||
if (window_info.id == (Window) NULL)
|
||
window_info.id=XWindowByName(display,root_window,resources.window_id);
|
||
}
|
||
if (window_info.id == (Window) NULL)
|
||
{
|
||
ThrowXWindowFatalException(XServerError,"NoWindowWithSpecifiedIDExists",
|
||
resources.window_id);
|
||
return(MagickFalse);
|
||
}
|
||
/*
|
||
Determine window visual id.
|
||
*/
|
||
window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
|
||
window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
|
||
(void) CopyMagickString(visual_type,"default",MaxTextExtent);
|
||
status=XGetWindowAttributes(display,window_info.id,&window_attributes);
|
||
if (status != 0)
|
||
(void) FormatLocaleString(visual_type,MaxTextExtent,"0x%lx",
|
||
XVisualIDFromVisual(window_attributes.visual));
|
||
if (visual_info == (XVisualInfo *) NULL)
|
||
{
|
||
/*
|
||
Allocate standard colormap.
|
||
*/
|
||
map_info=XAllocStandardColormap();
|
||
if (map_info == (XStandardColormap *) NULL)
|
||
ThrowXWindowFatalException(XServerFatalError,"MemoryAllocationFailed",
|
||
image->filename);
|
||
map_info->colormap=(Colormap) NULL;
|
||
pixel.pixels=(unsigned long *) NULL;
|
||
/*
|
||
Initialize visual info.
|
||
*/
|
||
resources.map_type=(char *) NULL;
|
||
resources.visual_type=visual_type;
|
||
visual_info=XBestVisualInfo(display,map_info,&resources);
|
||
if (visual_info == (XVisualInfo *) NULL)
|
||
ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
|
||
resources.visual_type);
|
||
/*
|
||
Initialize window info.
|
||
*/
|
||
window_info.ximage=(XImage *) NULL;
|
||
window_info.matte_image=(XImage *) NULL;
|
||
window_info.pixmap=(Pixmap) NULL;
|
||
window_info.matte_pixmap=(Pixmap) NULL;
|
||
}
|
||
/*
|
||
Free previous root colors.
|
||
*/
|
||
if (window_info.id == root_window)
|
||
(void) XDestroyWindowColors(display,root_window);
|
||
/*
|
||
Initialize Standard Colormap.
|
||
*/
|
||
resources.colormap=SharedColormap;
|
||
XMakeStandardColormap(display,visual_info,&resources,image,map_info,&pixel);
|
||
/*
|
||
Graphic context superclass.
|
||
*/
|
||
context_values.background=pixel.background_color.pixel;
|
||
context_values.foreground=pixel.foreground_color.pixel;
|
||
pixel.annotate_context=XCreateGC(display,window_info.id,
|
||
(size_t) (GCBackground | GCForeground),&context_values);
|
||
if (pixel.annotate_context == (GC) NULL)
|
||
ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
|
||
image->filename);
|
||
/*
|
||
Initialize Image window attributes.
|
||
*/
|
||
window_info.name=AcquireString("\0");
|
||
window_info.icon_name=AcquireString("\0");
|
||
XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
|
||
&resources,&window_info);
|
||
/*
|
||
Create the X image.
|
||
*/
|
||
window_info.width=(unsigned int) image->columns;
|
||
window_info.height=(unsigned int) image->rows;
|
||
if ((image->columns != window_info.width) ||
|
||
(image->rows != window_info.height))
|
||
ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
|
||
image->filename);
|
||
(void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>",
|
||
window_attributes.width,window_attributes.height);
|
||
geometry_info.width=window_info.width;
|
||
geometry_info.height=window_info.height;
|
||
geometry_info.x=(ssize_t) window_info.x;
|
||
geometry_info.y=(ssize_t) window_info.y;
|
||
(void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
|
||
&geometry_info.width,&geometry_info.height);
|
||
window_info.width=(unsigned int) geometry_info.width;
|
||
window_info.height=(unsigned int) geometry_info.height;
|
||
window_info.x=(int) geometry_info.x;
|
||
window_info.y=(int) geometry_info.y;
|
||
status=XMakeImage(display,&resources,&window_info,image,window_info.width,
|
||
window_info.height);
|
||
if (status == MagickFalse)
|
||
ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
|
||
image->filename);
|
||
window_info.x=0;
|
||
window_info.y=0;
|
||
if (image->debug != MagickFalse)
|
||
{
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Image: %s[%.20g] %.20gx%.20g ",image->filename,(double) image->scene,
|
||
(double) image->columns,(double) image->rows);
|
||
if (image->colors != 0)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
|
||
image->colors);
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),"%s",image->magick);
|
||
}
|
||
/*
|
||
Adjust image dimensions as specified by backdrop or geometry options.
|
||
*/
|
||
width=(int) window_info.width;
|
||
height=(int) window_info.height;
|
||
if (resources.backdrop != MagickFalse)
|
||
{
|
||
/*
|
||
Center image on window.
|
||
*/
|
||
window_info.x=(window_attributes.width/2)-
|
||
(window_info.ximage->width/2);
|
||
window_info.y=(window_attributes.height/2)-
|
||
(window_info.ximage->height/2);
|
||
width=window_attributes.width;
|
||
height=window_attributes.height;
|
||
}
|
||
if ((resources.image_geometry != (char *) NULL) &&
|
||
(*resources.image_geometry != '\0'))
|
||
{
|
||
char
|
||
default_geometry[MaxTextExtent];
|
||
|
||
int
|
||
flags,
|
||
gravity;
|
||
|
||
XSizeHints
|
||
*size_hints;
|
||
|
||
/*
|
||
User specified geometry.
|
||
*/
|
||
size_hints=XAllocSizeHints();
|
||
if (size_hints == (XSizeHints *) NULL)
|
||
ThrowXWindowFatalException(ResourceLimitFatalError,
|
||
"MemoryAllocationFailed",image->filename);
|
||
size_hints->flags=0L;
|
||
(void) FormatLocaleString(default_geometry,MaxTextExtent,"%dx%d",
|
||
width,height);
|
||
flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
|
||
default_geometry,window_info.border_width,size_hints,&window_info.x,
|
||
&window_info.y,&width,&height,&gravity);
|
||
if (flags & (XValue | YValue))
|
||
{
|
||
width=window_attributes.width;
|
||
height=window_attributes.height;
|
||
}
|
||
(void) XFree((void *) size_hints);
|
||
}
|
||
/*
|
||
Create the X pixmap.
|
||
*/
|
||
window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
|
||
(unsigned int) height,window_info.depth);
|
||
if (window_info.pixmap == (Pixmap) NULL)
|
||
ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
|
||
image->filename);
|
||
/*
|
||
Display pixmap on the window.
|
||
*/
|
||
if (((unsigned int) width > window_info.width) ||
|
||
((unsigned int) height > window_info.height))
|
||
(void) XFillRectangle(display,window_info.pixmap,
|
||
window_info.annotate_context,0,0,(unsigned int) width,
|
||
(unsigned int) height);
|
||
(void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
|
||
window_info.ximage,0,0,window_info.x,window_info.y,(unsigned int)
|
||
window_info.width,(unsigned int) window_info.height);
|
||
(void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
|
||
(void) XClearWindow(display,window_info.id);
|
||
delay=1000*image->delay/MagickMax(image->ticks_per_second,1L);
|
||
XDelay(display,delay == 0UL ? 10UL : delay);
|
||
(void) XSync(display,MagickFalse);
|
||
return(window_info.id == root_window ? MagickTrue : MagickFalse);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ X D i s p l a y I m a g e %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% XDisplayImage() displays an image via X11. A new image is created and
|
||
% returned if the user interactively transforms the displayed image.
|
||
%
|
||
% The format of the XDisplayImage method is:
|
||
%
|
||
% Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
|
||
% char **argv,int argc,Image **image,size_t *state)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o nexus: Method XDisplayImage returns an image when the
|
||
% user chooses 'Open Image' from the command menu or picks a tile
|
||
% from the image directory. Otherwise a null image is returned.
|
||
%
|
||
% o display: Specifies a connection to an X server; returned from
|
||
% XOpenDisplay.
|
||
%
|
||
% o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
|
||
%
|
||
% o argv: Specifies the application's argument list.
|
||
%
|
||
% o argc: Specifies the number of arguments.
|
||
%
|
||
% o image: Specifies an address to an address of an Image structure;
|
||
%
|
||
*/
|
||
MagickExport Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
|
||
char **argv,int argc,Image **image,size_t *state)
|
||
{
|
||
#define MagnifySize 256 /* must be a power of 2 */
|
||
#define MagickMenus 10
|
||
#define MagickTitle "Commands"
|
||
|
||
static const char
|
||
*CommandMenu[] =
|
||
{
|
||
"File",
|
||
"Edit",
|
||
"View",
|
||
"Transform",
|
||
"Enhance",
|
||
"Effects",
|
||
"F/X",
|
||
"Image Edit",
|
||
"Miscellany",
|
||
"Help",
|
||
(char *) NULL
|
||
},
|
||
*FileMenu[] =
|
||
{
|
||
"Open...",
|
||
"Next",
|
||
"Former",
|
||
"Select...",
|
||
"Save...",
|
||
"Print...",
|
||
"Delete...",
|
||
"New...",
|
||
"Visual Directory...",
|
||
"Quit",
|
||
(char *) NULL
|
||
},
|
||
*EditMenu[] =
|
||
{
|
||
"Undo",
|
||
"Redo",
|
||
"Cut",
|
||
"Copy",
|
||
"Paste",
|
||
(char *) NULL
|
||
},
|
||
*ViewMenu[] =
|
||
{
|
||
"Half Size",
|
||
"Original Size",
|
||
"Double Size",
|
||
"Resize...",
|
||
"Apply",
|
||
"Refresh",
|
||
"Restore",
|
||
(char *) NULL
|
||
},
|
||
*TransformMenu[] =
|
||
{
|
||
"Crop",
|
||
"Chop",
|
||
"Flop",
|
||
"Flip",
|
||
"Rotate Right",
|
||
"Rotate Left",
|
||
"Rotate...",
|
||
"Shear...",
|
||
"Roll...",
|
||
"Trim Edges",
|
||
(char *) NULL
|
||
},
|
||
*EnhanceMenu[] =
|
||
{
|
||
"Hue...",
|
||
"Saturation...",
|
||
"Brightness...",
|
||
"Gamma...",
|
||
"Spiff",
|
||
"Dull",
|
||
"Contrast Stretch...",
|
||
"Sigmoidal Contrast...",
|
||
"Normalize",
|
||
"Equalize",
|
||
"Negate",
|
||
"Grayscale",
|
||
"Map...",
|
||
"Quantize...",
|
||
(char *) NULL
|
||
},
|
||
*EffectsMenu[] =
|
||
{
|
||
"Despeckle",
|
||
"Emboss",
|
||
"Reduce Noise",
|
||
"Add Noise...",
|
||
"Sharpen...",
|
||
"Blur...",
|
||
"Threshold...",
|
||
"Edge Detect...",
|
||
"Spread...",
|
||
"Shade...",
|
||
"Raise...",
|
||
"Segment...",
|
||
(char *) NULL
|
||
},
|
||
*FXMenu[] =
|
||
{
|
||
"Solarize...",
|
||
"Sepia Tone...",
|
||
"Swirl...",
|
||
"Implode...",
|
||
"Vignette...",
|
||
"Wave...",
|
||
"Oil Paint...",
|
||
"Charcoal Draw...",
|
||
(char *) NULL
|
||
},
|
||
*ImageEditMenu[] =
|
||
{
|
||
"Annotate...",
|
||
"Draw...",
|
||
"Color...",
|
||
"Matte...",
|
||
"Composite...",
|
||
"Add Border...",
|
||
"Add Frame...",
|
||
"Comment...",
|
||
"Launch...",
|
||
"Region of Interest...",
|
||
(char *) NULL
|
||
},
|
||
*MiscellanyMenu[] =
|
||
{
|
||
"Image Info",
|
||
"Zoom Image",
|
||
"Show Preview...",
|
||
"Show Histogram",
|
||
"Show Matte",
|
||
"Background...",
|
||
"Slide Show...",
|
||
"Preferences...",
|
||
(char *) NULL
|
||
},
|
||
*HelpMenu[] =
|
||
{
|
||
"Overview",
|
||
"Browse Documentation",
|
||
"About Display",
|
||
(char *) NULL
|
||
},
|
||
*ShortCutsMenu[] =
|
||
{
|
||
"Next",
|
||
"Former",
|
||
"Open...",
|
||
"Save...",
|
||
"Print...",
|
||
"Undo",
|
||
"Restore",
|
||
"Image Info",
|
||
"Quit",
|
||
(char *) NULL
|
||
},
|
||
*VirtualMenu[] =
|
||
{
|
||
"Image Info",
|
||
"Print",
|
||
"Next",
|
||
"Quit",
|
||
(char *) NULL
|
||
};
|
||
|
||
static const char
|
||
**Menus[MagickMenus] =
|
||
{
|
||
FileMenu,
|
||
EditMenu,
|
||
ViewMenu,
|
||
TransformMenu,
|
||
EnhanceMenu,
|
||
EffectsMenu,
|
||
FXMenu,
|
||
ImageEditMenu,
|
||
MiscellanyMenu,
|
||
HelpMenu
|
||
};
|
||
|
||
static CommandType
|
||
CommandMenus[] =
|
||
{
|
||
NullCommand,
|
||
NullCommand,
|
||
NullCommand,
|
||
NullCommand,
|
||
NullCommand,
|
||
NullCommand,
|
||
NullCommand,
|
||
NullCommand,
|
||
NullCommand,
|
||
NullCommand,
|
||
},
|
||
FileCommands[] =
|
||
{
|
||
OpenCommand,
|
||
NextCommand,
|
||
FormerCommand,
|
||
SelectCommand,
|
||
SaveCommand,
|
||
PrintCommand,
|
||
DeleteCommand,
|
||
NewCommand,
|
||
VisualDirectoryCommand,
|
||
QuitCommand
|
||
},
|
||
EditCommands[] =
|
||
{
|
||
UndoCommand,
|
||
RedoCommand,
|
||
CutCommand,
|
||
CopyCommand,
|
||
PasteCommand
|
||
},
|
||
ViewCommands[] =
|
||
{
|
||
HalfSizeCommand,
|
||
OriginalSizeCommand,
|
||
DoubleSizeCommand,
|
||
ResizeCommand,
|
||
ApplyCommand,
|
||
RefreshCommand,
|
||
RestoreCommand
|
||
},
|
||
TransformCommands[] =
|
||
{
|
||
CropCommand,
|
||
ChopCommand,
|
||
FlopCommand,
|
||
FlipCommand,
|
||
RotateRightCommand,
|
||
RotateLeftCommand,
|
||
RotateCommand,
|
||
ShearCommand,
|
||
RollCommand,
|
||
TrimCommand
|
||
},
|
||
EnhanceCommands[] =
|
||
{
|
||
HueCommand,
|
||
SaturationCommand,
|
||
BrightnessCommand,
|
||
GammaCommand,
|
||
SpiffCommand,
|
||
DullCommand,
|
||
ContrastStretchCommand,
|
||
SigmoidalContrastCommand,
|
||
NormalizeCommand,
|
||
EqualizeCommand,
|
||
NegateCommand,
|
||
GrayscaleCommand,
|
||
MapCommand,
|
||
QuantizeCommand
|
||
},
|
||
EffectsCommands[] =
|
||
{
|
||
DespeckleCommand,
|
||
EmbossCommand,
|
||
ReduceNoiseCommand,
|
||
AddNoiseCommand,
|
||
SharpenCommand,
|
||
BlurCommand,
|
||
ThresholdCommand,
|
||
EdgeDetectCommand,
|
||
SpreadCommand,
|
||
ShadeCommand,
|
||
RaiseCommand,
|
||
SegmentCommand
|
||
},
|
||
FXCommands[] =
|
||
{
|
||
SolarizeCommand,
|
||
SepiaToneCommand,
|
||
SwirlCommand,
|
||
ImplodeCommand,
|
||
VignetteCommand,
|
||
WaveCommand,
|
||
OilPaintCommand,
|
||
CharcoalDrawCommand
|
||
},
|
||
ImageEditCommands[] =
|
||
{
|
||
AnnotateCommand,
|
||
DrawCommand,
|
||
ColorCommand,
|
||
MatteCommand,
|
||
CompositeCommand,
|
||
AddBorderCommand,
|
||
AddFrameCommand,
|
||
CommentCommand,
|
||
LaunchCommand,
|
||
RegionofInterestCommand
|
||
},
|
||
MiscellanyCommands[] =
|
||
{
|
||
InfoCommand,
|
||
ZoomCommand,
|
||
ShowPreviewCommand,
|
||
ShowHistogramCommand,
|
||
ShowMatteCommand,
|
||
BackgroundCommand,
|
||
SlideShowCommand,
|
||
PreferencesCommand
|
||
},
|
||
HelpCommands[] =
|
||
{
|
||
HelpCommand,
|
||
BrowseDocumentationCommand,
|
||
VersionCommand
|
||
},
|
||
ShortCutsCommands[] =
|
||
{
|
||
NextCommand,
|
||
FormerCommand,
|
||
OpenCommand,
|
||
SaveCommand,
|
||
PrintCommand,
|
||
UndoCommand,
|
||
RestoreCommand,
|
||
InfoCommand,
|
||
QuitCommand
|
||
},
|
||
VirtualCommands[] =
|
||
{
|
||
InfoCommand,
|
||
PrintCommand,
|
||
NextCommand,
|
||
QuitCommand
|
||
};
|
||
|
||
static CommandType
|
||
*Commands[MagickMenus] =
|
||
{
|
||
FileCommands,
|
||
EditCommands,
|
||
ViewCommands,
|
||
TransformCommands,
|
||
EnhanceCommands,
|
||
EffectsCommands,
|
||
FXCommands,
|
||
ImageEditCommands,
|
||
MiscellanyCommands,
|
||
HelpCommands
|
||
};
|
||
|
||
char
|
||
command[MaxTextExtent],
|
||
*directory,
|
||
geometry[MaxTextExtent],
|
||
resource_name[MaxTextExtent];
|
||
|
||
CommandType
|
||
command_type;
|
||
|
||
Image
|
||
*display_image,
|
||
*nexus;
|
||
|
||
int
|
||
entry,
|
||
id;
|
||
|
||
KeySym
|
||
key_symbol;
|
||
|
||
MagickStatusType
|
||
context_mask,
|
||
status;
|
||
|
||
RectangleInfo
|
||
geometry_info;
|
||
|
||
register int
|
||
i;
|
||
|
||
static char
|
||
working_directory[MaxTextExtent];
|
||
|
||
static XPoint
|
||
vid_info;
|
||
|
||
static XWindowInfo
|
||
*magick_windows[MaxXWindows];
|
||
|
||
static unsigned int
|
||
number_windows;
|
||
|
||
struct stat
|
||
attributes;
|
||
|
||
time_t
|
||
timer,
|
||
timestamp,
|
||
update_time;
|
||
|
||
unsigned int
|
||
height,
|
||
width;
|
||
|
||
size_t
|
||
delay;
|
||
|
||
WarningHandler
|
||
warning_handler;
|
||
|
||
Window
|
||
root_window;
|
||
|
||
XClassHint
|
||
*class_hints;
|
||
|
||
XEvent
|
||
event;
|
||
|
||
XFontStruct
|
||
*font_info;
|
||
|
||
XGCValues
|
||
context_values;
|
||
|
||
XPixelInfo
|
||
*icon_pixel,
|
||
*pixel;
|
||
|
||
XResourceInfo
|
||
*icon_resources;
|
||
|
||
XStandardColormap
|
||
*icon_map,
|
||
*map_info;
|
||
|
||
XVisualInfo
|
||
*icon_visual,
|
||
*visual_info;
|
||
|
||
XWindowChanges
|
||
window_changes;
|
||
|
||
XWindows
|
||
*windows;
|
||
|
||
XWMHints
|
||
*manager_hints;
|
||
|
||
assert(image != (Image **) NULL);
|
||
assert((*image)->signature == MagickSignature);
|
||
if ((*image)->debug != MagickFalse)
|
||
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
|
||
display_image=(*image);
|
||
warning_handler=(WarningHandler) NULL;
|
||
windows=XSetWindows((XWindows *) ~0);
|
||
if (windows != (XWindows *) NULL)
|
||
{
|
||
int
|
||
status;
|
||
|
||
if (*working_directory == '\0')
|
||
(void) CopyMagickString(working_directory,".",MaxTextExtent);
|
||
status=chdir(working_directory);
|
||
if (status == -1)
|
||
(void) ThrowMagickException(&(*image)->exception,GetMagickModule(),
|
||
FileOpenError,"UnableToOpenFile","%s",working_directory);
|
||
warning_handler=resource_info->display_warnings ?
|
||
SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
|
||
warning_handler=resource_info->display_warnings ?
|
||
SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
Allocate windows structure.
|
||
*/
|
||
resource_info->colors=display_image->colors;
|
||
windows=XSetWindows(XInitializeWindows(display,resource_info));
|
||
if (windows == (XWindows *) NULL)
|
||
ThrowXWindowFatalException(XServerFatalError,"UnableToCreateWindow",
|
||
(*image)->filename);
|
||
/*
|
||
Initialize window id's.
|
||
*/
|
||
number_windows=0;
|
||
magick_windows[number_windows++]=(&windows->icon);
|
||
magick_windows[number_windows++]=(&windows->backdrop);
|
||
magick_windows[number_windows++]=(&windows->image);
|
||
magick_windows[number_windows++]=(&windows->info);
|
||
magick_windows[number_windows++]=(&windows->command);
|
||
magick_windows[number_windows++]=(&windows->widget);
|
||
magick_windows[number_windows++]=(&windows->popup);
|
||
magick_windows[number_windows++]=(&windows->magnify);
|
||
magick_windows[number_windows++]=(&windows->pan);
|
||
for (i=0; i < (int) number_windows; i++)
|
||
magick_windows[i]->id=(Window) NULL;
|
||
vid_info.x=0;
|
||
vid_info.y=0;
|
||
}
|
||
/*
|
||
Initialize font info.
|
||
*/
|
||
if (windows->font_info != (XFontStruct *) NULL)
|
||
(void) XFreeFont(display,windows->font_info);
|
||
windows->font_info=XBestFont(display,resource_info,MagickFalse);
|
||
if (windows->font_info == (XFontStruct *) NULL)
|
||
ThrowXWindowFatalException(XServerFatalError,"UnableToLoadFont",
|
||
resource_info->font);
|
||
/*
|
||
Initialize Standard Colormap.
|
||
*/
|
||
map_info=windows->map_info;
|
||
icon_map=windows->icon_map;
|
||
visual_info=windows->visual_info;
|
||
icon_visual=windows->icon_visual;
|
||
pixel=windows->pixel_info;
|
||
icon_pixel=windows->icon_pixel;
|
||
font_info=windows->font_info;
|
||
icon_resources=windows->icon_resources;
|
||
class_hints=windows->class_hints;
|
||
manager_hints=windows->manager_hints;
|
||
root_window=XRootWindow(display,visual_info->screen);
|
||
nexus=NewImageList();
|
||
if (display_image->debug != MagickFalse)
|
||
{
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Image: %s[%.20g] %.20gx%.20g ",display_image->filename,
|
||
(double) display_image->scene,(double) display_image->columns,
|
||
(double) display_image->rows);
|
||
if (display_image->colors != 0)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),"%.20gc ",(double)
|
||
display_image->colors);
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
|
||
display_image->magick);
|
||
}
|
||
XMakeStandardColormap(display,visual_info,resource_info,display_image,
|
||
map_info,pixel);
|
||
display_image->taint=MagickFalse;
|
||
/*
|
||
Initialize graphic context.
|
||
*/
|
||
windows->context.id=(Window) NULL;
|
||
XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
|
||
resource_info,&windows->context);
|
||
(void) CloneString(&class_hints->res_name,resource_info->client_name);
|
||
(void) CloneString(&class_hints->res_class,resource_info->client_name);
|
||
class_hints->res_class[0]=(char) toupper((int) class_hints->res_class[0]);
|
||
manager_hints->flags=InputHint | StateHint;
|
||
manager_hints->input=MagickFalse;
|
||
manager_hints->initial_state=WithdrawnState;
|
||
XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
|
||
&windows->context);
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Window id: 0x%lx (context)",windows->context.id);
|
||
context_values.background=pixel->background_color.pixel;
|
||
context_values.font=font_info->fid;
|
||
context_values.foreground=pixel->foreground_color.pixel;
|
||
context_values.graphics_exposures=MagickFalse;
|
||
context_mask=(MagickStatusType)
|
||
(GCBackground | GCFont | GCForeground | GCGraphicsExposures);
|
||
if (pixel->annotate_context != (GC) NULL)
|
||
(void) XFreeGC(display,pixel->annotate_context);
|
||
pixel->annotate_context=XCreateGC(display,windows->context.id,
|
||
context_mask,&context_values);
|
||
if (pixel->annotate_context == (GC) NULL)
|
||
ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
|
||
display_image->filename);
|
||
context_values.background=pixel->depth_color.pixel;
|
||
if (pixel->widget_context != (GC) NULL)
|
||
(void) XFreeGC(display,pixel->widget_context);
|
||
pixel->widget_context=XCreateGC(display,windows->context.id,context_mask,
|
||
&context_values);
|
||
if (pixel->widget_context == (GC) NULL)
|
||
ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
|
||
display_image->filename);
|
||
context_values.background=pixel->foreground_color.pixel;
|
||
context_values.foreground=pixel->background_color.pixel;
|
||
context_values.plane_mask=context_values.background ^
|
||
context_values.foreground;
|
||
if (pixel->highlight_context != (GC) NULL)
|
||
(void) XFreeGC(display,pixel->highlight_context);
|
||
pixel->highlight_context=XCreateGC(display,windows->context.id,
|
||
(size_t) (context_mask | GCPlaneMask),&context_values);
|
||
if (pixel->highlight_context == (GC) NULL)
|
||
ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
|
||
display_image->filename);
|
||
(void) XDestroyWindow(display,windows->context.id);
|
||
/*
|
||
Initialize icon window.
|
||
*/
|
||
XGetWindowInfo(display,icon_visual,icon_map,icon_pixel,(XFontStruct *) NULL,
|
||
icon_resources,&windows->icon);
|
||
windows->icon.geometry=resource_info->icon_geometry;
|
||
XBestIconSize(display,&windows->icon,display_image);
|
||
windows->icon.attributes.colormap=XDefaultColormap(display,
|
||
icon_visual->screen);
|
||
windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
|
||
manager_hints->flags=InputHint | StateHint;
|
||
manager_hints->input=MagickFalse;
|
||
manager_hints->initial_state=IconicState;
|
||
XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
|
||
&windows->icon);
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (icon)",
|
||
windows->icon.id);
|
||
/*
|
||
Initialize graphic context for icon window.
|
||
*/
|
||
if (icon_pixel->annotate_context != (GC) NULL)
|
||
(void) XFreeGC(display,icon_pixel->annotate_context);
|
||
context_values.background=icon_pixel->background_color.pixel;
|
||
context_values.foreground=icon_pixel->foreground_color.pixel;
|
||
icon_pixel->annotate_context=XCreateGC(display,windows->icon.id,
|
||
(size_t) (GCBackground | GCForeground),&context_values);
|
||
if (icon_pixel->annotate_context == (GC) NULL)
|
||
ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
|
||
display_image->filename);
|
||
windows->icon.annotate_context=icon_pixel->annotate_context;
|
||
/*
|
||
Initialize Image window.
|
||
*/
|
||
XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
|
||
&windows->image);
|
||
windows->image.shape=MagickTrue; /* non-rectangular shape hint */
|
||
if (resource_info->use_shared_memory == MagickFalse)
|
||
windows->image.shared_memory=MagickFalse;
|
||
if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
|
||
{
|
||
char
|
||
*title;
|
||
|
||
title=InterpretImageProperties(resource_info->image_info,display_image,
|
||
resource_info->title);
|
||
(void) CopyMagickString(windows->image.name,title,MaxTextExtent);
|
||
(void) CopyMagickString(windows->image.icon_name,title,MaxTextExtent);
|
||
title=DestroyString(title);
|
||
}
|
||
else
|
||
{
|
||
char
|
||
filename[MaxTextExtent];
|
||
|
||
/*
|
||
Window name is the base of the filename.
|
||
*/
|
||
GetPathComponent(display_image->magick_filename,TailPath,filename);
|
||
if (display_image->scene == 0)
|
||
(void) FormatLocaleString(windows->image.name,MaxTextExtent,
|
||
"%s: %s",MagickPackageName,filename);
|
||
else
|
||
(void) FormatLocaleString(windows->image.name,MaxTextExtent,
|
||
"%s: %s[scene: %.20g frames: %.20g]",MagickPackageName,filename,
|
||
(double) display_image->scene,(double) GetImageListLength(
|
||
display_image));
|
||
(void) CopyMagickString(windows->image.icon_name,filename,MaxTextExtent);
|
||
}
|
||
if (resource_info->immutable)
|
||
windows->image.immutable=MagickTrue;
|
||
windows->image.use_pixmap=resource_info->use_pixmap;
|
||
windows->image.geometry=resource_info->image_geometry;
|
||
(void) FormatLocaleString(geometry,MaxTextExtent,"%ux%u+0+0>!",
|
||
XDisplayWidth(display,visual_info->screen),
|
||
XDisplayHeight(display,visual_info->screen));
|
||
geometry_info.width=display_image->columns;
|
||
geometry_info.height=display_image->rows;
|
||
geometry_info.x=0;
|
||
geometry_info.y=0;
|
||
(void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
|
||
&geometry_info.width,&geometry_info.height);
|
||
windows->image.width=(unsigned int) geometry_info.width;
|
||
windows->image.height=(unsigned int) geometry_info.height;
|
||
windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
|
||
ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
|
||
KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
|
||
PropertyChangeMask | StructureNotifyMask | SubstructureNotifyMask;
|
||
XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
|
||
resource_info,&windows->backdrop);
|
||
if ((resource_info->backdrop) || (windows->backdrop.id != (Window) NULL))
|
||
{
|
||
/*
|
||
Initialize backdrop window.
|
||
*/
|
||
windows->backdrop.x=0;
|
||
windows->backdrop.y=0;
|
||
(void) CloneString(&windows->backdrop.name,"Backdrop");
|
||
windows->backdrop.flags=(size_t) (USSize | USPosition);
|
||
windows->backdrop.width=(unsigned int)
|
||
XDisplayWidth(display,visual_info->screen);
|
||
windows->backdrop.height=(unsigned int)
|
||
XDisplayHeight(display,visual_info->screen);
|
||
windows->backdrop.border_width=0;
|
||
windows->backdrop.immutable=MagickTrue;
|
||
windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
|
||
ButtonReleaseMask;
|
||
windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
|
||
StructureNotifyMask;
|
||
manager_hints->flags=IconWindowHint | InputHint | StateHint;
|
||
manager_hints->icon_window=windows->icon.id;
|
||
manager_hints->input=MagickTrue;
|
||
manager_hints->initial_state=resource_info->iconic ? IconicState :
|
||
NormalState;
|
||
XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
|
||
&windows->backdrop);
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Window id: 0x%lx (backdrop)",windows->backdrop.id);
|
||
(void) XMapWindow(display,windows->backdrop.id);
|
||
(void) XClearWindow(display,windows->backdrop.id);
|
||
if (windows->image.id != (Window) NULL)
|
||
{
|
||
(void) XDestroyWindow(display,windows->image.id);
|
||
windows->image.id=(Window) NULL;
|
||
}
|
||
/*
|
||
Position image in the center the backdrop.
|
||
*/
|
||
windows->image.flags|=USPosition;
|
||
windows->image.x=(XDisplayWidth(display,visual_info->screen)/2)-
|
||
(windows->image.width/2);
|
||
windows->image.y=(XDisplayHeight(display,visual_info->screen)/2)-
|
||
(windows->image.height/2);
|
||
}
|
||
manager_hints->flags=IconWindowHint | InputHint | StateHint;
|
||
manager_hints->icon_window=windows->icon.id;
|
||
manager_hints->input=MagickTrue;
|
||
manager_hints->initial_state=resource_info->iconic ? IconicState :
|
||
NormalState;
|
||
if (windows->group_leader.id != (Window) NULL)
|
||
{
|
||
/*
|
||
Follow the leader.
|
||
*/
|
||
manager_hints->flags|=WindowGroupHint;
|
||
manager_hints->window_group=windows->group_leader.id;
|
||
(void) XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Window id: 0x%lx (group leader)",windows->group_leader.id);
|
||
}
|
||
XMakeWindow(display,
|
||
(Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
|
||
argv,argc,class_hints,manager_hints,&windows->image);
|
||
(void) XChangeProperty(display,windows->image.id,windows->im_protocols,
|
||
XA_STRING,8,PropModeReplace,(unsigned char *) NULL,0);
|
||
if (windows->group_leader.id != (Window) NULL)
|
||
(void) XSetTransientForHint(display,windows->image.id,
|
||
windows->group_leader.id);
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (image)",
|
||
windows->image.id);
|
||
/*
|
||
Initialize Info widget.
|
||
*/
|
||
XGetWindowInfo(display,visual_info,map_info,pixel,font_info,resource_info,
|
||
&windows->info);
|
||
(void) CloneString(&windows->info.name,"Info");
|
||
(void) CloneString(&windows->info.icon_name,"Info");
|
||
windows->info.border_width=1;
|
||
windows->info.x=2;
|
||
windows->info.y=2;
|
||
windows->info.flags|=PPosition;
|
||
windows->info.attributes.win_gravity=UnmapGravity;
|
||
windows->info.attributes.event_mask=ButtonPressMask | ExposureMask |
|
||
StructureNotifyMask;
|
||
manager_hints->flags=InputHint | StateHint | WindowGroupHint;
|
||
manager_hints->input=MagickFalse;
|
||
manager_hints->initial_state=NormalState;
|
||
manager_hints->window_group=windows->image.id;
|
||
XMakeWindow(display,windows->image.id,argv,argc,class_hints,manager_hints,
|
||
&windows->info);
|
||
windows->info.highlight_stipple=XCreateBitmapFromData(display,
|
||
windows->info.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
|
||
windows->info.shadow_stipple=XCreateBitmapFromData(display,
|
||
windows->info.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
|
||
(void) XSetTransientForHint(display,windows->info.id,windows->image.id);
|
||
if (windows->image.mapped != MagickFalse)
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (info)",
|
||
windows->info.id);
|
||
/*
|
||
Initialize Command widget.
|
||
*/
|
||
XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
|
||
resource_info,&windows->command);
|
||
windows->command.data=MagickMenus;
|
||
(void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
|
||
(void) FormatLocaleString(resource_name,MaxTextExtent,"%s.command",
|
||
resource_info->client_name);
|
||
windows->command.geometry=XGetResourceClass(resource_info->resource_database,
|
||
resource_name,"geometry",(char *) NULL);
|
||
(void) CloneString(&windows->command.name,MagickTitle);
|
||
windows->command.border_width=0;
|
||
windows->command.flags|=PPosition;
|
||
windows->command.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
|
||
ButtonReleaseMask | EnterWindowMask | ExposureMask | LeaveWindowMask |
|
||
OwnerGrabButtonMask | StructureNotifyMask;
|
||
manager_hints->flags=InputHint | StateHint | WindowGroupHint;
|
||
manager_hints->input=MagickTrue;
|
||
manager_hints->initial_state=NormalState;
|
||
manager_hints->window_group=windows->image.id;
|
||
XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
|
||
&windows->command);
|
||
windows->command.highlight_stipple=XCreateBitmapFromData(display,
|
||
windows->command.id,(char *) HighlightBitmap,HighlightWidth,
|
||
HighlightHeight);
|
||
windows->command.shadow_stipple=XCreateBitmapFromData(display,
|
||
windows->command.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
|
||
(void) XSetTransientForHint(display,windows->command.id,windows->image.id);
|
||
if (windows->command.mapped != MagickFalse)
|
||
(void) XMapRaised(display,windows->command.id);
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Window id: 0x%lx (command)",windows->command.id);
|
||
/*
|
||
Initialize Widget window.
|
||
*/
|
||
XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
|
||
resource_info,&windows->widget);
|
||
(void) FormatLocaleString(resource_name,MaxTextExtent,"%s.widget",
|
||
resource_info->client_name);
|
||
windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
|
||
resource_name,"geometry",(char *) NULL);
|
||
windows->widget.border_width=0;
|
||
windows->widget.flags|=PPosition;
|
||
windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
|
||
ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
|
||
KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
|
||
StructureNotifyMask;
|
||
manager_hints->flags=InputHint | StateHint | WindowGroupHint;
|
||
manager_hints->input=MagickTrue;
|
||
manager_hints->initial_state=NormalState;
|
||
manager_hints->window_group=windows->image.id;
|
||
XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
|
||
&windows->widget);
|
||
windows->widget.highlight_stipple=XCreateBitmapFromData(display,
|
||
windows->widget.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
|
||
windows->widget.shadow_stipple=XCreateBitmapFromData(display,
|
||
windows->widget.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
|
||
(void) XSetTransientForHint(display,windows->widget.id,windows->image.id);
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Window id: 0x%lx (widget)",windows->widget.id);
|
||
/*
|
||
Initialize popup window.
|
||
*/
|
||
XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
|
||
resource_info,&windows->popup);
|
||
windows->popup.border_width=0;
|
||
windows->popup.flags|=PPosition;
|
||
windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
|
||
ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
|
||
KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
|
||
manager_hints->flags=InputHint | StateHint | WindowGroupHint;
|
||
manager_hints->input=MagickTrue;
|
||
manager_hints->initial_state=NormalState;
|
||
manager_hints->window_group=windows->image.id;
|
||
XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
|
||
&windows->popup);
|
||
windows->popup.highlight_stipple=XCreateBitmapFromData(display,
|
||
windows->popup.id,(char *) HighlightBitmap,HighlightWidth,HighlightHeight);
|
||
windows->popup.shadow_stipple=XCreateBitmapFromData(display,
|
||
windows->popup.id,(char *) ShadowBitmap,ShadowWidth,ShadowHeight);
|
||
(void) XSetTransientForHint(display,windows->popup.id,windows->image.id);
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Window id: 0x%lx (pop up)",windows->popup.id);
|
||
/*
|
||
Initialize Magnify window and cursor.
|
||
*/
|
||
XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
|
||
resource_info,&windows->magnify);
|
||
if (resource_info->use_shared_memory == MagickFalse)
|
||
windows->magnify.shared_memory=MagickFalse;
|
||
(void) FormatLocaleString(resource_name,MaxTextExtent,"%s.magnify",
|
||
resource_info->client_name);
|
||
windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
|
||
resource_name,"geometry",(char *) NULL);
|
||
(void) FormatLocaleString(windows->magnify.name,MaxTextExtent,"Magnify %uX",
|
||
resource_info->magnify);
|
||
if (windows->magnify.cursor != (Cursor) NULL)
|
||
(void) XFreeCursor(display,windows->magnify.cursor);
|
||
windows->magnify.cursor=XMakeCursor(display,windows->image.id,
|
||
map_info->colormap,resource_info->background_color,
|
||
resource_info->foreground_color);
|
||
if (windows->magnify.cursor == (Cursor) NULL)
|
||
ThrowXWindowFatalException(XServerFatalError,"UnableToCreateCursor",
|
||
display_image->filename);
|
||
windows->magnify.width=MagnifySize;
|
||
windows->magnify.height=MagnifySize;
|
||
windows->magnify.flags|=PPosition;
|
||
windows->magnify.min_width=MagnifySize;
|
||
windows->magnify.min_height=MagnifySize;
|
||
windows->magnify.width_inc=MagnifySize;
|
||
windows->magnify.height_inc=MagnifySize;
|
||
windows->magnify.data=resource_info->magnify;
|
||
windows->magnify.attributes.cursor=windows->magnify.cursor;
|
||
windows->magnify.attributes.event_mask=ButtonPressMask | ButtonReleaseMask |
|
||
ExposureMask | KeyPressMask | KeyReleaseMask | OwnerGrabButtonMask |
|
||
StructureNotifyMask;
|
||
manager_hints->flags=InputHint | StateHint | WindowGroupHint;
|
||
manager_hints->input=MagickTrue;
|
||
manager_hints->initial_state=NormalState;
|
||
manager_hints->window_group=windows->image.id;
|
||
XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
|
||
&windows->magnify);
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Window id: 0x%lx (magnify)",windows->magnify.id);
|
||
(void) XSetTransientForHint(display,windows->magnify.id,windows->image.id);
|
||
/*
|
||
Initialize panning window.
|
||
*/
|
||
XGetWindowInfo(display,visual_info,map_info,pixel,font_info,
|
||
resource_info,&windows->pan);
|
||
(void) CloneString(&windows->pan.name,"Pan Icon");
|
||
windows->pan.width=windows->icon.width;
|
||
windows->pan.height=windows->icon.height;
|
||
(void) FormatLocaleString(resource_name,MaxTextExtent,"%s.pan",
|
||
resource_info->client_name);
|
||
windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
|
||
resource_name,"geometry",(char *) NULL);
|
||
(void) XParseGeometry(windows->pan.geometry,&windows->pan.x,&windows->pan.y,
|
||
&windows->pan.width,&windows->pan.height);
|
||
windows->pan.flags|=PPosition;
|
||
windows->pan.immutable=MagickTrue;
|
||
windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
|
||
ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
|
||
StructureNotifyMask;
|
||
manager_hints->flags=InputHint | StateHint | WindowGroupHint;
|
||
manager_hints->input=MagickFalse;
|
||
manager_hints->initial_state=NormalState;
|
||
manager_hints->window_group=windows->image.id;
|
||
XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
|
||
&windows->pan);
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),"Window id: 0x%lx (pan)",
|
||
windows->pan.id);
|
||
(void) XSetTransientForHint(display,windows->pan.id,windows->image.id);
|
||
if (windows->info.mapped != MagickFalse)
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
if ((windows->image.mapped == MagickFalse) ||
|
||
(windows->backdrop.id != (Window) NULL))
|
||
(void) XMapWindow(display,windows->image.id);
|
||
/*
|
||
Set our progress monitor and warning handlers.
|
||
*/
|
||
if (warning_handler == (WarningHandler) NULL)
|
||
{
|
||
warning_handler=resource_info->display_warnings ?
|
||
SetErrorHandler(XWarning) : SetErrorHandler((ErrorHandler) NULL);
|
||
warning_handler=resource_info->display_warnings ?
|
||
SetWarningHandler(XWarning) : SetWarningHandler((WarningHandler) NULL);
|
||
}
|
||
/*
|
||
Initialize Image and Magnify X images.
|
||
*/
|
||
windows->image.x=0;
|
||
windows->image.y=0;
|
||
windows->magnify.shape=MagickFalse;
|
||
width=(unsigned int) display_image->columns;
|
||
height=(unsigned int) display_image->rows;
|
||
if ((display_image->columns != width) || (display_image->rows != height))
|
||
ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
|
||
display_image->filename);
|
||
status=XMakeImage(display,resource_info,&windows->image,display_image,
|
||
width,height);
|
||
if (status == MagickFalse)
|
||
ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
|
||
display_image->filename);
|
||
status=XMakeImage(display,resource_info,&windows->magnify,(Image *) NULL,
|
||
windows->magnify.width,windows->magnify.height);
|
||
if (status == MagickFalse)
|
||
ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
|
||
display_image->filename);
|
||
if (windows->magnify.mapped != MagickFalse)
|
||
(void) XMapRaised(display,windows->magnify.id);
|
||
if (windows->pan.mapped != MagickFalse)
|
||
(void) XMapRaised(display,windows->pan.id);
|
||
windows->image.window_changes.width=(int) display_image->columns;
|
||
windows->image.window_changes.height=(int) display_image->rows;
|
||
(void) XConfigureImage(display,resource_info,windows,display_image);
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
(void) XSync(display,MagickFalse);
|
||
/*
|
||
Respond to events.
|
||
*/
|
||
delay=display_image->delay/MagickMax(display_image->ticks_per_second,1L);
|
||
timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
|
||
update_time=0;
|
||
if (resource_info->update != MagickFalse)
|
||
{
|
||
MagickBooleanType
|
||
status;
|
||
|
||
/*
|
||
Determine when file data was last modified.
|
||
*/
|
||
status=GetPathAttributes(display_image->filename,&attributes);
|
||
if (status != MagickFalse)
|
||
update_time=attributes.st_mtime;
|
||
}
|
||
*state&=(~FormerImageState);
|
||
*state&=(~MontageImageState);
|
||
*state&=(~NextImageState);
|
||
do
|
||
{
|
||
/*
|
||
Handle a window event.
|
||
*/
|
||
if (windows->image.mapped != MagickFalse)
|
||
if ((display_image->delay != 0) || (resource_info->update != 0))
|
||
{
|
||
if (timer < time((time_t *) NULL))
|
||
{
|
||
if (resource_info->update == MagickFalse)
|
||
*state|=NextImageState | ExitState;
|
||
else
|
||
{
|
||
MagickBooleanType
|
||
status;
|
||
|
||
/*
|
||
Determine if image file was modified.
|
||
*/
|
||
status=GetPathAttributes(display_image->filename,&attributes);
|
||
if (status != MagickFalse)
|
||
if (update_time != attributes.st_mtime)
|
||
{
|
||
/*
|
||
Redisplay image.
|
||
*/
|
||
(void) FormatLocaleString(
|
||
resource_info->image_info->filename,MaxTextExtent,
|
||
"%s:%s",display_image->magick,
|
||
display_image->filename);
|
||
nexus=ReadImage(resource_info->image_info,
|
||
&display_image->exception);
|
||
if (nexus != (Image *) NULL)
|
||
{
|
||
nexus=DestroyImage(nexus);
|
||
*state|=NextImageState | ExitState;
|
||
}
|
||
}
|
||
delay=display_image->delay/MagickMax(
|
||
display_image->ticks_per_second,1L);
|
||
timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
|
||
}
|
||
}
|
||
if (XEventsQueued(display,QueuedAfterFlush) == 0)
|
||
{
|
||
/*
|
||
Do not block if delay > 0.
|
||
*/
|
||
XDelay(display,SuspendTime << 2);
|
||
continue;
|
||
}
|
||
}
|
||
timestamp=time((time_t *) NULL);
|
||
(void) XNextEvent(display,&event);
|
||
if (windows->image.stasis == MagickFalse)
|
||
windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
|
||
MagickTrue : MagickFalse;
|
||
if (windows->magnify.stasis == MagickFalse)
|
||
windows->magnify.stasis=(time((time_t *) NULL)-timestamp) > 0 ?
|
||
MagickTrue : MagickFalse;
|
||
if (event.xany.window == windows->command.id)
|
||
{
|
||
/*
|
||
Select a command from the Command widget.
|
||
*/
|
||
id=XCommandWidget(display,windows,CommandMenu,&event);
|
||
if (id < 0)
|
||
continue;
|
||
(void) CopyMagickString(command,CommandMenu[id],MaxTextExtent);
|
||
command_type=CommandMenus[id];
|
||
if (id < MagickMenus)
|
||
{
|
||
/*
|
||
Select a command from a pop-up menu.
|
||
*/
|
||
entry=XMenuWidget(display,windows,CommandMenu[id],Menus[id],
|
||
command);
|
||
if (entry < 0)
|
||
continue;
|
||
(void) CopyMagickString(command,Menus[id][entry],MaxTextExtent);
|
||
command_type=Commands[id][entry];
|
||
}
|
||
if (command_type != NullCommand)
|
||
nexus=XMagickCommand(display,resource_info,windows,command_type,
|
||
&display_image);
|
||
continue;
|
||
}
|
||
switch (event.type)
|
||
{
|
||
case ButtonPress:
|
||
{
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Button Press: 0x%lx %u +%d+%d",event.xbutton.window,
|
||
event.xbutton.button,event.xbutton.x,event.xbutton.y);
|
||
if ((event.xbutton.button == Button3) &&
|
||
(event.xbutton.state & Mod1Mask))
|
||
{
|
||
/*
|
||
Convert Alt-Button3 to Button2.
|
||
*/
|
||
event.xbutton.button=Button2;
|
||
event.xbutton.state&=(~Mod1Mask);
|
||
}
|
||
if (event.xbutton.window == windows->backdrop.id)
|
||
{
|
||
(void) XSetInputFocus(display,event.xbutton.window,RevertToParent,
|
||
event.xbutton.time);
|
||
break;
|
||
}
|
||
if (event.xbutton.window == windows->image.id)
|
||
{
|
||
switch (event.xbutton.button)
|
||
{
|
||
case Button1:
|
||
{
|
||
if (resource_info->immutable)
|
||
{
|
||
/*
|
||
Select a command from the Virtual menu.
|
||
*/
|
||
entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
|
||
command);
|
||
if (entry >= 0)
|
||
nexus=XMagickCommand(display,resource_info,windows,
|
||
VirtualCommands[entry],&display_image);
|
||
break;
|
||
}
|
||
/*
|
||
Map/unmap Command widget.
|
||
*/
|
||
if (windows->command.mapped != MagickFalse)
|
||
(void) XWithdrawWindow(display,windows->command.id,
|
||
windows->command.screen);
|
||
else
|
||
{
|
||
(void) XCommandWidget(display,windows,CommandMenu,
|
||
(XEvent *) NULL);
|
||
(void) XMapRaised(display,windows->command.id);
|
||
}
|
||
break;
|
||
}
|
||
case Button2:
|
||
{
|
||
/*
|
||
User pressed the image magnify button.
|
||
*/
|
||
(void) XMagickCommand(display,resource_info,windows,ZoomCommand,
|
||
&display_image);
|
||
XMagnifyImage(display,windows,&event);
|
||
break;
|
||
}
|
||
case Button3:
|
||
{
|
||
if (resource_info->immutable)
|
||
{
|
||
/*
|
||
Select a command from the Virtual menu.
|
||
*/
|
||
entry=XMenuWidget(display,windows,"Commands",VirtualMenu,
|
||
command);
|
||
if (entry >= 0)
|
||
nexus=XMagickCommand(display,resource_info,windows,
|
||
VirtualCommands[entry],&display_image);
|
||
break;
|
||
}
|
||
if (display_image->montage != (char *) NULL)
|
||
{
|
||
/*
|
||
Open or delete a tile from a visual image directory.
|
||
*/
|
||
nexus=XTileImage(display,resource_info,windows,
|
||
display_image,&event);
|
||
if (nexus != (Image *) NULL)
|
||
*state|=MontageImageState | NextImageState | ExitState;
|
||
vid_info.x=(short int) windows->image.x;
|
||
vid_info.y=(short int) windows->image.y;
|
||
break;
|
||
}
|
||
/*
|
||
Select a command from the Short Cuts menu.
|
||
*/
|
||
entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
|
||
command);
|
||
if (entry >= 0)
|
||
nexus=XMagickCommand(display,resource_info,windows,
|
||
ShortCutsCommands[entry],&display_image);
|
||
break;
|
||
}
|
||
case Button4:
|
||
{
|
||
/*
|
||
Wheel up.
|
||
*/
|
||
XTranslateImage(display,windows,*image,XK_Up);
|
||
break;
|
||
}
|
||
case Button5:
|
||
{
|
||
/*
|
||
Wheel down.
|
||
*/
|
||
XTranslateImage(display,windows,*image,XK_Down);
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
if (event.xbutton.window == windows->magnify.id)
|
||
{
|
||
int
|
||
factor;
|
||
|
||
static const char
|
||
*MagnifyMenu[] =
|
||
{
|
||
"2",
|
||
"4",
|
||
"5",
|
||
"6",
|
||
"7",
|
||
"8",
|
||
"9",
|
||
"3",
|
||
(char *) NULL,
|
||
};
|
||
|
||
static KeySym
|
||
MagnifyCommands[] =
|
||
{
|
||
XK_2,
|
||
XK_4,
|
||
XK_5,
|
||
XK_6,
|
||
XK_7,
|
||
XK_8,
|
||
XK_9,
|
||
XK_3
|
||
};
|
||
|
||
/*
|
||
Select a magnify factor from the pop-up menu.
|
||
*/
|
||
factor=XMenuWidget(display,windows,"Magnify",MagnifyMenu,command);
|
||
if (factor >= 0)
|
||
XMagnifyWindowCommand(display,windows,0,MagnifyCommands[factor]);
|
||
break;
|
||
}
|
||
if (event.xbutton.window == windows->pan.id)
|
||
{
|
||
switch (event.xbutton.button)
|
||
{
|
||
case Button4:
|
||
{
|
||
/*
|
||
Wheel up.
|
||
*/
|
||
XTranslateImage(display,windows,*image,XK_Up);
|
||
break;
|
||
}
|
||
case Button5:
|
||
{
|
||
/*
|
||
Wheel down.
|
||
*/
|
||
XTranslateImage(display,windows,*image,XK_Down);
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
XPanImage(display,windows,&event);
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
delay=display_image->delay/MagickMax(display_image->ticks_per_second,
|
||
1L);
|
||
timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
|
||
break;
|
||
}
|
||
case ButtonRelease:
|
||
{
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Button Release: 0x%lx %u +%d+%d",event.xbutton.window,
|
||
event.xbutton.button,event.xbutton.x,event.xbutton.y);
|
||
break;
|
||
}
|
||
case ClientMessage:
|
||
{
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Client Message: 0x%lx 0x%lx %d 0x%lx",event.xclient.window,
|
||
event.xclient.message_type,event.xclient.format,(unsigned long)
|
||
event.xclient.data.l[0]);
|
||
if (event.xclient.message_type == windows->im_protocols)
|
||
{
|
||
if (*event.xclient.data.l == (long) windows->im_update_widget)
|
||
{
|
||
(void) CloneString(&windows->command.name,MagickTitle);
|
||
windows->command.data=MagickMenus;
|
||
(void) XCommandWidget(display,windows,CommandMenu,
|
||
(XEvent *) NULL);
|
||
break;
|
||
}
|
||
if (*event.xclient.data.l == (long) windows->im_update_colormap)
|
||
{
|
||
/*
|
||
Update graphic context and window colormap.
|
||
*/
|
||
for (i=0; i < (int) number_windows; i++)
|
||
{
|
||
if (magick_windows[i]->id == windows->icon.id)
|
||
continue;
|
||
context_values.background=pixel->background_color.pixel;
|
||
context_values.foreground=pixel->foreground_color.pixel;
|
||
(void) XChangeGC(display,magick_windows[i]->annotate_context,
|
||
context_mask,&context_values);
|
||
(void) XChangeGC(display,magick_windows[i]->widget_context,
|
||
context_mask,&context_values);
|
||
context_values.background=pixel->foreground_color.pixel;
|
||
context_values.foreground=pixel->background_color.pixel;
|
||
context_values.plane_mask=context_values.background ^
|
||
context_values.foreground;
|
||
(void) XChangeGC(display,magick_windows[i]->highlight_context,
|
||
(size_t) (context_mask | GCPlaneMask),
|
||
&context_values);
|
||
magick_windows[i]->attributes.background_pixel=
|
||
pixel->background_color.pixel;
|
||
magick_windows[i]->attributes.border_pixel=
|
||
pixel->border_color.pixel;
|
||
magick_windows[i]->attributes.colormap=map_info->colormap;
|
||
(void) XChangeWindowAttributes(display,magick_windows[i]->id,
|
||
(unsigned long) magick_windows[i]->mask,
|
||
&magick_windows[i]->attributes);
|
||
}
|
||
if (windows->pan.mapped != MagickFalse)
|
||
{
|
||
(void) XSetWindowBackgroundPixmap(display,windows->pan.id,
|
||
windows->pan.pixmap);
|
||
(void) XClearWindow(display,windows->pan.id);
|
||
XDrawPanRectangle(display,windows);
|
||
}
|
||
if (windows->backdrop.id != (Window) NULL)
|
||
(void) XInstallColormap(display,map_info->colormap);
|
||
break;
|
||
}
|
||
if (*event.xclient.data.l == (long) windows->im_former_image)
|
||
{
|
||
*state|=FormerImageState | ExitState;
|
||
break;
|
||
}
|
||
if (*event.xclient.data.l == (long) windows->im_next_image)
|
||
{
|
||
*state|=NextImageState | ExitState;
|
||
break;
|
||
}
|
||
if (*event.xclient.data.l == (long) windows->im_retain_colors)
|
||
{
|
||
*state|=RetainColorsState;
|
||
break;
|
||
}
|
||
if (*event.xclient.data.l == (long) windows->im_exit)
|
||
{
|
||
*state|=ExitState;
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
if (event.xclient.message_type == windows->dnd_protocols)
|
||
{
|
||
Atom
|
||
selection,
|
||
type;
|
||
|
||
int
|
||
format,
|
||
status;
|
||
|
||
unsigned char
|
||
*data;
|
||
|
||
unsigned long
|
||
after,
|
||
length;
|
||
|
||
/*
|
||
Display image named by the Drag-and-Drop selection.
|
||
*/
|
||
if ((*event.xclient.data.l != 2) && (*event.xclient.data.l != 128))
|
||
break;
|
||
selection=XInternAtom(display,"DndSelection",MagickFalse);
|
||
status=XGetWindowProperty(display,root_window,selection,0L,(long)
|
||
MaxTextExtent,MagickFalse,(Atom) AnyPropertyType,&type,&format,
|
||
&length,&after,&data);
|
||
if ((status != Success) || (length == 0))
|
||
break;
|
||
if (*event.xclient.data.l == 2)
|
||
{
|
||
/*
|
||
Offix DND.
|
||
*/
|
||
(void) CopyMagickString(resource_info->image_info->filename,
|
||
(char *) data,MaxTextExtent);
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
XDND.
|
||
*/
|
||
if (strncmp((char *) data, "file:", 5) != 0)
|
||
{
|
||
(void) XFree((void *) data);
|
||
break;
|
||
}
|
||
(void) CopyMagickString(resource_info->image_info->filename,
|
||
((char *) data)+5,MaxTextExtent);
|
||
}
|
||
nexus=ReadImage(resource_info->image_info,
|
||
&display_image->exception);
|
||
CatchException(&display_image->exception);
|
||
if (nexus != (Image *) NULL)
|
||
*state|=NextImageState | ExitState;
|
||
(void) XFree((void *) data);
|
||
break;
|
||
}
|
||
/*
|
||
If client window delete message, exit.
|
||
*/
|
||
if (event.xclient.message_type != windows->wm_protocols)
|
||
break;
|
||
if (*event.xclient.data.l != (long) windows->wm_delete_window)
|
||
break;
|
||
(void) XWithdrawWindow(display,event.xclient.window,
|
||
visual_info->screen);
|
||
if (event.xclient.window == windows->image.id)
|
||
{
|
||
*state|=ExitState;
|
||
break;
|
||
}
|
||
if (event.xclient.window == windows->pan.id)
|
||
{
|
||
/*
|
||
Restore original image size when pan window is deleted.
|
||
*/
|
||
windows->image.window_changes.width=windows->image.ximage->width;
|
||
windows->image.window_changes.height=windows->image.ximage->height;
|
||
(void) XConfigureImage(display,resource_info,windows,
|
||
display_image);
|
||
}
|
||
break;
|
||
}
|
||
case ConfigureNotify:
|
||
{
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Configure Notify: 0x%lx %dx%d+%d+%d %d",event.xconfigure.window,
|
||
event.xconfigure.width,event.xconfigure.height,event.xconfigure.x,
|
||
event.xconfigure.y,event.xconfigure.send_event);
|
||
if (event.xconfigure.window == windows->image.id)
|
||
{
|
||
/*
|
||
Image window has a new configuration.
|
||
*/
|
||
if (event.xconfigure.send_event != 0)
|
||
{
|
||
XWindowChanges
|
||
window_changes;
|
||
|
||
/*
|
||
Position the transient windows relative of the Image window.
|
||
*/
|
||
if (windows->command.geometry == (char *) NULL)
|
||
if (windows->command.mapped == MagickFalse)
|
||
{
|
||
windows->command.x=event.xconfigure.x-
|
||
windows->command.width-25;
|
||
windows->command.y=event.xconfigure.y;
|
||
XConstrainWindowPosition(display,&windows->command);
|
||
window_changes.x=windows->command.x;
|
||
window_changes.y=windows->command.y;
|
||
(void) XReconfigureWMWindow(display,windows->command.id,
|
||
windows->command.screen,(unsigned int) (CWX | CWY),
|
||
&window_changes);
|
||
}
|
||
if (windows->widget.geometry == (char *) NULL)
|
||
if (windows->widget.mapped == MagickFalse)
|
||
{
|
||
windows->widget.x=event.xconfigure.x+
|
||
event.xconfigure.width/10;
|
||
windows->widget.y=event.xconfigure.y+
|
||
event.xconfigure.height/10;
|
||
XConstrainWindowPosition(display,&windows->widget);
|
||
window_changes.x=windows->widget.x;
|
||
window_changes.y=windows->widget.y;
|
||
(void) XReconfigureWMWindow(display,windows->widget.id,
|
||
windows->widget.screen,(unsigned int) (CWX | CWY),
|
||
&window_changes);
|
||
}
|
||
if (windows->magnify.geometry == (char *) NULL)
|
||
if (windows->magnify.mapped == MagickFalse)
|
||
{
|
||
windows->magnify.x=event.xconfigure.x+
|
||
event.xconfigure.width+25;
|
||
windows->magnify.y=event.xconfigure.y;
|
||
XConstrainWindowPosition(display,&windows->magnify);
|
||
window_changes.x=windows->magnify.x;
|
||
window_changes.y=windows->magnify.y;
|
||
(void) XReconfigureWMWindow(display,windows->magnify.id,
|
||
windows->magnify.screen,(unsigned int) (CWX | CWY),
|
||
&window_changes);
|
||
}
|
||
if (windows->pan.geometry == (char *) NULL)
|
||
if (windows->pan.mapped == MagickFalse)
|
||
{
|
||
windows->pan.x=event.xconfigure.x+
|
||
event.xconfigure.width+25;
|
||
windows->pan.y=event.xconfigure.y+
|
||
windows->magnify.height+50;
|
||
XConstrainWindowPosition(display,&windows->pan);
|
||
window_changes.x=windows->pan.x;
|
||
window_changes.y=windows->pan.y;
|
||
(void) XReconfigureWMWindow(display,windows->pan.id,
|
||
windows->pan.screen,(unsigned int) (CWX | CWY),
|
||
&window_changes);
|
||
}
|
||
}
|
||
if ((event.xconfigure.width == (int) windows->image.width) &&
|
||
(event.xconfigure.height == (int) windows->image.height))
|
||
break;
|
||
windows->image.width=(unsigned int) event.xconfigure.width;
|
||
windows->image.height=(unsigned int) event.xconfigure.height;
|
||
windows->image.x=0;
|
||
windows->image.y=0;
|
||
if (display_image->montage != (char *) NULL)
|
||
{
|
||
windows->image.x=vid_info.x;
|
||
windows->image.y=vid_info.y;
|
||
}
|
||
if ((windows->image.mapped != MagickFalse) &&
|
||
(windows->image.stasis != MagickFalse))
|
||
{
|
||
/*
|
||
Update image window configuration.
|
||
*/
|
||
windows->image.window_changes.width=event.xconfigure.width;
|
||
windows->image.window_changes.height=event.xconfigure.height;
|
||
(void) XConfigureImage(display,resource_info,windows,
|
||
display_image);
|
||
}
|
||
/*
|
||
Update pan window configuration.
|
||
*/
|
||
if ((event.xconfigure.width < windows->image.ximage->width) ||
|
||
(event.xconfigure.height < windows->image.ximage->height))
|
||
{
|
||
(void) XMapRaised(display,windows->pan.id);
|
||
XDrawPanRectangle(display,windows);
|
||
}
|
||
else
|
||
if (windows->pan.mapped != MagickFalse)
|
||
(void) XWithdrawWindow(display,windows->pan.id,
|
||
windows->pan.screen);
|
||
break;
|
||
}
|
||
if (event.xconfigure.window == windows->magnify.id)
|
||
{
|
||
unsigned int
|
||
magnify;
|
||
|
||
/*
|
||
Magnify window has a new configuration.
|
||
*/
|
||
windows->magnify.width=(unsigned int) event.xconfigure.width;
|
||
windows->magnify.height=(unsigned int) event.xconfigure.height;
|
||
if (windows->magnify.mapped == MagickFalse)
|
||
break;
|
||
magnify=1;
|
||
while ((int) magnify <= event.xconfigure.width)
|
||
magnify<<=1;
|
||
while ((int) magnify <= event.xconfigure.height)
|
||
magnify<<=1;
|
||
magnify>>=1;
|
||
if (((int) magnify != event.xconfigure.width) ||
|
||
((int) magnify != event.xconfigure.height))
|
||
{
|
||
window_changes.width=(int) magnify;
|
||
window_changes.height=(int) magnify;
|
||
(void) XReconfigureWMWindow(display,windows->magnify.id,
|
||
windows->magnify.screen,(unsigned int) (CWWidth | CWHeight),
|
||
&window_changes);
|
||
break;
|
||
}
|
||
if ((windows->magnify.mapped != MagickFalse) &&
|
||
(windows->magnify.stasis != MagickFalse))
|
||
{
|
||
status=XMakeImage(display,resource_info,&windows->magnify,
|
||
display_image,windows->magnify.width,windows->magnify.height);
|
||
XMakeMagnifyImage(display,windows);
|
||
}
|
||
break;
|
||
}
|
||
if ((windows->magnify.mapped != MagickFalse) &&
|
||
(event.xconfigure.window == windows->pan.id))
|
||
{
|
||
/*
|
||
Pan icon window has a new configuration.
|
||
*/
|
||
if (event.xconfigure.send_event != 0)
|
||
{
|
||
windows->pan.x=event.xconfigure.x;
|
||
windows->pan.y=event.xconfigure.y;
|
||
}
|
||
windows->pan.width=(unsigned int) event.xconfigure.width;
|
||
windows->pan.height=(unsigned int) event.xconfigure.height;
|
||
break;
|
||
}
|
||
if (event.xconfigure.window == windows->icon.id)
|
||
{
|
||
/*
|
||
Icon window has a new configuration.
|
||
*/
|
||
windows->icon.width=(unsigned int) event.xconfigure.width;
|
||
windows->icon.height=(unsigned int) event.xconfigure.height;
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case DestroyNotify:
|
||
{
|
||
/*
|
||
Group leader has exited.
|
||
*/
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Destroy Notify: 0x%lx",event.xdestroywindow.window);
|
||
if (event.xdestroywindow.window == windows->group_leader.id)
|
||
{
|
||
*state|=ExitState;
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case EnterNotify:
|
||
{
|
||
/*
|
||
Selectively install colormap.
|
||
*/
|
||
if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
|
||
if (event.xcrossing.mode != NotifyUngrab)
|
||
XInstallColormap(display,map_info->colormap);
|
||
break;
|
||
}
|
||
case Expose:
|
||
{
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Expose: 0x%lx %dx%d+%d+%d",event.xexpose.window,
|
||
event.xexpose.width,event.xexpose.height,event.xexpose.x,
|
||
event.xexpose.y);
|
||
/*
|
||
Refresh windows that are now exposed.
|
||
*/
|
||
if ((event.xexpose.window == windows->image.id) &&
|
||
(windows->image.mapped != MagickFalse))
|
||
{
|
||
XRefreshWindow(display,&windows->image,&event);
|
||
delay=display_image->delay/MagickMax(
|
||
display_image->ticks_per_second,1L);
|
||
timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
|
||
break;
|
||
}
|
||
if ((event.xexpose.window == windows->magnify.id) &&
|
||
(windows->magnify.mapped != MagickFalse))
|
||
{
|
||
XMakeMagnifyImage(display,windows);
|
||
break;
|
||
}
|
||
if (event.xexpose.window == windows->pan.id)
|
||
{
|
||
XDrawPanRectangle(display,windows);
|
||
break;
|
||
}
|
||
if (event.xexpose.window == windows->icon.id)
|
||
{
|
||
XRefreshWindow(display,&windows->icon,&event);
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case KeyPress:
|
||
{
|
||
int
|
||
length;
|
||
|
||
/*
|
||
Respond to a user key press.
|
||
*/
|
||
length=XLookupString((XKeyEvent *) &event.xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
*(command+length)='\0';
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Key press: %d 0x%lx (%s)",event.xkey.state,(unsigned long)
|
||
key_symbol,command);
|
||
if (event.xkey.window == windows->image.id)
|
||
{
|
||
command_type=XImageWindowCommand(display,resource_info,windows,
|
||
event.xkey.state,key_symbol,&display_image);
|
||
if (command_type != NullCommand)
|
||
nexus=XMagickCommand(display,resource_info,windows,command_type,
|
||
&display_image);
|
||
}
|
||
if (event.xkey.window == windows->magnify.id)
|
||
XMagnifyWindowCommand(display,windows,event.xkey.state,key_symbol);
|
||
if (event.xkey.window == windows->pan.id)
|
||
{
|
||
if ((key_symbol == XK_q) || (key_symbol == XK_Escape))
|
||
(void) XWithdrawWindow(display,windows->pan.id,
|
||
windows->pan.screen);
|
||
else
|
||
if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
|
||
XTextViewWidget(display,resource_info,windows,MagickFalse,
|
||
"Help Viewer - Image Pan",ImagePanHelp);
|
||
else
|
||
XTranslateImage(display,windows,*image,key_symbol);
|
||
}
|
||
delay=display_image->delay/MagickMax(
|
||
display_image->ticks_per_second,1L);
|
||
timer=time((time_t *) NULL)+(delay == 0 ? 1 : delay)+1;
|
||
break;
|
||
}
|
||
case KeyRelease:
|
||
{
|
||
/*
|
||
Respond to a user key release.
|
||
*/
|
||
(void) XLookupString((XKeyEvent *) &event.xkey,command,(int)
|
||
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Key release: 0x%lx (%c)",(unsigned long) key_symbol,*command);
|
||
break;
|
||
}
|
||
case LeaveNotify:
|
||
{
|
||
/*
|
||
Selectively uninstall colormap.
|
||
*/
|
||
if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
|
||
if (event.xcrossing.mode != NotifyUngrab)
|
||
XUninstallColormap(display,map_info->colormap);
|
||
break;
|
||
}
|
||
case MapNotify:
|
||
{
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),"Map Notify: 0x%lx",
|
||
event.xmap.window);
|
||
if (event.xmap.window == windows->backdrop.id)
|
||
{
|
||
(void) XSetInputFocus(display,event.xmap.window,RevertToParent,
|
||
CurrentTime);
|
||
windows->backdrop.mapped=MagickTrue;
|
||
break;
|
||
}
|
||
if (event.xmap.window == windows->image.id)
|
||
{
|
||
if (windows->backdrop.id != (Window) NULL)
|
||
(void) XInstallColormap(display,map_info->colormap);
|
||
if (LocaleCompare(display_image->magick,"LOGO") == 0)
|
||
{
|
||
if (LocaleCompare(display_image->filename,"LOGO") == 0)
|
||
nexus=XOpenImage(display,resource_info,windows,MagickFalse);
|
||
}
|
||
if (((int) windows->image.width < windows->image.ximage->width) ||
|
||
((int) windows->image.height < windows->image.ximage->height))
|
||
(void) XMapRaised(display,windows->pan.id);
|
||
windows->image.mapped=MagickTrue;
|
||
break;
|
||
}
|
||
if (event.xmap.window == windows->magnify.id)
|
||
{
|
||
XMakeMagnifyImage(display,windows);
|
||
windows->magnify.mapped=MagickTrue;
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
break;
|
||
}
|
||
if (event.xmap.window == windows->pan.id)
|
||
{
|
||
XMakePanImage(display,resource_info,windows,display_image);
|
||
windows->pan.mapped=MagickTrue;
|
||
break;
|
||
}
|
||
if (event.xmap.window == windows->info.id)
|
||
{
|
||
windows->info.mapped=MagickTrue;
|
||
break;
|
||
}
|
||
if (event.xmap.window == windows->icon.id)
|
||
{
|
||
MagickBooleanType
|
||
taint;
|
||
|
||
/*
|
||
Create an icon image.
|
||
*/
|
||
taint=display_image->taint;
|
||
XMakeStandardColormap(display,icon_visual,icon_resources,
|
||
display_image,icon_map,icon_pixel);
|
||
(void) XMakeImage(display,icon_resources,&windows->icon,
|
||
display_image,windows->icon.width,windows->icon.height);
|
||
display_image->taint=taint;
|
||
(void) XSetWindowBackgroundPixmap(display,windows->icon.id,
|
||
windows->icon.pixmap);
|
||
(void) XClearWindow(display,windows->icon.id);
|
||
(void) XWithdrawWindow(display,windows->info.id,
|
||
windows->info.screen);
|
||
windows->icon.mapped=MagickTrue;
|
||
break;
|
||
}
|
||
if (event.xmap.window == windows->command.id)
|
||
{
|
||
windows->command.mapped=MagickTrue;
|
||
break;
|
||
}
|
||
if (event.xmap.window == windows->popup.id)
|
||
{
|
||
windows->popup.mapped=MagickTrue;
|
||
break;
|
||
}
|
||
if (event.xmap.window == windows->widget.id)
|
||
{
|
||
windows->widget.mapped=MagickTrue;
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
case MappingNotify:
|
||
{
|
||
(void) XRefreshKeyboardMapping(&event.xmapping);
|
||
break;
|
||
}
|
||
case NoExpose:
|
||
break;
|
||
case PropertyNotify:
|
||
{
|
||
Atom
|
||
type;
|
||
|
||
int
|
||
format,
|
||
status;
|
||
|
||
unsigned char
|
||
*data;
|
||
|
||
unsigned long
|
||
after,
|
||
length;
|
||
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Property Notify: 0x%lx 0x%lx %d",event.xproperty.window,
|
||
event.xproperty.atom,event.xproperty.state);
|
||
if (event.xproperty.atom != windows->im_remote_command)
|
||
break;
|
||
/*
|
||
Display image named by the remote command protocol.
|
||
*/
|
||
status=XGetWindowProperty(display,event.xproperty.window,
|
||
event.xproperty.atom,0L,(long) MaxTextExtent,MagickFalse,(Atom)
|
||
AnyPropertyType,&type,&format,&length,&after,&data);
|
||
if ((status != Success) || (length == 0))
|
||
break;
|
||
if (LocaleCompare((char *) data,"-quit") == 0)
|
||
{
|
||
XClientMessage(display,windows->image.id,windows->im_protocols,
|
||
windows->im_exit,CurrentTime);
|
||
(void) XFree((void *) data);
|
||
break;
|
||
}
|
||
(void) CopyMagickString(resource_info->image_info->filename,
|
||
(char *) data,MaxTextExtent);
|
||
(void) XFree((void *) data);
|
||
nexus=ReadImage(resource_info->image_info,&display_image->exception);
|
||
CatchException(&display_image->exception);
|
||
if (nexus != (Image *) NULL)
|
||
*state|=NextImageState | ExitState;
|
||
break;
|
||
}
|
||
case ReparentNotify:
|
||
{
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Reparent Notify: 0x%lx=>0x%lx",event.xreparent.parent,
|
||
event.xreparent.window);
|
||
break;
|
||
}
|
||
case UnmapNotify:
|
||
{
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),
|
||
"Unmap Notify: 0x%lx",event.xunmap.window);
|
||
if (event.xunmap.window == windows->backdrop.id)
|
||
{
|
||
windows->backdrop.mapped=MagickFalse;
|
||
break;
|
||
}
|
||
if (event.xunmap.window == windows->image.id)
|
||
{
|
||
windows->image.mapped=MagickFalse;
|
||
break;
|
||
}
|
||
if (event.xunmap.window == windows->magnify.id)
|
||
{
|
||
windows->magnify.mapped=MagickFalse;
|
||
break;
|
||
}
|
||
if (event.xunmap.window == windows->pan.id)
|
||
{
|
||
windows->pan.mapped=MagickFalse;
|
||
break;
|
||
}
|
||
if (event.xunmap.window == windows->info.id)
|
||
{
|
||
windows->info.mapped=MagickFalse;
|
||
break;
|
||
}
|
||
if (event.xunmap.window == windows->icon.id)
|
||
{
|
||
if (map_info->colormap == icon_map->colormap)
|
||
XConfigureImageColormap(display,resource_info,windows,
|
||
display_image);
|
||
(void) XFreeStandardColormap(display,icon_visual,icon_map,
|
||
icon_pixel);
|
||
windows->icon.mapped=MagickFalse;
|
||
break;
|
||
}
|
||
if (event.xunmap.window == windows->command.id)
|
||
{
|
||
windows->command.mapped=MagickFalse;
|
||
break;
|
||
}
|
||
if (event.xunmap.window == windows->popup.id)
|
||
{
|
||
if (windows->backdrop.id != (Window) NULL)
|
||
(void) XSetInputFocus(display,windows->image.id,RevertToParent,
|
||
CurrentTime);
|
||
windows->popup.mapped=MagickFalse;
|
||
break;
|
||
}
|
||
if (event.xunmap.window == windows->widget.id)
|
||
{
|
||
if (windows->backdrop.id != (Window) NULL)
|
||
(void) XSetInputFocus(display,windows->image.id,RevertToParent,
|
||
CurrentTime);
|
||
windows->widget.mapped=MagickFalse;
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
if (display_image->debug != MagickFalse)
|
||
(void) LogMagickEvent(X11Event,GetMagickModule(),"Event type: %d",
|
||
event.type);
|
||
break;
|
||
}
|
||
}
|
||
} while (!(*state & ExitState));
|
||
if ((*state & ExitState) == 0)
|
||
(void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
|
||
&display_image);
|
||
else
|
||
if (resource_info->confirm_edit != MagickFalse)
|
||
{
|
||
/*
|
||
Query user if image has changed.
|
||
*/
|
||
if ((resource_info->immutable == MagickFalse) &&
|
||
(display_image->taint != MagickFalse))
|
||
{
|
||
int
|
||
status;
|
||
|
||
status=XConfirmWidget(display,windows,"Your image changed.",
|
||
"Do you want to save it");
|
||
if (status == 0)
|
||
*state&=(~ExitState);
|
||
else
|
||
if (status > 0)
|
||
(void) XMagickCommand(display,resource_info,windows,SaveCommand,
|
||
&display_image);
|
||
}
|
||
}
|
||
if ((windows->visual_info->klass == GrayScale) ||
|
||
(windows->visual_info->klass == PseudoColor) ||
|
||
(windows->visual_info->klass == DirectColor))
|
||
{
|
||
/*
|
||
Withdraw pan and Magnify window.
|
||
*/
|
||
if (windows->info.mapped != MagickFalse)
|
||
(void) XWithdrawWindow(display,windows->info.id,windows->info.screen);
|
||
if (windows->magnify.mapped != MagickFalse)
|
||
(void) XWithdrawWindow(display,windows->magnify.id,
|
||
windows->magnify.screen);
|
||
if (windows->command.mapped != MagickFalse)
|
||
(void) XWithdrawWindow(display,windows->command.id,
|
||
windows->command.screen);
|
||
}
|
||
if (windows->pan.mapped != MagickFalse)
|
||
(void) XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
|
||
if (resource_info->backdrop == MagickFalse)
|
||
if (windows->backdrop.mapped)
|
||
{
|
||
(void) XWithdrawWindow(display,windows->backdrop.id,
|
||
windows->backdrop.screen);
|
||
(void) XDestroyWindow(display,windows->backdrop.id);
|
||
windows->backdrop.id=(Window) NULL;
|
||
(void) XWithdrawWindow(display,windows->image.id,
|
||
windows->image.screen);
|
||
(void) XDestroyWindow(display,windows->image.id);
|
||
windows->image.id=(Window) NULL;
|
||
}
|
||
XSetCursorState(display,windows,MagickTrue);
|
||
XCheckRefreshWindows(display,windows);
|
||
if (((*state & FormerImageState) != 0) || ((*state & NextImageState) != 0))
|
||
*state&=(~ExitState);
|
||
if (*state & ExitState)
|
||
{
|
||
/*
|
||
Free Standard Colormap.
|
||
*/
|
||
(void) XFreeStandardColormap(display,icon_visual,icon_map,icon_pixel);
|
||
if (resource_info->map_type == (char *) NULL)
|
||
(void) XFreeStandardColormap(display,visual_info,map_info,pixel);
|
||
/*
|
||
Free X resources.
|
||
*/
|
||
if (resource_info->copy_image != (Image *) NULL)
|
||
{
|
||
resource_info->copy_image=DestroyImage(resource_info->copy_image);
|
||
resource_info->copy_image=NewImageList();
|
||
}
|
||
DestroyXResources();
|
||
}
|
||
(void) XSync(display,MagickFalse);
|
||
/*
|
||
Restore our progress monitor and warning handlers.
|
||
*/
|
||
(void) SetErrorHandler(warning_handler);
|
||
(void) SetWarningHandler(warning_handler);
|
||
/*
|
||
Change to home directory.
|
||
*/
|
||
directory=getcwd(working_directory,MaxTextExtent);
|
||
(void) directory;
|
||
{
|
||
int
|
||
status;
|
||
|
||
if (*resource_info->home_directory == '\0')
|
||
(void) CopyMagickString(resource_info->home_directory,".",MaxTextExtent);
|
||
status=chdir(resource_info->home_directory);
|
||
if (status == -1)
|
||
(void) ThrowMagickException(&display_image->exception,GetMagickModule(),
|
||
FileOpenError,"UnableToOpenFile","%s",resource_info->home_directory);
|
||
}
|
||
*image=display_image;
|
||
return(nexus);
|
||
}
|
||
#else
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ D i s p l a y I m a g e s %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% DisplayImages() displays an image sequence to any X window screen. It
|
||
% returns a value other than 0 if successful. Check the exception member
|
||
% of image to determine the reason for any failure.
|
||
%
|
||
% The format of the DisplayImages method is:
|
||
%
|
||
% MagickBooleanType DisplayImages(const ImageInfo *image_info,
|
||
% Image *images)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o image_info: the image info.
|
||
%
|
||
% o image: the image.
|
||
%
|
||
*/
|
||
MagickExport MagickBooleanType DisplayImages(const ImageInfo *image_info,
|
||
Image *image)
|
||
{
|
||
assert(image_info != (const ImageInfo *) NULL);
|
||
assert(image_info->signature == MagickSignature);
|
||
assert(image != (Image *) NULL);
|
||
assert(image->signature == MagickSignature);
|
||
if (image->debug != MagickFalse)
|
||
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
|
||
(void) ThrowMagickException(&image->exception,GetMagickModule(),
|
||
MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",
|
||
image->filename);
|
||
return(MagickFalse);
|
||
}
|
||
|
||
/*
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
% %
|
||
% %
|
||
% %
|
||
+ R e m o t e D i s p l a y C o m m a n d %
|
||
% %
|
||
% %
|
||
% %
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
%
|
||
% RemoteDisplayCommand() encourages a remote display program to display the
|
||
% specified image filename.
|
||
%
|
||
% The format of the RemoteDisplayCommand method is:
|
||
%
|
||
% MagickBooleanType RemoteDisplayCommand(const ImageInfo *image,
|
||
% const char *window,const char *filename,ExceptionInfo *exception)
|
||
%
|
||
% A description of each parameter follows:
|
||
%
|
||
% o image_info: the image info.
|
||
%
|
||
% o window: Specifies the name or id of an X window.
|
||
%
|
||
% o filename: the name of the image filename to display.
|
||
%
|
||
% o exception: return any errors or warnings in this structure.
|
||
%
|
||
*/
|
||
MagickExport MagickBooleanType RemoteDisplayCommand(const ImageInfo *image_info,
|
||
const char *window,const char *filename,ExceptionInfo *exception)
|
||
{
|
||
assert(image_info != (const ImageInfo *) NULL);
|
||
assert(image_info->signature == MagickSignature);
|
||
assert(filename != (char *) NULL);
|
||
(void) window;
|
||
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
|
||
(void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
|
||
"DelegateLibrarySupportNotBuiltIn","`%s' (X11)",image_info->filename);
|
||
return(MagickFalse);
|
||
}
|
||
#endif
|