/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % 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, Sel