/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % 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. */ (void) getcwd(working_directory,MaxTextExtent-1); (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); 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); }