This is display.c in view mode; [Download] [Up]
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% 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 %
% %
% %
% Display Machine Independent File Format Image via X11. %
% %
% %
% %
% Software Design %
% John Cristy %
% July 1992 %
% %
% %
% Copyright 1997 E. I. du Pont de Nemours and Company %
% %
% Permission to use, copy, modify, distribute, and sell this software and %
% its documentation for any purpose is hereby granted without fee, %
% provided that the above Copyright notice appear in all copies and that %
% both that Copyright notice and this permission notice appear in %
% supporting documentation, and that the name of E. I. du Pont de Nemours %
% and Company not be used in advertising or publicity pertaining to %
% distribution of the software without specific, written prior %
% permission. E. I. du Pont de Nemours and Company makes no representations %
% about the suitability of this software for any purpose. It is provided %
% "as is" without express or implied warranty. %
% %
% E. I. du Pont de Nemours and Company disclaims all warranties with regard %
% to this software, including all implied warranties of merchantability %
% and fitness, in no event shall E. I. du Pont de Nemours and Company be %
% liable for any special, indirect or consequential damages or any %
% damages whatsoever resulting from loss of use, data or profits, whether %
% in an action of contract, negligence or other tortious action, arising %
% out of or in connection with the use or performance of this software. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Display is a machine architecture independent image processing
% and display program. It can display any image in the MIFF format on
% any workstation display running X. Display first determines the
% hardware capabilities of the workstation. If the number of unique
% colors in the image is less than or equal to the number the workstation
% can support, the image is displayed in an X window. Otherwise the
% number of colors in the image is first reduced to match the color
% resolution of the workstation before it is displayed.
%
% This means that a continuous-tone 24 bits-per-pixel image can display on a
% 8 bit pseudo-color device or monochrome device. In most instances the
% reduced color image closely resembles the original. Alternatively, a
% monochrome or pseudo-color image can display on a continuous-tone 24
% bits-per-pixel device.
%
% The Display program command syntax is:
%
% Usage: display [options ...] file [ [options ...] file ...]
%
% Where options include:
% -backdrop display image centered on a backdrop
% -border geometry surround image with a border of color
% -colormap type Shared or Private
% -colors value preferred number of colors in the image
% -colorspace type GRAY, OHTA, RGB, XYZ, YCbCr, YIQ, YPbPr, or YUV
% -comment string annotate image with comment",
% -compress type RunlengthEncoded or Zip
% -contrast enhance or reduce the image contrast
% -crop geometry preferred size and location of the cropped image
% -delay seconds display the next image after pausing
% -density geometry vertical and horizontal density of the image
% -despeckle reduce the speckles within an image
% -display server display image to this X server
% -dispose method GIF disposal method
% -dither apply Floyd/Steinberg error diffusion to image
% -edge factor apply a filter to detect edges in the image
% -enhance apply a digital filter to enhance a noisy image
% -flip flip image in the vertical direction
% -flop flop image in the horizontal direction
% -frame geometry surround image with an ornamental border
% -gamma value level of gamma correction
% -geometry geometry preferred size and location of the Image window
% -immutable displayed image cannot be modified
% -interlace type None, Line, Plane, or Partition
% -label name assign a label to an image
% -map type display image using this Standard Colormap
% -matte store matte channel if the image has one
% -monochrome transform image to black and white
% -negate apply color inversion to image
% -page geometry size and location of the Postscript page
% -quality value JPEG quality setting
% -raise value lighten/darken image edges to create a 3-D effect
% -roll geometry roll an image vertically or horizontally
% -rotate degrees apply Paeth rotation to the image
% -sample geometry scale image with pixel sampling
% -scene value image scene number
% -segment value segment an image
% -sharpen factor apply a filter to sharpen the image
% -size geometry width and height of image
% -texture filename name of texture to tile onto the image background
% -treedepth value depth of the color classification tree
% -update seconds detect when image file is modified and redisplay
% -verbose print detailed information about the image
% -visual type display image using this visual type
% -window id display image to background of this window
% -window_group id exit program when this window id is destroyed
% -write filename write image to a file
%
% In addition to those listed above, you can specify these standard X
% resources as command line options: -background, -bordercolor,
% -borderwidth, -font, -foreground, -iconGeometry, -iconic, -mattecolor,
% -name, -shared_memory, -usePixmap, or -title.
%
% Change '-' to '+' in any option above to reverse its effect. For
% example, specify +matte to store the image without its matte channel.
%
% By default, the image format of `file' is determined by its magic
% number. To specify a particular image format, precede the filename
% with an image format name and a colon (i.e. ps:image) or specify the
% image type as the filename suffix (i.e. image.ps). Specify 'file' as
% '-' for standard input or output.
%
% Buttons:
% 1 press to map or unmap the Command widget
% 2 press and drag to magnify a region of an image
% 3 press to load an image from a visual image directory
%
%
*/
/*
Include declarations.
*/
#include "magick.h"
#include "display.h"
#include "version.h"
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% U s a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function Usage displays the program command syntax.
%
% The format of the Usage routine is:
%
% Usage(client_name)
%
% A description of each parameter follows:
%
% o client_name: a character string representing the name of the client
% program.
%
*/
static void Usage(const char *client_name)
{
char
**p;
static char
*buttons[]=
{
"1 press to map or unmap the Command widget",
"2 press and drag to magnify a region of an image",
"3 press to load an image from a visual image directory",
(char *) NULL
},
*options[]=
{
"-backdrop display image centered on a backdrop",
"-border geometry surround image with a border of color",
"-colormap type Shared or Private",
"-colors value preferred number of colors in the image",
"-colorspace type GRAY, OHTA, RGB, XYZ, YCbCr, YIQ, YPbPr, or YUV",
"-comment string annotate image with comment",
"-compress type RunlengthEncoded or Zip",
"-contrast enhance or reduce the image contrast",
"-crop geometry preferred size and location of the cropped image",
"-delay seconds display the next image after pausing",
"-density geometry vertical and horizontal density of the image",
"-despeckle reduce the speckles within an image",
"-display server display image to this X server",
"-dispose method GIF disposal method",
"-dither apply Floyd/Steinberg error diffusion to image",
"-edge factor apply a filter to detect edges in the image",
"-enhance apply a digital filter to enhance a noisy image",
"-flip flip image in the vertical direction",
"-flop flop image in the horizontal direction",
"-frame geometry surround image with an ornamental border",
"-gamma value level of gamma correction",
"-geometry geometry preferred size and location of the Image window",
"-immutable displayed image cannot be modified",
"-interlace type None, Line, Plane, or Partition",
"-label name assign a label to an image",
"-map type display image using this Standard Colormap",
"-matte store matte channel if the image has one",
"-monochrome transform image to black and white",
"-negate apply color inversion to image",
"-page geometry size and location of the Postscript page",
"-quality value JPEG quality setting",
"-raise value lighten/darken image edges to create a 3-D effect",
"-roll geometry roll an image vertically or horizontally",
"-rotate degrees apply Paeth rotation to the image",
"-scene value image scene number",
"-segment value segment an image",
"-sample geometry scale image with pixel sampling",
"-sharpen factor apply a filter to sharpen the image",
"-size geometry width and height of image",
"-texture filename name of texture to tile onto the image background",
"-treedepth value depth of the color classification tree",
"-update seconds detect when image file is modified and redisplay",
"-verbose print detailed information about the image",
"-visual type display image using this visual type",
"-window id display image to background of this window",
"-window_group id exit program when this window id is destroyed",
"-write filename write image to a file",
(char *) NULL
};
(void) printf("Version: %s\n\n",Version);
(void) printf(
"Usage: %s [-options ...] file [ [-options ...] file ...]\n",client_name);
(void) printf("\nWhere options include: \n");
for (p=options; *p != (char *) NULL; p++)
(void) printf(" %s\n",*p);
(void) printf(
"\nIn addition to those listed above, you can specify these standard X\n");
(void) printf(
"resources as command line options: -background, -bordercolor,\n");
(void) printf(
"-borderwidth, -font, -foreground, -iconGeometry, -iconic, -mattecolor,\n");
(void) printf(
"-name, -shared_memory, -usePixmap, or -title.\n");
(void) printf(
"\nChange '-' to '+' in any option above to reverse its effect. For\n");
(void) printf(
"example, specify +matte to store the image without a matte channel.\n");
(void) printf(
"\nBy default, the image format of `file' is determined by its magic\n");
(void) printf(
"number. To specify a particular image format, precede the filename\n");
(void) printf(
"with an image format name and a colon (i.e. ps:image) or specify the\n");
(void) printf(
"image type as the filename suffix (i.e. image.ps). Specify 'file' as\n");
(void) printf("'-' for standard input or output.\n");
(void) printf("\nButtons: \n");
for (p=buttons; *p != (char *) NULL; p++)
(void) printf(" %s\n",*p);
Exit(1);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X A n n o t a t e E d i t I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XAnnotateEditImage annotates the image with text.
%
% The format of the XAnnotateEditImage routine is:
%
% XAnnotateEditImage(display,resource_info,windows,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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
*/
static unsigned int XAnnotateEditImage(Display *display,
XResourceInfo *resource_info,XWindows *windows,Image *image)
{
static char
*AnnotateMenu[]=
{
"Font Name",
"Font Color",
"Box Color",
"Rotate Text",
"Help",
"Dismiss",
(char *) NULL
},
*TextMenu[]=
{
"Help",
"Dismiss",
(char *) NULL
};
static double
degrees = 0.0;
static ModeType
AnnotateCommands[]=
{
AnnotateNameCommand,
AnnotateFontColorCommand,
AnnotateBackgroundColorCommand,
AnnotateRotateCommand,
AnnotateHelpCommand,
AnnotateDismissCommand
},
TextCommands[]=
{
TextHelpCommand,
TextDismissCommand
};
static unsigned int
box_id = MaxNumberPens-2,
font_id = 0,
pen_id = 0,
transparent_box = True,
transparent_pen = False;
char
*ColorMenu[MaxNumberPens+1],
command[MaxTextExtent],
text[MaxTextExtent];
Cursor
cursor;
GC
annotate_context;
int
id,
pen_number,
x,
y;
KeySym
key_symbol;
register char
*p;
register int
i;
unsigned int
height,
status,
width;
unsigned long
state;
XAnnotateInfo
*annotate_info,
*previous_info;
XColor
color;
XFontStruct
*font_info;
XEvent
event,
text_event;
/*
Map Command widget.
*/
windows->command.name="Annotate";
windows->command.data=4;
(void) XCommandWidget(display,windows,AnnotateMenu,(XEvent *) NULL);
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);
state=DefaultState;
do
{
if (windows->info.mapped)
{
/*
Display pointer position.
*/
(void) sprintf(text," %+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);
if (id < 0)
continue;
switch (AnnotateCommands[id])
{
case AnnotateNameCommand:
{
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]=(char *) NULL;
/*
Select a font name from the pop-up menu.
*/
font_number=XMenuWidget(display,windows,AnnotateMenu[id],
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=font_number;
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]=(char *) NULL;
/*
Select a pen color from the pop-up menu.
*/
pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
ColorMenu,command);
if (pen_number < 0)
break;
transparent_pen=pen_number == (MaxNumberPens-2);
if (transparent_pen)
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->image.map_info->colormap,
resource_info->pen_colors[pen_number],&color);
XBestPixel(display,windows->image.map_info->colormap,
(XColor *) NULL,(unsigned int) MaxColors,&color);
windows->image.pixel_info->pen_colors[pen_number]=color;
pen_id=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]=(char *) NULL;
/*
Select a pen color from the pop-up menu.
*/
pen_number=XMenuWidget(display,windows,AnnotateMenu[id],
ColorMenu,command);
if (pen_number < 0)
break;
transparent_box=pen_number == (MaxNumberPens-2);
if (transparent_box)
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->image.map_info->colormap,
resource_info->pen_colors[pen_number],&color);
XBestPixel(display,windows->image.map_info->colormap,
(XColor *) NULL,(unsigned int) MaxColors,&color);
windows->image.pixel_info->pen_colors[pen_number]=color;
box_id=pen_number;
break;
}
case AnnotateRotateCommand:
{
int
entry;
static char
angle[MaxTextExtent] = "30.0",
*RotateMenu[]=
{
"-90",
"-45",
"-30",
"0",
"30",
"45",
"90",
"180",
(char *) NULL,
(char *) NULL,
};
/*
Select a command from the pop-up menu.
*/
RotateMenu[8]="Dialog...";
entry=XMenuWidget(display,windows,AnnotateMenu[id],RotateMenu,
command);
if (entry < 0)
break;
if (entry != 8)
{
degrees=atof(RotateMenu[entry]);
break;
}
(void) XDialogWidget(display,windows,"OK","Enter rotation angle:",
angle);
if (*angle == '\0')
break;
degrees=atof(angle);
break;
}
case AnnotateHelpCommand:
{
XTextViewWidget(display,resource_info,windows,False,
"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,sizeof(command),
&key_symbol,(XComposeStatus *) NULL);
switch (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,False,
"Help Viewer - Image Annotation",ImageAnnotateHelp);
break;
}
default:
{
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)
{
if ((x < (windows->info.x+windows->info.width)) &&
(y < (windows->info.y+windows->info.height)))
XWithdrawWindow(display,windows->info.id,windows->info.screen);
}
else
if ((x > (windows->info.x+windows->info.width)) ||
(y > (windows->info.y+windows->info.height)))
XMapWindow(display,windows->info.id);
break;
}
default:
break;
}
} while (!(state & ExitState));
XWithdrawWindow(display,windows->info.id,windows->info.screen);
if (state & EscapeState)
return(True);
/*
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->image.font_info;
}
if ((x+font_info->max_bounds.width) >= windows->image.width)
x=windows->image.width-font_info->max_bounds.width;
if (y < (font_info->ascent+font_info->descent))
y=font_info->ascent+font_info->descent;
if ((font_info->max_bounds.width > windows->image.width) ||
((font_info->ascent+font_info->descent) >= windows->image.height))
return(False);
/*
Initialize annotate structure.
*/
annotate_info=(XAnnotateInfo *) malloc(sizeof(XAnnotateInfo));
if (annotate_info == (XAnnotateInfo *) NULL)
return(False);
XGetAnnotateInfo(annotate_info);
annotate_info->x=x;
annotate_info->y=y;
if (!transparent_box && !transparent_pen)
annotate_info->stencil=OpaqueStencil;
else
if (!transparent_box)
annotate_info->stencil=BackgroundStencil;
else
annotate_info->stencil=ForegroundStencil;
annotate_info->height=font_info->ascent+font_info->descent;
annotate_info->degrees=degrees;
annotate_info->font_info=font_info;
annotate_info->text=(char *) malloc(
(windows->image.width/Max(font_info->min_bounds.width,1)+2)*sizeof(char));
if (annotate_info->text == (char *) NULL)
return(False);
/*
Create cursor and set graphic context.
*/
cursor=XCreateFontCursor(display,XC_pencil);
XDefineCursor(display,windows->image.id,cursor);
annotate_context=windows->image.annotate_context;
XSetFont(display,annotate_context,font_info->fid);
XSetBackground(display,annotate_context,
windows->image.pixel_info->pen_colors[box_id].pixel);
XSetForeground(display,annotate_context,
windows->image.pixel_info->pen_colors[pen_id].pixel);
/*
Begin annotating the image with text.
*/
windows->command.name="Text";
windows->command.data=0;
(void) XCommandWidget(display,windows,TextMenu,(XEvent *) NULL);
state=DefaultState;
XDrawString(display,windows->image.id,annotate_context,x,y,"_",1);
text_event.xexpose.width=(unsigned 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';
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.
*/
XSetBackground(display,annotate_context,
windows->image.pixel_info->background_color.pixel);
XSetForeground(display,annotate_context,
windows->image.pixel_info->foreground_color.pixel);
id=XCommandWidget(display,windows,AnnotateMenu,&event);
XSetBackground(display,annotate_context,
windows->image.pixel_info->pen_colors[box_id].pixel);
XSetForeground(display,annotate_context,
windows->image.pixel_info->pen_colors[pen_id].pixel);
if (id < 0)
continue;
switch (TextCommands[id])
{
case TextHelpCommand:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Annotation",ImageAnnotateHelp);
XDefineCursor(display,windows->image.id,cursor);
break;
}
case TextDismissCommand:
{
/*
Finished annotating.
*/
annotate_info->width=XTextWidth(font_info,annotate_info->text,
Extent(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;
XClearArea(display,windows->image.id,x,text_event.xexpose.y,
text_event.xexpose.width,text_event.xexpose.height,False);
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.
*/
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)
XDrawString(display,windows->image.id,annotate_context,
text_info->x,text_info->y,text_info->text,
Extent(text_info->text));
else
XDrawImageString(display,windows->image.id,annotate_context,
text_info->x,text_info->y,text_info->text,
Extent(text_info->text));
text_info=text_info->previous;
}
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,sizeof(command),
&key_symbol,(XComposeStatus *) NULL);
*(command+length)='\0';
if ((event.xkey.state & ControlMask) || (event.xkey.state & Mod1Mask))
state|=ModifierState;
if (state & ModifierState)
switch (key_symbol)
{
case XK_u:
case XK_U:
{
key_symbol=DeleteCommand;
break;
}
default:
break;
}
switch (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+=Extent(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 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=XTextWidth(font_info,annotate_info->text,
Extent(annotate_info->text));
XRefreshWindow(display,&windows->image,&text_event);
state|=ExitState;
break;
}
default:
{
/*
Draw a single character on the Image window.
*/
if (state & ModifierState)
break;
if (*command == '\0')
break;
*p=(*command);
if (annotate_info->stencil == ForegroundStencil)
XDrawString(display,windows->image.id,annotate_context,x,y,p,1);
else
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) < windows->image.width)
break;
}
case XK_Return:
case XK_KP_Enter:
{
/*
Advance to the next line of text.
*/
*p='\0';
annotate_info->width=XTextWidth(font_info,annotate_info->text,
Extent(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 *) malloc(sizeof(XAnnotateInfo));
if (annotate_info->next == (XAnnotateInfo *) NULL)
return(False);
*annotate_info->next=(*annotate_info);
annotate_info->next->previous=annotate_info;
annotate_info=annotate_info->next;
annotate_info->text=(char *) malloc((windows->image.width/
Max(font_info->min_bounds.width,1)+2)*sizeof(char));
if (annotate_info->text == (char *) NULL)
return(False);
annotate_info->y+=annotate_info->height;
if (annotate_info->y > windows->image.height)
annotate_info->y=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,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,2047L,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 < length; i++)
{
if (data[i] != '\n')
{
/*
Draw a single character on the Image window.
*/
*p=data[i];
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) < windows->image.width)
continue;
}
/*
Advance to the next line of text.
*/
*p='\0';
annotate_info->width=XTextWidth(font_info,annotate_info->text,
Extent(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 *) malloc(sizeof(XAnnotateInfo));
if (annotate_info->next == (XAnnotateInfo *) NULL)
return(False);
*annotate_info->next=(*annotate_info);
annotate_info->next->previous=annotate_info;
annotate_info=annotate_info->next;
annotate_info->text=(char *) malloc((windows->image.width/
Max(font_info->min_bounds.width,1)+2)*sizeof(char));
if (annotate_info->text == (char *) NULL)
return(False);
annotate_info->y+=annotate_info->height;
if (annotate_info->y > windows->image.height)
annotate_info->y=annotate_info->height;
annotate_info->next=(XAnnotateInfo *) NULL;
x=annotate_info->x;
y=annotate_info->y;
p=annotate_info->text;
}
XFree((void *) data);
break;
}
default:
break;
}
} while (!(state & ExitState));
XFreeCursor(display,cursor);
/*
Annotation is relative to image configuration.
*/
x=0;
y=0;
width=image->columns;
height=image->rows;
if (windows->image.crop_geometry != (char *) NULL)
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
/*
Initialize annotated image.
*/
XSetCursorState(display,windows,True);
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;
free((char *) annotate_info->text);
free((char *) annotate_info);
annotate_info=previous_info;
continue;
}
/*
Determine pixel index for box and pen color.
*/
windows->image.pixel_info->box_color=
windows->image.pixel_info->pen_colors[box_id];
if (windows->image.pixel_info->colors != 0)
for (i=0; i < windows->image.pixel_info->colors; i++)
if (windows->image.pixel_info->pixels[i] ==
windows->image.pixel_info->pen_colors[box_id].pixel)
{
windows->image.pixel_info->box_index=i;
break;
}
windows->image.pixel_info->pen_color=
windows->image.pixel_info->pen_colors[pen_id];
if (windows->image.pixel_info->colors != 0)
for (i=0; i < windows->image.pixel_info->colors; i++)
if (windows->image.pixel_info->pixels[i] ==
windows->image.pixel_info->pen_colors[pen_id].pixel)
{
windows->image.pixel_info->pen_index=i;
break;
}
/*
Define the annotate geometry string.
*/
annotate_info->x=
width*(annotate_info->x+windows->image.x)/windows->image.ximage->width;
annotate_info->y=height*(annotate_info->y-font_info->ascent+
windows->image.y)/windows->image.ximage->height;
(void) sprintf(annotate_info->geometry,"%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->image.pixel_info,annotate_info,image);
if (status == 0)
return(False);
/*
Free up memory.
*/
previous_info=annotate_info->previous;
free((char *) annotate_info->text);
free((char *) annotate_info);
annotate_info=previous_info;
}
XSetForeground(display,annotate_context,
windows->image.pixel_info->foreground_color.pixel);
XSetBackground(display,annotate_context,
windows->image.pixel_info->background_color.pixel);
XSetFont(display,annotate_context,windows->image.font_info->fid);
XSetCursorState(display,windows,False);
XFreeFont(display,font_info);
/*
Update image configuration.
*/
XConfigureImageColormap(display,resource_info,windows,image);
(void) XConfigureImage(display,resource_info,windows,image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X B a c k g r o u n d I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XBackgroundImage displays the image in the background of a window.
%
% The format of the XBackgroundImage routine is:
%
% status=XBackgroundImage(display,resource_info,windows,image)
%
% A description of each parameter follows:
%
% o status: Function XBackgroundImage return True if the image is
% printed. False is returned is there is a memory shortage or if the
% image fails to print.
%
% 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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
%
*/
static unsigned int XBackgroundImage(Display *display,
XResourceInfo *resource_info,XWindows *windows,Image **image)
{
#define BackgroundImageText " Backgrounding the image... "
static char
window_id[MaxTextExtent] = "root";
XResourceInfo
background_resources;
unsigned int
status;
/*
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(False);
(void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
XInfoWidget(display,windows,BackgroundImageText);
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
background_resources=(*resource_info);
background_resources.window_id=window_id;
background_resources.backdrop=status;
status=XDisplayBackgroundImage(display,&background_resources,*image);
if (status)
XClientMessage(display,windows->image.id,windows->im_protocols,
windows->im_retain_colors,CurrentTime);
XSetCursorState(display,windows,False);
(void) XMagickCommand(display,resource_info,windows,UndoCommand,image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X C h o p I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XChopImage chops the X image.
%
% The format of the XChopImage routine is:
%
% status=XChopImage(display,resource_info,windows,image)
%
% A description of each parameter follows:
%
% o status: Function XChopImage return True if the image is
% cut. False is returned is there is a memory shortage or if the
% image fails to cut.
%
% 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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
%
*/
static unsigned int XChopImage(Display *display,XResourceInfo *resource_info,
XWindows *windows,Image **image)
{
static char
*ChopMenu[]=
{
"Direction",
"Help",
"Dismiss",
(char *) NULL
};
static ModeType
ChopCommands[]=
{
ChopDirectionCommand,
ChopHelpCommand,
ChopDismissCommand
},
direction = HorizontalChopCommand,
DirectionCommands[]=
{
HorizontalChopCommand,
VerticalChopCommand
};
char
text[MaxTextExtent];
Image
*chop_image;
int
id,
x,
y;
RectangleInfo
chop_info;
unsigned int
distance,
height,
width;
unsigned long
scale_factor,
state;
XEvent
event;
XSegment
segment_info;
/*
Map Command widget.
*/
windows->command.name="Chop";
windows->command.data=1;
(void) XCommandWidget(display,windows,ChopMenu,(XEvent *) NULL);
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);
state=DefaultState;
do
{
if (windows->info.mapped)
{
/*
Display pointer position.
*/
(void) sprintf(text," %+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 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,False,
"Help Viewer - Image Chopping",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=event.xbutton.x;
segment_info.x2=event.xbutton.x;
segment_info.y1=event.xbutton.y;
segment_info.y2=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,
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
switch (key_symbol)
{
case XK_Escape:
case XK_F20:
{
/*
Prematurely exit.
*/
state|=EscapeState;
state|=ExitState;
break;
}
case XK_F1:
case XK_Help:
{
XSetFunction(display,windows->image.highlight_context,GXcopy);
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Chopping",ImageChopHelp);
XSetFunction(display,windows->image.highlight_context,GXinvert);
break;
}
default:
{
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)
{
if ((x < (windows->info.x+windows->info.width)) &&
(y < (windows->info.y+windows->info.height)))
XWithdrawWindow(display,windows->info.id,windows->info.screen);
}
else
if ((x > (windows->info.x+windows->info.width)) ||
(y > (windows->info.y+windows->info.height)))
XMapWindow(display,windows->info.id);
}
}
} while (!(state & ExitState));
XWithdrawWindow(display,windows->info.id,windows->info.screen);
if (state & EscapeState)
return(True);
/*
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;
XSetFunction(display,windows->image.highlight_context,GXinvert);
state=DefaultState;
do
{
if (distance > 9)
{
/*
Display info and draw chopping line.
*/
if (!windows->info.mapped)
XMapWindow(display,windows->info.id);
(void) sprintf(text," %ux%u%+d%+d",chop_info.width,chop_info.height,
chop_info.x,chop_info.y);
XInfoWidget(display,windows,text);
XHighlightLine(display,windows->image.id,
windows->image.highlight_context,&segment_info);
}
else
if (windows->info.mapped)
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=event.xmotion.x;
segment_info.y2=event.xmotion.y;
break;
}
case ButtonRelease:
{
/*
User has committed to chopping line.
*/
segment_info.x2=event.xbutton.x;
segment_info.y2=event.xbutton.y;
state|=ExitState;
break;
}
case Expose:
break;
case MotionNotify:
{
segment_info.x2=event.xmotion.x;
segment_info.y2=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=
((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=segment_info.x2-segment_info.x1+1;
chop_info.x=windows->image.x+segment_info.x1;
chop_info.height=0;
chop_info.y=0;
if (segment_info.x1 > segment_info.x2)
{
chop_info.width=segment_info.x1-segment_info.x2+1;
chop_info.x=windows->image.x+segment_info.x2;
}
}
else
{
chop_info.width=0;
chop_info.height=segment_info.y2-segment_info.y1+1;
chop_info.x=0;
chop_info.y=windows->image.y+segment_info.y1;
if (segment_info.y1 > segment_info.y2)
{
chop_info.height=segment_info.y1-segment_info.y2+1;
chop_info.y=windows->image.y+segment_info.y2;
}
}
} while (!(state & ExitState));
XSetFunction(display,windows->image.highlight_context,GXcopy);
XWithdrawWindow(display,windows->info.id,windows->info.screen);
if (distance <= 9)
return(True);
/*
Image chopping is relative to image configuration.
*/
(void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
windows->image.window_changes.width=
windows->image.ximage->width-chop_info.width;
windows->image.window_changes.height=
windows->image.ximage->height-chop_info.height;
x=0;
y=0;
width=(*image)->columns;
height=(*image)->rows;
if (windows->image.crop_geometry != (char *) NULL)
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
scale_factor=UpShift(width)/windows->image.ximage->width;
chop_info.x+=x;
chop_info.x=DownShift(chop_info.x*scale_factor);
chop_info.width=DownShift(chop_info.width*scale_factor);
scale_factor=UpShift(height)/windows->image.ximage->height;
chop_info.y+=y;
chop_info.y=DownShift(chop_info.y*scale_factor);
chop_info.height=DownShift(chop_info.height*scale_factor);
/*
Chop image.
*/
chop_image=ChopImage(*image,&chop_info);
XSetCursorState(display,windows,False);
if (chop_image == (Image *) NULL)
return(False);
DestroyImage(*image);
*image=chop_image;
/*
Update image configuration.
*/
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X C o l o r E d i t I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function 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 routine is:
%
% XColorEditImage(display,resource_info,windows,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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
*/
static unsigned int XColorEditImage(Display *display,
XResourceInfo *resource_info,XWindows *windows,Image **image)
{
static char
*ColorEditMenu[]=
{
"Pixel Color",
"Method",
"Delta",
"Undo",
"Help",
"Dismiss",
(char *) NULL
};
static ModeType
ColorEditCommands[]=
{
ColorEditColorCommand,
ColorEditMethodCommand,
ColorEditDeltaCommand,
ColorEditUndoCommand,
ColorEditHelpCommand,
ColorEditDismissCommand
};
static PaintMethod
method = PointMethod;
static unsigned int
delta = 0,
pen_id = 0;
char
command[MaxTextExtent],
text[MaxTextExtent];
Cursor
cursor;
int
entry,
id,
x,
x_offset,
y,
y_offset;
register int
i;
register RunlengthPacket
*p;
unsigned int
height,
width;
unsigned long
state;
XColor
color;
XEvent
event;
/*
Map Command widget.
*/
windows->command.name="Color Edit";
windows->command.data=3;
(void) XCommandWidget(display,windows,ColorEditMenu,(XEvent *) NULL);
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->image.map_info->colormap,resource_info->background_color,
resource_info->foreground_color);
XDefineCursor(display,windows->image.id,cursor);
/*
Track pointer until button 1 is pressed.
*/
XQueryPosition(display,windows->image.id,&x,&y);
state=DefaultState;
do
{
if (windows->info.mapped)
{
/*
Display pointer position.
*/
(void) sprintf(text," %+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)
{
XDefineCursor(display,windows->image.id,cursor);
continue;
}
switch (ColorEditCommands[id])
{
case ColorEditColorCommand:
{
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]=(char *) NULL;
/*
Select a pen color from the pop-up menu.
*/
pen_number=XMenuWidget(display,windows,ColorEditMenu[id],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->image.map_info->colormap,
resource_info->pen_colors[pen_number],&color);
XBestPixel(display,windows->image.map_info->colormap,
(XColor *) NULL,(unsigned int) MaxColors,&color);
windows->image.pixel_info->pen_colors[pen_number]=color;
pen_id=pen_number;
break;
}
case ColorEditMethodCommand:
{
static char
*MethodMenu[]=
{
"point",
"replace",
"floodfill",
"reset",
(char *) NULL,
};
/*
Select a method from the pop-up menu.
*/
entry=
XMenuWidget(display,windows,ColorEditMenu[id],MethodMenu,command);
if (entry >= 0)
method=(PaintMethod) entry;
break;
}
case ColorEditDeltaCommand:
{
static char
*DeltaMenu[]=
{
"0",
"1",
"2",
"4",
"8",
"16",
"32",
(char *) NULL,
(char *) NULL,
},
value[MaxTextExtent] = "3";
/*
Select a delta value from the pop-up menu.
*/
DeltaMenu[7]="Dialog...";
entry=XMenuWidget(display,windows,ColorEditMenu[id],DeltaMenu,
command);
if (entry < 0)
break;
if (entry != 7)
{
delta=atoi(DeltaMenu[entry]);
break;
}
(void) XDialogWidget(display,windows,"Ok","Enter delta value:",
value);
if (*value == '\0')
break;
delta=atoi(value);
break;
}
case ColorEditUndoCommand:
{
(void) XMagickCommand(display,resource_info,windows,UndoCommand,
image);
break;
}
case ColorEditHelpCommand:
default:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Annotation",ImageColorEditHelp);
break;
}
case ColorEditDismissCommand:
{
/*
Prematurely exit.
*/
state|=EscapeState;
state|=ExitState;
break;
}
}
XDefineCursor(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);
XDefineCursor(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,sizeof(command),
&key_symbol,(XComposeStatus *) NULL);
switch (key_symbol)
{
case XK_Escape:
case XK_F20:
{
/*
Prematurely exit.
*/
state|=ExitState;
break;
}
case XK_F1:
case XK_Help:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Annotation",ImageColorEditHelp);
break;
}
default:
{
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)
{
if ((x < (windows->info.x+windows->info.width)) &&
(y < (windows->info.y+windows->info.height)))
XWithdrawWindow(display,windows->info.id,windows->info.screen);
}
else
if ((x > (windows->info.x+windows->info.width)) ||
(y > (windows->info.y+windows->info.height)))
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)
{
int
x,
y;
/*
Pixel edit is relative to image configuration.
*/
XClearArea(display,windows->image.id,x_offset,y_offset,1,1,True);
color=windows->image.pixel_info->pen_colors[pen_id];
XPutPixel(windows->image.ximage,x_offset,y_offset,color.pixel);
x=0;
y=0;
width=(*image)->columns;
height=(*image)->rows;
if (windows->image.crop_geometry != (char *) NULL)
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,
&height);
x_offset=
width*(windows->image.x+x_offset)/windows->image.ximage->width+x;
y_offset=
height*(windows->image.y+y_offset)/windows->image.ximage->height+y;
if ((x_offset < 0) || (y_offset < 0))
continue;
if ((x_offset >= (*image)->columns) || (y_offset >= (*image)->rows))
continue;
switch (method)
{
case PointMethod:
default:
{
/*
Update color information using point algorithm.
*/
(*image)->class=DirectClass;
if (!UncompressImage(*image))
break;
p=(*image)->pixels+(y_offset*(*image)->columns+x_offset);
p->red=XDownScale(color.red);
p->green=XDownScale(color.green);
p->blue=XDownScale(color.blue);
break;
}
case ReplaceMethod:
{
RunlengthPacket
target;
/*
Update color information using replace algorithm.
*/
x=0;
p=(*image)->pixels;
for (i=0; i < (*image)->packets; i++)
{
x+=(p->length+1);
if (x > (y_offset*(*image)->columns+x_offset))
break;
p++;
}
target=(*image)->pixels[i];
if ((*image)->class == DirectClass)
{
p=(*image)->pixels;
for (i=0; i < (*image)->packets; i++)
{
if (ColorMatch(*p,target,delta))
{
p->red=XDownScale(color.red);
p->green=XDownScale(color.green);
p->blue=XDownScale(color.blue);
}
p++;
}
}
else
{
for (i=0; i < (*image)->colors; i++)
if (ColorMatch((*image)->colormap[i],target,delta))
{
(*image)->colormap[i].red=XDownScale(color.red);
(*image)->colormap[i].green=XDownScale(color.green);
(*image)->colormap[i].blue=XDownScale(color.blue);
}
SyncImage(*image);
}
break;
}
case FloodfillMethod:
{
ColorPacket
pen_color;
/*
Update color information using floodfill algorithm.
*/
(*image)->class=DirectClass;
if (!UncompressImage(*image))
break;
pen_color.red=XDownScale(color.red);
pen_color.green=XDownScale(color.green);
pen_color.blue=XDownScale(color.blue);
ColorFloodfillImage(*image,x_offset,y_offset,&pen_color,delta);
break;
}
case ResetMethod:
{
/*
Update color information using reset algorithm.
*/
(*image)->class=DirectClass;
p=(*image)->pixels;
for (i=0; i < (*image)->packets; i++)
{
p->red=XDownScale(color.red);
p->green=XDownScale(color.green);
p->blue=XDownScale(color.blue);
p++;
}
break;
}
}
state&=(~UpdateConfigurationState);
}
} while (!(state & ExitState));
XSetCursorState(display,windows,False);
XFreeCursor(display,cursor);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X C o m p o s i t e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function 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 routine is:
%
% status=XCompositeImage(display,resource_info,windows,image)
%
% A description of each parameter follows:
%
% o status: Function XCompositeImage returns True if the image is
% composited. False is returned is there is a memory shortage or if the
% image fails to be composited.
%
% 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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
*/
static unsigned int XCompositeImage(Display *display,
XResourceInfo *resource_info,XWindows *windows,Image *image)
{
static char
*CompositeMenu[]=
{
"Operators",
"Blend",
"Displace",
"Help",
"Dismiss",
(char *) NULL
},
displacement_geometry[MaxTextExtent] = "30x30",
filename[MaxTextExtent] = "\0";
static CompositeOperator
compose = ReplaceCompositeOp;
static ModeType
CompositeCommands[]=
{
CompositeOperatorsCommand,
CompositeBlendCommand,
CompositeDisplaceCommand,
CompositeHelpCommand,
CompositeDismissCommand
};
char
text[MaxTextExtent];
Cursor
cursor;
double
blend;
Image
*composite_image;
int
id,
x,
y;
RectangleInfo
highlight_info,
composite_info;
unsigned int
height,
width;
unsigned long
scale_factor,
state;
XEvent
event;
/*
Request image file name from user.
*/
XFileBrowserWidget(display,windows,"Composite",filename);
if (*filename == '\0')
return(True);
/*
Read image.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
(void) strcpy(resource_info->image_info->filename,filename);
composite_image=ReadImage(resource_info->image_info);
XSetCursorState(display,windows,False);
if (composite_image == (Image *) NULL)
{
XNoticeWidget(display,windows,"Unable to read image:",filename);
return(False);
}
if (!composite_image->matte)
{
/*
Request mask image file name from user.
*/
XNoticeWidget(display,windows,
"Your image does not have the required matte information.",
"Press dismiss and choose an image to use as a mask.");
XFileBrowserWidget(display,windows,"Composite",filename);
if (*filename != '\0')
{
char
size[MaxTextExtent];
Image
*mask_image;
ImageInfo
image_info;
/*
Read image.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
GetImageInfo(&image_info);
(void) strcpy(image_info.filename,filename);
image_info.size=size;
(void) sprintf(image_info.size,"%ux%u",composite_image->columns,
composite_image->rows);
mask_image=ReadImage(&image_info);
XSetCursorState(display,windows,False);
if (mask_image == (Image *) NULL)
{
XNoticeWidget(display,windows,"Unable to read image:",filename);
return(False);
}
CompositeImage(composite_image,AddMaskCompositeOp,mask_image,0,0);
DestroyImage(mask_image);
}
}
/*
Map Command widget.
*/
windows->command.name="Composite";
windows->command.data=1;
(void) XCommandWidget(display,windows,CompositeMenu,(XEvent *) NULL);
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);
composite_info.x=windows->image.x+x;
composite_info.y=windows->image.y+y;
composite_info.width=0;
composite_info.height=0;
cursor=XCreateFontCursor(display,XC_ul_angle);
XSetFunction(display,windows->image.highlight_context,GXinvert);
blend=0.0;
state=DefaultState;
do
{
if (windows->info.mapped)
{
/*
Display pointer position.
*/
(void) sprintf(text," %+d%+d ",composite_info.x,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];
static char
*OperatorMenu[]=
{
"over",
"in",
"out",
"atop",
"xor",
"plus",
"minus",
"add",
"subtract",
"difference",
"bumpmap",
"replace",
(char *) NULL,
};
/*
Select a command from the pop-up menu.
*/
compose=(CompositeOperator) (XMenuWidget(display,windows,
CompositeMenu[id],OperatorMenu,command)+1);
break;
}
case CompositeBlendCommand:
{
static char
factor[MaxTextExtent] = "20.0";
/*
Blend the two images a given percent.
*/
XSetFunction(display,windows->image.highlight_context,GXcopy);
(void) XDialogWidget(display,windows,"Blend",
"Enter the blend factor (0.0 - 99.9%):",factor);
XSetFunction(display,windows->image.highlight_context,GXinvert);
if (*factor == '\0')
break;
blend=atof(factor);
compose=BlendCompositeOp;
break;
}
case CompositeDisplaceCommand:
{
/*
Get horizontal and vertical scale displacement geometry.
*/
XSetFunction(display,windows->image.highlight_context,GXcopy);
(void) XDialogWidget(display,windows,"Displace",
"Enter the horizontal and vertical scale:",displacement_geometry);
XSetFunction(display,windows->image.highlight_context,GXinvert);
if (*displacement_geometry == '\0')
break;
compose=DisplaceCompositeOp;
break;
}
case CompositeHelpCommand:
{
XSetFunction(display,windows->image.highlight_context,GXcopy);
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Compositing",ImageCompositeHelp);
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 (resource_info->debug)
(void) fprintf(stderr,"Button Press: 0x%lx %u +%d+%d\n",
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;
XDefineCursor(display,windows->image.id,cursor);
composite_info.x=windows->image.x+event.xbutton.x;
composite_info.y=windows->image.y+event.xbutton.y;
break;
}
case ButtonRelease:
{
if (resource_info->debug)
(void) fprintf(stderr,"Button Release: 0x%lx %u +%d+%d\n",
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=windows->image.x+event.xbutton.x;
composite_info.y=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,sizeof(command),
&key_symbol,(XComposeStatus *) NULL);
*(command+length)='\0';
if (resource_info->debug)
(void) fprintf(stderr,"Key press: 0x%lx (%s)\n",key_symbol,command);
switch (key_symbol)
{
case XK_Escape:
case XK_F20:
{
/*
Prematurely exit.
*/
DestroyImage(composite_image);
state|=EscapeState;
state|=ExitState;
break;
}
case XK_F1:
case XK_Help:
{
XSetFunction(display,windows->image.highlight_context,GXcopy);
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Compositing",ImageCompositeHelp);
XSetFunction(display,windows->image.highlight_context,GXinvert);
break;
}
default:
{
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)
{
if ((x < (windows->info.x+windows->info.width)) &&
(y < (windows->info.y+windows->info.height)))
XWithdrawWindow(display,windows->info.id,windows->info.screen);
}
else
if ((x > (windows->info.x+windows->info.width)) ||
(y > (windows->info.y+windows->info.height)))
XMapWindow(display,windows->info.id);
composite_info.x=windows->image.x+x;
composite_info.y=windows->image.y+y;
break;
}
default:
{
if (resource_info->debug)
(void) fprintf(stderr,"Event type: %d\n",event.type);
break;
}
}
} while (!(state & ExitState));
XSetFunction(display,windows->image.highlight_context,GXcopy);
XSetCursorState(display,windows,False);
XFreeCursor(display,cursor);
if (state & EscapeState)
return(True);
/*
Image compositing is relative to image configuration.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
x=0;
y=0;
width=image->columns;
height=image->rows;
if (windows->image.crop_geometry != (char *) NULL)
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
scale_factor=UpShift(width)/windows->image.ximage->width;
composite_info.x+=x;
composite_info.x=DownShift(composite_info.x*scale_factor);
composite_info.width=DownShift(composite_info.width*scale_factor);
scale_factor=UpShift(height)/windows->image.ximage->height;
composite_info.y+=y;
composite_info.y=DownShift(composite_info.y*scale_factor);
composite_info.height=DownShift(composite_info.height*scale_factor);
if ((composite_info.width != composite_image->columns) ||
(composite_info.height != composite_image->rows))
{
Image
*zoomed_image;
/*
Scale composite image.
*/
zoomed_image=ZoomImage(composite_image,composite_info.width,
composite_info.height,MitchellFilter);
DestroyImage(composite_image);
if (zoomed_image == (Image *) NULL)
{
XSetCursorState(display,windows,False);
return(False);
}
composite_image=zoomed_image;
}
if (compose == DisplaceCompositeOp)
composite_image->geometry=displacement_geometry;
if (blend != 0.0)
{
register int
i;
register RunlengthPacket
*p;
unsigned short
index;
/*
Create mattes for blending.
*/
index=(unsigned short) (((int) DownScale(MaxRGB)*blend)/100);
composite_image->class=DirectClass;
composite_image->matte=True;
p=composite_image->pixels;
for (i=0; i < composite_image->packets; i++)
{
p->index=index;
p++;
}
index=(unsigned short)
((int) DownScale(MaxRGB)-((int) DownScale(MaxRGB)*blend)/100);
image->class=DirectClass;
image->matte=True;
p=image->pixels;
for (i=0; i < image->packets; i++)
{
p->index=index;
p++;
}
}
/*
Composite image with X Image window.
*/
CompositeImage(image,compose,composite_image,composite_info.x,
composite_info.y);
DestroyImage(composite_image);
XSetCursorState(display,windows,False);
/*
Update image configuration.
*/
XConfigureImageColormap(display,resource_info,windows,image);
(void) XConfigureImage(display,resource_info,windows,image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X C o n f i g u r e I m a g e C o l o r m a p %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XConfigureImageColormap creates a new X colormap.
%
% The format of the XConfigureImageColormap routine is:
%
% XConfigureImageColormap(display,resource_info,windows,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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
%
*/
static void XConfigureImageColormap(Display *display,
XResourceInfo *resource_info,XWindows *windows,Image *image)
{
Colormap
colormap;
/*
Make standard colormap.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
if (image->packets == (image->columns*image->rows))
CompressImage(image);
XMakeStandardColormap(display,windows->image.visual_info,resource_info,
image,windows->image.map_info,windows->image.pixel_info);
colormap=windows->image.map_info->colormap;
XSetWindowColormap(display,windows->image.id,colormap);
XSetWindowColormap(display,windows->command.id,colormap);
XSetWindowColormap(display,windows->widget.id,colormap);
if (windows->magnify.mapped)
XSetWindowColormap(display,windows->magnify.id,colormap);
if (windows->pan.mapped)
XSetWindowColormap(display,windows->pan.id,colormap);
XSetCursorState(display,windows,False);
XClientMessage(display,windows->image.id,windows->im_protocols,
windows->im_update_colormap,CurrentTime);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X C o n f i g u r e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function 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 routine is:
%
% status=XConfigureImage(display,resource_info,windows,image)
%
% A description of each parameter follows:
%
% o status: Function XConfigureImage returns True if the window is
% resized. False is returned is there is a memory shortage or if the
% window fails to resize.
%
% 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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
%
*/
static unsigned int XConfigureImage(Display *display,
XResourceInfo *resource_info,XWindows *windows,Image *image)
{
char
geometry[MaxTextExtent];
int
x,
y;
unsigned int
height,
mask,
stasis,
status,
width;
XSizeHints
*size_hints;
XWindowChanges
window_changes;
/*
Dismiss if window dimensions are zero.
*/
width=windows->image.window_changes.width;
height=windows->image.window_changes.height;
if (resource_info->debug)
(void) fprintf(stderr,"Configure Image: %dx%d=>%ux%u\n",
windows->image.ximage->width,windows->image.ximage->height,width,height);
if ((width*height) == 0)
return(True);
/*
Resize image to fit Image window dimensions.
*/
XSetCursorState(display,windows,True);
XFlush(display);
stasis=(width == windows->image.ximage->width) &&
(height == windows->image.ximage->height);
windows->magnify.x=width*windows->magnify.x/windows->image.ximage->width;
windows->magnify.y=height*windows->magnify.y/windows->image.ximage->height;
windows->image.x=width*windows->image.x/windows->image.ximage->width;
windows->image.y=height*windows->image.y/windows->image.ximage->height;
status=XMakeImage(display,resource_info,&windows->image,image,width,height);
if (status == False)
XNoticeWidget(display,windows,"Unable to configure X image:",
windows->image.name);
/*
Notify window manager of the new configuration.
*/
(void) sprintf(geometry,"%ux%u>!",
XDisplayWidth(display,windows->image.screen),
XDisplayHeight(display,windows->image.screen));
(void) ParseImageGeometry(geometry,&x,&y,&width,&height);
window_changes.width=width;
window_changes.height=height;
mask=CWWidth | CWHeight;
if (resource_info->backdrop)
{
mask|=CWX | CWY;
window_changes.x=
(XDisplayWidth(display,windows->image.screen) >> 1)-(width >> 1);
window_changes.y=
(XDisplayHeight(display,windows->image.screen) >> 1)-(height >> 1);
}
XReconfigureWMWindow(display,windows->image.id,windows->image.screen,mask,
&window_changes);
if (image->matte)
XClearWindow(display,windows->image.id);
if (stasis)
XRefreshWindow(display,&windows->image,(XEvent *) NULL);
/*
Update Magnify window configuration.
*/
if (windows->magnify.mapped)
XMakeMagnifyImage(display,windows);
/*
Update pan window configuration.
*/
windows->pan.crop_geometry=windows->image.crop_geometry;
XBestIconSize(display,&windows->pan,image);
while ((windows->pan.width < MinPanSize) &&
(windows->pan.height < MinPanSize))
{
windows->pan.width<<=1;
windows->pan.height<<=1;
}
if (windows->pan.geometry != (char *) NULL)
(void) ParseImageGeometry(windows->pan.geometry,&windows->pan.x,
&windows->pan.y,&windows->pan.width,&windows->pan.height);
window_changes.width=windows->pan.width;
window_changes.height=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;
XSetNormalHints(display,windows->pan.id,size_hints);
XFree((void *) size_hints);
}
XReconfigureWMWindow(display,windows->pan.id,windows->pan.screen,CWWidth |
CWHeight,&window_changes);
if (windows->pan.mapped)
XMakePanImage(display,resource_info,windows,image);
/*
Update icon window configuration.
*/
windows->icon.crop_geometry=windows->image.crop_geometry;
XBestIconSize(display,&windows->icon,image);
window_changes.width=windows->icon.width;
window_changes.height=windows->icon.height;
XReconfigureWMWindow(display,windows->icon.id,windows->icon.screen,
CWWidth | CWHeight,&window_changes);
XSetCursorState(display,windows,False);
return(status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X C r o p I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function 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 routine is:
%
% status=XCropImage(display,resource_info,windows,image,mode)
%
% A description of each parameter follows:
%
% o status: Function XCropImage returns True if the image is
% copyped. False is returned is there is a memory shortage or if the
% image fails to be copyped.
%
% 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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
% o mode: This unsigned value specified whether the image should be
% cropped, copied, or cut.
%
%
*/
static unsigned int XCropImage(Display *display,XResourceInfo *resource_info,
XWindows *windows,Image *image,const ClipboardMode mode)
{
static char
*CropModeMenu[]=
{
"Help",
"Dismiss",
(char *) NULL
},
*RectifyModeMenu[]=
{
"Crop",
"Help",
"Dismiss",
(char *) NULL
};
static ModeType
CropCommands[]=
{
CropHelpCommand,
CropDismissCommand
},
RectifyCommands[]=
{
RectifyCopyCommand,
RectifyHelpCommand,
RectifyDismissCommand
};
char
command[MaxTextExtent],
text[MaxTextExtent];
Cursor
cursor;
int
id,
x,
y;
KeySym
key_symbol;
Image
*crop_image;
RectangleInfo
crop_info,
highlight_info;
register RunlengthPacket
*p;
unsigned int
height,
width;
unsigned long
scale_factor,
state;
XEvent
event;
/*
Map Command widget.
*/
switch (mode)
{
case CopyMode:
{
windows->command.name="Copy";
break;
}
case CropMode:
{
windows->command.name="Crop";
break;
}
case CutMode:
{
windows->command.name="Cut";
break;
}
}
RectifyModeMenu[0]=windows->command.name;
windows->command.data=0;
(void) XCommandWidget(display,windows,CropModeMenu,(XEvent *) NULL);
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);
crop_info.x=windows->image.x+x;
crop_info.y=windows->image.y+y;
crop_info.width=0;
crop_info.height=0;
cursor=XCreateFontCursor(display,XC_fleur);
state=DefaultState;
do
{
if (windows->info.mapped)
{
/*
Display pointer position.
*/
(void) sprintf(text," %+d%+d ",crop_info.x,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,False,
"Help Viewer - Image Copying",ImageCopyHelp);
break;
}
case CropMode:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Cropping",ImageCropHelp);
break;
}
case CutMode:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Cutting",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.
*/
XDefineCursor(display,windows->image.id,cursor);
crop_info.x=windows->image.x+event.xbutton.x;
crop_info.y=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,sizeof(command),
&key_symbol,(XComposeStatus *) NULL);
switch (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,False,
"Help Viewer - Image Copying",ImageCopyHelp);
break;
}
case CropMode:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Cropping",ImageCropHelp);
break;
}
case CutMode:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Cutting",ImageCutHelp);
break;
}
}
break;
}
default:
{
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)
{
if ((x < (windows->info.x+windows->info.width)) &&
(y < (windows->info.y+windows->info.height)))
XWithdrawWindow(display,windows->info.id,windows->info.screen);
}
else
if ((x > (windows->info.x+windows->info.width)) ||
(y > (windows->info.y+windows->info.height)))
XMapWindow(display,windows->info.id);
crop_info.x=windows->image.x+x;
crop_info.y=windows->image.y+y;
break;
}
default:
break;
}
} while (!(state & ExitState));
if (state & EscapeState)
{
/*
User want to exit without cropping.
*/
XWithdrawWindow(display,windows->info.id,windows->info.screen);
XFreeCursor(display,cursor);
return(True);
}
XSetFunction(display,windows->image.highlight_context,GXinvert);
do
{
/*
Size rectangle as pointer moves until the mouse button is released.
*/
x=crop_info.x;
y=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)
XMapWindow(display,windows->info.id);
(void) sprintf(text," %ux%u%+d%+d",crop_info.width,crop_info.height,
crop_info.x,crop_info.y);
XInfoWidget(display,windows,text);
XHighlightRectangle(display,windows->image.id,
windows->image.highlight_context,&highlight_info);
}
else
if (windows->info.mapped)
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=windows->image.x+event.xbutton.x;
crop_info.y=windows->image.y+event.xbutton.y;
break;
}
case ButtonRelease:
{
/*
User has committed to cropping rectangle.
*/
crop_info.x=windows->image.x+event.xbutton.x;
crop_info.y=windows->image.y+event.xbutton.y;
XSetCursorState(display,windows,False);
state|=ExitState;
if (strcmp(windows->command.name,"Rectify") == 0)
break;
windows->command.name="Rectify";
windows->command.data=0;
(void) XCommandWidget(display,windows,RectifyModeMenu,
(XEvent *) NULL);
break;
}
case Expose:
break;
case MotionNotify:
{
crop_info.x=windows->image.x+event.xmotion.x;
crop_info.y=windows->image.y+event.xmotion.y;
}
default:
break;
}
if (((crop_info.x != x) && (crop_info.y != y)) || (state & ExitState))
{
/*
Check boundary conditions.
*/
if (crop_info.x < 0)
crop_info.x=0;
else
if (crop_info.x > windows->image.ximage->width)
crop_info.x=windows->image.ximage->width;
if (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=x;
}
if (crop_info.y < 0)
crop_info.y=0;
else
if (crop_info.y > windows->image.ximage->height)
crop_info.y=windows->image.ximage->height;
if (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=y;
}
}
} while (!(state & ExitState));
/*
Wait for user to grab a corner of the rectangle or press return.
*/
state=DefaultState;
do
{
if (windows->info.mapped)
{
/*
Display pointer position.
*/
(void) sprintf(text," %ux%u%+d%+d",crop_info.width,crop_info.height,
crop_info.x,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.
*/
XSetFunction(display,windows->image.highlight_context,GXcopy);
id=XCommandWidget(display,windows,RectifyModeMenu,&event);
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:
{
XSetFunction(display,windows->image.highlight_context,GXcopy);
switch (mode)
{
case CopyMode:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Copying",ImageCopyHelp);
break;
}
case CropMode:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Cropping",ImageCropHelp);
break;
}
case CutMode:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Cutting",ImageCutHelp);
break;
}
}
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 < (crop_info.x+RoiDelta)) && (x > (crop_info.x-RoiDelta)) &&
(y < (crop_info.y+RoiDelta)) && (y > (crop_info.y-RoiDelta)))
{
crop_info.x=crop_info.x+crop_info.width;
crop_info.y=crop_info.y+crop_info.height;
state|=UpdateConfigurationState;
break;
}
if ((x < (crop_info.x+RoiDelta)) && (x > (crop_info.x-RoiDelta)) &&
(y < (crop_info.y+crop_info.height+RoiDelta)) &&
(y > (crop_info.y+crop_info.height-RoiDelta)))
{
crop_info.x=crop_info.x+crop_info.width;
state|=UpdateConfigurationState;
break;
}
if ((x < (crop_info.x+crop_info.width+RoiDelta)) &&
(x > (crop_info.x+crop_info.width-RoiDelta)) &&
(y < (crop_info.y+RoiDelta)) && (y > (crop_info.y-RoiDelta)))
{
crop_info.y=crop_info.y+crop_info.height;
state|=UpdateConfigurationState;
break;
}
if ((x < (crop_info.x+crop_info.width+RoiDelta)) &&
(x > (crop_info.x+crop_info.width-RoiDelta)) &&
(y < (crop_info.y+crop_info.height+RoiDelta)) &&
(y > (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);
break;
}
case Expose:
{
if (event.xexpose.window == windows->image.id)
if (event.xexpose.count == 0)
{
event.xexpose.x=highlight_info.x;
event.xexpose.y=highlight_info.y;
event.xexpose.width=highlight_info.width;
event.xexpose.height=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,
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
switch (key_symbol)
{
case XK_Escape:
case XK_F20:
state|=EscapeState;
case XK_Return:
{
state|=ExitState;
break;
}
case XK_F1:
case XK_Help:
{
XSetFunction(display,windows->image.highlight_context,GXcopy);
switch (mode)
{
case CopyMode:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Copying",ImageCopyHelp);
break;
}
case CropMode:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Cropping",ImageCropHelp);
break;
}
case CutMode:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Cutting",ImageCutHelp);
break;
}
}
XSetFunction(display,windows->image.highlight_context,GXinvert);
break;
}
default:
{
XBell(display,0);
break;
}
}
break;
}
case KeyRelease:
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)
{
if ((x < (windows->info.x+windows->info.width)) &&
(y < (windows->info.y+windows->info.height)))
XWithdrawWindow(display,windows->info.id,windows->info.screen);
}
else
if ((x > (windows->info.x+windows->info.width)) ||
(y > (windows->info.y+windows->info.height)))
XMapWindow(display,windows->info.id);
break;
}
default:
break;
}
if (state & UpdateConfigurationState)
{
XPutBackEvent(display,&event);
XDefineCursor(display,windows->image.id,cursor);
break;
}
} while (!(state & ExitState));
} while (!(state & ExitState));
XSetFunction(display,windows->image.highlight_context,GXcopy);
XSetCursorState(display,windows,False);
if (state & EscapeState)
return(True);
if (mode == CropMode)
if ((crop_info.width != windows->image.ximage->width) ||
(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=crop_info.width;
windows->image.window_changes.height=crop_info.height;
(void) XConfigureImage(display,resource_info,windows,image);
return(True);
}
/*
Copy image before applying image transforms.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
x=0;
y=0;
width=image->columns;
height=image->rows;
if (windows->image.crop_geometry != (char *) NULL)
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
scale_factor=UpShift(width)/windows->image.ximage->width;
crop_info.x+=x;
crop_info.x=DownShift(crop_info.x*scale_factor);
crop_info.width=DownShift(crop_info.width*scale_factor);
scale_factor=UpShift(height)/windows->image.ximage->height;
crop_info.y+=y;
crop_info.y=DownShift(crop_info.y*scale_factor);
crop_info.height=DownShift(crop_info.height*scale_factor);
crop_image=CropImage(image,&crop_info);
XSetCursorState(display,windows,False);
if (crop_image == (Image *) NULL)
return(False);
if (copy_image != (Image *) NULL)
DestroyImage(copy_image);
copy_image=crop_image;
if (mode == CopyMode)
{
(void) XConfigureImage(display,resource_info,windows,image);
return(True);
}
/*
Cut image.
*/
image->class=DirectClass;
if (!image->matte)
{
/*
Initialize matte data.
*/
p=image->pixels;
for (x=0; x < image->packets; x++)
{
p->index=Opaque;
p++;
}
image->matte=True;
}
if (UncompressImage(image))
for (y=0; y < crop_info.height; y++)
{
p=image->pixels+(crop_info.y+y)*image->columns+crop_info.x;
for (x=0; x < crop_info.width; x++)
{
p->index=Transparent;
p++;
}
}
/*
Update image configuration.
*/
XConfigureImageColormap(display,resource_info,windows,image);
(void) XConfigureImage(display,resource_info,windows,image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X D i s p l a y B a c k g r o u n d I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XDisplayBackgroundImage displays an image in the background of a
% window.
%
% The format of the XDisplayBackgroundImage routine is:
%
% status=XDisplayBackgroundImage(display,resource_info,image)
%
% A description of each parameter follows:
%
% o status: Function XDisplayBackgroundImage returns True if the
% designated window is the root window.
%
% 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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
%
*/
static unsigned int XDisplayBackgroundImage(Display *display,
XResourceInfo *resource_info,Image *image)
{
char
geometry[MaxTextExtent],
visual_type[MaxTextExtent];
static XPixelInfo
pixel_info;
static XStandardColormap
*map_info;
static XVisualInfo
*visual_info = (XVisualInfo *) NULL;
static XWindowInfo
window_info;
unsigned int
height,
status,
width;
Window
root_window;
XGCValues
context_values;
XResourceInfo
resources;
XWindowAttributes
window_attributes;
/*
Determine target window.
*/
resources=(*resource_info);
window_info.id=(Window) NULL;
root_window=XRootWindow(display,XDefaultScreen(display));
if (Latin1Compare(resources.window_id,"root") == 0)
window_info.id=root_window;
else
{
if (isdigit(*resources.window_id))
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)
Error("No window with specified id exists",resources.window_id);
/*
Determine window visual id.
*/
window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
(void) strcpy(visual_type,"default");
status=XGetWindowAttributes(display,window_info.id,&window_attributes);
if (status != False)
(void) sprintf(visual_type,"0x%lx",
XVisualIDFromVisual(window_attributes.visual));
if (visual_info == (XVisualInfo *) NULL)
{
/*
Allocate standard colormap.
*/
map_info=XAllocStandardColormap();
if (map_info == (XStandardColormap *) NULL)
Error("Unable to create standard colormap","Memory allocation failed");
map_info->colormap=(Colormap) NULL;
pixel_info.pixels=(unsigned long *) NULL;
pixel_info.gamma_map=(XColor *) 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)
Error("Unable to get visual",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;
window_info.shared_memory=False;
}
/*
Free previous root colors.
*/
if (window_info.id == root_window)
XDestroyWindowColors(display,root_window);
/*
Initialize colormap.
*/
resources.colormap=SharedColormap;
XMakeStandardColormap(display,visual_info,&resources,image,map_info,
&pixel_info);
/*
Graphic context superclass.
*/
context_values.background=pixel_info.background_color.pixel;
context_values.foreground=pixel_info.foreground_color.pixel;
pixel_info.annotate_context=XCreateGC(display,window_info.id,GCBackground |
GCForeground,&context_values);
if (pixel_info.annotate_context == (GC) NULL)
Error("Unable to create graphic context",(char *) NULL);
/*
Initialize Image window attributes.
*/
XGetWindowInfo(display,visual_info,map_info,&pixel_info,(XFontStruct *) NULL,
&resources,&window_info);
/*
Create the X image.
*/
window_info.width=image->columns;
window_info.height=image->rows;
(void) sprintf(geometry,"%ux%u>!",window_attributes.width,
window_attributes.height);
(void) ParseImageGeometry(geometry,&window_info.x,&window_info.y,
&window_info.width,&window_info.height);
status=XMakeImage(display,&resources,&window_info,image,window_info.width,
window_info.height);
if (status == False)
Error("Unable to create X image",(char *) NULL);
window_info.x=0;
window_info.y=0;
if (resources.debug)
{
(void) fprintf(stderr,"Image: %s[%u] %ux%u ",image->filename,
image->scene,image->columns,image->rows);
if (image->colors != 0)
(void) fprintf(stderr,"%uc ",image->colors);
(void) fprintf(stderr,"%s\n",image->magick);
}
/*
Adjust image dimensions as specified by backdrop or geometry options.
*/
width=window_info.width;
height=window_info.height;
if (resources.backdrop)
{
/*
Center image on root window.
*/
window_info.x=(window_attributes.width >> 1)-
(window_info.ximage->width >> 1);
window_info.y=(window_attributes.height >> 1)-
(window_info.ximage->height >> 1);
width=window_attributes.width;
height=window_attributes.height;
}
if (resources.image_geometry != (char *) NULL)
{
char
default_geometry[MaxTextExtent];
int
flags,
gravity;
XSizeHints
*size_hints;
/*
User specified geometry.
*/
size_hints=XAllocSizeHints();
if (size_hints == (XSizeHints *) NULL)
Error("Unable to display on window","Memory allocation failed");
size_hints->flags=(long) NULL;
(void) sprintf(default_geometry,"%ux%u",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,(int *) &width,(int *) &height,&gravity);
if (flags & (XValue | YValue))
{
width=window_attributes.width;
height=window_attributes.height;
}
XFree((void *) size_hints);
}
/*
Create the X pixmap.
*/
window_info.pixmap=
XCreatePixmap(display,window_info.id,width,height,window_info.depth);
if (window_info.pixmap == (Pixmap) NULL)
Error("Unable to create X pixmap",(char *) NULL);
/*
Display pixmap on the window.
*/
if ((width > window_info.width) || (height > window_info.height))
XFillRectangle(display,window_info.pixmap,window_info.annotate_context,
0,0,width,height);
XPutImage(display,window_info.pixmap,window_info.annotate_context,
window_info.ximage,0,0,window_info.x,window_info.y,window_info.width,
window_info.height);
XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
XClearWindow(display,window_info.id);
if (resources.delay != 0)
XDelay(display,1000*resources.delay);
return(window_info.id == root_window);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X D i s p l a y I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function 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 routine is:
%
% loaded_image=XDisplayImage(display,resource_info,argv,argc,image,state)
%
% A description of each parameter follows:
%
% o loaded_image: Function 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;
% returned from ReadImage.
%
%
*/
static Image *XDisplayImage(Display *display,XResourceInfo *resource_info,
char **argv,int argc,Image **image,unsigned long *state)
{
#define MagnifySize 256 /* must be a power of 2 */
#define MagickMenus 10
#define MaxWindows 10
#define MagickTitle "Commands"
static 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",
"Equalize",
"Normalize",
"Negate",
"Grayscale",
"Map...",
"Quantize...",
(char *) NULL
},
*EffectsMenu[]=
{
"Despeckle",
"Reduce Noise",
"Add Noise...",
"Sharpen...",
"Blur...",
"Threshold...",
"Edge Detect...",
"Emboss...",
"Spread...",
"Solarize...",
"Shade...",
"Raise...",
"Segment...",
(char *) NULL
},
*FXMenu[]=
{
"Swirl...",
"Implode...",
"Wave...",
"Oil Painting...",
"Charcoal Drawing...",
(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...",
"Undo",
"Restore",
"Gamma...",
"Image Info",
"Quit",
(char *) NULL
},
*ImmutableMenu[]=
{
"Image Info",
"Quit",
(char *) NULL
};
static 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,
EqualizeCommand,
NormalizeCommand,
NegateCommand,
GrayscaleCommand,
MapCommand,
QuantizeCommand
},
EffectsCommands[]=
{
DespeckleCommand,
ReduceNoiseCommand,
AddNoiseCommand,
SharpenCommand,
BlurCommand,
ThresholdCommand,
EdgeDetectCommand,
EmbossCommand,
SpreadCommand,
SolarizeCommand,
ShadeCommand,
RaiseCommand,
SegmentCommand
},
FXCommands[]=
{
SwirlCommand,
ImplodeCommand,
WaveCommand,
OilPaintCommand,
CharcoalDrawingCommand
},
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,
UndoCommand,
RestoreCommand,
GammaCommand,
InfoCommand,
QuitCommand
},
ImmutableCommands[]=
{
InfoCommand,
QuitCommand
};
static CommandType
*Commands[MagickMenus]=
{
FileCommands,
EditCommands,
ViewCommands,
TransformCommands,
EnhanceCommands,
EffectsCommands,
FXCommands,
ImageEditCommands,
MiscellanyCommands,
HelpCommands
};
char
command[MaxTextExtent],
geometry[MaxTextExtent],
image_signature[MaxTextExtent],
resource_name[MaxTextExtent];
CommandType
command_type;
Image
*displayed_image,
*loaded_image;
int
entry,
id,
status;
KeySym
key_symbol;
MonitorHandler
handler;
register int
i;
static char
working_directory[MaxTextExtent];
static Window
root_window;
static XClassHint
*class_hints;
static XFontStruct
*font_info;
static XPixelInfo
icon_pixel,
pixel_info;
static XPoint
vid_info;
static XResourceInfo
icon_resources;
static XStandardColormap
*icon_map,
*map_info;
static XVisualInfo
*icon_visual,
*visual_info = (XVisualInfo *) NULL;
static XWindowInfo
*magick_windows[MaxWindows];
static XWMHints
*manager_hints;
static unsigned int
number_windows;
struct stat
file_info;
time_t
timer,
timestamp,
update_time;
unsigned int
context_mask;
XEvent
event;
XGCValues
context_values;
XWindowChanges
window_changes;
if (visual_info != (XVisualInfo *) NULL)
(void) chdir(working_directory);
else
{
/*
Allocate standard colormap.
*/
if (resource_info->debug)
{
XSynchronize(display,True);
(void) fprintf(stderr,"Version: %s\n",Version);
}
map_info=XAllocStandardColormap();
icon_map=XAllocStandardColormap();
if ((map_info == (XStandardColormap *) NULL) ||
(icon_map == (XStandardColormap *) NULL))
Error("Unable to create standard colormap","Memory allocation failed");
map_info->colormap=(Colormap) NULL;
icon_map->colormap=(Colormap) NULL;
pixel_info.pixels=(unsigned long *) NULL;
pixel_info.gamma_map=(XColor *) NULL;
pixel_info.annotate_context=(GC) NULL;
pixel_info.highlight_context=(GC) NULL;
pixel_info.widget_context=(GC) NULL;
font_info=(XFontStruct *) NULL;
icon_pixel.annotate_context=(GC) NULL;
icon_pixel.pixels=(unsigned long *) NULL;
icon_pixel.gamma_map=(XColor *) NULL;
/*
Allocate visual.
*/
icon_resources=(*resource_info);
icon_resources.map_type=(char *) NULL;
icon_resources.visual_type="default";
icon_resources.colormap=SharedColormap;
visual_info=XBestVisualInfo(display,map_info,resource_info);
icon_visual=XBestVisualInfo(display,icon_map,&icon_resources);
if ((visual_info == (XVisualInfo *) NULL) ||
(icon_visual == (XVisualInfo *) NULL))
Error("Unable to get visual",resource_info->visual_type);
if (resource_info->debug)
{
(void) fprintf(stderr,"Visual:\n");
(void) fprintf(stderr," visual id: 0x%lx\n",visual_info->visualid);
(void) fprintf(stderr," class: %s\n",
XVisualClassName(visual_info->class));
(void) fprintf(stderr," depth: %d planes\n",visual_info->depth);
(void) fprintf(stderr," size of colormap: %d entries\n",
visual_info->colormap_size);
(void) fprintf(stderr," red, green, blue masks: 0x%lx 0x%lx 0x%lx\n",
visual_info->red_mask,visual_info->green_mask,
visual_info->blue_mask);
(void) fprintf(stderr," significant bits in color: %d bits\n",
visual_info->bits_per_rgb);
}
/*
Allocate atoms.
*/
windows=(XWindows *) malloc(sizeof(XWindows));
if (windows == (XWindows *) NULL)
Error("Unable to create X windows","Memory allocation failed");
windows->wm_protocols=XInternAtom(display,"WM_PROTOCOLS",False);
windows->wm_delete_window=XInternAtom(display,"WM_DELETE_WINDOW",False);
windows->wm_take_focus=XInternAtom(display,"WM_TAKE_FOCUS",False);
windows->im_protocols=XInternAtom(display,"IM_PROTOCOLS",False);
windows->im_update_widget=XInternAtom(display,"IM_UPDATE_WIDGET",False);
windows->im_update_colormap=
XInternAtom(display,"IM_UPDATE_COLORMAP",False);
windows->im_update_signature=
XInternAtom(display,"IM_UPDATE_SIGNATURE",False);
*image_signature='\0';
windows->im_former_image=XInternAtom(display,"IM_FORMER_IMAGE",False);
windows->im_next_image=XInternAtom(display,"IM_NEXT_IMAGE",False);
windows->im_retain_colors=XInternAtom(display,"IM_RETAIN_COLORS",False);
windows->im_exit=XInternAtom(display,"IM_EXIT",False);
windows->dnd_protocols=XInternAtom(display,"DndProtocol",False);
if (resource_info->debug)
{
(void) fprintf(stderr,"Protocols:\n");
(void) fprintf(stderr," Window Manager: 0x%lx\n",
windows->wm_protocols);
(void) fprintf(stderr," delete window: 0x%lx\n",
windows->wm_delete_window);
(void) fprintf(stderr," take focus: 0x%lx\n",
windows->wm_take_focus);
(void) fprintf(stderr," ImageMagick: 0x%lx\n",
windows->im_protocols);
(void) fprintf(stderr," update widget: 0x%lx\n",
windows->im_update_widget);
(void) fprintf(stderr," update colormap: 0x%lx\n",
windows->im_update_colormap);
(void) fprintf(stderr," update signature: 0x%lx\n",
windows->im_update_signature);
(void) fprintf(stderr," former image: 0x%lx\n",
windows->im_former_image);
(void) fprintf(stderr," next image: 0x%lx\n",
windows->im_next_image);
(void) fprintf(stderr," retain colors: 0x%lx\n",
windows->im_retain_colors);
(void) fprintf(stderr," exit: 0x%lx\n",windows->im_exit);
(void) fprintf(stderr," Drag and Drop: 0x%lx\n",
windows->dnd_protocols);
}
/*
Allocate class and manager hints.
*/
class_hints=XAllocClassHint();
manager_hints=XAllocWMHints();
if ((class_hints == (XClassHint *) NULL) ||
(manager_hints == (XWMHints *) NULL))
Error("Unable to allocate X hints",(char *) NULL);
/*
Determine group leader if we have one.
*/
root_window=XRootWindow(display,visual_info->screen);
windows->group_leader.id=(Window) NULL;
if (resource_info->window_group != (char *) NULL)
{
if (isdigit(*resource_info->window_group))
windows->group_leader.id=XWindowByID(display,root_window,(Window)
strtol((char *) resource_info->window_group,(char **) NULL,0));
if (windows->group_leader.id == (Window) NULL)
windows->group_leader.id=
XWindowByName(display,root_window,resource_info->window_group);
}
/*
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 < number_windows; i++)
magick_windows[i]->id=(Window) NULL;
vid_info.x=0;
vid_info.y=0;
}
/*
Initialize Standard Colormap.
*/
loaded_image=(Image *) NULL;
displayed_image=(*image);
if (resource_info->debug)
{
(void) fprintf(stderr,"Image: %s[%u] %ux%u ",displayed_image->filename,
displayed_image->scene,displayed_image->columns,displayed_image->rows);
if (displayed_image->colors != 0)
(void) fprintf(stderr,"%uc ",displayed_image->colors);
(void) fprintf(stderr,"%s\n",displayed_image->magick);
}
XMakeStandardColormap(display,visual_info,resource_info,displayed_image,
map_info,&pixel_info);
/*
Initialize font info.
*/
if (font_info != (XFontStruct *) NULL)
XFreeFont(display,font_info);
font_info=XBestFont(display,resource_info,False);
if (font_info == (XFontStruct *) NULL)
Error("Unable to load font",resource_info->font);
/*
Initialize graphic context.
*/
windows->context.id=(Window) NULL;
XGetWindowInfo(display,visual_info,map_info,&pixel_info,font_info,
resource_info,&windows->context);
class_hints->res_name="superclass";
class_hints->res_class="Display";
manager_hints->flags=InputHint | StateHint;
manager_hints->input=False;
manager_hints->initial_state=WithdrawnState;
XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
&windows->context);
if (resource_info->debug)
(void) fprintf(stderr,"Window id: 0x%lx (context)\n",windows->context.id);
context_values.background=pixel_info.background_color.pixel;
context_values.font=font_info->fid;
context_values.foreground=pixel_info.foreground_color.pixel;
context_values.graphics_exposures=False;
context_mask=GCBackground | GCFont | GCForeground | GCGraphicsExposures;
if (pixel_info.annotate_context != (GC) NULL)
XFreeGC(display,pixel_info.annotate_context);
pixel_info.annotate_context=
XCreateGC(display,windows->context.id,context_mask,&context_values);
if (pixel_info.annotate_context == (GC) NULL)
Error("Unable to create graphic context",(char *) NULL);
context_values.background=pixel_info.depth_color.pixel;
if (pixel_info.widget_context != (GC) NULL)
XFreeGC(display,pixel_info.widget_context);
pixel_info.widget_context=
XCreateGC(display,windows->context.id,context_mask,&context_values);
if (pixel_info.widget_context == (GC) NULL)
Error("Unable to create graphic context",(char *) NULL);
context_values.background=pixel_info.foreground_color.pixel;
context_values.foreground=pixel_info.background_color.pixel;
context_values.plane_mask=
context_values.background ^ context_values.foreground;
if (pixel_info.highlight_context != (GC) NULL)
XFreeGC(display,pixel_info.highlight_context);
pixel_info.highlight_context=XCreateGC(display,windows->context.id,
context_mask | GCPlaneMask,&context_values);
if (pixel_info.highlight_context == (GC) NULL)
Error("Unable to create graphic context",(char *) NULL);
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,displayed_image);
windows->icon.attributes.colormap=
XDefaultColormap(display,icon_visual->screen);
windows->icon.attributes.event_mask=ExposureMask | StructureNotifyMask;
class_hints->res_name="icon";
manager_hints->flags=InputHint | StateHint;
manager_hints->input=False;
manager_hints->initial_state=IconicState;
XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
&windows->icon);
if (resource_info->debug)
(void) fprintf(stderr,"Window id: 0x%lx (icon)\n",windows->icon.id);
/*
Initialize graphic context for icon window.
*/
if (icon_pixel.annotate_context != (GC) NULL)
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,
GCBackground | GCForeground,&context_values);
if (icon_pixel.annotate_context == (GC) NULL)
Error("Unable to create graphic context",(char *) NULL);
windows->icon.annotate_context=icon_pixel.annotate_context;
/*
Initialize Image window.
*/
if (windows->image.id != (Window) NULL)
{
free((char *) windows->image.name);
free((char *) windows->image.icon_name);
}
XGetWindowInfo(display,visual_info,map_info,&pixel_info,font_info,
resource_info,&windows->image);
windows->image.shape=True;
windows->image.name=(char *) malloc(MaxTextExtent*sizeof(char));
windows->image.icon_name=(char *) malloc(MaxTextExtent*sizeof(char));
if ((windows->image.name == NULL) || (windows->image.icon_name == NULL))
Error("Unable to create Image window","Memory allocation failed");
if ((resource_info->title != (char *) NULL) && !(*state & MontageImageState))
{
/*
User specified window name.
*/
(void) strcpy(windows->image.name,resource_info->title);
(void) strcpy(windows->image.icon_name,resource_info->title);
}
else
{
register char
*p;
register Image
*q;
unsigned int
count;
/*
Window name is the base of the filename.
*/
p=displayed_image->filename+Extent(displayed_image->filename)-1;
while ((p > displayed_image->filename) && (*(p-1) != *BasenameSeparator))
p--;
(void) sprintf(windows->image.name,"ImageMagick: %s[%u]",p,
displayed_image->scene);
q=displayed_image;
while (q->previous != (Image *) NULL)
q=q->previous;
for (count=1; q->next != (Image *) NULL; count++)
q=q->next;
(void) sprintf(windows->image.name,"ImageMagick: %s[%u of %u]",p,
displayed_image->scene,count);
if ((displayed_image->previous == (Image *) NULL) &&
(displayed_image->next == (Image *) NULL) &&
(displayed_image->scene == 0))
(void) sprintf(windows->image.name,"ImageMagick: %s",p);
(void) strcpy(windows->image.icon_name,p);
}
if (resource_info->immutable)
windows->image.immutable=True;
windows->image.use_pixmap=resource_info->use_pixmap;
windows->image.geometry=resource_info->image_geometry;
windows->image.width=displayed_image->columns;
windows->image.height=displayed_image->rows;
(void) sprintf(geometry,"%ux%u>!",XDisplayWidth(display,visual_info->screen),
XDisplayHeight(display,visual_info->screen));
(void) ParseImageGeometry(geometry,&windows->image.x,&windows->image.y,
&windows->image.width,&windows->image.height);
windows->image.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
StructureNotifyMask | SubstructureNotifyMask;
XGetWindowInfo(display,visual_info,map_info,&pixel_info,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;
windows->backdrop.name="ImageMagick Backdrop";
windows->backdrop.flags=USSize | USPosition;
windows->backdrop.width=XDisplayWidth(display,visual_info->screen);
windows->backdrop.height=XDisplayHeight(display,visual_info->screen);
windows->backdrop.border_width=0;
windows->backdrop.immutable=True;
windows->backdrop.attributes.do_not_propagate_mask=ButtonPressMask |
ButtonReleaseMask;
windows->backdrop.attributes.event_mask=ButtonPressMask | KeyPressMask |
StructureNotifyMask;
windows->backdrop.attributes.override_redirect=True;
class_hints->res_name="backdrop";
manager_hints->flags=IconWindowHint | InputHint | StateHint;
manager_hints->icon_window=windows->icon.id;
manager_hints->input=True;
manager_hints->initial_state=
resource_info->iconic ? IconicState : NormalState;
XMakeWindow(display,root_window,argv,argc,class_hints,manager_hints,
&windows->backdrop);
if (resource_info->debug)
(void) fprintf(stderr,"Window id: 0x%lx (backdrop)\n",
windows->backdrop.id);
XMapWindow(display,windows->backdrop.id);
XClearWindow(display,windows->backdrop.id);
if (windows->image.id != (Window) NULL)
{
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) >> 1)-
(windows->image.width >> 1);
windows->image.y=(XDisplayHeight(display,visual_info->screen) >> 1)-
(windows->image.height >> 1);
}
if (resource_info->name == (char *) NULL)
class_hints->res_name=resource_info->client_name;
else
class_hints->res_name=resource_info->name;
manager_hints->flags=IconWindowHint | InputHint | StateHint;
manager_hints->icon_window=windows->icon.id;
manager_hints->input=True;
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;
XSelectInput(display,windows->group_leader.id,StructureNotifyMask);
if (resource_info->debug)
(void) fprintf(stderr,"Window id: 0x%lx (group leader)\n",
windows->group_leader.id);
}
XMakeWindow(display,
(Window) (resource_info->backdrop ? windows->backdrop.id : root_window),
argv,argc,class_hints,manager_hints,&windows->image);
if (windows->group_leader.id != (Window) NULL)
XSetTransientForHint(display,windows->image.id,windows->group_leader.id);
if (resource_info->debug)
(void) fprintf(stderr,"Window id: 0x%lx (image)\n",windows->image.id);
/*
Initialize X image structure.
*/
windows->image.x=0;
windows->image.y=0;
status=XMakeImage(display,resource_info,&windows->image,displayed_image,
displayed_image->columns,displayed_image->rows);
if (status == False)
Error("Unable to create X image",(char *) NULL);
if (!windows->image.mapped || (windows->backdrop.id != (Window) NULL))
XMapWindow(display,windows->image.id);
if (windows->image.mapped)
XRefreshWindow(display,&windows->image,(XEvent *) NULL);
XClientMessage(display,windows->image.id,windows->im_protocols,
windows->im_update_signature,CurrentTime);
/*
Initialize Info widget.
*/
XGetWindowInfo(display,visual_info,map_info,&pixel_info,font_info,
resource_info,&windows->info);
windows->info.name="Info";
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;
class_hints->res_name="info";
manager_hints->flags=InputHint | StateHint | WindowGroupHint;
manager_hints->input=False;
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);
XSetTransientForHint(display,windows->info.id,windows->image.id);
if (windows->image.mapped)
XWithdrawWindow(display,windows->info.id,windows->info.screen);
if (resource_info->debug)
(void) fprintf(stderr,"Window id: 0x%lx (info)\n",windows->info.id);
/*
Initialize Command widget.
*/
XGetWindowInfo(display,visual_info,map_info,&pixel_info,font_info,
resource_info,&windows->command);
windows->command.data=MagickMenus;
(void) XCommandWidget(display,windows,CommandMenu,(XEvent *) NULL);
(void) sprintf(resource_name,"%s.command",resource_info->client_name);
windows->command.geometry=XGetResourceClass(resource_info->resource_database,
resource_name,"geometry",(char *) NULL);
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;
class_hints->res_name="command";
manager_hints->flags=InputHint | StateHint | WindowGroupHint;
manager_hints->input=False;
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=windows->info.highlight_stipple;
windows->command.shadow_stipple=windows->info.shadow_stipple;
XSetTransientForHint(display,windows->command.id,windows->image.id);
if (windows->command.mapped)
XMapRaised(display,windows->command.id);
if (resource_info->debug)
(void) fprintf(stderr,"Window id: 0x%lx (command)\n",windows->command.id);
/*
Initialize Widget window.
*/
if (windows->widget.id != (Window) NULL)
free((char *) windows->widget.name);
XGetWindowInfo(display,visual_info,map_info,&pixel_info,font_info,
resource_info,&windows->widget);
(void) sprintf(resource_name,"%s.widget",resource_info->client_name);
windows->widget.geometry=XGetResourceClass(resource_info->resource_database,
resource_name,"geometry",(char *) NULL);
windows->widget.name=(char *) malloc(MaxTextExtent*sizeof(char));
if (windows->widget.name == NULL)
Error("Unable to create Image window","Memory allocation failed");
*windows->widget.name='\0';
windows->widget.border_width=0;
windows->widget.flags|=PPosition;
windows->widget.attributes.backing_store=WhenMapped;
windows->widget.attributes.save_under=True;
windows->widget.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
KeyReleaseMask | LeaveWindowMask | OwnerGrabButtonMask |
StructureNotifyMask;
class_hints->res_name="widget";
manager_hints->flags=InputHint | StateHint | WindowGroupHint;
manager_hints->input=True;
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=windows->info.highlight_stipple;
windows->widget.shadow_stipple=windows->info.shadow_stipple;
XSetTransientForHint(display,windows->widget.id,windows->image.id);
if (resource_info->debug)
(void) fprintf(stderr,"Window id: 0x%lx (widget)\n",windows->widget.id);
/*
Initialize popup window.
*/
if (windows->popup.id != (Window) NULL)
free((char *) windows->popup.name);
XGetWindowInfo(display,visual_info,map_info,&pixel_info,font_info,
resource_info,&windows->popup);
windows->popup.name=(char *) malloc(MaxTextExtent*sizeof(char));
if (windows->popup.name == NULL)
Error("Unable to create Image window","Memory allocation failed");
*windows->popup.name='\0';
windows->popup.border_width=0;
windows->popup.flags|=PPosition;
windows->popup.attributes.backing_store=WhenMapped;
windows->popup.attributes.save_under=True;
windows->popup.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
ButtonReleaseMask | EnterWindowMask | ExposureMask | KeyPressMask |
KeyReleaseMask | LeaveWindowMask | StructureNotifyMask;
class_hints->res_name="popup";
manager_hints->flags=InputHint | StateHint | WindowGroupHint;
manager_hints->input=True;
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=windows->info.highlight_stipple;
windows->popup.shadow_stipple=windows->info.shadow_stipple;
XSetTransientForHint(display,windows->popup.id,windows->image.id);
if (resource_info->debug)
(void) fprintf(stderr,"Window id: 0x%lx (pop up)\n",windows->popup.id);
/*
Initialize Magnify window and cursor.
*/
if (windows->magnify.id != (Window) NULL)
free((char *) windows->magnify.name);
XGetWindowInfo(display,visual_info,map_info,&pixel_info,font_info,
resource_info,&windows->magnify);
(void) sprintf(resource_name,"%s.magnify",resource_info->client_name);
windows->magnify.geometry=XGetResourceClass(resource_info->resource_database,
resource_name,"geometry",(char *) NULL);
windows->magnify.name=(char *) malloc(MaxTextExtent*sizeof(char));
if (windows->magnify.name == NULL)
Error("Unable to create Magnify window","Memory allocation failed");
(void) sprintf(windows->magnify.name,"Magnify %uX",resource_info->magnify);
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)
Error("Unable to create cursor",(char *) NULL);
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;
class_hints->res_name="magnify";
manager_hints->flags=InputHint | StateHint | WindowGroupHint;
manager_hints->input=True;
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 (resource_info->debug)
(void) fprintf(stderr,"Window id: 0x%lx (magnify)\n",windows->magnify.id);
XSetTransientForHint(display,windows->magnify.id,windows->image.id);
handler=SetMonitorHandler((MonitorHandler) NULL);
status=XMakeImage(display,resource_info,&windows->magnify,displayed_image,
windows->magnify.width,windows->magnify.height);
(void) SetMonitorHandler(handler);
if (status == False)
Error("Unable to create X magnify image",(char *) NULL);
if (windows->magnify.mapped)
XMapRaised(display,windows->magnify.id);
/*
Initialize panning window.
*/
XGetWindowInfo(display,visual_info,map_info,&pixel_info,font_info,
resource_info,&windows->pan);
windows->pan.name="Pan Icon";
windows->pan.width=windows->icon.width;
windows->pan.height=windows->icon.height;
(void) sprintf(resource_name,"%s.pan",resource_info->client_name);
windows->pan.geometry=XGetResourceClass(resource_info->resource_database,
resource_name,"geometry",(char *) NULL);
if (windows->pan.geometry != (char *) NULL)
(void) ParseImageGeometry(windows->pan.geometry,&windows->pan.x,
&windows->pan.y,&windows->pan.width,&windows->pan.height);
windows->pan.flags|=PPosition;
windows->pan.immutable=True;
windows->pan.attributes.event_mask=ButtonMotionMask | ButtonPressMask |
ButtonReleaseMask | ExposureMask | KeyPressMask | KeyReleaseMask |
StructureNotifyMask;
class_hints->res_name="pan";
manager_hints->flags=InputHint | StateHint | WindowGroupHint;
manager_hints->input=True;
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 (resource_info->debug)
(void) fprintf(stderr,"Window id: 0x%lx (pan)\n",windows->pan.id);
XSetTransientForHint(display,windows->pan.id,windows->image.id);
if (windows->info.mapped)
XWithdrawWindow(display,windows->info.id,windows->info.screen);
if (windows->image.mapped)
if ((windows->image.width < windows->image.ximage->width) ||
(windows->image.height < windows->image.ximage->height))
XMapRaised(display,windows->pan.id);
/*
Respond to events.
*/
(void) SetMonitorHandler(XProgressMonitor);
(void) SetWarningHandler(XWarning);
if (!resource_info->display_warnings)
(void) SetWarningHandler((ErrorHandler) NULL);
timer=time((time_t *) NULL)+resource_info->delay+1;
update_time=0;
if (resource_info->update)
{
/*
Determine when file data was last modified.
*/
status=stat(displayed_image->filename,&file_info);
if (status == 0)
update_time=file_info.st_mtime;
}
*state&=(~FormerImageState);
*state&=(~MontageImageState);
*state&=(~NextImageState);
do
{
/*
Handle a window event.
*/
if (windows->image.mapped && resource_info->delay)
{
if (timer < time((time_t *) NULL))
if (!resource_info->update)
*state|=NextImageState | ExitState;
else
{
/*
Determine if image file was modified.
*/
status=stat(displayed_image->filename,&file_info);
if (status == 0)
if (update_time != file_info.st_mtime)
{
/*
Redisplay image.
*/
(void) strcpy(resource_info->image_info->filename,
displayed_image->filename);
loaded_image=ReadImage(resource_info->image_info);
if (loaded_image != (Image *) NULL)
*state|=NextImageState | ExitState;
}
timer=time((time_t *) NULL)+resource_info->delay+1;
}
if (XEventsQueued(display,QueuedAfterFlush) == 0)
{
/*
Do not block if delay > 0.
*/
XDelay(display,SuspendTime << 2);
continue;
}
}
timestamp=time((time_t *) NULL);
XNextEvent(display,&event);
if (!windows->image.stasis)
windows->image.stasis=(time((time_t *) NULL)-timestamp) > 0;
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) strcpy(command,CommandMenu[id]);
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) strcpy(command,Menus[id][entry]);
command_type=Commands[id][entry];
}
if (command_type != NullCommand)
loaded_image=XMagickCommand(display,resource_info,windows,
command_type,&displayed_image);
continue;
}
switch (event.type)
{
case ButtonPress:
{
if (resource_info->debug)
(void) fprintf(stderr,"Button Press: 0x%lx %u +%d+%d\n",
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)
{
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 Immutable menu.
*/
entry=XMenuWidget(display,windows,"Commands",ImmutableMenu,
command);
if (entry >= 0)
loaded_image=XMagickCommand(display,resource_info,
windows,ImmutableCommands[entry],&displayed_image);
break;
}
/*
Map/unmap Command widget.
*/
if (windows->command.mapped)
XWithdrawWindow(display,windows->command.id,
windows->command.screen);
else
{
(void) XCommandWidget(display,windows,CommandMenu,
(XEvent *) NULL);
XMapRaised(display,windows->command.id);
}
break;
}
case Button2:
{
/*
User pressed the image magnify button.
*/
(void) XMagickCommand(display,resource_info,windows,ZoomCommand,
&displayed_image);
XMagnifyImage(display,windows,&event);
break;
}
case Button3:
{
if (displayed_image->montage != (char *) NULL)
{
/*
Open or delete a tile from a visual image directory.
*/
loaded_image=XTileImage(display,resource_info,windows,
displayed_image,&event);
if (loaded_image != (Image *) NULL)
*state|=MontageImageState | NextImageState | ExitState;
vid_info.x=windows->image.x;
vid_info.y=windows->image.y;
break;
}
if (resource_info->immutable)
{
/*
Select a command from the Immutable menu.
*/
entry=XMenuWidget(display,windows,"Commands",ImmutableMenu,
command);
if (entry >= 0)
loaded_image=XMagickCommand(display,resource_info,
windows,ImmutableCommands[entry],&displayed_image);
break;
}
/*
Select a command from the Short Cuts menu.
*/
entry=XMenuWidget(display,windows,"Short Cuts",ShortCutsMenu,
command);
if (entry >= 0)
loaded_image=XMagickCommand(display,resource_info,windows,
ShortCutsCommands[entry],&displayed_image);
break;
}
default:
break;
}
break;
}
if (event.xbutton.window == windows->magnify.id)
{
char
command[MaxTextExtent];
int
factor;
static 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)
{
XPanImage(display,windows,&event);
break;
}
timer=time((time_t *) NULL)+resource_info->delay+1;
break;
}
case ButtonRelease:
{
if (resource_info->debug)
(void) fprintf(stderr,"Button Release: 0x%lx %u +%d+%d\n",
event.xbutton.window,event.xbutton.button,event.xbutton.x,
event.xbutton.y);
break;
}
case ClientMessage:
{
if (resource_info->debug)
(void) fprintf(stderr,"Client Message: 0x%lx 0x%lx %d 0x%lx\n",
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 == windows->im_update_widget)
{
windows->command.name=MagickTitle;
windows->command.data=MagickMenus;
(void) XCommandWidget(display,windows,CommandMenu,
(XEvent *) NULL);
break;
}
if (*event.xclient.data.l == windows->im_update_colormap)
{
/*
Update graphic context and window colormap.
*/
for (i=0; i < number_windows; i++)
{
if (magick_windows[i]->id == windows->icon.id)
continue;
context_values.background=pixel_info.background_color.pixel;
context_values.foreground=pixel_info.foreground_color.pixel;
XChangeGC(display,magick_windows[i]->annotate_context,
context_mask,&context_values);
XChangeGC(display,magick_windows[i]->widget_context,
context_mask,&context_values);
context_values.background=pixel_info.foreground_color.pixel;
context_values.foreground=pixel_info.background_color.pixel;
context_values.plane_mask=
context_values.background ^ context_values.foreground;
XChangeGC(display,magick_windows[i]->highlight_context,
context_mask | GCPlaneMask,&context_values);
magick_windows[i]->attributes.background_pixel=
pixel_info.background_color.pixel;
magick_windows[i]->attributes.border_pixel=
pixel_info.border_color.pixel;
magick_windows[i]->attributes.colormap=map_info->colormap;
XChangeWindowAttributes(display,magick_windows[i]->id,
magick_windows[i]->mask,&magick_windows[i]->attributes);
}
if (windows->pan.mapped)
{
XSetWindowBackgroundPixmap(display,windows->pan.id,
windows->pan.pixmap);
XClearWindow(display,windows->pan.id);
XDrawPanRectangle(display,windows);
}
if (windows->backdrop.id != (Window) NULL)
XInstallColormap(display,map_info->colormap);
break;
}
if (*event.xclient.data.l == windows->im_update_signature)
{
SignatureImage(displayed_image);
(void) strcpy(image_signature,displayed_image->signature);
break;
}
if (*event.xclient.data.l == windows->im_former_image)
{
*state|=FormerImageState | ExitState;
break;
}
if (*event.xclient.data.l == windows->im_next_image)
{
*state|=NextImageState | ExitState;
break;
}
if (*event.xclient.data.l == windows->im_retain_colors)
{
*state|=RetainColorsState;
break;
}
if (*event.xclient.data.l == 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 ((int) (*event.xclient.data.l) != 2)
break;
selection=XInternAtom(display,"DndSelection",False);
status=XGetWindowProperty(display,root_window,selection,0L,2047L,
False,(Atom) AnyPropertyType,&type,&format,&length,&after,&data);
if ((status != Success) || (length == 0))
break;
(void) strcpy(resource_info->image_info->filename,(char *) data);
loaded_image=ReadImage(resource_info->image_info);
if (loaded_image != (Image *) NULL)
*state|=NextImageState | ExitState;
XFree((void *) data);
break;
}
/*
If client window delete message, exit.
*/
if (event.xclient.message_type != windows->wm_protocols)
break;
if (*event.xclient.data.l != windows->wm_delete_window)
break;
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,
displayed_image);
}
break;
}
case ConfigureNotify:
{
if (resource_info->debug)
(void) fprintf(stderr,"Configure Notify: 0x%lx %dx%d+%d+%d %d\n",
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)
{
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;
XReconfigureWMWindow(display,windows->command.id,
windows->command.screen,CWX | CWY,&window_changes);
}
if (windows->magnify.geometry == (char *) NULL)
if (!windows->magnify.mapped)
{
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;
XReconfigureWMWindow(display,windows->magnify.id,
windows->magnify.screen,CWX | CWY,&window_changes);
}
if (windows->pan.geometry == (char *) NULL)
if (!windows->pan.mapped)
{
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;
XReconfigureWMWindow(display,windows->pan.id,
windows->pan.screen,CWX | CWY,&window_changes);
}
}
if ((event.xconfigure.width == windows->image.width) &&
(event.xconfigure.height == windows->image.height))
{
if (windows->image.mapped)
XRefreshWindow(display,&windows->image,(XEvent *) NULL);
break;
}
windows->image.width=event.xconfigure.width;
windows->image.height=event.xconfigure.height;
windows->image.x=0;
windows->image.y=0;
if (displayed_image->montage != (char *) NULL)
{
windows->image.x=vid_info.x;
windows->image.y=vid_info.y;
}
if (windows->image.mapped && windows->image.stasis)
{
/*
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,
displayed_image);
}
if ((event.xconfigure.width < windows->image.ximage->width) ||
(event.xconfigure.height < windows->image.ximage->height))
{
XMapRaised(display,windows->pan.id);
XDrawPanRectangle(display,windows);
}
else
if (windows->pan.mapped)
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=event.xconfigure.width;
windows->magnify.height=event.xconfigure.height;
if (!windows->magnify.mapped)
break;
magnify=1;
while (magnify <= event.xconfigure.width)
magnify<<=1;
while (magnify <= event.xconfigure.height)
magnify<<=1;
magnify>>=1;
if ((magnify != event.xconfigure.width) ||
(magnify != event.xconfigure.height))
{
window_changes.width=magnify;
window_changes.height=magnify;
XReconfigureWMWindow(display,windows->magnify.id,
windows->magnify.screen,CWWidth | CWHeight,&window_changes);
break;
}
handler=SetMonitorHandler((MonitorHandler) NULL);
status=XMakeImage(display,resource_info,&windows->magnify,
displayed_image,windows->magnify.width,windows->magnify.height);
XMakeMagnifyImage(display,windows);
(void) SetMonitorHandler(handler);
break;
}
if (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=event.xconfigure.width;
windows->pan.height=event.xconfigure.height;
break;
}
if (event.xconfigure.window == windows->icon.id)
{
/*
Icon window has a new configuration.
*/
windows->icon.width=event.xconfigure.width;
windows->icon.height=event.xconfigure.height;
break;
}
break;
}
case DestroyNotify:
{
/*
Group leader has exited.
*/
if (resource_info->debug)
(void) fprintf(stderr,"Destroy Notify: 0x%lx\n",
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)
XInductColormap(display,map_info->colormap);
break;
}
case Expose:
{
if (resource_info->debug)
(void) fprintf(stderr,"Expose: 0x%lx %dx%d+%d+%d\n",
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)
if (windows->image.mapped)
{
XRefreshWindow(display,&windows->image,&event);
timer=time((time_t *) NULL)+resource_info->delay+1;
break;
}
if (event.xexpose.window == windows->magnify.id)
if (event.xexpose.count == 0)
if (windows->magnify.mapped)
{
XMakeMagnifyImage(display,windows);
break;
}
if (event.xexpose.window == windows->pan.id)
if (event.xexpose.count == 0)
{
XDrawPanRectangle(display,windows);
break;
}
if (event.xexpose.window == windows->icon.id)
if (event.xexpose.count == 0)
{
XRefreshWindow(display,&windows->icon,&event);
break;
}
break;
}
case KeyPress:
{
int
length;
/*
Respond to a user key press.
*/
length=XLookupString((XKeyEvent *) &event.xkey,command,sizeof(command),
&key_symbol,(XComposeStatus *) NULL);
*(command+length)='\0';
if (resource_info->debug)
(void) fprintf(stderr,"Key press: %d 0x%lx (%s)\n",event.xkey.state,
key_symbol,command);
if (event.xkey.window == windows->image.id)
{
command_type=XImageWindowCommand(display,resource_info,windows,
event.xkey.state,key_symbol,&displayed_image);
if (command_type != NullCommand)
loaded_image=XMagickCommand(display,resource_info,windows,
command_type,&displayed_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)
XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
else
if ((key_symbol == XK_F1) || (key_symbol == XK_Help))
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Panning",ImagePanHelp);
else
XTranslateImage(display,windows,*image,key_symbol);
timer=time((time_t *) NULL)+resource_info->delay+1;
break;
}
case KeyRelease:
{
/*
Respond to a user key release.
*/
(void) XLookupString((XKeyEvent *) &event.xkey,command,sizeof(command),
&key_symbol,(XComposeStatus *) NULL);
if (resource_info->debug)
(void) fprintf(stderr,"Key release: 0x%lx (%c)\n",key_symbol,
*command);
break;
}
case LeaveNotify:
{
/*
Selectively uninstall colormap.
*/
if (map_info->colormap != XDefaultColormap(display,visual_info->screen))
if (event.xcrossing.mode != NotifyUngrab)
XUninductColormap(display,map_info->colormap);
break;
}
case MapNotify:
{
if (resource_info->debug)
(void) fprintf(stderr,"Map Notify: 0x%lx\n",event.xmap.window);
if (event.xmap.window == windows->backdrop.id)
{
XSetInputFocus(display,event.xmap.window,RevertToParent,
CurrentTime);
windows->backdrop.mapped=True;
break;
}
if (event.xmap.window == windows->image.id)
{
if (windows->backdrop.id != (Window) NULL)
XInstallColormap(display,map_info->colormap);
if (strcmp(displayed_image->magick,"LOGO") == 0)
if (strcmp(displayed_image->filename,"Untitled") == 0)
loaded_image=XOpenImage(display,resource_info,windows,False);
else
*state|=NextImageState | ExitState;
if ((windows->image.width < windows->image.ximage->width) ||
(windows->image.height < windows->image.ximage->height))
XMapRaised(display,windows->pan.id);
windows->image.mapped=True;
break;
}
if (event.xmap.window == windows->magnify.id)
{
XMakeMagnifyImage(display,windows);
windows->magnify.mapped=True;
XWithdrawWindow(display,windows->info.id,windows->info.screen);
break;
}
if (event.xmap.window == windows->pan.id)
{
XMakePanImage(display,resource_info,windows,displayed_image);
windows->pan.mapped=True;
break;
}
if (event.xmap.window == windows->info.id)
{
windows->info.mapped=True;
break;
}
if (event.xmap.window == windows->icon.id)
{
/*
Create an icon image.
*/
XMakeStandardColormap(display,icon_visual,&icon_resources,
displayed_image,icon_map,&icon_pixel);
(void) XMakeImage(display,&icon_resources,&windows->icon,
displayed_image,windows->icon.width,windows->icon.height);
XSetWindowBackgroundPixmap(display,windows->icon.id,
windows->icon.pixmap);
XClearWindow(display,windows->icon.id);
XWithdrawWindow(display,windows->info.id,windows->info.screen);
windows->icon.mapped=True;
break;
}
if (event.xmap.window == windows->command.id)
{
windows->command.mapped=True;
break;
}
if (event.xmap.window == windows->popup.id)
{
windows->popup.mapped=True;
break;
}
if (event.xmap.window == windows->widget.id)
{
windows->widget.mapped=True;
break;
}
break;
}
case MappingNotify:
{
XRefreshKeyboardMapping(&event.xmapping);
break;
}
case NoExpose:
break;
case ReparentNotify:
{
if (resource_info->debug)
(void) fprintf(stderr,"Reparent Notify: 0x%lx=>0x%lx\n",
event.xreparent.parent,event.xreparent.window);
break;
}
case UnmapNotify:
{
if (resource_info->debug)
(void) fprintf(stderr,"Unmap Notify: 0x%lx\n",event.xunmap.window);
if (event.xunmap.window == windows->backdrop.id)
{
windows->backdrop.mapped=False;
break;
}
if (event.xunmap.window == windows->image.id)
{
windows->image.mapped=False;
break;
}
if (event.xunmap.window == windows->magnify.id)
{
windows->magnify.mapped=False;
break;
}
if (event.xunmap.window == windows->pan.id)
{
windows->pan.mapped=False;
break;
}
if (event.xunmap.window == windows->info.id)
{
windows->info.mapped=False;
break;
}
if (event.xunmap.window == windows->icon.id)
{
if (map_info->colormap == icon_map->colormap)
XConfigureImageColormap(display,resource_info,windows,
displayed_image);
XFreeStandardColormap(display,icon_visual,icon_map,&icon_pixel);
windows->icon.mapped=False;
break;
}
if (event.xunmap.window == windows->command.id)
{
windows->command.mapped=False;
break;
}
if (event.xunmap.window == windows->popup.id)
{
if (windows->backdrop.id != (Window) NULL)
XSetInputFocus(display,windows->image.id,RevertToParent,
CurrentTime);
windows->popup.mapped=False;
break;
}
if (event.xunmap.window == windows->widget.id)
{
if (windows->backdrop.id != (Window) NULL)
XSetInputFocus(display,windows->image.id,RevertToParent,
CurrentTime);
windows->widget.mapped=False;
break;
}
break;
}
default:
{
if (resource_info->debug)
(void) fprintf(stderr,"Event type: %d\n",event.type);
break;
}
}
}
while (!(*state & ExitState));
if (!(*state & ExitState))
(void) XMagickCommand(display,resource_info,windows,FreeBuffersCommand,
&displayed_image);
else
{
/*
Query user if image has changed.
*/
SignatureImage(displayed_image);
if (strcmp(displayed_image->signature,image_signature) != 0)
{
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,
&displayed_image);
}
}
/*
Withdraw pan and Magnify window.
*/
if (windows->info.mapped)
XWithdrawWindow(display,windows->info.id,windows->info.screen);
if (windows->pan.mapped)
XWithdrawWindow(display,windows->pan.id,windows->pan.screen);
if (windows->magnify.mapped)
XWithdrawWindow(display,windows->magnify.id,windows->magnify.screen);
if (windows->command.mapped)
XWithdrawWindow(display,windows->command.id,windows->command.screen);
if (!resource_info->backdrop)
if (windows->backdrop.mapped)
{
XWithdrawWindow(display,windows->backdrop.id,windows->backdrop.screen);
XDestroyWindow(display,windows->backdrop.id);
windows->backdrop.id=(Window) NULL;
XWithdrawWindow(display,windows->image.id,windows->image.screen);
XDestroyWindow(display,windows->image.id);
windows->image.id=(Window) NULL;
}
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
if ((*state & FormerImageState) || (*state & NextImageState))
*state&=(~ExitState);
/*
Change to home directory.
*/
getwd(working_directory);
(void) chdir(resource_info->home_directory);
*image=displayed_image;
return(loaded_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X D r a w I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XDrawEditImage draws a graphic primitive (point, line, rectangle,
% etc.) on the image.
%
% The format of the XDrawEditImage routine is:
%
% status=XDrawEditImage(display,resource_info,windows,degrees,image)
%
% A description of each parameter follows:
%
% o status: Function XDrawEditImage return True if the image is drawn
% upon. False is returned is there is a memory shortage or if the
% image cannot be drawn on.
%
% 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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
%
*/
static unsigned int XDrawEditImage(Display *display,
XResourceInfo *resource_info,XWindows *windows,Image **image)
{
static char
*DrawMenu[]=
{
"Primitive",
"Color",
"Stipple",
"Width",
"Undo",
"Help",
"Dismiss",
(char *) NULL
};
static PrimitiveType
primitive = PointPrimitive;
static ModeType
DrawCommands[]=
{
DrawPrimitiveCommand,
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;
double
degrees;
int
entry,
id,
number_coordinates,
x,
y;
RectangleInfo
rectangle_info;
register int
i;
unsigned int
distance,
height,
max_coordinates,
status,
width;
unsigned long
state;
Window
root_window;
XDrawInfo
draw_info;
XEvent
event;
XPoint
*coordinate_info;
XSegment
line_info;
/*
Allocate polygon info.
*/
max_coordinates=2048;
coordinate_info=(XPoint *) malloc(max_coordinates*sizeof(XPoint));
if (coordinate_info == (XPoint *) NULL)
{
Warning("Unable to draw on image","Memory allocation failed");
return(False);
}
/*
Map Command widget.
*/
windows->command.name="Draw";
windows->command.data=4;
(void) XCommandWidget(display,windows,DrawMenu,(XEvent *) NULL);
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=True;
cursor=XCreateFontCursor(display,XC_tcross);
for ( ; ; )
{
XQueryPosition(display,windows->image.id,&x,&y);
XDefineCursor(display,windows->image.id,cursor);
state=DefaultState;
do
{
if (windows->info.mapped)
{
/*
Display pointer position.
*/
(void) sprintf(text," %+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 DrawPrimitiveCommand:
{
static char
*Primitives[]=
{
"point",
"line",
"rectangle",
"fill rectangle",
"ellipse",
"fill ellipse",
"polygon",
"fill polygon",
(char *) NULL,
};
/*
Select a command from the pop-up menu.
*/
primitive=(PrimitiveType) (XMenuWidget(display,windows,
DrawMenu[id],Primitives,command)+1);
break;
}
case DrawColorCommand:
{
char
*ColorMenu[MaxNumberPens+1];
int
pen_number;
unsigned int
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],ColorMenu,
command);
if (pen_number < 0)
break;
transparent=pen_number == (MaxNumberPens-2);
if (transparent)
{
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->image.map_info->colormap,
resource_info->pen_colors[pen_number],&color);
XBestPixel(display,windows->image.map_info->colormap,
(XColor *) NULL,(unsigned int) MaxColors,&color);
windows->image.pixel_info->pen_colors[pen_number]=color;
pen_id=pen_number;
draw_info.stencil=OpaqueStencil;
break;
}
case DrawStippleCommand:
{
static char
filename[MaxTextExtent] = "\0",
*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)
XFreePixmap(display,stipple);
stipple=(Pixmap) NULL;
if (entry == 6)
break;
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:
default:
{
stipple=XCreateBitmapFromData(display,root_window,
(char *) HighlightBitmap,HighlightWidth,
HighlightHeight);
break;
}
}
break;
}
XFileBrowserWidget(display,windows,"Stipple",filename);
if (*filename == '\0')
break;
status=XReadBitmapFile(display,root_window,filename,&width,
&height,&stipple,&x,&y);
if (status != BitmapSuccess)
XNoticeWidget(display,windows,"Unable to read X bitmap image:",
filename);
break;
}
case DrawWidthCommand:
{
static char
width[MaxTextExtent] = "3",
*WidthsMenu[]=
{
"1",
"2",
"4",
"8",
"16",
(char *) NULL,
(char *) NULL,
};
/*
Select a command from the pop-up menu.
*/
WidthsMenu[5]="Dialog...";
entry=XMenuWidget(display,windows,DrawMenu[id],WidthsMenu,
command);
if (entry < 0)
break;
if (entry != 5)
{
line_width=atoi(WidthsMenu[entry]);
break;
}
(void) XDialogWidget(display,windows,"Ok","Enter line width:",
width);
if (*width == '\0')
break;
line_width=atoi(width);
break;
}
case DrawUndoCommand:
{
(void) XMagickCommand(display,resource_info,windows,UndoCommand,
image);
break;
}
case DrawHelpCommand:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Rotation",ImageDrawHelp);
XDefineCursor(display,windows->image.id,cursor);
break;
}
case DrawDismissCommand:
{
/*
Prematurely exit.
*/
state|=EscapeState;
state|=ExitState;
break;
}
default:
break;
}
XDefineCursor(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:
{
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,
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
switch (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,False,
"Help Viewer - Image Rotation",ImageDrawHelp);
break;
}
default:
{
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)
{
if ((x < (windows->info.x+windows->info.width)) &&
(y < (windows->info.y+windows->info.height)))
XWithdrawWindow(display,windows->info.id,windows->info.screen);
}
else
if ((x > (windows->info.x+windows->info.width)) ||
(y > (windows->info.y+windows->info.height)))
XMapWindow(display,windows->info.id);
break;
}
}
} while (!(state & ExitState));
XWithdrawWindow(display,windows->info.id,windows->info.screen);
if (state & EscapeState)
break;
/*
Draw primitive 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=x;
rectangle_info.y=y;
rectangle_info.width=0;
rectangle_info.height=0;
number_coordinates=1;
coordinate_info->x=x;
coordinate_info->y=y;
XSetFunction(display,windows->image.highlight_context,GXinvert);
state=DefaultState;
do
{
switch (primitive)
{
case PointPrimitive:
default:
{
if (number_coordinates > 1)
{
XDrawLines(display,windows->image.id,
windows->image.highlight_context,coordinate_info,
number_coordinates,CoordModeOrigin);
(void) sprintf(text," %+d%+d",
coordinate_info[number_coordinates-1].x,
coordinate_info[number_coordinates-1].y);
XInfoWidget(display,windows,text);
}
break;
}
case LinePrimitive:
{
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) sprintf(text," %.2f",degrees);
XInfoWidget(display,windows,text);
XHighlightLine(display,windows->image.id,
windows->image.highlight_context,&line_info);
}
else
if (windows->info.mapped)
XWithdrawWindow(display,windows->info.id,windows->info.screen);
break;
}
case RectanglePrimitive:
case FillRectanglePrimitive:
{
if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
{
/*
Display info and draw drawing rectangle.
*/
(void) sprintf(text," %ux%u%+d%+d",rectangle_info.width,
rectangle_info.height,rectangle_info.x,rectangle_info.y);
XInfoWidget(display,windows,text);
XHighlightRectangle(display,windows->image.id,
windows->image.highlight_context,&rectangle_info);
}
else
if (windows->info.mapped)
XWithdrawWindow(display,windows->info.id,windows->info.screen);
break;
}
case EllipsePrimitive:
case FillEllipsePrimitive:
{
if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
{
/*
Display info and draw drawing rectangle.
*/
(void) sprintf(text," %ux%u%+d%+d",rectangle_info.width,
rectangle_info.height,rectangle_info.x,rectangle_info.y);
XInfoWidget(display,windows,text);
XHighlightEllipse(display,windows->image.id,
windows->image.highlight_context,&rectangle_info);
}
else
if (windows->info.mapped)
XWithdrawWindow(display,windows->info.id,windows->info.screen);
break;
}
case PolygonPrimitive:
case FillPolygonPrimitive:
{
if (number_coordinates > 1)
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) sprintf(text," %.2f",degrees);
XInfoWidget(display,windows,text);
XHighlightLine(display,windows->image.id,
windows->image.highlight_context,&line_info);
}
else
if (windows->info.mapped)
XWithdrawWindow(display,windows->info.id,windows->info.screen);
break;
}
}
/*
Wait for next event.
*/
XScreenEvent(display,windows,&event);
switch (primitive)
{
case PointPrimitive:
default:
{
if (number_coordinates > 1)
XDrawLines(display,windows->image.id,
windows->image.highlight_context,coordinate_info,
number_coordinates,CoordModeOrigin);
break;
}
case LinePrimitive:
{
if (distance > 9)
XHighlightLine(display,windows->image.id,
windows->image.highlight_context,&line_info);
break;
}
case RectanglePrimitive:
case FillRectanglePrimitive:
{
if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
XHighlightRectangle(display,windows->image.id,
windows->image.highlight_context,&rectangle_info);
break;
}
case EllipsePrimitive:
case FillEllipsePrimitive:
{
if ((rectangle_info.width > 3) && (rectangle_info.height > 3))
XHighlightEllipse(display,windows->image.id,
windows->image.highlight_context,&rectangle_info);
break;
}
case PolygonPrimitive:
case FillPolygonPrimitive:
{
if (number_coordinates > 1)
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 primitive.
*/
line_info.x2=event.xbutton.x;
line_info.y2=event.xbutton.y;
rectangle_info.x=event.xbutton.x;
rectangle_info.y=event.xbutton.y;
coordinate_info[number_coordinates].x=event.xbutton.x;
coordinate_info[number_coordinates].y=event.xbutton.y;
if (((primitive != PolygonPrimitive) &&
(primitive != FillPolygonPrimitive)) || (distance <= 9))
{
state|=ExitState;
break;
}
number_coordinates++;
if (number_coordinates < max_coordinates)
{
line_info.x1=event.xbutton.x;
line_info.y1=event.xbutton.y;
break;
}
max_coordinates<<=1;
coordinate_info=(XPoint *)
realloc(coordinate_info,max_coordinates*sizeof(XPoint));
if (coordinate_info == (XPoint *) NULL)
Warning("Unable to draw on image","Memory allocation failed");
break;
}
case Expose:
break;
case MotionNotify:
{
if (event.xmotion.window != windows->image.id)
break;
if (primitive != PointPrimitive)
{
line_info.x2=event.xmotion.x;
line_info.y2=event.xmotion.y;
rectangle_info.x=event.xmotion.x;
rectangle_info.y=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 < max_coordinates)
break;
max_coordinates<<=1;
coordinate_info=(XPoint *)
realloc(coordinate_info,max_coordinates*sizeof(XPoint));
if (coordinate_info == (XPoint *) NULL)
Warning("Unable to draw on image","Memory allocation failed");
break;
}
default:
break;
}
/*
Check boundary conditions.
*/
if (line_info.x2 < 0)
line_info.x2=0;
else
if (line_info.x2 > windows->image.width)
line_info.x2=windows->image.width;
if (line_info.y2 < 0)
line_info.y2=0;
else
if (line_info.y2 > windows->image.height)
line_info.y2=windows->image.height;
distance=
((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 (((rectangle_info.x != x) && (rectangle_info.y != y)) ||
(state & ExitState))
{
if (rectangle_info.x < 0)
rectangle_info.x=0;
else
if (rectangle_info.x > windows->image.width)
rectangle_info.x=windows->image.width;
if (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=x;
}
if (rectangle_info.y < 0)
rectangle_info.y=0;
else
if (rectangle_info.y > windows->image.height)
rectangle_info.y=windows->image.height;
if (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=y;
}
}
} while (!(state & ExitState));
XSetFunction(display,windows->image.highlight_context,GXcopy);
if ((primitive == PointPrimitive) || (primitive == PolygonPrimitive) ||
(primitive == FillPolygonPrimitive))
{
/*
Determine polygon bounding box.
*/
rectangle_info.x=coordinate_info->x;
rectangle_info.y=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 (coordinate_info[i].x < rectangle_info.x)
rectangle_info.x=Max(coordinate_info[i].x,0);
if (coordinate_info[i].y < rectangle_info.y)
rectangle_info.y=Max(coordinate_info[i].y,0);
}
rectangle_info.width=x-rectangle_info.x;
rectangle_info.height=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 ((primitive == RectanglePrimitive) ||
(primitive == EllipsePrimitive))
{
rectangle_info.width--;
rectangle_info.height--;
}
/*
Drawing is relative to image configuration.
*/
draw_info.x=rectangle_info.x;
draw_info.y=rectangle_info.y;
(void) XMagickCommand(display,resource_info,windows,SaveToUndoBufferCommand,
image);
x=0;
y=0;
width=(*image)->columns;
height=(*image)->rows;
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 >> 1);
if (draw_info.x < 0)
draw_info.x=0;
draw_info.x=width*draw_info.x/windows->image.ximage->width;
draw_info.y+=windows->image.y-(line_width >> 1);
if (draw_info.y < 0)
draw_info.y=0;
draw_info.y=height*draw_info.y/windows->image.ximage->height;
draw_info.width=rectangle_info.width+(line_width << 1);
if (draw_info.width > (*image)->columns)
draw_info.width=(*image)->columns;
draw_info.height=rectangle_info.height+(line_width << 1);
if (draw_info.height > (*image)->rows)
draw_info.height=(*image)->rows;
(void) sprintf(draw_info.geometry,"%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.primitive=primitive;
draw_info.stipple=stipple;
draw_info.line_width=line_width;
draw_info.line_info=line_info;
if (line_info.x1 > (line_width >> 1))
draw_info.line_info.x1=line_width >> 1;
if (line_info.y1 > (line_width >> 1))
draw_info.line_info.y1=line_width >> 1;
draw_info.line_info.x2=line_info.x2-line_info.x1+(line_width >> 1);
draw_info.line_info.y2=line_info.y2-line_info.y1+(line_width >> 1);
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 > (line_width >> 1))
draw_info.rectangle_info.x=line_width >> 1;
if (draw_info.rectangle_info.y > (line_width >> 1))
draw_info.rectangle_info.y=line_width >> 1;
draw_info.number_coordinates=number_coordinates;
draw_info.coordinate_info=coordinate_info;
windows->image.pixel_info->pen_color=
windows->image.pixel_info->pen_colors[pen_id];
/*
Draw primitive on image.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
status=XDrawImage(display,windows->image.pixel_info,&draw_info,*image);
XSetCursorState(display,windows,False);
/*
Update image colormap and return to image drawing.
*/
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
}
XSetCursorState(display,windows,False);
free((char *) coordinate_info);
return(status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X D r a w P a n R e c t a n g l e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XDrawPanRectangle draws a rectangle in the pan window. The pan
% window displays a zoomed image and the rectangle shows which portion of
% the image is displayed in the Image window.
%
% The format of the XDrawPanRectangle routine is:
%
% XDrawPanRectangle(display,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)
{
unsigned long
scale_factor;
RectangleInfo
highlight_info;
/*
Determine dimensions of the panning rectangle.
*/
scale_factor=(unsigned long)
(UpShift(windows->pan.width)/windows->image.ximage->width);
highlight_info.x=DownShift(windows->image.x*scale_factor);
highlight_info.width=DownShift(windows->image.width*scale_factor);
scale_factor=(unsigned long)
(UpShift(windows->pan.height)/windows->image.ximage->height);
highlight_info.y=DownShift(windows->image.y*scale_factor);
highlight_info.height=DownShift(windows->image.height*scale_factor);
/*
Display the panning rectangle.
*/
XClearWindow(display,windows->pan.id);
XHighlightRectangle(display,windows->pan.id,windows->pan.annotate_context,
&highlight_info);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X I m a g e W i n d o w C o m m a n d %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function 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 routine is:
%
% loaded_image=XImageWindowCommand(display,resource_info,windows,state,
% key_symbol,image)
%
% A description of each parameter follows:
%
% o loaded_image: Function 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: Specifies a pointer to a Image structure; XImageWIndowCommand
% may transform the image and return a new image pointer.
%
%
*/
static CommandType XImageWindowCommand(Display *display,
XResourceInfo *resource_info,XWindows *windows,const unsigned int state,
KeySym key_symbol,Image **image)
{
static char
delta[MaxTextExtent] = "",
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[Extent(delta)+1]='\0';
delta[Extent(delta)]=Digits[key_symbol-XK_0];
resource_info->quantum=atoi(delta);
return(NullCommand);
}
last_symbol=key_symbol;
if (resource_info->immutable)
{
/*
Immutable image window has a restricted command set.
*/
switch(key_symbol)
{
case XK_question:
return(InfoCommand);
case XK_q:
{
if (!(state & ControlMask))
break;
return(QuitCommand);
}
default:
break;
}
return(NullCommand);
}
switch (key_symbol)
{
case XK_o:
{
if (!(state & ControlMask))
break;
return(OpenCommand);
}
case XK_space:
return(NextCommand);
case XK_BackSpace:
return(FormerCommand);
case XK_s:
{
if (state & Mod1Mask)
return(SwirlCommand);
if (!(state & ControlMask))
return(ShearCommand);
return(SaveCommand);
}
case XK_p:
case XK_Print:
{
if (state & Mod1Mask)
return(OilPaintCommand);
if (state & Mod4Mask)
return(ColorCommand);
if (!(state & ControlMask))
return(NullCommand);
return(PrintCommand);
}
case XK_d:
{
if (state & Mod4Mask)
return(DrawCommand);
if (!(state & ControlMask))
return(NullCommand);
return(DeleteCommand);
}
case XK_Select:
{
if (!(state & ControlMask))
return(NullCommand);
return(SelectCommand);
}
case XK_n:
{
if (!(state & ControlMask))
return(NullCommand);
return(NewCommand);
}
case XK_q:
case XK_Cancel:
{
if (!(state & ControlMask))
return(NullCommand);
return(QuitCommand);
}
case XK_z:
case XK_Undo:
{
if (!(state & ControlMask))
return(NullCommand);
return(UndoCommand);
}
case XK_r:
case XK_Redo:
{
if (!(state & ControlMask))
return(RollCommand);
return(RedoCommand);
}
case XK_x:
{
if (!(state & ControlMask))
return(NullCommand);
return(CutCommand);
}
case XK_c:
{
if (state & Mod1Mask)
return(CharcoalDrawingCommand);
if (!(state & ControlMask))
return(CropCommand);
return(CopyCommand);
}
case XK_v:
case XK_Insert:
{
if (state & Mod4Mask)
return(CompositeCommand);
if (!(state & ControlMask))
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_equal:
return(EqualizeCommand);
case XK_N:
return(NormalizeCommand);
case XK_asciitilde:
return(NegateCommand);
case XK_period:
return(GrayscaleCommand);
case XK_numbersign:
return(QuantizeCommand);
case XK_F2:
return(DespeckleCommand);
case XK_F3:
return(ReduceNoiseCommand);
case XK_F4:
return(AddNoiseCommand);
case XK_F5:
return(SharpenCommand);
case XK_F6:
return(BlurCommand);
case XK_F7:
return(ThresholdCommand);
case XK_F8:
return(EdgeDetectCommand);
case XK_F9:
return(EmbossCommand);
case XK_F10:
return(SpreadCommand);
case XK_F11:
return(SolarizeCommand);
case XK_F12:
return(ShadeCommand);
case XK_F13:
return(RaiseCommand);
case XK_F14:
return(SegmentCommand);
case XK_i:
{
if (!(state & Mod1Mask))
return(NullCommand);
return(ImplodeCommand);
}
case XK_w:
{
if (!(state & Mod1Mask))
return(NullCommand);
return(WaveCommand);
}
case XK_m:
{
if (!(state & Mod4Mask))
return(NullCommand);
return(MatteCommand);
}
case XK_b:
{
if (!(state & Mod4Mask))
return(NullCommand);
return(AddBorderCommand);
}
case XK_f:
{
if (!(state & Mod4Mask))
return(NullCommand);
return(AddFrameCommand);
}
case XK_exclam:
{
if (!(state & Mod4Mask))
return(NullCommand);
return(CommentCommand);
}
case XK_a:
{
if (state & Mod1Mask)
return(ApplyCommand);
if (state & Mod4Mask)
return(AnnotateCommand);
if (!(state & ControlMask))
return(NullCommand);
return(RegionofInterestCommand);
}
case XK_question:
return(InfoCommand);
case XK_plus:
return(ZoomCommand);
case XK_P:
{
if (!(state & ShiftMask))
return(NullCommand);
return(ShowPreviewCommand);
}
case XK_Execute:
return(LaunchCommand);
case XK_F1:
return(HelpCommand);
case XK_Find:
return(BrowseDocumentationCommand);
case XK_Menu:
{
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)
{
RectangleInfo
crop_info;
/*
Trim one pixel from edge of image.
*/
crop_info.x=0;
crop_info.y=0;
crop_info.width=windows->image.ximage->width;
crop_info.height=windows->image.ximage->height;
if ((key_symbol == XK_Up) || (key_symbol == XK_KP_Up))
{
if (resource_info->quantum >= crop_info.height)
resource_info->quantum=crop_info.height-1;
crop_info.height-=resource_info->quantum;
}
if ((key_symbol == XK_Down) || (key_symbol == XK_KP_Down))
{
if (resource_info->quantum >= (crop_info.height-crop_info.y))
resource_info->quantum=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 >= crop_info.width)
resource_info->quantum=crop_info.width-1;
crop_info.width-=resource_info->quantum;
}
if ((key_symbol == XK_Right) || (key_symbol == XK_KP_Right))
{
if (resource_info->quantum >= (crop_info.width-crop_info.x))
resource_info->quantum=crop_info.width-crop_info.x-1;
crop_info.x+=resource_info->quantum;
crop_info.width-=resource_info->quantum;
}
if ((windows->image.x+windows->image.width) > crop_info.width)
windows->image.x=crop_info.width-windows->image.width;
if ((windows->image.y+windows->image.height) > crop_info.height)
windows->image.y=crop_info.height-windows->image.height;
XSetCropGeometry(display,windows,&crop_info,*image);
windows->image.window_changes.width=crop_info.width;
windows->image.window_changes.height=crop_info.height;
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 %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function 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 routine is:
%
% loaded_image=XMagickCommand(display,resource_info,windows,command,image)
%
% A description of each parameter follows:
%
% o loaded_image: Function 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: Specifies a pointer to a Image structure; 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
*argv[10],
geometry[MaxTextExtent],
modulate_factors[MaxTextExtent];
Image
*cache_image,
*loaded_image;
ImageInfo
image_info;
int
status,
x,
y;
static char
color[MaxTextExtent] = "gray";
static Image
*redo_image = (Image *) NULL,
*undo_image = (Image *) NULL;
unsigned int
height,
width;
XCheckRefreshWindows(display,windows);
switch (command)
{
case FreeBuffersCommand:
{
/*
Free memory from the undo and redo cache.
*/
while (undo_image != (Image *) NULL)
{
cache_image=undo_image;
undo_image=undo_image->previous;
DestroyImage(cache_image->list);
DestroyImage(cache_image);
}
undo_image=(Image *) NULL;
if (redo_image != (Image *) NULL)
DestroyImage(redo_image);
redo_image=(Image *) NULL;
return((Image *) NULL);
}
case UndoCommand:
{
/*
Undo the last image transformation.
*/
if (undo_image == (Image *) NULL)
{
XBell(display,0);
return((Image *) NULL);
}
cache_image=undo_image;
undo_image=undo_image->previous;
windows->image.window_changes.width=cache_image->columns;
windows->image.window_changes.height=cache_image->rows;
if (windows->image.crop_geometry != (char *) NULL)
free((char *) windows->image.crop_geometry);
windows->image.crop_geometry=cache_image->geometry;
if (redo_image != (Image *) NULL)
DestroyImage(redo_image);
redo_image=(*image);
*image=cache_image->list;
DestroyImage(cache_image);
if (windows->image.orphan)
return((Image *) NULL);
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
return((Image *) NULL);
}
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 EqualizeCommand:
case NormalizeCommand:
case HueCommand:
case SaturationCommand:
case BrightnessCommand:
case GammaCommand:
case SpiffCommand:
case DullCommand:
case GrayscaleCommand:
case MapCommand:
case QuantizeCommand:
case DespeckleCommand:
case ReduceNoiseCommand:
case AddNoiseCommand:
case SharpenCommand:
case BlurCommand:
case ThresholdCommand:
case EdgeDetectCommand:
case EmbossCommand:
case SpreadCommand:
case SolarizeCommand:
case ShadeCommand:
case RaiseCommand:
case SegmentCommand:
case SwirlCommand:
case ImplodeCommand:
case WaveCommand:
case OilPaintCommand:
case CharcoalDrawingCommand:
case AnnotateCommand:
case AddBorderCommand:
case AddFrameCommand:
case CompositeCommand:
case CommentCommand:
case LaunchCommand:
case RegionofInterestCommand:
case SaveToUndoBufferCommand:
case RedoCommand:
{
Image
*previous_image;
unsigned int
bytes;
bytes=(unsigned int) ((*image)->packets*sizeof(RunlengthPacket));
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->packets*sizeof(RunlengthPacket);
if (bytes <= (resource_info->undo_cache << 20))
{
previous_image=previous_image->previous;
continue;
}
bytes-=previous_image->list->packets*sizeof(RunlengthPacket);
if (previous_image == undo_image)
undo_image=(Image *) NULL;
else
previous_image->next->previous=(Image *) NULL;
break;
}
while (previous_image != (Image *) NULL)
{
/*
Delete any excess memory from undo cache.
*/
cache_image=previous_image;
previous_image=previous_image->previous;
cache_image->file=(FILE *) NULL;
DestroyImage(cache_image->list);
DestroyImage(cache_image);
}
}
if (bytes > (resource_info->undo_cache << 20))
break;
/*
Save image before transformations are applied.
*/
cache_image=AllocateImage((ImageInfo *) NULL);
if (cache_image == (Image *) NULL)
break;
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
(*image)->orphan=True;
cache_image->list=
CloneImage(*image,(*image)->columns,(*image)->rows,True);
(*image)->orphan=False;
XSetCursorState(display,windows,False);
if (cache_image->list == (Image *) NULL)
{
DestroyImage(cache_image);
break;
}
cache_image->columns=windows->image.ximage->width;
cache_image->rows=windows->image.ximage->height;
cache_image->geometry=windows->image.crop_geometry;
if (windows->image.crop_geometry != (char *) NULL)
{
cache_image->geometry=(char *) malloc(MaxTextExtent*sizeof(char));
if (cache_image->geometry != (char *) NULL)
(void) strcpy(cache_image->geometry,windows->image.crop_geometry);
}
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)
{
XBell(display,0);
return((Image *) NULL);
}
windows->image.window_changes.width=redo_image->columns;
windows->image.window_changes.height=redo_image->rows;
if (windows->image.crop_geometry != (char *) NULL)
free((char *) windows->image.crop_geometry);
windows->image.crop_geometry=redo_image->geometry;
DestroyImage(*image);
*image=redo_image;
redo_image=(Image *) NULL;
if (windows->image.orphan)
return((Image *) NULL);
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
return((Image *) NULL);
}
/*
Process user command.
*/
argv[0]=resource_info->client_name;
loaded_image=(Image *) NULL;
windows->image.window_changes.width=windows->image.ximage->width;
windows->image.window_changes.height=windows->image.ximage->height;
switch (command)
{
case OpenCommand:
{
/*
Load image.
*/
loaded_image=XOpenImage(display,resource_info,windows,False);
break;
}
case NextCommand:
{
/*
Display next image.
*/
XClientMessage(display,windows->image.id,windows->im_protocols,
windows->im_next_image,CurrentTime);
break;
}
case FormerCommand:
{
/*
Display former image.
*/
XClientMessage(display,windows->image.id,windows->im_protocols,
windows->im_former_image,CurrentTime);
break;
}
case SelectCommand:
{
/*
Select image.
*/
(void) chdir(resource_info->home_directory);
loaded_image=XOpenImage(display,resource_info,windows,True);
break;
}
case SaveCommand:
{
/*
Save image.
*/
status=XSaveImage(display,resource_info,windows,image);
if (status == False)
{
XNoticeWidget(display,windows,"Unable to write X image:",
(*image)->filename);
break;
}
break;
}
case PrintCommand:
{
/*
Print image.
*/
status=XPrintImage(display,resource_info,windows,image);
if (status == False)
{
XNoticeWidget(display,windows,"Unable to print X image:",
(*image)->filename);
break;
}
break;
}
case DeleteCommand:
{
static char
filename[MaxTextExtent] = "\0";
/*
Delete image file.
*/
XFileBrowserWidget(display,windows,"Delete",filename);
if (*filename == '\0')
break;
status=remove(filename);
if (status != False)
XNoticeWidget(display,windows,"Unable to delete image file:",filename);
break;
}
case NewCommand:
{
static char
*format = "gradation",
color[MaxTextExtent] = "gray",
geometry[MaxTextExtent] = "640x480";
/*
Query user for canvas geometry.
*/
status=XDialogWidget(display,windows,"New","Enter image geometry:",
geometry);
if (*geometry == '\0')
break;
if (!status)
format="xc";
XColorBrowserWidget(display,windows,"Select",color);
if (*color == '\0')
break;
/*
Create canvas.
*/
GetImageInfo(&image_info);
(void) sprintf(image_info.filename,"%s:%s",format,color);
image_info.size=geometry;
loaded_image=ReadImage(&image_info);
free((char *) image_info.filename);
XClientMessage(display,windows->image.id,windows->im_protocols,
windows->im_next_image,CurrentTime);
break;
}
case VisualDirectoryCommand:
{
/*
Visual Image directory.
*/
loaded_image=XVisualDirectoryImage(display,resource_info,windows);
break;
}
case QuitCommand:
{
/*
Exit program.
*/
if (!resource_info->confirm_exit)
XClientMessage(display,windows->image.id,windows->im_protocols,
windows->im_exit,CurrentTime);
else
{
/*
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 == False)
{
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 >> 1;
windows->image.window_changes.height=windows->image.ximage->height >> 1;
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case OriginalSizeCommand:
{
/*
Original image size.
*/
windows->image.window_changes.width=(*image)->columns;
windows->image.window_changes.height=(*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:
{
unsigned int
height,
width;
/*
Resize image.
*/
width=windows->image.ximage->width;
height=windows->image.ximage->height;
(void) sprintf(geometry,"%ux%u",width,height);
status=XDialogWidget(display,windows,"Resize",
"Enter resize geometry (e.g. 640x480, 200%):",geometry);
if (*geometry == '\0')
break;
if (!status)
(void) strcat(geometry,"!");
(void) ParseImageGeometry(geometry,&x,&y,&width,&height);
windows->image.window_changes.width=width;
windows->image.window_changes.height=height;
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case ApplyCommand:
{
char
image_geometry[MaxTextExtent];
if ((windows->image.crop_geometry == (char *) NULL) &&
((*image)->columns == windows->image.ximage->width) &&
((*image)->rows == windows->image.ximage->height) &&
(resource_info->number_colors == 0))
break;
/*
Apply size transforms to image.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
/*
Crop and/or scale displayed image.
*/
(void) sprintf(image_geometry,"%dx%d!",windows->image.ximage->width,
windows->image.ximage->height);
TransformImage(image,windows->image.crop_geometry,image_geometry);
if (windows->image.crop_geometry != (char *) NULL)
{
free((char *) windows->image.crop_geometry);
windows->image.crop_geometry=(char *) NULL;
}
windows->image.x=0;
windows->image.y=0;
if (resource_info->number_colors != 0)
{
/*
Reduce the number of colors in the image.
*/
if (((*image)->class == DirectClass) ||
((*image)->colors > resource_info->number_colors) ||
(resource_info->colorspace == GRAYColorspace))
{
QuantizeInfo
quantize_info;
GetQuantizeInfo(&quantize_info);
quantize_info.number_colors=resource_info->number_colors;
quantize_info.tree_depth=resource_info->tree_depth;
quantize_info.dither=resource_info->dither;
quantize_info.colorspace=resource_info->colorspace;
QuantizeImage(&quantize_info,*image);
}
SyncImage(*image);
}
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 == (*image)->columns) &&
(windows->image.height == (*image)->rows) &&
(windows->image.crop_geometry == (char *) NULL))
{
XBell(display,0);
break;
}
windows->image.window_changes.width=(*image)->columns;
windows->image.window_changes.height=(*image)->rows;
if (windows->image.crop_geometry != (char *) NULL)
{
free((char *) 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 == False)
{
XNoticeWidget(display,windows,"Unable to cut X image",
(*image)->filename);
break;
}
break;
}
case FlopCommand:
{
/*
Flop image scanlines.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="-flop";
MogrifyImage(resource_info->image_info,2,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.crop_geometry != (char *) NULL)
{
/*
Flop crop geometry.
*/
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,
&height);
(void) sprintf(windows->image.crop_geometry,"%ux%u%+d%+d",width,
height,(int) (*image)->columns-(int) width-x,y);
}
if (windows->image.orphan)
break;
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case FlipCommand:
{
/*
Flip image scanlines.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="-flip";
MogrifyImage(resource_info->image_info,2,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.crop_geometry != (char *) NULL)
{
/*
Flip crop geometry.
*/
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,
&height);
(void) sprintf(windows->image.crop_geometry,"%ux%u%+d%+d",width,
height,x,(int) (*image)->rows-(int) height-y);
}
if (windows->image.orphan)
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 == False)
{
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 == False)
{
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 == False)
{
XNoticeWidget(display,windows,"Unable to rotate X image",
(*image)->filename);
break;
}
break;
}
case ShearCommand:
{
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,True);
XCheckRefreshWindows(display,windows);
argv[1]="-bordercolor";
argv[2]=color;
argv[3]="-shear";
argv[4]=geometry;
MogrifyImage(resource_info->image_info,5,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
windows->image.window_changes.width=(*image)->columns;
windows->image.window_changes.height=(*image)->rows;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case RollCommand:
{
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,True);
XCheckRefreshWindows(display,windows);
argv[1]="-roll";
argv[2]=geometry;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
windows->image.window_changes.width=(*image)->columns;
windows->image.window_changes.height=(*image)->rows;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case TrimCommand:
{
/*
Trim image.
*/
status=XTrimImage(display,resource_info,windows,*image);
if (status == False)
{
XNoticeWidget(display,windows,"Unable to trim X image",
(*image)->filename);
break;
}
break;
}
case HueCommand:
{
static char
hue_percent[MaxTextExtent] = "3";
/*
Query user for percent hue change.
*/
(void) XDialogWidget(display,windows,"Apply",
"Enter percent change in image hue:",hue_percent);
if (*hue_percent == '\0')
break;
/*
Vary the image hue.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
(void) strcpy(modulate_factors,"0.0/0.0/");
(void) strcat(modulate_factors,hue_percent);
argv[1]="-modulate";
argv[2]=modulate_factors;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case SaturationCommand:
{
static char
saturation_percent[MaxTextExtent] = "10";
/*
Query user for percent saturation change.
*/
(void) XDialogWidget(display,windows,"Apply",
"Enter percent change in color saturation:",saturation_percent);
if (*saturation_percent == '\0')
break;
/*
Vary color saturation.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
(void) strcpy(modulate_factors,"0.0/");
(void) strcat(modulate_factors,saturation_percent);
argv[1]="-modulate";
argv[2]=modulate_factors;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case BrightnessCommand:
{
static char
brightness_percent[MaxTextExtent] = "3";
/*
Query user for percent brightness change.
*/
(void) XDialogWidget(display,windows,"Apply",
"Enter percent change in color brightness:",brightness_percent);
if (*brightness_percent == '\0')
break;
/*
Vary the color brightness.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
(void) strcpy(modulate_factors,brightness_percent);
argv[1]="-modulate";
argv[2]=modulate_factors;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
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,True);
XCheckRefreshWindows(display,windows);
argv[1]="-gamma";
argv[2]=factor;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case SpiffCommand:
{
/*
Sharpen the image contrast.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="-contrast";
MogrifyImage(resource_info->image_info,2,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case DullCommand:
{
/*
Dull the image contrast.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="+contrast";
MogrifyImage(resource_info->image_info,2,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
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,True);
XCheckRefreshWindows(display,windows);
argv[1]="-equalize";
MogrifyImage(resource_info->image_info,2,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
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,True);
XCheckRefreshWindows(display,windows);
argv[1]="-normalize";
MogrifyImage(resource_info->image_info,2,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case NegateCommand:
{
/*
Negate colors in image.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="-negate";
MogrifyImage(resource_info->image_info,2,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case GrayscaleCommand:
{
/*
Convert image to grayscale.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="-colorspace";
argv[2]="gray";
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case MapCommand:
{
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,True);
XCheckRefreshWindows(display,windows);
argv[1]="-map";
argv[2]=filename;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case QuantizeCommand:
{
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,True);
XCheckRefreshWindows(display,windows);
argv[1]="-colors";
argv[2]=colors;
argv[3]=status ? "-dither" : "+dither";
MogrifyImage(resource_info->image_info,4,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case DespeckleCommand:
{
/*
Despeckle image.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="-despeckle";
MogrifyImage(resource_info->image_info,2,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case ReduceNoiseCommand:
{
/*
Reduce noise in the image.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="-noise";
MogrifyImage(resource_info->image_info,2,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case AddNoiseCommand:
{
static char
noise_type[MaxTextExtent] = "gaussian";
/*
Add noise to the image.
*/
XListBrowserWidget(display,windows,&windows->widget,NoiseTypes,
"Add Noise","Select a type of noise to add to your image:",noise_type);
if (*noise_type == '\0')
break;
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="+noise";
argv[2]=noise_type;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case SharpenCommand:
{
static char
factor[MaxTextExtent] = "60.0";
/*
Query user for sharpen factor.
*/
(void) XDialogWidget(display,windows,"Sharpen",
"Enter the sharpening factor (0.0 - 99.9%):",factor);
if (*factor == '\0')
break;
/*
Sharpen image scanlines.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="-sharpen";
argv[2]=factor;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case BlurCommand:
{
static char
factor[MaxTextExtent] = "60.0";
/*
Query user for blur factor.
*/
(void) XDialogWidget(display,windows,"Blur",
"Enter the blurring factor (0.0 - 99.9%):",factor);
if (*factor == '\0')
break;
/*
Blur an image.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="-blur";
argv[2]=factor;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case ThresholdCommand:
{
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,True);
XCheckRefreshWindows(display,windows);
argv[1]="-threshold";
argv[2]=factor;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case EdgeDetectCommand:
{
static char
factor[MaxTextExtent] = "50.0";
/*
Query user for edge factor.
*/
(void) XDialogWidget(display,windows,"Detect Edges",
"Enter the edge detect factor (0.0 - 99.9%):",factor);
if (*factor == '\0')
break;
/*
Detect edge in image.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="-edge";
argv[2]=factor;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case EmbossCommand:
{
/*
Emboss image scanlines.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="-emboss";
MogrifyImage(resource_info->image_info,2,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case SpreadCommand:
{
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,True);
XCheckRefreshWindows(display,windows);
argv[1]="-spread";
argv[2]=amount;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case SolarizeCommand:
{
static char
factor[MaxTextExtent] = "128";
/*
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,True);
XCheckRefreshWindows(display,windows);
argv[1]="-solarize";
argv[2]=factor;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case ShadeCommand:
{
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,True);
XCheckRefreshWindows(display,windows);
argv[1]=status ? "-shade" : "+shade";
argv[2]=geometry;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
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,True);
XCheckRefreshWindows(display,windows);
argv[1]="-raise";
argv[2]=bevel_width;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case SegmentCommand:
{
static char
threshold[MaxTextExtent] = "1.5";
/*
Query user for smoothing threshold.
*/
(void) XDialogWidget(display,windows,"Segment","Smoothing threshold:",
threshold);
if (*threshold == '\0')
break;
/*
Segment an image.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="-segment";
argv[2]=threshold;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case SwirlCommand:
{
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,True);
XCheckRefreshWindows(display,windows);
argv[1]="-swirl";
argv[2]=degrees;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case ImplodeCommand:
{
static char
factor[MaxTextExtent] = "30.0";
/*
Query user for implode factor.
*/
(void) XDialogWidget(display,windows,"Implode",
"Enter the implosion/explosion factor (-99.9 - 99.9%):",factor);
if (*factor == '\0')
break;
/*
Implode image pixels about the center.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="-implode";
argv[2]=factor;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case WaveCommand:
{
static char
geometry[MaxTextExtent] = "10x10";
/*
Query user for the shade geometry.
*/
(void) XDialogWidget(display,windows,"Wave",
"Enter the amplitude and length of the wave:",geometry);
if (*geometry == '\0')
break;
/*
Shade image pixels.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="-wave";
argv[2]=geometry;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case OilPaintCommand:
{
static char
radius[MaxTextExtent] = "3";
/*
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,True);
XCheckRefreshWindows(display,windows);
argv[1]="-paint";
argv[2]=radius;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case CharcoalDrawingCommand:
{
static char
factor[MaxTextExtent] = "50";
/*
Query user for bevel width.
*/
(void) XDialogWidget(display,windows,"Charcoal Drawing",
"Enter the charcoal factor (0 - 99.9%):",factor);
if (*factor == '\0')
break;
/*
Raise an image.
*/
(void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
argv[1]="-charcoal";
argv[2]=factor;
MogrifyImage(resource_info->image_info,3,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
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 == False)
{
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 == False)
{
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 == False)
{
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 == False)
{
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 == False)
{
XNoticeWidget(display,windows,"Unable to composite X image",
(*image)->filename);
break;
}
break;
}
case AddBorderCommand:
{
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,True);
XCheckRefreshWindows(display,windows);
argv[1]="-bordercolor";
argv[2]=color;
argv[3]="-border";
argv[4]=geometry;
MogrifyImage(resource_info->image_info,5,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
windows->image.window_changes.width=(*image)->columns;
windows->image.window_changes.height=(*image)->rows;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case AddFrameCommand:
{
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,True);
XCheckRefreshWindows(display,windows);
argv[1]="-mattecolor";
argv[2]=color;
argv[3]="-frame";
argv[4]=geometry;
MogrifyImage(resource_info->image_info,5,argv,image);
XSetCursorState(display,windows,False);
if (windows->image.orphan)
break;
windows->image.window_changes.width=(*image)->columns;
windows->image.window_changes.height=(*image)->rows;
XConfigureImageColormap(display,resource_info,windows,*image);
(void) XConfigureImage(display,resource_info,windows,*image);
break;
}
case CommentCommand:
{
char
command[MaxTextExtent],
filename[MaxTextExtent];
FILE
*file;
/*
Edit image comment.
*/
TemporaryFilename(filename);
if ((*image)->comments != (char *) NULL)
{
register char
*p;
file=fopen(filename,WriteBinaryType);
if (file == (FILE *) NULL)
{
XNoticeWidget(display,windows,"Unable to edit image comment",
filename);
break;
}
for (p=(*image)->comments; *p != '\0'; p++)
(void) putc((int) *p,file);
(void) putc('\n',file);
(void) fclose(file);
}
(void) sprintf(command,EditorCommand,filename);
if (resource_info->editor_command != (char *) NULL)
(void) sprintf(command,resource_info->editor_command,filename);
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
status=SystemCommand(command);
if (status)
XNoticeWidget(display,windows,"Unable to edit image comment",command);
else
{
(void) sprintf(command,"@%s",filename);
CommentImage(*image,command);
}
(void) remove(filename);
XSetCursorState(display,windows,False);
break;
}
case LaunchCommand:
{
char
command[MaxTextExtent],
filename[MaxTextExtent],
retain_filename[MaxTextExtent];
/*
Launch program.
*/
TemporaryFilename(filename);
(void) sprintf(command,resource_info->launch_command,filename);
(void) XDialogWidget(display,windows,"Launch","Launch command:",command);
if (*command == '\0')
break;
(void) sprintf(command,LauncherCommand,filename);
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
(void) strcpy(retain_filename,(*image)->filename);
(void) sprintf((*image)->filename,"%s:%s",LaunchFormat,filename);
GetImageInfo(&image_info);
status=WriteImage(&image_info,*image);
if (status)
{
status=SystemCommand(command);
if (status)
XNoticeWidget(display,windows,"Unable to launch image editor",
command);
else
{
loaded_image=ReadImage(&image_info);
XClientMessage(display,windows->image.id,windows->im_protocols,
windows->im_next_image,CurrentTime);
}
}
(void) remove(filename);
(void) strcpy(loaded_image->filename,retain_filename);
XSetCursorState(display,windows,False);
break;
}
case RegionofInterestCommand:
{
/*
Apply an image processing technique to a region of interest.
*/
(void) XROIImage(display,resource_info,windows,image);
break;
}
case InfoCommand:
{
/*
Display image info.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
XDisplayImageInfo(display,resource_info,windows,undo_image,*image);
XSetCursorState(display,windows,False);
break;
}
case ZoomCommand:
{
/*
Zoom image.
*/
if (windows->magnify.mapped)
XRaiseWindow(display,windows->magnify.id);
else
{
/*
Make magnify image.
*/
XSetCursorState(display,windows,True);
status=XMakeImage(display,resource_info,&windows->magnify,*image,
windows->magnify.width,windows->magnify.height);
if (status == False)
Error("Unable to create magnify image",(char *) NULL);
XMapRaised(display,windows->magnify.id);
XSetCursorState(display,windows,False);
}
break;
}
case ShowPreviewCommand:
{
static char
preview_type[MaxTextExtent] = "Gamma";
char
command[MaxTextExtent],
filename[MaxTextExtent],
server_name[MaxTextExtent];
register int
i;
/*
Select preview type from menu.
*/
XListBrowserWidget(display,windows,&windows->widget,PreviewTypes,
"Preview","Select an enhancement, effect, or F/X:",preview_type);
if (*preview_type == '\0')
break;
GetImageInfo(&image_info);
for (i=0; PreviewTypes[i] != (char *) NULL; i++)
if (strcmp(PreviewTypes[i],preview_type) == 0)
break;
image_info.preview_type=(PreviewType) i;
if (PreviewTypes[i] == (char *) NULL)
{
XNoticeWidget(display,windows,"unknown image operator",preview_type);
break;
}
/*
Show image preview.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
TemporaryFilename(filename);
*server_name='\0';
if (resource_info->server_name != (char *) NULL)
(void) sprintf(server_name,"-display %s",resource_info->server_name);
(void) sprintf(command,ShowImageCommand,server_name,
windows->image.id,"Preview",(*image)->filename,filename);
(void) sprintf((*image)->filename,"preview:%s",filename);
status=WriteImage(&image_info,*image);
(void) sprintf((*image)->filename,(*image)->magick_filename);
XCheckRefreshWindows(display,windows);
if (status)
status=!SystemCommand(command);
if (!status)
{
XNoticeWidget(display,windows,"Unable to show image preview",command);
(void) remove(filename);
}
XDelay(display,1500);
XSetCursorState(display,windows,False);
break;
}
case ShowHistogramCommand:
{
char
command[MaxTextExtent],
filename[MaxTextExtent],
server_name[MaxTextExtent];
/*
Show image histogram.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
TemporaryFilename(filename);
*server_name='\0';
if (resource_info->server_name != (char *) NULL)
(void) sprintf(server_name,"-display %s",resource_info->server_name);
(void) sprintf(command,ShowImageCommand,server_name,
windows->image.id,"Histogram",(*image)->filename,filename);
(void) sprintf((*image)->filename,"histogram:%s",filename);
GetImageInfo(&image_info);
status=WriteImage(&image_info,*image);
(void) sprintf((*image)->filename,(*image)->magick_filename);
XCheckRefreshWindows(display,windows);
if (status)
status=!SystemCommand(command);
if (!status)
{
XNoticeWidget(display,windows,"Unable to show image histogram",
command);
(void) remove(filename);
}
XDelay(display,1500);
XSetCursorState(display,windows,False);
break;
}
case ShowMatteCommand:
{
char
command[MaxTextExtent],
filename[MaxTextExtent],
server_name[MaxTextExtent];
if (!(*image)->matte)
{
XNoticeWidget(display,windows,
"Image does not have any matte information",(*image)->filename);
break;
}
/*
Show image matte.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
TemporaryFilename(filename);
*server_name='\0';
if (resource_info->server_name != (char *) NULL)
(void) sprintf(server_name,"-display %s",resource_info->server_name);
(void) sprintf(command,ShowImageCommand,server_name,
windows->image.id,"Matte",(*image)->filename,filename);
(void) sprintf((*image)->filename,"matte:%s",filename);
GetImageInfo(&image_info);
status=WriteImage(&image_info,*image);
(void) sprintf((*image)->filename,(*image)->magick_filename);
XCheckRefreshWindows(display,windows);
if (status)
status=!SystemCommand(command);
if (!status)
{
XNoticeWidget(display,windows,"Unable to show image matte",
command);
(void) remove(filename);
}
XDelay(display,1500);
XSetCursorState(display,windows,False);
break;
}
case BackgroundCommand:
{
/*
Background image.
*/
status=XBackgroundImage(display,resource_info,windows,image);
if (status == False)
break;
(*image)->orphan=True;
loaded_image=CloneImage(*image,(*image)->columns,(*image)->rows,True);
(*image)->orphan=False;
if (loaded_image != (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.
*/
resource_info->delay=0;
(void) XDialogWidget(display,windows,"Slide Show",
"Pause how many seconds between images:",delay);
if (*delay == '\0')
break;
resource_info->delay=atoi(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 == False)
break;
(*image)->orphan=True;
loaded_image=CloneImage(*image,(*image)->columns,(*image)->rows,True);
(*image)->orphan=False;
if (loaded_image != (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,False,
"Help Viewer - Display",ImageMagickHelp);
break;
}
case BrowseDocumentationCommand:
{
Atom
mozilla_atom;
char
command[MaxTextExtent];
Window
mozilla_window,
root_window;
/*
Browse the ImageMagick documentation.
*/
root_window=XRootWindow(display,XDefaultScreen(display));
mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",False);
mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
if (mozilla_window != (Window) NULL)
{
/*
Display documentation using Netscape remote control.
*/
(void) sprintf(command,"openURL(%s,new-window,noraise)",
DocumentationURL);
mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",False);
XChangeProperty(display,mozilla_window,mozilla_atom,XA_STRING,8,
PropModeReplace,(unsigned char *) command,Extent(command));
XSetCursorState(display,windows,False);
break;
}
(void) sprintf(command,resource_info->browse_command,DocumentationURL);
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
status=SystemCommand(command);
if (status)
XNoticeWidget(display,windows,"Unable to browse documentation",command);
XDelay(display,1500);
XSetCursorState(display,windows,False);
break;
}
case VersionCommand:
{
XNoticeWidget(display,windows,Version,
"Copyright 1997 E. I. du Pont de Nemours and Company");
break;
}
case SaveToUndoBufferCommand:
break;
default:
{
XBell(display,0);
break;
}
}
return(loaded_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X M a g n i f y I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function 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 routine is:
%
% XMagnifyImage(display,windows,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;
unsigned long
state;
/*
Update magnified image until the mouse button is released.
*/
XDefineCursor(display,windows->image.id,windows->magnify.cursor);
state=DefaultState;
x=event->xbutton.x;
y=event->xbutton.y;
windows->magnify.x=windows->image.x+x;
windows->magnify.y=windows->image.y+y;
do
{
/*
Map and unmap Info widget as text cursor crosses its boundaries.
*/
if (windows->info.mapped)
{
if ((x < (windows->info.x+windows->info.width)) &&
(y < (windows->info.y+windows->info.height)))
XWithdrawWindow(display,windows->info.id,windows->info.screen);
}
else
if ((x > (windows->info.x+windows->info.width)) ||
(y > (windows->info.y+windows->info.height)))
XMapWindow(display,windows->info.id);
if (windows->info.mapped)
{
/*
Display pointer position.
*/
(void) sprintf(text," %+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 >= windows->image.width)
x=windows->image.width-1;
if (y < 0)
y=0;
else
if (y >= windows->image.height)
y=windows->image.height-1;
} while (!(state & ExitState));
/*
Display magnified image.
*/
XSetCursorState(display,windows,False);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X M a g n i f y W i n d o w C o m m a n d %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XMagnifyWindowCommand moves the image within an Magnify window by
% one pixel as specified by the key symbol.
%
% The format of the XMagnifyWindowCommand routine is:
%
% XMagnifyWindowCommand(display,windows,state,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 unsigned int state,const KeySym key_symbol)
{
unsigned int
quantum;
/*
User specified a magnify factor or position.
*/
quantum=1;
if (state & Mod1Mask)
quantum=10;
switch (key_symbol)
{
case QuitCommand:
{
XWithdrawWindow(display,windows->magnify.id,windows->magnify.screen);
break;
}
case XK_Home:
case XK_KP_Home:
{
windows->magnify.x=windows->image.width >> 1;
windows->magnify.y=windows->image.height >> 1;
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 < (windows->image.width-1))
windows->magnify.x+=quantum;
break;
}
case XK_Down:
case XK_KP_Down:
{
if (windows->magnify.y < (windows->image.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=(unsigned int) (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=(unsigned int) (key_symbol-XK_KP_0);
break;
}
default:
break;
}
XMakeMagnifyImage(display,windows);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X M a k e P a n I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XMakePanImage creates a thumbnail of the image and displays it in
% the Pan icon window.
%
% The format of the XMakePanImage routine is:
%
% XMakePanImage(display,resource_info,windows,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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
%
*/
static void XMakePanImage(Display *display,XResourceInfo *resource_info,
XWindows *windows,Image *image)
{
unsigned int
status;
/*
Create and display image for panning icon.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
windows->pan.x=windows->image.x;
windows->pan.y=windows->image.y;
status=XMakeImage(display,resource_info,&windows->pan,image,
windows->pan.width,windows->pan.height);
if (status == False)
Error("Unable to create Pan icon image",(char *) NULL);
XSetWindowBackgroundPixmap(display,windows->pan.id,windows->pan.pixmap);
XClearWindow(display,windows->pan.id);
XDrawPanRectangle(display,windows);
XSetCursorState(display,windows,False);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X M a t t a E d i t I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function 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 routine is:
%
% XMatteEditImage(display,resource_info,windows,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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
*/
static unsigned int XMatteEditImage(Display *display,
XResourceInfo *resource_info,XWindows *windows,Image **image)
{
static char
matte[MaxTextExtent] = "0",
*MatteEditMenu[]=
{
"Method",
"Delta",
"Matte Value",
"Undo",
"Help",
"Dismiss",
(char *) NULL
};
static ModeType
MatteEditCommands[]=
{
MatteEditMethod,
MatteEditDeltaCommand,
MatteEditValueCommand,
MatteEditUndoCommand,
MatteEditHelpCommand,
MatteEditDismissCommand
};
static PaintMethod
method = PointMethod;
static unsigned int
delta = 0;
char
command[MaxTextExtent],
text[MaxTextExtent];
Cursor
cursor;
int
entry,
id,
x,
x_offset,
y,
y_offset;
register int
i;
register RunlengthPacket
*p;
unsigned int
height,
width;
unsigned long
state;
XEvent
event;
/*
Map Command widget.
*/
windows->command.name="Matte Edit";
windows->command.data=2;
(void) XCommandWidget(display,windows,MatteEditMenu,(XEvent *) NULL);
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->image.map_info->colormap,resource_info->background_color,
resource_info->foreground_color);
XDefineCursor(display,windows->image.id,cursor);
/*
Track pointer until button 1 is pressed.
*/
XQueryPosition(display,windows->image.id,&x,&y);
state=DefaultState;
do
{
if (windows->info.mapped)
{
/*
Display pointer position.
*/
(void) sprintf(text," %+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)
{
XDefineCursor(display,windows->image.id,cursor);
continue;
}
switch (MatteEditCommands[id])
{
case MatteEditMethod:
{
static char
*MethodMenu[]=
{
"point",
"replace",
"floodfill",
"reset",
(char *) NULL,
};
/*
Select a method from the pop-up menu.
*/
entry=
XMenuWidget(display,windows,MatteEditMenu[id],MethodMenu,command);
if (entry >= 0)
method=(PaintMethod) entry;
break;
}
case MatteEditDeltaCommand:
{
static char
*DeltaMenu[]=
{
"0",
"1",
"2",
"4",
"8",
"16",
"32",
(char *) NULL,
(char *) NULL,
},
value[MaxTextExtent] = "3";
/*
Select a delta value from the pop-up menu.
*/
DeltaMenu[7]="Dialog...";
entry=XMenuWidget(display,windows,MatteEditMenu[id],DeltaMenu,
command);
if (entry < 0)
break;
if (entry != 7)
{
delta=atoi(DeltaMenu[entry]);
break;
}
(void) XDialogWidget(display,windows,"Ok","Enter delta value:",
value);
if (*value == '\0')
break;
delta=atoi(value);
break;
}
case MatteEditValueCommand:
{
/*
Request matte value from the user.
*/
(void) XDialogWidget(display,windows,"Matte","Enter matte value:",
matte);
break;
}
case MatteEditUndoCommand:
{
(void) XMagickCommand(display,resource_info,windows,UndoCommand,
image);
break;
}
case MatteEditHelpCommand:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Matte Edit",ImageMatteEditHelp);
break;
}
case MatteEditDismissCommand:
{
/*
Prematurely exit.
*/
state|=EscapeState;
state|=ExitState;
break;
}
default:
break;
}
XDefineCursor(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);
XDefineCursor(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,sizeof(command),
&key_symbol,(XComposeStatus *) NULL);
switch (key_symbol)
{
case XK_Escape:
case XK_F20:
{
/*
Prematurely exit.
*/
state|=ExitState;
break;
}
case XK_F1:
case XK_Help:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Matte Edit",ImageMatteEditHelp);
break;
}
default:
{
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)
{
if ((x < (windows->info.x+windows->info.width)) &&
(y < (windows->info.y+windows->info.height)))
XWithdrawWindow(display,windows->info.id,windows->info.screen);
}
else
if ((x > (windows->info.x+windows->info.width)) ||
(y > (windows->info.y+windows->info.height)))
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)
{
int
x,
y;
/*
Matte edit is relative to image configuration.
*/
XClearArea(display,windows->image.id,x_offset,y_offset,1,1,True);
XPutPixel(windows->image.ximage,x_offset,y_offset,
windows->image.pixel_info->background_color.pixel);
x=0;
y=0;
width=(*image)->columns;
height=(*image)->rows;
if (windows->image.crop_geometry != (char *) NULL)
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,
&width,&height);
x_offset=
width*(windows->image.x+x_offset)/windows->image.ximage->width+x;
y_offset=
height*(windows->image.y+y_offset)/windows->image.ximage->height+y;
if ((x_offset < 0) || (y_offset < 0))
continue;
if ((x_offset >= (*image)->columns) || (y_offset >= (*image)->rows))
continue;
(*image)->class=DirectClass;
if (!(*image)->matte)
{
/*
Initialize matte data.
*/
p=(*image)->pixels;
for (i=0; i < (*image)->packets; i++)
{
p->index=Opaque;
p++;
}
(*image)->matte=True;
}
switch (method)
{
case PointMethod:
default:
{
/*
Update matte information using point algorithm.
*/
if (!UncompressImage(*image))
break;
p=(*image)->pixels+(y_offset*(*image)->columns+x_offset);
p->index=atoi(matte) & 0xff;
break;
}
case ReplaceMethod:
{
RunlengthPacket
target;
/*
Update matte information using replace algorithm.
*/
x=0;
p=(*image)->pixels;
for (i=0; i < (*image)->packets; i++)
{
x+=(p->length+1);
if (x > (y_offset*(*image)->columns+x_offset))
break;
p++;
}
target=(*image)->pixels[i];
p=(*image)->pixels;
for (i=0; i < (*image)->packets; i++)
{
if (ColorMatch(*p,target,delta))
p->index=atoi(matte) & 0xff;
p++;
}
break;
}
case FloodfillMethod:
{
/*
Update matte information using floodfill algorithm.
*/
if (!UncompressImage(*image))
break;
MatteFloodfillImage(*image,x_offset,y_offset,atoi(matte) & 0xff,
delta);
break;
}
case ResetMethod:
{
/*
Update matte information using reset algorithm.
*/
p=(*image)->pixels;
for (i=0; i < (*image)->packets; i++)
{
p->index=atoi(matte) & 0xff;
p++;
}
if ((atoi(matte) & 0xff) == Opaque)
(*image)->matte=False;
break;
}
}
state&=(~UpdateConfigurationState);
}
} while (!(state & ExitState));
XSetCursorState(display,windows,False);
XFreeCursor(display,cursor);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X O p e n I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XOpenImage loads an image from a file.
%
% The format of the XOpenImage routine is:
%
% loaded_image=XOpenImage(display,resource_info,windows,command)
%
% A description of each parameter follows:
%
% o loaded_image: Function XOpenImage returns an image if can be loaded
% 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.
%
% 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 unsigned int command)
{
Image
*loaded_image;
ImageInfo
image_info;
MonitorHandler
handler;
static char
filename[MaxTextExtent] = "\0";
/*
Request file name from user.
*/
if (!command)
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)
{
Warning("Unable to select image","XGetCommand failed");
return((Image *) NULL);
}
filelist=(char **) malloc(count*sizeof(char *));
if (filelist == (char **) NULL)
{
Warning("Unable to select image","Memory allocation failed");
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,filelist,"Load",
"Select Image to Load:",filename);
free((char *) filelist);
XFreeStringList(files);
}
if (*filename == '\0')
return((Image *) NULL);
GetImageInfo(&image_info);
(void) strcpy(image_info.filename,filename);
SetImageInfo(&image_info,False);
if (strcmp(image_info.magick,"X") == 0)
{
char
seconds[MaxTextExtent];
/*
User may want to delay the X server screen grab.
*/
(void) strcpy(seconds,"0");
(void) XDialogWidget(display,windows,"Grab","Enter any delay in seconds:",
seconds);
if (*seconds == '\0')
return((Image *) NULL);
XDelay(display,1000*atoi(seconds));
}
if ((strcmp(image_info.magick,"CMYK") == 0) ||
(strcmp(image_info.magick,"GRAY") == 0) ||
(strcmp(image_info.magick,"MAP") == 0) ||
(strcmp(image_info.magick,"MATTE") == 0) ||
(strcmp(image_info.magick,"RGB") == 0) ||
(strcmp(image_info.magick,"TEXT") == 0) ||
(strcmp(image_info.magick,"TILE") == 0) ||
(strcmp(image_info.magick,"UYVY") == 0) ||
(strcmp(image_info.magick,"XC") == 0) ||
(strcmp(image_info.magick,"YUV") == 0))
{
static char
geometry[MaxTextExtent] = "512x512";
/*
Request image size from the user.
*/
if (resource_info->image_info->size != (char *) NULL)
(void) strcpy(geometry,resource_info->image_info->size);
resource_info->image_info->size=geometry;
(void) XDialogWidget(display,windows,"Load",
"Enter the image geometry:",geometry);
}
/*
Load the image.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
(void) strcpy(resource_info->image_info->filename,filename);
if (strcmp(image_info.magick,"X") == 0)
handler=SetMonitorHandler((MonitorHandler) NULL);
loaded_image=ReadImage(resource_info->image_info);
if (strcmp(image_info.magick,"X") == 0)
(void) SetMonitorHandler(handler);
XSetCursorState(display,windows,False);
if (loaded_image != (Image *) NULL)
XClientMessage(display,windows->image.id,windows->im_protocols,
windows->im_next_image,CurrentTime);
else
{
char
*text,
**textlist;
FILE
*file;
int
c;
register char
*p;
unsigned int
length;
/*
Unknown image format.
*/
file=(FILE *) fopen(filename,"r");
if (file == (FILE *) NULL)
return((Image *) NULL);
length=MaxTextExtent;
text=(char *) malloc(length*sizeof(char));
for (p=text ; text != (char *) NULL; p++)
{
c=fgetc(file);
if (c == EOF)
break;
if ((p-text+1) >= length)
{
*p='\0';
length<<=1;
text=(char *) realloc((char *) text,length*sizeof(char));
if (text == (char *) NULL)
break;
p=text+Extent(text);
}
*p=(unsigned char) c;
}
(void) fclose(file);
if (text == (char *) NULL)
return((Image *) NULL);
*p='\0';
textlist=StringToList(text);
if (textlist != (char **) NULL)
{
char
title[MaxTextExtent];
register int
i;
(void) sprintf(title,"Unknown format: %s",filename);
XTextViewWidget(display,resource_info,windows,True,title,textlist);
for (i=0; textlist[i] != (char *) NULL; i++)
free((char *) textlist[i]);
free((char *) textlist);
}
free((char *) text);
}
return(loaded_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X P a n I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XPanImage pans the image until the mouse button is released.
%
% The format of the XPanImage routine is:
%
% XPanImage(display,windows,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;
RectangleInfo
pan_info;
unsigned long
state,
x_factor,
y_factor;
/*
Define cursor.
*/
if ((windows->image.ximage->width > windows->image.width) &&
(windows->image.ximage->height > windows->image.height))
cursor=XCreateFontCursor(display,XC_fleur);
else
if (windows->image.ximage->width > windows->image.width)
cursor=XCreateFontCursor(display,XC_sb_h_double_arrow);
else
if (windows->image.ximage->height > windows->image.height)
cursor=XCreateFontCursor(display,XC_sb_v_double_arrow);
else
cursor=XCreateFontCursor(display,XC_arrow);
XDefineCursor(display,windows->pan.id,cursor);
/*
Pan image as pointer moves until the mouse button is released.
*/
x_factor=(unsigned long)
UpShift(windows->image.ximage->width)/windows->pan.width;
y_factor=(unsigned long)
UpShift(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;
state=UpdateConfigurationState;
do
{
switch (event->type)
{
case ButtonPress:
{
/*
User choose an initial pan location.
*/
pan_info.x=event->xbutton.x;
pan_info.y=event->xbutton.y;
state|=UpdateConfigurationState;
break;
}
case ButtonRelease:
{
/*
User has finished panning the image.
*/
pan_info.x=event->xbutton.x;
pan_info.y=event->xbutton.y;
state|=UpdateConfigurationState | ExitState;
break;
}
case MotionNotify:
{
pan_info.x=event->xmotion.x;
pan_info.y=event->xmotion.y;
state|=UpdateConfigurationState;
}
default:
break;
}
if (state & UpdateConfigurationState)
{
/*
Check boundary conditions.
*/
pan_info.x=DownShift((pan_info.x-(pan_info.width >> 1))*x_factor);
if (pan_info.x < 0)
pan_info.x=0;
else
if ((pan_info.x+windows->image.width) > windows->image.ximage->width)
pan_info.x=windows->image.ximage->width-windows->image.width;
pan_info.y=DownShift((pan_info.y-(pan_info.height >> 1))*y_factor);
if (pan_info.y < 0)
pan_info.y=0;
else
if ((pan_info.y+windows->image.height) >
windows->image.ximage->height)
pan_info.y=windows->image.ximage->height-windows->image.height;
if ((windows->image.x != pan_info.x) ||
(windows->image.y != pan_info.y))
{
/*
Display image pan offset.
*/
windows->image.x=pan_info.x;
windows->image.y=pan_info.y;
(void) sprintf(text," %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))
XScreenEvent(display,windows,event);
} while (!(state & ExitState));
/*
Restore cursor.
*/
XDefineCursor(display,windows->pan.id,windows->pan.cursor);
XFreeCursor(display,cursor);
XWithdrawWindow(display,windows->info.id,windows->info.screen);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X P a s t e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function 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 routine is:
%
% status=XPasteImage(display,resource_info,windows,image)
%
% A description of each parameter follows:
%
% o status: Function XPasteImage returns True if the image is
% pasted. False is returned is there is a memory shortage or if the
% image fails to be pasted.
%
% 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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
*/
static unsigned int XPasteImage(Display *display,XResourceInfo *resource_info,
XWindows *windows,Image *image)
{
static char
*PasteMenu[]=
{
"Operator",
"Help",
"Dismiss",
(char *) NULL
};
static ModeType
PasteCommands[]=
{
PasteOperatorsCommand,
PasteHelpCommand,
PasteDismissCommand
};
static CompositeOperator
operation = ReplaceCompositeOp;
char
text[MaxTextExtent];
Cursor
cursor;
Image
*paste_image;
int
id,
x,
y;
RectangleInfo
highlight_info,
paste_info;
unsigned int
height,
width;
unsigned long
scale_factor,
state;
XEvent
event;
/*
Copy image.
*/
if (copy_image == (Image *) NULL)
return(False);
copy_image->orphan=True;
paste_image=CloneImage(copy_image,copy_image->columns,copy_image->rows,True);
copy_image->orphan=False;
/*
Map Command widget.
*/
windows->command.name="Paste";
windows->command.data=1;
(void) XCommandWidget(display,windows,PasteMenu,(XEvent *) NULL);
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,False);
XQueryPosition(display,windows->image.id,&x,&y);
paste_info.x=windows->image.x+x;
paste_info.y=windows->image.y+y;
paste_info.width=0;
paste_info.height=0;
cursor=XCreateFontCursor(display,XC_ul_angle);
XSetFunction(display,windows->image.highlight_context,GXinvert);
state=DefaultState;
do
{
if (windows->info.mapped)
{
/*
Display pointer position.
*/
(void) sprintf(text," %+d%+d ",paste_info.x,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];
static char
*OperatorMenu[]=
{
"over",
"in",
"out",
"atop",
"xor",
"plus",
"minus",
"add",
"subtract",
"difference",
"bumpmap",
"replace",
(char *) NULL,
};
/*
Select a command from the pop-up menu.
*/
operation=(CompositeOperator) (XMenuWidget(display,windows,
PasteMenu[id],OperatorMenu,command)+1);
break;
}
case PasteHelpCommand:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Compositing",ImagePasteHelp);
break;
}
case PasteDismissCommand:
{
/*
Prematurely exit.
*/
state|=EscapeState;
state|=ExitState;
break;
}
default:
break;
}
continue;
}
switch (event.type)
{
case ButtonPress:
{
if (resource_info->debug)
(void) fprintf(stderr,"Button Press: 0x%lx %u +%d+%d\n",
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.
*/
x=0;
y=0;
width=image->columns;
height=image->rows;
if (windows->image.crop_geometry != (char *) NULL)
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,
&width,&height);
scale_factor=UpShift(windows->image.ximage->width)/width;
paste_info.width=DownShift(paste_image->columns*scale_factor);
scale_factor=UpShift(windows->image.ximage->height)/height;
paste_info.height=DownShift(paste_image->rows*scale_factor);
XDefineCursor(display,windows->image.id,cursor);
paste_info.x=windows->image.x+event.xbutton.x;
paste_info.y=windows->image.y+event.xbutton.y;
break;
}
case ButtonRelease:
{
if (resource_info->debug)
(void) fprintf(stderr,"Button Release: 0x%lx %u +%d+%d\n",
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=windows->image.x+event.xbutton.x;
paste_info.y=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,sizeof(command),
&key_symbol,(XComposeStatus *) NULL);
*(command+length)='\0';
if (resource_info->debug)
(void) fprintf(stderr,"Key press: 0x%lx (%s)\n",key_symbol,command);
switch (key_symbol)
{
case XK_Escape:
case XK_F20:
{
/*
Prematurely exit.
*/
DestroyImage(paste_image);
state|=EscapeState;
state|=ExitState;
break;
}
case XK_F1:
case XK_Help:
{
XSetFunction(display,windows->image.highlight_context,GXcopy);
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Compositing",ImagePasteHelp);
XSetFunction(display,windows->image.highlight_context,GXinvert);
break;
}
default:
{
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)
{
if ((x < (windows->info.x+windows->info.width)) &&
(y < (windows->info.y+windows->info.height)))
XWithdrawWindow(display,windows->info.id,windows->info.screen);
}
else
if ((x > (windows->info.x+windows->info.width)) ||
(y > (windows->info.y+windows->info.height)))
XMapWindow(display,windows->info.id);
paste_info.x=windows->image.x+x;
paste_info.y=windows->image.y+y;
break;
}
default:
{
if (resource_info->debug)
(void) fprintf(stderr,"Event type: %d\n",event.type);
break;
}
}
} while (!(state & ExitState));
XSetFunction(display,windows->image.highlight_context,GXcopy);
XSetCursorState(display,windows,False);
XFreeCursor(display,cursor);
if (state & EscapeState)
return(True);
/*
Image pasting is relative to image configuration.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
x=0;
y=0;
width=image->columns;
height=image->rows;
if (windows->image.crop_geometry != (char *) NULL)
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
scale_factor=UpShift(width)/windows->image.ximage->width;
paste_info.x+=x;
paste_info.x=DownShift(paste_info.x*scale_factor);
paste_info.width=DownShift(paste_info.width*scale_factor);
scale_factor=UpShift(height)/windows->image.ximage->height;
paste_info.y+=y;
paste_info.y=DownShift(paste_info.y*scale_factor);
paste_info.height=DownShift(paste_info.height*scale_factor);
/*
Paste image with X Image window.
*/
CompositeImage(image,operation,paste_image,paste_info.x,paste_info.y);
DestroyImage(paste_image);
XSetCursorState(display,windows,False);
/*
Update image colormap.
*/
XConfigureImageColormap(display,resource_info,windows,image);
(void) XConfigureImage(display,resource_info,windows,image);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X P r i n t I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XPrintImage prints an image to a Postscript printer.
%
% The format of the XPrintImage routine is:
%
% status=XPrintImage(display,resource_info,windows,image)
%
% A description of each parameter follows:
%
% o status: Function XPrintImage return True if the image is
% printed. False is returned is there is a memory shortage or if the
% image fails to print.
%
% 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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
%
*/
static unsigned int XPrintImage(Display *display,XResourceInfo *resource_info,
XWindows *windows,Image **image)
{
char
command[MaxTextExtent],
filename[MaxTextExtent],
geometry[MaxTextExtent];
ImageInfo
*image_info;
int
status;
static char
print_command[MaxTextExtent];
/*
Request Postscript page geometry from user.
*/
image_info=resource_info->image_info;
(void) sprintf(geometry,PSPageGeometry);
if (image_info->page != (char *) NULL)
(void) strcpy(geometry,image_info->page);
XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
"Select Postscript Page Geometry:",geometry);
if (*geometry == '\0')
return(True);
image_info->page=PostscriptGeometry(geometry);
/*
Request file name from user.
*/
XCheckRefreshWindows(display,windows);
TemporaryFilename(filename);
(void) strcpy(print_command,resource_info->print_command);
(void) XDialogWidget(display,windows,"Print","Print command:",print_command);
if (*print_command == '\0')
return(True);
if (strcmp(print_command,resource_info->print_command) != 0)
{
resource_info->print_command=print_command;
XUserPreferences(resource_info);
}
/*
Print image.
*/
(void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
(void) sprintf((*image)->filename,"%s:%s",PrinterFormat,filename);
status=WriteImage(image_info,*image);
(void) sprintf(command,print_command,filename);
status&=SystemCommand(command);
#if !defined(vms) && !defined(macintosh) && !defined(WIN32)
(void) remove(filename);
#endif
XSetCursorState(display,windows,False);
(void) XMagickCommand(display,resource_info,windows,UndoCommand,image);
return(status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X P r o g r e s s M o n i t o r %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XProgressMonitor displays the progress a task is making in
% completing a task.
%
% The format of the XProgressMonitor routine is:
%
% XProgressMonitor(task,quantum,span)
%
% A description of each parameter follows:
%
% o task: Identifies the task in progress.
%
% o quantum: Specifies the quantum position within the span which represents
% how much progress has been made in completing a task.
%
% o span: Specifies the span relative to completing a task.
%
%
*/
static void XProgressMonitor(char *task,const unsigned int quantum,
const unsigned int span)
{
XMonitorWidget(display,windows,task,quantum,span);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X R O I I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XROIImage applies an image processing technique to a region
% of interest.
%
% The format of the XROIImage routine is:
%
% status=XROIImage(display,resource_info,windows,image)
%
% A description of each parameter follows:
%
% o status: Function XROIImage returns True if the image is
% cropped. False is returned is there is a memory shortage or if the
% image fails to be cropped.
%
% 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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
%
*/
static unsigned int XROIImage(Display *display,XResourceInfo *resource_info,
XWindows *windows,Image **image)
{
#define ApplyMenus 7
static 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",
"Equalize",
"Normalize",
"Negate",
"Grayscale",
"Map...",
"Quantize...",
(char *) NULL
},
*EffectsMenu[]=
{
"Despeckle",
"Reduce Noise",
"Add Noise",
"Sharpen...",
"Blur...",
"Threshold...",
"Edge Detect...",
"Emboss...",
"Spread...",
"Solarize...",
"Shade...",
"Raise...",
"Segment...",
(char *) NULL
},
*FXMenu[]=
{
"Swirl...",
"Implode...",
"Wave...",
"Oil Painting...",
"Charcoal Drawing...",
(char *) NULL
},
*MiscellanyMenu[]=
{
"Image Info",
"Zoom Image",
"Show Preview...",
"Show Histogram",
"Show Matte",
(char *) NULL
};
static char
**Menus[ApplyMenus]=
{
FileMenu,
EditMenu,
TransformMenu,
EnhanceMenu,
EffectsMenu,
FXMenu,
MiscellanyMenu
};
static 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,
EqualizeCommand,
NormalizeCommand,
NegateCommand,
GrayscaleCommand,
MapCommand,
QuantizeCommand
},
EffectsCommands[]=
{
DespeckleCommand,
ReduceNoiseCommand,
AddNoiseCommand,
SharpenCommand,
BlurCommand,
EdgeDetectCommand,
EmbossCommand,
SpreadCommand,
SolarizeCommand,
ShadeCommand,
RaiseCommand,
SegmentCommand
},
FXCommands[]=
{
SwirlCommand,
ImplodeCommand,
WaveCommand,
OilPaintCommand,
CharcoalDrawingCommand
},
MiscellanyCommands[]=
{
InfoCommand,
ZoomCommand,
ShowPreviewCommand,
ShowHistogramCommand,
ShowMatteCommand
},
ROICommands[]=
{
ROIHelpCommand,
ROIDismissCommand
};
static 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;
MonitorHandler
handler;
RectangleInfo
crop_info,
highlight_info,
roi_info;
unsigned int
height,
width;
unsigned long
scale_factor,
state;
XEvent
event;
/*
Map Command widget.
*/
windows->command.name="ROI";
windows->command.data=0;
(void) XCommandWidget(display,windows,ROIMenu,(XEvent *) NULL);
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);
roi_info.x=windows->image.x+x;
roi_info.y=windows->image.y+y;
roi_info.width=0;
roi_info.height=0;
cursor=XCreateFontCursor(display,XC_fleur);
state=DefaultState;
do
{
if (windows->info.mapped)
{
/*
Display pointer position.
*/
(void) sprintf(text," %+d%+d ",roi_info.x,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,False,
"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.
*/
XDefineCursor(display,windows->image.id,cursor);
roi_info.x=windows->image.x+event.xbutton.x;
roi_info.y=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,sizeof(command),
&key_symbol,(XComposeStatus *) NULL);
switch (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,False,
"Help Viewer - Region of Interest",ImageROIHelp);
break;
}
default:
{
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)
{
if ((x < (windows->info.x+windows->info.width)) &&
(y < (windows->info.y+windows->info.height)))
XWithdrawWindow(display,windows->info.id,windows->info.screen);
}
else
if ((x > (windows->info.x+windows->info.width)) ||
(y > (windows->info.y+windows->info.height)))
XMapWindow(display,windows->info.id);
roi_info.x=windows->image.x+x;
roi_info.y=windows->image.y+y;
break;
}
default:
break;
}
} while (!(state & ExitState));
if (state & EscapeState)
{
/*
User want to exit without region of interest.
*/
XWithdrawWindow(display,windows->info.id,windows->info.screen);
XFreeCursor(display,cursor);
return(True);
}
XSetFunction(display,windows->image.highlight_context,GXinvert);
do
{
/*
Size rectangle as pointer moves until the mouse button is released.
*/
x=roi_info.x;
y=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)
XMapWindow(display,windows->info.id);
(void) sprintf(text," %ux%u%+d%+d",roi_info.width,roi_info.height,
roi_info.x,roi_info.y);
XInfoWidget(display,windows,text);
XHighlightRectangle(display,windows->image.id,
windows->image.highlight_context,&highlight_info);
}
else
if (windows->info.mapped)
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=windows->image.x+event.xbutton.x;
roi_info.y=windows->image.y+event.xbutton.y;
break;
}
case ButtonRelease:
{
/*
User has committed to region of interest rectangle.
*/
roi_info.x=windows->image.x+event.xbutton.x;
roi_info.y=windows->image.y+event.xbutton.y;
XSetCursorState(display,windows,False);
state|=ExitState;
if (strcmp(windows->command.name,"Apply") == 0)
break;
windows->command.name="Apply";
windows->command.data=ApplyMenus;
(void) XCommandWidget(display,windows,ApplyMenu,(XEvent *) NULL);
break;
}
case Expose:
break;
case MotionNotify:
{
roi_info.x=windows->image.x+event.xmotion.x;
roi_info.y=windows->image.y+event.xmotion.y;
}
default:
break;
}
if (((roi_info.x != x) && (roi_info.y != y)) || (state & ExitState))
{
/*
Check boundary conditions.
*/
if (roi_info.x < 0)
roi_info.x=0;
else
if (roi_info.x > windows->image.ximage->width)
roi_info.x=windows->image.ximage->width;
if (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=x;
}
if (roi_info.y < 0)
roi_info.y=0;
else
if (roi_info.y > windows->image.ximage->height)
roi_info.y=windows->image.ximage->height;
if (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=y;
}
}
} while (!(state & ExitState));
/*
Wait for user to grab a corner of the rectangle or press return.
*/
state=DefaultState;
command_type=NullCommand;
do
{
if (windows->info.mapped)
{
/*
Display pointer position.
*/
(void) sprintf(text," %ux%u%+d%+d",roi_info.width,roi_info.height,
roi_info.x,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)
{
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.
*/
handler=SetMonitorHandler((MonitorHandler) NULL);
crop_info=roi_info;
x=0;
y=0;
width=(*image)->columns;
height=(*image)->rows;
if (windows->image.crop_geometry != (char *) NULL)
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,
&width,&height);
scale_factor=UpShift(width)/windows->image.ximage->width;
crop_info.x+=x;
crop_info.x=DownShift(crop_info.x*scale_factor);
crop_info.width=DownShift(crop_info.width*scale_factor);
scale_factor=UpShift(height)/windows->image.ximage->height;
crop_info.y+=y;
crop_info.y=DownShift(crop_info.y*scale_factor);
crop_info.height=DownShift(crop_info.height*scale_factor);
roi_image=CropImage(*image,&crop_info);
(void) SetMonitorHandler(handler);
if (roi_image == (Image *) NULL)
continue;
/*
Apply image processing technique to the region of interest.
*/
windows->image.orphan=True;
(void) XMagickCommand(display,resource_info,windows,command_type,
&roi_image);
handler=SetMonitorHandler((MonitorHandler) NULL);
(void) XMagickCommand(display,resource_info,windows,
SaveToUndoBufferCommand,image);
windows->image.orphan=False;
CompositeImage(*image,ReplaceCompositeOp,roi_image,
crop_info.x,crop_info.y);
DestroyImage(roi_image);
(void) SetMonitorHandler(handler);
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);
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.
*/
XSetFunction(display,windows->image.highlight_context,GXcopy);
command_type=NullCommand;
id=XCommandWidget(display,windows,ApplyMenu,&event);
if (id >= 0)
{
(void) strcpy(command,ApplyMenu[id]);
command_type=ApplyCommands[id];
if (id < ApplyMenus)
{
/*
Select a command from a pop-up menu.
*/
entry=XMenuWidget(display,windows,ApplyMenu[id],Menus[id],
command);
if (entry >= 0)
{
(void) strcpy(command,Menus[id][entry]);
command_type=Commands[id][entry];
}
}
}
XSetFunction(display,windows->image.highlight_context,GXinvert);
XHighlightRectangle(display,windows->image.id,
windows->image.highlight_context,&highlight_info);
if (command_type == HelpCommand)
{
XSetFunction(display,windows->image.highlight_context,GXcopy);
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Region of Interest",ImageROIHelp);
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 < (roi_info.x+RoiDelta)) && (x > (roi_info.x-RoiDelta)) &&
(y < (roi_info.y+RoiDelta)) && (y > (roi_info.y-RoiDelta)))
{
roi_info.x=roi_info.x+roi_info.width;
roi_info.y=roi_info.y+roi_info.height;
state|=UpdateConfigurationState;
break;
}
if ((x < (roi_info.x+RoiDelta)) && (x > (roi_info.x-RoiDelta)) &&
(y < (roi_info.y+roi_info.height+RoiDelta)) &&
(y > (roi_info.y+roi_info.height-RoiDelta)))
{
roi_info.x=roi_info.x+roi_info.width;
state|=UpdateConfigurationState;
break;
}
if ((x < (roi_info.x+roi_info.width+RoiDelta)) &&
(x > (roi_info.x+roi_info.width-RoiDelta)) &&
(y < (roi_info.y+RoiDelta)) && (y > (roi_info.y-RoiDelta)))
{
roi_info.y=roi_info.y+roi_info.height;
state|=UpdateConfigurationState;
break;
}
if ((x < (roi_info.x+roi_info.width+RoiDelta)) &&
(x > (roi_info.x+roi_info.width-RoiDelta)) &&
(y < (roi_info.y+roi_info.height+RoiDelta)) &&
(y > (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);
break;
}
case Expose:
{
if (event.xexpose.window == windows->image.id)
if (event.xexpose.count == 0)
{
event.xexpose.x=highlight_info.x;
event.xexpose.y=highlight_info.y;
event.xexpose.width=highlight_info.width;
event.xexpose.height=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,
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
switch (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_F1:
case XK_Help:
{
XSetFunction(display,windows->image.highlight_context,GXcopy);
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Region of Interest",ImageROIHelp);
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;
}
}
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)
{
if ((x < (windows->info.x+windows->info.width)) &&
(y < (windows->info.y+windows->info.height)))
XWithdrawWindow(display,windows->info.id,windows->info.screen);
}
else
if ((x > (windows->info.x+windows->info.width)) ||
(y > (windows->info.y+windows->info.height)))
XMapWindow(display,windows->info.id);
break;
}
default:
break;
}
if (state & UpdateConfigurationState)
{
XPutBackEvent(display,&event);
XDefineCursor(display,windows->image.id,cursor);
break;
}
} while (!(state & ExitState));
} while (!(state & ExitState));
XSetFunction(display,windows->image.highlight_context,GXcopy);
XSetCursorState(display,windows,False);
if (state & EscapeState)
return(True);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X R o t a t e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function 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 routine is:
%
% status=XRotateImage(display,resource_info,windows,degrees,image)
%
% A description of each parameter follows:
%
% o status: Function XRotateImage return True if the image is
% rotated. False is returned is there is a memory shortage or if the
% image fails to rotate.
%
% 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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
%
*/
static unsigned int XRotateImage(Display *display,XResourceInfo *resource_info,
XWindows *windows,double degrees,Image **image)
{
static char
*RotateMenu[]=
{
"Pixel Color",
"Direction",
"Crop",
"Sharpen",
"Help",
"Dismiss",
(char *) NULL
};
static ModeType
direction = HorizontalRotateCommand,
DirectionCommands[]=
{
HorizontalRotateCommand,
VerticalRotateCommand
},
RotateCommands[]=
{
RotateColorCommand,
RotateDirectionCommand,
RotateCropCommand,
RotateSharpenCommand,
RotateHelpCommand,
RotateDismissCommand
};
static unsigned int
crop = False,
pen_id = 0,
sharpen = True;
char
command[MaxTextExtent],
text[MaxTextExtent];
double
normalized_degrees;
Image
*rotated_image;
int
id,
x,
y;
register int
i;
unsigned int
height,
rotations,
width;
if (degrees == 0.0)
{
unsigned int
distance;
unsigned long
state;
XEvent
event;
XSegment
rotate_info;
/*
Map Command widget.
*/
windows->command.name="Rotate";
windows->command.data=4;
(void) XCommandWidget(display,windows,RotateMenu,(XEvent *) NULL);
XMapRaised(display,windows->command.id);
XClientMessage(display,windows->image.id,windows->im_protocols,
windows->im_update_widget,CurrentTime);
/*
Wait for first button press.
*/
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;
XSetFunction(display,windows->image.highlight_context,GXcopy);
switch (RotateCommands[id])
{
case RotateColorCommand:
{
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]=(char *) NULL;
/*
Select a pen color from the pop-up menu.
*/
pen_number=XMenuWidget(display,windows,RotateMenu[id],
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->image.map_info->colormap,
resource_info->pen_colors[pen_number],&color);
XBestPixel(display,windows->image.map_info->colormap,
(XColor *) NULL,(unsigned int) MaxColors,&color);
windows->image.pixel_info->pen_colors[pen_number]=color;
pen_id=pen_number;
break;
}
case RotateDirectionCommand:
{
static 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 RotateCropCommand:
{
static char
*Options[]=
{
"false",
"true",
(char *) NULL,
};
/*
Select a command from the pop-up menu.
*/
crop=XMenuWidget(display,windows,RotateMenu[id],
Options,command);
break;
}
case RotateSharpenCommand:
{
static char
*Options[]=
{
"false",
"true",
(char *) NULL,
};
/*
Select a command from the pop-up menu.
*/
sharpen=XMenuWidget(display,windows,RotateMenu[id],
Options,command);
break;
}
case RotateHelpCommand:
{
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Rotation",ImageRotateHelp);
break;
}
case RotateDismissCommand:
{
/*
Prematurely exit.
*/
state|=EscapeState;
state|=ExitState;
break;
}
default:
break;
}
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.
*/
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,
sizeof(command),&key_symbol,(XComposeStatus *) NULL);
switch (key_symbol)
{
case XK_Escape:
case XK_F20:
{
/*
Prematurely exit.
*/
state|=EscapeState;
state|=ExitState;
break;
}
case XK_F1:
case XK_Help:
{
XSetFunction(display,windows->image.highlight_context,GXcopy);
XTextViewWidget(display,resource_info,windows,False,
"Help Viewer - Image Rotation",ImageRotateHelp);
XSetFunction(display,windows->image.highlight_context,GXinvert);
break;
}
default:
{
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));
XSetFunction(display,windows->image.highlight_context,GXcopy);
XWithdrawWindow(display,windows->info.id,windows->info.screen);
if (state & EscapeState)
return(True);
/*
Draw line as pointer moves until the mouse button is released.
*/
distance=0;
XSetFunction(display,windows->image.highlight_context,GXinvert);
state=DefaultState;
do
{
if (distance > 9)
{
/*
Display info and draw rotation line.
*/
if (!windows->info.mapped)
XMapWindow(display,windows->info.id);
(void) sprintf(text," %.2f",
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)
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 > windows->image.width)
rotate_info.x2=windows->image.width;
if (rotate_info.y2 < 0)
rotate_info.y2=0;
else
if (rotate_info.y2 > windows->image.height)
rotate_info.y2=windows->image.height;
/*
Compute rotation angle from the slope of the line.
*/
degrees=0.0;
distance=
((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));
XSetFunction(display,windows->image.highlight_context,GXcopy);
XWithdrawWindow(display,windows->info.id,windows->info.screen);
if (distance <= 9)
return(True);
}
if (direction == VerticalRotateCommand)
degrees-=90.0;
if (degrees == 0.0)
return(True);
/*
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,True);
XCheckRefreshWindows(display,windows);
(*image)->border_color.red=
XDownScale(windows->image.pixel_info->pen_colors[pen_id].red);
(*image)->border_color.green=
XDownScale(windows->image.pixel_info->pen_colors[pen_id].green);
(*image)->border_color.blue=
XDownScale(windows->image.pixel_info->pen_colors[pen_id].blue);
(*image)->border_color.index=0;
rotated_image=RotateImage(*image,degrees,crop,sharpen);
XSetCursorState(display,windows,False);
if (rotated_image == (Image *) NULL)
return(False);
DestroyImage(*image);
*image=rotated_image;
if (windows->image.crop_geometry != (char *) NULL)
{
/*
Rotate crop geometry.
*/
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
switch (rotations % 4)
{
default:
case 0:
break;
case 1:
{
/*
Rotate 90 degrees.
*/
(void) sprintf(windows->image.crop_geometry,"%ux%u%+d%+d",
height,width,(int) (*image)->columns-(int) height-y,x);
break;
}
case 2:
{
/*
Rotate 180 degrees.
*/
(void) sprintf(windows->image.crop_geometry,"%ux%u%+d%+d",
width,height,(int) width-x,(int) height-y);
break;
}
case 3:
{
/*
Rotate 270 degrees.
*/
(void) sprintf(windows->image.crop_geometry,"%ux%u%+d%+d",
height,width,y,(int) (*image)->rows-(int) width-x);
break;
}
}
}
if (windows->image.orphan)
return(True);
if (normalized_degrees != 0.0)
{
/*
Update image colormap.
*/
windows->image.window_changes.width=(*image)->columns;
windows->image.window_changes.height=(*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=width;
windows->image.window_changes.height=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(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X S a v e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XSaveImage saves an image to a file.
%
% The format of the XSaveImage routine is:
%
% status=XSaveImage(display,resource_info,windows,image)
%
% A description of each parameter follows:
%
% o status: Function XSaveImage return True if the image is
% written. False is returned is there is a memory shortage or if the
% image fails to write.
%
% 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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
%
*/
static unsigned int XSaveImage(Display *display,XResourceInfo *resource_info,
XWindows *windows,Image **image)
{
char
filename[MaxTextExtent];
ImageInfo
*image_info;
int
status;
/*
Request file name from user.
*/
if (resource_info->write_filename != (char *) NULL)
(void) strcpy(filename,resource_info->write_filename);
else
{
char
working_directory[MaxTextExtent];
register char
*p;
p=(*image)->filename+Extent((*image)->filename)-1;
while ((p > (*image)->filename) && (*(p-1) != *BasenameSeparator))
p--;
(void) strcpy(filename,p);
(void) strcpy(working_directory,(*image)->filename);
working_directory[p-(*image)->filename]='\0';
if (p != (*image)->filename)
(void) chdir(working_directory);
}
XFileBrowserWidget(display,windows,"Save",filename);
if (*filename == '\0')
return(True);
if (IsAccessible(filename))
{
/*
File exists-- seek user's permission before overwriting.
*/
status=XConfirmWidget(display,windows,"Overwrite",filename);
if (status <= 0)
return(True);
}
image_info=resource_info->image_info;
(void) strcpy(image_info->filename,filename);
SetImageInfo(resource_info->image_info,False);
if ((strcmp(image_info->magick,"JPEG") == 0) ||
(strcmp(image_info->magick,"JPG") == 0))
{
char
quality[MaxTextExtent];
/*
Request JPEG quality from user.
*/
(void) sprintf(quality,"%u",image_info->quality);
status=XDialogWidget(display,windows,"Save","Enter JPEG quality:",
quality);
if (*quality == '\0')
return(True);
image_info->quality=atoi(quality);
image_info->interlace=status ? PlaneInterlace : NoneInterlace;
}
if ((strcmp(image_info->magick,"EPS") == 0) ||
(strcmp(image_info->magick,"PS") == 0) ||
(strcmp(image_info->magick,"PS2") == 0))
{
char
geometry[MaxTextExtent];
/*
Request Postscript page geometry from user.
*/
(void) sprintf(geometry,PSPageGeometry);
if (image_info->page != (char *) NULL)
(void) strcpy(geometry,image_info->page);
XListBrowserWidget(display,windows,&windows->widget,PageSizes,"Select",
"Select Postscript Page Geometry:",geometry);
if (*geometry != '\0')
image_info->page=PostscriptGeometry(geometry);
}
/*
Write image.
*/
(void) XMagickCommand(display,resource_info,windows,ApplyCommand,image);
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
(void) strcpy((*image)->filename,filename);
status=WriteImage(image_info,*image);
XSetCursorState(display,windows,False);
(void) XMagickCommand(display,resource_info,windows,UndoCommand,image);
XClientMessage(display,windows->image.id,windows->im_protocols,
windows->im_update_signature,CurrentTime);
return(status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X S c r e e n E v e n t %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XScreenEvent handles global events associated with the Pan and
% Magnify windows.
%
% The format of the XScreenEvent function is:
%
% XScreenEvent(display,windows,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.
%
%
*/
static int XPredicate(Display *display,XEvent *event,char *data)
{
register XWindows
*windows;
windows=(XWindows *) data;
if ((event->type == ClientMessage) &&
(event->xclient.window == windows->image.id))
return(False);
return(True);
}
static void XScreenEvent(Display *display,XWindows *windows,XEvent *event)
{
MonitorHandler
handler;
register int
x,
y;
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)
{
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 >= windows->image.width)
x=windows->image.width-1;
windows->magnify.x=windows->image.x+x;
if (y < 0)
y=0;
else
if (y >= windows->image.height)
y=windows->image.height-1;
windows->magnify.y=windows->image.y+y;
if (!windows->magnify.mapped)
XMapRaised(display,windows->magnify.id);
handler=SetMonitorHandler((MonitorHandler) NULL);
XMakeMagnifyImage(display,windows);
(void) SetMonitorHandler(handler);
if (event->type == ButtonRelease)
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 != windows->wm_delete_window)
break;
if (event->xclient.window == windows->magnify.id)
{
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=event->xconfigure.width;
windows->magnify.height=event->xconfigure.height;
if (!windows->magnify.mapped)
break;
magnify=1;
while (magnify <= event->xconfigure.width)
magnify<<=1;
while (magnify <= event->xconfigure.height)
magnify<<=1;
magnify>>=1;
if ((magnify != event->xconfigure.width) ||
(magnify != event->xconfigure.height))
{
XWindowChanges
window_changes;
window_changes.width=magnify;
window_changes.height=magnify;
XReconfigureWMWindow(display,windows->magnify.id,
windows->magnify.screen,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,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=True;
XWithdrawWindow(display,windows->info.id,windows->info.screen);
break;
}
if (event->xmap.window == windows->info.id)
{
windows->info.mapped=True;
break;
}
break;
}
case MotionNotify:
{
while (XCheckMaskEvent(display,ButtonMotionMask,event));
if (event->xmotion.window == windows->image.id)
if (windows->magnify.mapped)
{
/*
Update magnified image.
*/
x=event->xmotion.x;
y=event->xmotion.y;
if (x < 0)
x=0;
else
if (x >= windows->image.width)
x=windows->image.width-1;
windows->magnify.x=windows->image.x+x;
if (y < 0)
y=0;
else
if (y >= windows->image.height)
y=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=False;
break;
}
if (event->xunmap.window == windows->info.id)
{
windows->info.mapped=False;
break;
}
break;
}
default:
break;
}
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X S e t C r o p G e o m e t r y %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function 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 routine is:
%
% XSetCropGeometry(display,windows,crop_info,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: Specifies a pointer to a Image structure.
%
%
*/
static void XSetCropGeometry(Display *display,XWindows *windows,
RectangleInfo *crop_info,Image *image)
{
char
text[MaxTextExtent];
int
x,
y;
unsigned int
height,
width;
unsigned long
scale_factor;
if (windows->info.mapped)
{
/*
Display info on cropping rectangle.
*/
(void) sprintf(text," %ux%u%+d%+d",crop_info->width,crop_info->height,
crop_info->x,crop_info->y);
XInfoWidget(display,windows,text);
}
/*
Cropping geometry is relative to any previous crop geometry.
*/
x=0;
y=0;
width=image->columns;
height=image->rows;
if (windows->image.crop_geometry != (char *) NULL)
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
else
{
/*
Allocate crop geometry string.
*/
windows->image.crop_geometry=(char *) malloc(MaxTextExtent*sizeof(char));
if (windows->image.crop_geometry == (char *) NULL)
Error("Unable to crop X image",windows->image.name);
}
/*
Define the crop geometry string from the cropping rectangle.
*/
scale_factor=UpShift(width)/windows->image.ximage->width;
if (crop_info->x > 0)
x+=DownShift(crop_info->x*scale_factor);
width=DownShift(crop_info->width*scale_factor);
if (width == 0)
width=1;
scale_factor=UpShift(height)/windows->image.ximage->height;
if (crop_info->y > 0)
y+=DownShift(crop_info->y*scale_factor);
height=DownShift(crop_info->height*scale_factor);
if (height == 0)
height=1;
(void) sprintf(windows->image.crop_geometry,"%ux%u%+d%+d",width,height,x,y);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X T i l e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XTileImage loads or deletes a selected tile from a visual
% image directory. The load or delete command is choosen from a menu.
%
% The format of the XTileImage routine is:
%
% tiled_image=XTileImage(display,resource_info,windows,image,event)
%
% A description of each parameter follows:
%
% o tiled_image: XTileImage reads or deletes the tiled 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: Specifies a pointer to a Image structure; 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 char
*VerbMenu[]=
{
"Load",
"Next",
"Former",
"Delete",
"Update",
(char *) NULL,
};
static ModeType
TileCommands[]=
{
TileLoadCommand,
TileNextCommand,
TileFormerCommand,
TileDeleteCommand,
TileUpdateCommand
};
char
command[MaxTextExtent],
filename[MaxTextExtent];
Image
*tiled_image;
int
id,
status,
tile,
x,
y;
register char
*p,
*q;
register int
i;
unsigned int
height,
width;
unsigned long
scale_factor;
/*
Tile image is relative to montage image configuration.
*/
x=0;
y=0;
width=image->columns;
height=image->rows;
if (windows->image.crop_geometry != (char *) NULL)
(void) XParseGeometry(windows->image.crop_geometry,&x,&y,&width,&height);
scale_factor=UpShift(width)/windows->image.ximage->width;
event->xbutton.x+=windows->image.x;
event->xbutton.x=DownShift(event->xbutton.x*scale_factor)+x;
scale_factor=UpShift(height)/windows->image.ximage->height;
event->xbutton.y+=windows->image.y;
event->xbutton.y=DownShift(event->xbutton.y*scale_factor)+y;
/*
Determine size and location of each tile in the visual image directory.
*/
x=0;
y=0;
width=image->columns;
height=image->rows;
(void) XParseGeometry(image->montage,&x,&y,&width,&height);
tile=((event->xbutton.y-y)/height)*((image->columns-x)/width)+
(event->xbutton.x-x)/width;
if (tile < 0)
{
/*
Button press is outside any tile.
*/
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.
*/
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) strncpy(filename,p,q-p);
filename[q-p]='\0';
/*
Perform command for the selected tile.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
tiled_image=(Image *) NULL;
switch (TileCommands[id])
{
case TileLoadCommand:
{
/*
Load tile image.
*/
XCheckRefreshWindows(display,windows);
(void) strcpy(resource_info->image_info->magick,"MIFF");
(void) strcpy(resource_info->image_info->filename,filename);
tiled_image=ReadImage(resource_info->image_info);
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 (!IsAccessible(filename))
{
XNoticeWidget(display,windows,"Image file does not exist:",filename);
break;
}
status=XConfirmWidget(display,windows,"Really delete tile",filename);
if (status <= 0)
break;
status=remove(filename);
if (status != False)
{
XNoticeWidget(display,windows,"Unable to delete image file:",
filename);
break;
}
}
case TileUpdateCommand:
{
int
x_offset,
y_offset;
register int
j;
register RunlengthPacket
*r;
/*
Ensure all the images exist.
*/
if (!UncompressImage(image))
return((Image *) NULL);
tile=0;
for (p=image->directory; *p != '\0'; p++)
{
q=p;
while ((*q != '\n') && (*q != '\0'))
q++;
(void) strncpy(filename,p,q-p);
filename[q-p]='\0';
p=q;
if (IsAccessible(filename))
{
tile++;
continue;
}
/*
Overwrite tile with background color.
*/
x_offset=width*(tile % ((image->columns-x)/width))+x;
y_offset=height*(tile/((image->columns-x)/width))+y;
for (i=0; i < height; i++)
{
r=image->pixels+((y_offset+i)*image->columns+x_offset);
for (j=0; j < width; j++)
*r++=(*image->pixels);
}
tile++;
}
windows->image.window_changes.width=image->columns;
windows->image.window_changes.height=image->rows;
XConfigureImageColormap(display,resource_info,windows,image);
(void) XConfigureImage(display,resource_info,windows,image);
break;
}
default:
break;
}
XSetCursorState(display,windows,False);
return(tiled_image);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X T r a n s l a t e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function 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 routine is:
%
% XTranslateImage(display,windows,image,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: Specifies a pointer to a Image structure; returned from
% ReadImage.
%
% 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 (key_symbol)
{
case XK_Home:
case XK_KP_Home:
{
windows->image.x=windows->image.width >> 1;
windows->image.y=windows->image.height >> 1;
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 ((windows->image.x+windows->image.width) > windows->image.ximage->width)
windows->image.x=windows->image.ximage->width-windows->image.width;
if (windows->image.y < 0)
windows->image.y=0;
else
if ((windows->image.y+windows->image.height) >
windows->image.ximage->height)
windows->image.y=windows->image.ximage->height-windows->image.height;
/*
Refresh Image window.
*/
(void) sprintf(text," %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);
XWithdrawWindow(display,windows->info.id,windows->info.screen);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X T r i m I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XTrimImage trims the edges from the Image window.
%
% The format of the XTrimImage routine is:
%
% status=XTrimImage(display,resource_info,windows,image)
%
% A description of each parameter follows:
%
% o status: Function XTrimImage returns True if the image is
% cropped. False is returned is there is a memory shortage or if the
% image fails to be cropped.
%
% 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 windows: Specifies a pointer to a XWindows structure.
%
% o image: Specifies a pointer to a Image structure.
%
%
*/
static unsigned int XTrimImage(Display *display,XResourceInfo *resource_info,
XWindows *windows,Image *image)
{
RectangleInfo
trim_info;
register int
x,
y;
unsigned long
background,
pixel;
/*
Trim edges from image.
*/
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
/*
Crop the left edge.
*/
background=XGetPixel(windows->image.ximage,0,0);
trim_info.width=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=x;
if (trim_info.x == windows->image.ximage->width)
{
XSetCursorState(display,windows,False);
return(False);
}
/*
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=x-trim_info.x+1;
/*
Crop the top edge.
*/
background=XGetPixel(windows->image.ximage,0,0);
trim_info.height=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=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=y-trim_info.y+1;
if ((trim_info.width != windows->image.width) ||
(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=trim_info.width;
windows->image.window_changes.height=trim_info.height;
(void) XConfigureImage(display,resource_info,windows,image);
}
XSetCursorState(display,windows,False);
return(True);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% X V i s u a l D i r e c t o r y I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XVisualDirectoryImage creates a Visual Image Directory.
%
% The format of the XVisualDirectoryImage routine is:
%
% loaded_image=XVisualDirectoryImage(display,resource_info,windows)
%
% A description of each parameter follows:
%
% o loaded_image: Function 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 LoadImageText " Loading images... "
#define TileImageText " Scaling image tiles... "
#define XClientName "montage"
char
*commands[5],
**filelist,
*resource_value,
window_id[MaxTextExtent];
Image
*image,
*montage_image,
*next_image;
ImageInfo
local_info;
int
number_files;
MonitorHandler
handler;
register int
i;
static char
filename[MaxTextExtent] = "\0",
filenames[MaxTextExtent] = "*";
unsigned int
backdrop;
XMontageInfo
vid_info;
XResourceInfo
background_resources,
vid_resources;
XrmDatabase
resource_database;
/*
Request file name from user.
*/
XFileBrowserWidget(display,windows,"Directory",filenames);
if (*filenames == '\0')
return((Image *) NULL);
/*
Expand the filenames.
*/
filelist=(char **) malloc(sizeof(char *));
if (filelist == (char **) NULL)
{
Warning("Memory allocation error",(char *) NULL);
return((Image *) NULL);
}
number_files=1;
filelist[0]=filenames;
ExpandFilenames(&number_files,&filelist);
if (number_files == 0)
{
Warning("No image files were found",filenames);
return((Image *) NULL);
}
/*
Get user defaults from X resource database.
*/
XGetMontageInfo(&vid_info);
resource_database=XGetResourceDatabase(display,XClientName);
XGetResourceInfo(resource_database,XClientName,&vid_resources);
vid_resources.background_color=XGetResourceInstance(resource_database,
XClientName,"background",DefaultTileBackground);
vid_resources.foreground_color=XGetResourceInstance(resource_database,
XClientName,"foreground",DefaultTileForeground);
vid_info.frame=XGetResourceClass(resource_database,XClientName,"frame",
(char *) NULL);
vid_resources.image_geometry=XGetResourceInstance(resource_database,
XClientName,"imageGeometry",DefaultTileGeometry);
vid_resources.matte_color=XGetResourceInstance(resource_database,XClientName,
"mattecolor",DefaultTileMatte);
resource_value=XGetResourceClass(resource_database,XClientName,"pointsize",
DefaultPointSize);
vid_info.pointsize=atoi(resource_value);
resource_value=
XGetResourceClass(resource_database,XClientName,"shadow","True");
vid_info.shadow=IsTrue(resource_value);
vid_info.texture=
XGetResourceClass(resource_database,XClientName,"texture","granite:");
vid_info.tile=XGetResourceClass(resource_database,XClientName,"tile",
vid_info.tile);
/*
Set image background resources.
*/
background_resources=(*resource_info);
background_resources.window_id=window_id;
(void) sprintf(background_resources.window_id,"0x%lx",windows->image.id);
background_resources.backdrop=True;
/*
Read each image and convert them to a tile.
*/
backdrop=(windows->image.visual_info->class == TrueColor) ||
(windows->image.visual_info->class == DirectColor);
local_info=(*resource_info->image_info);
image=(Image *) NULL;
commands[0]=resource_info->client_name;
commands[1]="-label";
commands[2]=DefaultTileLabel;
XSetCursorState(display,windows,True);
XCheckRefreshWindows(display,windows);
for (i=0; i < number_files; i++)
{
handler=SetMonitorHandler((MonitorHandler) NULL);
local_info.filename=filelist[i];
*local_info.magick='\0';
if (local_info.size == (char *) NULL)
local_info.size=vid_resources.image_geometry;
next_image=ReadImage(&local_info);
if (filelist[i] != filenames)
free((char *) filelist[i]);
if (next_image != (Image *) NULL)
{
MogrifyImages(&local_info,3,commands,&next_image);
next_image->matte=False;
if (backdrop)
{
(void) XDisplayBackgroundImage(display,&background_resources,
next_image);
XSetCursorState(display,windows,True);
}
if (image == (Image *) NULL)
image=next_image;
else
{
image->next=next_image;
image->next->previous=image;
image=image->next;
}
}
(void) SetMonitorHandler(handler);
ProgressMonitor(LoadImageText,i,number_files);
}
free((char *) filelist);
if (image == (Image *) NULL)
{
XSetCursorState(display,windows,False);
Warning("No images were loaded",filenames);
return((Image *) NULL);
}
while (image->previous != (Image *) NULL)
image=image->previous;
/*
Create the Visual Image Directory.
*/
(void) strcpy(vid_info.filename,filename);
montage_image=XMontageImages(&vid_resources,&vid_info,image);
DestroyImages(image);
XSetCursorState(display,windows,False);
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 W a r n i n g %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Function XWarning displays a warning message in a Notice widget.
%
% The format of the XWarning routine is:
%
% XWarning(message,qualifier)
%
% A description of each parameter follows:
%
% o message: Specifies the message to display before terminating the
% program.
%
% o qualifier: Specifies any qualifier to the message.
%
%
*/
static void XWarning(const char *message,const char *qualifier)
{
char
text[MaxTextExtent];
if (message == (char *) NULL)
return;
(void) strcpy(text,message);
(void) strcat(text,":");
XNoticeWidget(display,windows,text,qualifier);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% M a i n %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
*/
int main(int argc,char **argv)
{
char
*client_name,
density[MaxTextExtent],
*option,
*resource_value,
*server_name;
float
x_density,
y_density;
Image
*image,
*next_image;
ImageInfo
image_info;
int
status,
x,
y;
register int
i,
j;
unsigned int
first_scene,
height,
*image_marker,
image_number,
last_scene,
scene,
width;
unsigned long
state;
XResourceInfo
resource_info;
XrmDatabase
resource_database;
/*
Set defaults.
*/
ReadCommandlLine(argc,&argv);
client_name=ClientName(*argv);
display=(Display *) NULL;
first_scene=0;
image=(Image *) NULL;
image_marker=(unsigned int *) malloc((argc+1)*sizeof(unsigned int));
if (image_marker == (unsigned int *) NULL)
Error("Unable to display image","Memory allocation failed");
for (i=0; i <= argc; i++)
image_marker[i]=argc;
image_number=0;
GetImageInfo(&image_info);
last_scene=0;
resource_database=(XrmDatabase) NULL;
server_name=(char *) NULL;
state=DefaultState;
/*
Check for server name specified on the command line.
*/
ExpandFilenames(&argc,&argv);
for (i=1; i < argc; i++)
{
/*
Check command line for server name.
*/
option=argv[i];
if ((Extent(option) == 1) || ((*option != '-') && (*option != '+')))
continue;
if (strcmp("display",option+1) == 0)
{
/*
User specified server name.
*/
i++;
if (i == argc)
Error("Missing server name on -display",(char *) NULL);
server_name=argv[i];
break;
}
if (strncmp("help",option+1,2) == 0)
Usage(client_name);
}
/*
Get user defaults from X resource database.
*/
display=XOpenDisplay(server_name);
if (display == (Display *) NULL)
Error("Unable to connect to X server",XDisplayName(server_name));
XSetErrorHandler(XError);
resource_database=XGetResourceDatabase(display,client_name);
XGetResourceInfo(resource_database,client_name,&resource_info);
resource_info.image_info=(&image_info);
(void) strcpy(density,PSDensityGeometry);
(void) sscanf(density,"%fx%f",&x_density,&y_density);
(void) XParseGeometry(PSPageGeometry,&x,&y,&width,&height);
(void) sprintf(density,"%f",Min(x_density,y_density)*
(XDisplayHeight(display,XDefaultScreen(display))-40)/(double) height);
image_info.density=
XGetResourceClass(resource_database,client_name,"density",density);
resource_value=
XGetResourceClass(resource_database,client_name,"interlace","plane");
image_info.interlace=UndefinedInterlace;
if (Latin1Compare("none",resource_value) == 0)
image_info.interlace=NoneInterlace;
if (Latin1Compare("line",resource_value) == 0)
image_info.interlace=LineInterlace;
if (Latin1Compare("plane",resource_value) == 0)
image_info.interlace=PlaneInterlace;
if (Latin1Compare("partition",resource_value) == 0)
image_info.interlace=PartitionInterlace;
if (image_info.interlace == UndefinedInterlace)
Warning("Unrecognized interlace type",resource_value);
image_info.page=XGetResourceClass(resource_database,client_name,
"pageGeometry",(char *) NULL);
resource_value=
XGetResourceClass(resource_database,client_name,"quality","75");
image_info.quality=atoi(resource_value);
resource_value=
XGetResourceClass(resource_database,client_name,"verbose","False");
image_info.verbose=IsTrue(resource_value);
/*
Parse command line.
*/
for (i=1; ((i <= argc) && !(state & ExitState)); i++)
{
if (i < argc)
option=argv[i];
else
if (image_number != 0)
break;
else
if (!isatty(STDIN_FILENO))
option="-";
else
option="logo:Untitled";
if ((Extent(option) > 1) && ((*option == '-') || (*option == '+')))
switch (*(option+1))
{
case 'b':
{
if (strncmp("backdrop",option+1,5) == 0)
{
resource_info.backdrop=(*option == '-');
break;
}
if ((strncmp("background",option+1,5) == 0) ||
(strncmp("bg",option+1,2) == 0))
{
resource_info.background_color=(char *) NULL;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing color on -background",(char *) NULL);
resource_info.background_color=argv[i];
}
break;
}
if (strcmp("border",option+1) == 0)
{
if (*option == '-')
{
i++;
if ((i == argc) || !IsGeometry(argv[i]))
Error("Missing geometry on -border",(char *) NULL);
}
break;
}
if (strncmp("bordercolor",option+1,7) == 0)
{
resource_info.border_color=(char *) NULL;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing color on -bordercolor",(char *) NULL);
resource_info.border_color=argv[i];
}
break;
}
if (strncmp("borderwidth",option+1,7) == 0)
{
resource_info.border_width=0;
if (*option == '-')
{
i++;
if ((i == argc) || !sscanf(argv[i],"%d",&x))
Error("Missing width on -borderwidth",(char *) NULL);
resource_info.border_width=atoi(argv[i]);
}
break;
}
Error("Unrecognized option",option);
break;
}
case 'c':
{
if (strncmp("colormap",option+1,6) == 0)
{
resource_info.colormap=PrivateColormap;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing type on -colormap",(char *) NULL);
option=argv[i];
resource_info.colormap=UndefinedColormap;
if (Latin1Compare("private",option) == 0)
resource_info.colormap=PrivateColormap;
if (Latin1Compare("shared",option) == 0)
resource_info.colormap=SharedColormap;
if (resource_info.colormap == UndefinedColormap)
Error("Invalid colormap type on -colormap",option);
}
break;
}
if (strncmp("colors",option+1,7) == 0)
{
resource_info.number_colors=0;
if (*option == '-')
{
i++;
if ((i == argc) || !sscanf(argv[i],"%d",&x))
Error("Missing colors on -colors",(char *) NULL);
resource_info.number_colors=atoi(argv[i]);
}
break;
}
if (strncmp("colorspace",option+1,7) == 0)
{
resource_info.colorspace=RGBColorspace;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing type on -colorspace",(char *) NULL);
option=argv[i];
resource_info.colorspace=UndefinedColorspace;
if (Latin1Compare("gray",option) == 0)
{
resource_info.colorspace=GRAYColorspace;
resource_info.number_colors=256;
resource_info.tree_depth=8;
}
if (Latin1Compare("ohta",option) == 0)
resource_info.colorspace=OHTAColorspace;
if (Latin1Compare("rgb",option) == 0)
resource_info.colorspace=RGBColorspace;
if (Latin1Compare("transparent",option) == 0)
resource_info.colorspace=TransparentColorspace;
if (Latin1Compare("xyz",option) == 0)
resource_info.colorspace=XYZColorspace;
if (Latin1Compare("ycbcr",option) == 0)
resource_info.colorspace=YCbCrColorspace;
if (Latin1Compare("yiq",option) == 0)
resource_info.colorspace=YIQColorspace;
if (Latin1Compare("ypbpr",option) == 0)
resource_info.colorspace=YPbPrColorspace;
if (Latin1Compare("yuv",option) == 0)
resource_info.colorspace=YUVColorspace;
if (resource_info.colorspace == UndefinedColorspace)
Error("Invalid colorspace type on -colorspace",option);
}
break;
}
if (strncmp("comment",option+1,4) == 0)
{
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing comment on -comment",(char *) NULL);
}
break;
}
if (strncmp("compress",option+1,3) == 0)
{
image_info.compression=NoCompression;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing type on -compress",(char *) NULL);
option=argv[i];
if (Latin1Compare("runlengthencoded",option) == 0)
image_info.compression=RunlengthEncodedCompression;
else
if (Latin1Compare("zip",option) == 0)
image_info.compression=ZipCompression;
else
Error("Invalid compression type on -compress",option);
}
break;
}
if (strncmp("contrast",option+1,3) == 0)
break;
if (strncmp("crop",option+1,2) == 0)
{
if (*option == '-')
{
i++;
if ((i == argc) || !IsGeometry(argv[i]))
Error("Missing geometry on -crop",(char *) NULL);
}
break;
}
Error("Unrecognized option",option);
break;
}
case 'd':
{
if (strncmp("debug",option+1,3) == 0)
{
resource_info.debug=(*option == '-');
break;
}
if (strncmp("delay",option+1,3) == 0)
{
resource_info.delay=0;
if (*option == '-')
{
i++;
if ((i == argc) || !sscanf(argv[i],"%d",&x))
Error("Missing seconds on -delay",(char *) NULL);
resource_info.delay=atoi(argv[i]);
}
break;
}
if (strncmp("density",option+1,3) == 0)
{
image_info.density=(char *) NULL;
if (*option == '-')
{
i++;
if ((i == argc) || !IsGeometry(argv[i]))
Error("Missing geometry on -density",(char *) NULL);
image_info.density=argv[i];
}
break;
}
if (strncmp("despeckle",option+1,3) == 0)
break;
if (strcmp("display",option+1) == 0)
{
server_name=(char *) NULL;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing server name on -display",(char *) NULL);
server_name=argv[i];
}
resource_info.server_name=server_name;
image_info.server_name=server_name;
break;
}
if (strncmp("dispose",option+1,5) == 0)
{
image_info.dispose=(char *) NULL;
if (*option == '-')
{
i++;
if ((i == argc) || !sscanf(argv[i],"%d",&x))
Error("Missing method on -dispose",(char *) NULL);
image_info.dispose=PostscriptGeometry(argv[i]);
}
break;
}
if (strncmp("dither",option+1,3) == 0)
{
resource_info.dither=(*option == '-');
break;
}
Error("Unrecognized option",option);
break;
}
case 'e':
{
if (strncmp("edge",option+1,2) == 0)
{
if (*option == '-')
{
i++;
if ((i == argc) || !sscanf(argv[i],"%f",(float *) &x))
Error("Missing factor on -edge",(char *) NULL);
}
break;
}
if (strncmp("enhance",option+1,2) == 0)
break;
Error("Unrecognized option",option);
break;
}
case 'f':
{
if (strncmp("flip",option+1,3) == 0)
break;
if (strncmp("flop",option+1,3) == 0)
break;
if (strncmp("font",option+1,3) == 0)
{
resource_info.font=(char *) NULL;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing font name on -font",(char *) NULL);
resource_info.font=argv[i];
}
break;
}
if ((strncmp("foreground",option+1,3) == 0) ||
(strncmp("fg",option+1,2) == 0))
{
resource_info.foreground_color=(char *) NULL;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing foreground on -foreground",(char *) NULL);
resource_info.foreground_color=argv[i];
}
break;
}
if (strncmp("frame",option+1,2) == 0)
{
if (*option == '-')
{
i++;
if ((i == argc) || !IsGeometry(argv[i]))
Error("Missing geometry on -frame",(char *) NULL);
}
break;
}
Error("Unrecognized option",option);
break;
}
case 'g':
{
if (strncmp("gamma",option+1,2) == 0)
{
if (*option == '-')
{
i++;
if ((i == argc) || !sscanf(argv[i],"%f",(float *) &x))
Error("Missing value on -gamma",(char *) NULL);
}
break;
}
if (strncmp("geometry",option+1,2) == 0)
{
resource_info.image_geometry=(char *) NULL;
if (*option == '-')
{
i++;
if ((i == argc) || !IsGeometry(argv[i]))
Error("Missing geometry on -geometry",(char *) NULL);
resource_info.image_geometry=argv[i];
}
break;
}
Error("Unrecognized option",option);
break;
}
case 'h':
{
if (strncmp("help",option+1,2) == 0)
Usage(client_name);
Error("Unrecognized option",option);
break;
}
case 'i':
{
if (strncmp("iconGeometry",option+1,5) == 0)
{
resource_info.icon_geometry=(char *) NULL;
if (*option == '-')
{
i++;
if ((i == argc) || !IsGeometry(argv[i]))
Error("Missing geometry on -iconGeometry",(char *) NULL);
resource_info.icon_geometry=argv[i];
}
break;
}
if (strncmp("iconic",option+1,5) == 0)
{
resource_info.iconic=(*option == '-');
break;
}
if (strncmp("immutable",option+1,5) == 0)
{
resource_info.immutable=(*option == '-');
break;
}
if (strncmp("interlace",option+1,3) == 0)
{
image_info.interlace=NoneInterlace;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing type on -interlace",(char *) NULL);
option=argv[i];
image_info.interlace=UndefinedInterlace;
if (Latin1Compare("none",option) == 0)
image_info.interlace=NoneInterlace;
if (Latin1Compare("line",option) == 0)
image_info.interlace=LineInterlace;
if (Latin1Compare("plane",option) == 0)
image_info.interlace=PlaneInterlace;
if (Latin1Compare("partition",option) == 0)
image_info.interlace=PartitionInterlace;
if (image_info.interlace == UndefinedInterlace)
Error("Invalid interlace type on -interlace",option);
}
break;
}
Error("Unrecognized option",option);
break;
}
case 'l':
{
if (strncmp("label",option+1,2) == 0)
{
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing label name on -label",(char *) NULL);
}
break;
}
Error("Unrecognized option",option);
break;
}
case 'm':
{
if (strncmp("magnify",option+1,3) == 0)
{
resource_info.magnify=2;
if (*option == '-')
{
i++;
if ((i == argc) || !sscanf(argv[i],"%d",&x))
Error("Missing level on -magnify",(char *) NULL);
resource_info.magnify=atoi(argv[i]);
}
break;
}
if (strncmp("map",option+1,3) == 0)
{
argv[i]="+sans";
resource_info.map_type=(char *) NULL;
if (*option == '-')
{
argv[i]="-sans";
i++;
if (i == argc)
Error("Missing map type on -map",(char *) NULL);
resource_info.map_type=argv[i];
}
break;
}
if (strcmp("matte",option+1) == 0)
break;
if (strncmp("mattecolor",option+1,6) == 0)
{
resource_info.matte_color=(char *) NULL;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing color on -mattecolor",(char *) NULL);
resource_info.matte_color=argv[i];
}
break;
}
if (strncmp("monochrome",option+1,3) == 0)
{
resource_info.monochrome=(*option == '-');
if (resource_info.monochrome)
{
resource_info.number_colors=2;
resource_info.tree_depth=8;
resource_info.colorspace=GRAYColorspace;
}
break;
}
Error("Unrecognized option",option);
break;
}
case 'n':
{
if (strncmp("name",option+1,2) == 0)
{
resource_info.name=(char *) NULL;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing name on -name",(char *) NULL);
resource_info.name=argv[i];
}
break;
}
if (strncmp("negate",option+1,2) == 0)
break;
Error("Unrecognized option",option);
break;
}
case 'p':
{
if (strncmp("page",option+1,3) == 0)
{
image_info.page=(char *) NULL;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing page geometry on -page",(char *) NULL);
image_info.page=PostscriptGeometry(argv[i]);
}
break;
}
Error("Unrecognized option",option);
break;
}
case 'q':
{
if (strncmp("quality",option+1,2) == 0)
{
image_info.quality=atoi(DefaultImageQuality);
if (*option == '-')
{
i++;
if ((i == argc) || !sscanf(argv[i],"%d",&x))
Error("Missing quality on -quality",(char *) NULL);
image_info.quality=atoi(argv[i]);
}
break;
}
Error("Unrecognized option",option);
break;
}
case 'r':
{
if (strncmp("raise",option+1,2) == 0)
{
i++;
if ((i == argc) || !sscanf(argv[i],"%d",&x))
Error("Missing bevel width on -raise",(char *) NULL);
break;
}
if (strncmp("roll",option+1,3) == 0)
{
if (*option == '-')
{
i++;
if ((i == argc) || !IsGeometry(argv[i]))
Error("Missing geometry on -roll",(char *) NULL);
}
break;
}
if (strncmp("rotate",option+1,3) == 0)
{
if (*option == '-')
{
i++;
if ((i == argc) || !IsGeometry(argv[i]))
Error("Missing degrees on -rotate",(char *) NULL);
}
break;
}
Error("Unrecognized option",option);
break;
}
case 's':
{
if (strncmp("sample",option+1,2) == 0)
{
if (*option == '-')
{
i++;
if ((i == argc) || !IsGeometry(argv[i]))
Error("Missing geometry on -sample",(char *) NULL);
}
break;
}
if (strncmp("scene",option+1,3) == 0)
{
first_scene=0;
last_scene=0;
if (*option == '-')
{
i++;
if ((i == argc) || !sscanf(argv[i],"%d",&x))
Error("Missing scene number on -scene",(char *) NULL);
first_scene=atoi(argv[i]);
last_scene=first_scene;
(void) sscanf(argv[i],"%u-%u",&first_scene,&last_scene);
}
break;
}
if (strncmp("segment",option+1,3) == 0)
{
if (*option == '-')
{
i++;
if ((i == argc) || !sscanf(argv[i],"%f",(float *) &x))
Error("Missing threshold on -segment",(char *) NULL);
}
break;
}
if (strncmp("sharpen",option+1,5) == 0)
{
if (*option == '-')
{
i++;
if ((i == argc) || !sscanf(argv[i],"%f",(float *) &x))
Error("Missing factor on -sharpen",(char *) NULL);
}
break;
}
if (strncmp("shared_memory",option+1,5) == 0)
{
resource_info.use_shared_memory=(*option == '-');
break;
}
if (strncmp("size",option+1,2) == 0)
{
image_info.size=(char *) NULL;
if (*option == '-')
{
i++;
if ((i == argc) || !IsGeometry(argv[i]))
Error("Missing geometry on -size",(char *) NULL);
image_info.size=argv[i];
}
break;
}
Error("Unrecognized option",option);
break;
}
case 't':
{
if (strncmp("text_font",option+1,3) == 0)
{
resource_info.text_font=(char *) NULL;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing font name on -text_font",(char *) NULL);
resource_info.text_font=argv[i];
}
break;
}
if (strncmp("texture",option+1,5) == 0)
{
image_info.texture=(char *) NULL;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing filename on -texture",(char *) NULL);
image_info.texture=argv[i];
}
break;
}
if (strncmp("title",option+1,2) == 0)
{
resource_info.title=(char *) NULL;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing title on -title",(char *) NULL);
resource_info.title=argv[i];
}
break;
}
if (strncmp("treedepth",option+1,3) == 0)
{
resource_info.tree_depth=0;
if (*option == '-')
{
i++;
if ((i == argc) || !sscanf(argv[i],"%d",&x))
Error("Missing depth on -treedepth",(char *) NULL);
resource_info.tree_depth=atoi(argv[i]);
}
break;
}
Error("Unrecognized option",option);
break;
}
case 'u':
{
if (strncmp("update",option+1,2) == 0)
{
resource_info.update=(*option == '-');
if (*option == '-')
{
i++;
if ((i == argc) || !sscanf(argv[i],"%d",&x))
Error("Missing seconds on -update",(char *) NULL);
resource_info.delay=atoi(argv[i]);
}
break;
}
if (strncmp("use_pixmap",option+1,2) == 0)
{
resource_info.use_pixmap=(*option == '-');
break;
}
Error("Unrecognized option",option);
break;
}
case 'v':
{
if (strncmp("verbose",option+1,2) == 0)
{
image_info.verbose=(*option == '-');
break;
}
if (strncmp("visual",option+1,2) == 0)
{
resource_info.visual_type=(char *) NULL;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing visual class on -visual",(char *) NULL);
resource_info.visual_type=argv[i];
}
break;
}
Error("Unrecognized option",option);
break;
}
case 'w':
{
if (strcmp("window",option+1) == 0)
{
resource_info.window_id=(char *) NULL;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing id, name, or 'root' on -window",
(char *) NULL);
resource_info.window_id=argv[i];
}
break;
}
if (strncmp("window_group",option+1,7) == 0)
{
resource_info.window_group=(char *) NULL;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing id, name, or 'root' on -window_group",
(char *) NULL);
resource_info.window_group=argv[i];
}
break;
}
if (strncmp("write",option+1,2) == 0)
{
resource_info.write_filename=(char *) NULL;
if (*option == '-')
{
i++;
if (i == argc)
Error("Missing file name on -write",(char *) NULL);
resource_info.write_filename=argv[i];
if (IsAccessible(resource_info.write_filename))
{
char
answer[2];
(void) fprintf(stderr,"Overwrite %s? ",
resource_info.write_filename);
(void) fgets(answer,sizeof(answer),stdin);
if (!((*answer == 'y') || (*answer == 'Y')))
Exit(1);
}
}
break;
}
Error("Unrecognized option",option);
break;
}
case '?':
{
Usage(client_name);
break;
}
default:
{
Error("Unrecognized option",option);
break;
}
}
else
{
/*
Option is a file name.
*/
for (scene=first_scene; scene <= last_scene ; scene++)
{
/*
Read image.
*/
(void) strcpy(image_info.filename,option);
if (first_scene != last_scene)
{
char
filename[MaxTextExtent];
/*
Form filename for multi-part images.
*/
(void) sprintf(filename,image_info.filename,scene);
if (strcmp(filename,image_info.filename) == 0)
(void) sprintf(filename,"%s.%u",image_info.filename,scene);
(void) strcpy(image_info.filename,filename);
}
(void) strcpy(image_info.magick,"MIFF");
image_info.server_name=resource_info.server_name;
image_info.font=resource_info.font;
image_info.dither=resource_info.dither;
image_info.monochrome=resource_info.monochrome;
image=ReadImage(&image_info);
if (image == (Image *) NULL)
if ((i < (argc-1)) || (scene < last_scene))
continue;
else
{
state|=ExitState;
break;
}
do
{
/*
Transmogrify image as defined by the image processing options.
*/
resource_info.quantum=1;
MogrifyImage(&image_info,i,argv,&image);
if (first_scene != last_scene)
image->scene=scene;
/*
Display image to X server.
*/
if (resource_info.window_id != (char *) NULL)
{
/*
Display image to a specified X window.
*/
status=XDisplayBackgroundImage(display,&resource_info,image);
if (status)
state|=RetainColorsState;
if (resource_info.delay == 0)
state|=ExitState;
}
else
do
{
Image
*loaded_image;
/*
Display image to X server.
*/
loaded_image=
XDisplayImage(display,&resource_info,argv,argc,&image,&state);
if (loaded_image == (Image *) NULL)
break;
while ((loaded_image != (Image *) NULL) &&
(!(state & ExitState)))
{
if (loaded_image->montage != (char *) NULL)
{
/*
User selected a visual directory image (montage).
*/
DestroyImages(image);
image=loaded_image;
break;
}
MogrifyImage(&image_info,i,argv,&loaded_image);
if (first_scene != last_scene)
image->scene=scene;
next_image=XDisplayImage(display,&resource_info,argv,argc,
&loaded_image,&state);
if (loaded_image != image)
DestroyImages(loaded_image);
loaded_image=next_image;
}
} while (!(state & ExitState));
if (resource_info.write_filename != (char *) NULL)
{
/*
Write image.
*/
(void) strcpy(image->filename,resource_info.write_filename);
(void) WriteImage(&image_info,image);
}
if (image_info.verbose)
DescribeImage(image,stderr,False);
/*
Proceed to next/previous image.
*/
next_image=image;
if (state & FormerImageState)
for (j=0; j < resource_info.quantum; j++)
{
next_image=next_image->previous;
if (next_image == (Image *) NULL)
break;
}
else
for (j=0; j < resource_info.quantum; j++)
{
next_image=next_image->next;
if (next_image == (Image *) NULL)
break;
}
if (next_image != (Image *) NULL)
image=next_image;
} while ((next_image != (Image *) NULL) && !(state & ExitState));
/*
Free image resources.
*/
DestroyImages(image);
if (!(state & FormerImageState))
image_marker[i]=image_number++;
else
{
/*
Proceed to previous image.
*/
for (i--; i > 0; i--)
if (image_marker[i] == (image_number-2))
break;
if (image_number != 0)
image_number--;
}
if (state & ExitState)
break;
}
}
/*
Determine if we should proceed to the first image.
*/
if (i == (argc-1))
if (!(state & ExitState))
if (resource_info.confirm_exit)
{
/*
Confirm program exit.
*/
status=XConfirmWidget(display,windows,"Do you really want to exit",
client_name);
if (status <= 0)
{
i=0;
image_number=0;
}
}
else
if (resource_info.window_id != (char *) NULL)
{
i=0;
image_number=0;
}
}
if (state & RetainColorsState)
XRetainWindowColors(display,XRootWindow(display,XDefaultScreen(display)));
XSync(display,False);
Exit(0);
return(False);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.