animate.c

Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %                AAA   N   N  IIIII  M   M   AAA   TTTTT  EEEEE               %
00007 %               A   A  NN  N    I    MM MM  A   A    T    E                   %
00008 %               AAAAA  N N N    I    M M M  AAAAA    T    EEE                 %
00009 %               A   A  N  NN    I    M   M  A   A    T    E                   %
00010 %               A   A  N   N  IIIII  M   M  A   A    T    EEEEE               %
00011 %                                                                             %
00012 %                                                                             %
00013 %              Methods to Interactively Animate an Image Sequence             %
00014 %                                                                             %
00015 %                             Software Design                                 %
00016 %                               John Cristy                                   %
00017 %                                July 1992                                    %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 */
00038 
00039 /*
00040   Include declarations.
00041 */
00042 #include "magick/studio.h"
00043 #include "magick/animate.h"
00044 #include "magick/animate-private.h"
00045 #include "magick/client.h"
00046 #include "magick/color.h"
00047 #include "magick/color-private.h"
00048 #include "magick/colorspace.h"
00049 #include "magick/constitute.h"
00050 #include "magick/delegate.h"
00051 #include "magick/exception.h"
00052 #include "magick/exception-private.h"
00053 #include "magick/geometry.h"
00054 #include "magick/image-private.h"
00055 #include "magick/layer.h"
00056 #include "magick/list.h"
00057 #include "magick/log.h"
00058 #include "magick/image.h"
00059 #include "magick/memory_.h"
00060 #include "magick/monitor.h"
00061 #include "magick/monitor-private.h"
00062 #include "magick/option.h"
00063 #include "magick/property.h"
00064 #include "magick/resource_.h"
00065 #include "magick/string_.h"
00066 #include "magick/transform.h"
00067 #include "magick/utility.h"
00068 #include "magick/version.h"
00069 #include "magick/widget.h"
00070 #include "magick/xwindow-private.h"
00071 
00072 #if defined(MAGICKCORE_X11_DELEGATE)
00073 /*
00074   Animate state declarations.
00075 */
00076 #define AutoReverseAnimationState 0x0004
00077 #define ForwardAnimationState 0x0008
00078 #define HighlightState  0x0010
00079 #define PlayAnimationState 0x0020
00080 #define RepeatAnimationState 0x0040
00081 #define StepAnimationState 0x0080
00082 
00083 /*
00084   Static declarations.
00085 */
00086 static const char
00087   *AnimateHelp[]=
00088   {
00089     "BUTTONS",
00090     "",
00091     "  Press any button to map or unmap the Command widget.",
00092     "",
00093     "COMMAND WIDGET",
00094     "  The Command widget lists a number of sub-menus and commands.",
00095     "  They are",
00096     "",
00097     "    Animate",
00098     "      Open...",
00099     "      Save...",
00100     "      Play",
00101     "      Step",
00102     "      Repeat",
00103     "      Auto Reverse",
00104     "    Speed",
00105     "      Slower",
00106     "      Faster",
00107     "    Direction",
00108     "      Forward",
00109     "      Reverse",
00110     "      Help",
00111     "        Overview",
00112     "        Browse Documentation",
00113     "        About Animate",
00114     "    Image Info",
00115     "    Quit",
00116     "",
00117     "  Menu items with a indented triangle have a sub-menu.  They",
00118     "  are represented above as the indented items.  To access a",
00119     "  sub-menu item, move the pointer to the appropriate menu and",
00120     "  press a button and drag.  When you find the desired sub-menu",
00121     "  item, release the button and the command is executed.  Move",
00122     "  the pointer away from the sub-menu if you decide not to",
00123     "  execute a particular command.",
00124     "",
00125     "KEYBOARD ACCELERATORS",
00126     "  Accelerators are one or two key presses that effect a",
00127     "  particular command.  The keyboard accelerators that",
00128     "  animate(1) understands is:",
00129     "",
00130     "  Ctl+O  Press to open an image from a file.",
00131     "",
00132     "  space  Press to display the next image in the sequence.",
00133     "",
00134     "  <      Press to speed-up the display of the images.  Refer to",
00135     "         -delay for more information.",
00136     "",
00137     "  >      Press to slow the display of the images.  Refer to",
00138     "         -delay for more information.",
00139     "",
00140     "  F1     Press to display helpful information about animate(1).",
00141     "",
00142     "  Find   Press to browse documentation about ImageMagick.",
00143     "",
00144     "  ?      Press to display information about the image.  Press",
00145     "         any key or button to erase the information.",
00146     "",
00147     "         This information is printed: image name;  image size;",
00148     "         and the total number of unique colors in the image.",
00149     "",
00150     "  Ctl-q  Press to discard all images and exit program.",
00151     (char *) NULL
00152   };
00153 
00154 /*
00155   Constant declarations.
00156 */
00157 static const char
00158   *PageSizes[]=
00159   {
00160     "Letter",
00161     "Tabloid",
00162     "Ledger",
00163     "Legal",
00164     "Statement",
00165     "Executive",
00166     "A3",
00167     "A4",
00168     "A5",
00169     "B4",
00170     "B5",
00171     "Folio",
00172     "Quarto",
00173     "10x14",
00174     (char *) NULL
00175   };
00176 
00177 static const unsigned char
00178   HighlightBitmap[8] =
00179   {
00180     (unsigned char) 0xaa,
00181     (unsigned char) 0x55,
00182     (unsigned char) 0xaa,
00183     (unsigned char) 0x55,
00184     (unsigned char) 0xaa,
00185     (unsigned char) 0x55,
00186     (unsigned char) 0xaa,
00187     (unsigned char) 0x55
00188   },
00189   ShadowBitmap[8] =
00190   {
00191     (unsigned char) 0x00,
00192     (unsigned char) 0x00,
00193     (unsigned char) 0x00,
00194     (unsigned char) 0x00,
00195     (unsigned char) 0x00,
00196     (unsigned char) 0x00,
00197     (unsigned char) 0x00,
00198     (unsigned char) 0x00
00199   };
00200 
00201 /*
00202   Enumeration declarations.
00203 */
00204 typedef enum
00205 {
00206   OpenCommand,
00207   SaveCommand,
00208   PlayCommand,
00209   StepCommand,
00210   RepeatCommand,
00211   AutoReverseCommand,
00212   SlowerCommand,
00213   FasterCommand,
00214   ForwardCommand,
00215   ReverseCommand,
00216   HelpCommand,
00217   BrowseDocumentationCommand,
00218   VersionCommand,
00219   InfoCommand,
00220   QuitCommand,
00221   StepBackwardCommand,
00222   StepForwardCommand,
00223   NullCommand
00224 } CommandType;
00225 
00226 /*
00227   Stipples.
00228 */
00229 #define HighlightWidth  8
00230 #define HighlightHeight  8
00231 #define ShadowWidth  8
00232 #define ShadowHeight  8
00233 
00234 /*
00235   Forward declarations.
00236 */
00237 static Image
00238   *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
00239     Image **,MagickStatusType *);
00240 
00241 static MagickBooleanType
00242   XSaveImage(Display *,XResourceInfo *,XWindows *,Image *);
00243 
00244 /*
00245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00246 %                                                                             %
00247 %                                                                             %
00248 %                                                                             %
00249 %   A n i m a t e I m a g e s                                                 %
00250 %                                                                             %
00251 %                                                                             %
00252 %                                                                             %
00253 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00254 %
00255 %  AnimateImages() repeatedly displays an image sequence to any X window
00256 %  screen.  It returns a value other than 0 if successful.  Check the
00257 %  exception member of image to determine the reason for any failure.
00258 %
00259 %  The format of the AnimateImages method is:
00260 %
00261 %      MagickBooleanType AnimateImages(const ImageInfo *image_info,
00262 %        Image *images)
00263 %
00264 %  A description of each parameter follows:
00265 %
00266 %    o image_info: the image info.
00267 %
00268 %    o image: the image.
00269 %
00270 */
00271 MagickExport MagickBooleanType AnimateImages(const ImageInfo *image_info,
00272   Image *images)
00273 {
00274   char
00275     *argv[1];
00276 
00277   Display
00278     *display;
00279 
00280   MagickStatusType
00281     status;
00282 
00283   XrmDatabase
00284     resource_database;
00285 
00286   XResourceInfo
00287     resource_info;
00288 
00289   assert(image_info != (const ImageInfo *) NULL);
00290   assert(image_info->signature == MagickSignature);
00291   assert(images != (Image *) NULL);
00292   assert(images->signature == MagickSignature);
00293   if (images->debug != MagickFalse)
00294     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
00295   display=XOpenDisplay(image_info->server_name);
00296   if (display == (Display *) NULL)
00297     {
00298       (void) ThrowMagickException(&images->exception,GetMagickModule(),
00299         XServerError,"UnableToOpenXServer","`%s'",XDisplayName(
00300         image_info->server_name));
00301       return(MagickFalse);
00302     }
00303   if (images->exception.severity != UndefinedException)
00304     CatchException(&images->exception);
00305   (void) XSetErrorHandler(XError);
00306   resource_database=XGetResourceDatabase(display,GetClientName());
00307   (void) ResetMagickMemory(&resource_info,0,sizeof(XResourceInfo));
00308   XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
00309   if (image_info->page != (char *) NULL)
00310     resource_info.image_geometry=AcquireString(image_info->page);
00311   resource_info.immutable=MagickTrue;
00312   argv[0]=AcquireString(GetClientName());
00313   (void) XAnimateImages(display,&resource_info,argv,1,images);
00314   argv[0]=DestroyString(argv[0]);
00315   (void) XCloseDisplay(display);
00316   XDestroyResourceInfo(&resource_info);
00317   status=images->exception.severity == UndefinedException ?
00318     MagickTrue : MagickFalse;
00319   return(status != 0 ? MagickTrue : MagickFalse);
00320 }
00321 
00322 /*
00323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00324 %                                                                             %
00325 %                                                                             %
00326 %                                                                             %
00327 +   X M a g i c k C o m m a n d                                               %
00328 %                                                                             %
00329 %                                                                             %
00330 %                                                                             %
00331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00332 %
00333 %  XMagickCommand() makes a transform to the image or Image window as specified
00334 %  by a user menu button or keyboard command.
00335 %
00336 %  The format of the XMagickCommand method is:
00337 %
00338 %      Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
00339 %        XWindows *windows,const CommandType command_type,Image **image,
00340 %        MagickStatusType *state)
00341 %
00342 %  A description of each parameter follows:
00343 %
00344 %    o display: Specifies a connection to an X server; returned from
00345 %      XOpenDisplay.
00346 %
00347 %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
00348 %
00349 %    o windows: Specifies a pointer to a XWindows structure.
00350 %
00351 %    o image: the image;  XMagickCommand
00352 %      may transform the image and return a new image pointer.
00353 %
00354 %    o state: Specifies a MagickStatusType;  XMagickCommand may return a
00355 %      modified state.
00356 %
00357 %
00358 */
00359 static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
00360   XWindows *windows,const CommandType command_type,Image **image,
00361   MagickStatusType *state)
00362 {
00363   Image
00364     *nexus;
00365 
00366   MagickBooleanType
00367     proceed;
00368 
00369   MagickStatusType
00370     status;
00371 
00372   XTextProperty
00373     window_name;
00374 
00375   /*
00376     Process user command.
00377   */
00378   nexus=NewImageList();
00379   switch (command_type)
00380   {
00381     case OpenCommand:
00382     {
00383       char
00384         **filelist;
00385 
00386       ExceptionInfo
00387         *exception;
00388 
00389       Image
00390         *images,
00391         *next;
00392 
00393       ImageInfo
00394         *read_info;
00395 
00396       int
00397         number_files;
00398 
00399       register int
00400         i;
00401 
00402       static char
00403         filenames[MaxTextExtent] = "*";
00404 
00405       if (resource_info->immutable != MagickFalse)
00406         break;
00407       /*
00408         Request file name from user.
00409       */
00410       XFileBrowserWidget(display,windows,"Animate",filenames);
00411       if (*filenames == '\0')
00412         return((Image *) NULL);
00413       /*
00414         Expand the filenames.
00415       */
00416       filelist=(char **) AcquireMagickMemory(sizeof(char *));
00417       if (filelist == (char **) NULL)
00418         {
00419           ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
00420             filenames);
00421           return((Image *) NULL);
00422         }
00423       number_files=1;
00424       filelist[0]=filenames;
00425       status=ExpandFilenames(&number_files,&filelist);
00426       if ((status == MagickFalse) || (number_files == 0))
00427         {
00428           if (number_files == 0)
00429             {
00430               ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
00431              return((Image *) NULL);
00432             }
00433           ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
00434             filenames);
00435           return((Image *) NULL);
00436         }
00437       read_info=CloneImageInfo(resource_info->image_info);
00438       exception=AcquireExceptionInfo();
00439       images=NewImageList();
00440       XSetCursorState(display,windows,MagickTrue);
00441       XCheckRefreshWindows(display,windows);
00442       for (i=0; i < number_files; i++)
00443       {
00444         (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
00445         filelist[i]=DestroyString(filelist[i]);
00446         *read_info->magick='\0';
00447         next=ReadImage(read_info,exception);
00448         CatchException(exception);
00449         if (next != (Image *) NULL)
00450           AppendImageToList(&images,next);
00451         if (number_files <= 5)
00452           continue;
00453         proceed=SetImageProgress(images,LoadImageTag,i,(MagickSizeType)
00454           number_files);
00455         if (proceed == MagickFalse)
00456           break;
00457       }
00458       filelist=(char **) RelinquishMagickMemory(filelist);
00459       exception=DestroyExceptionInfo(exception);
00460       read_info=DestroyImageInfo(read_info);
00461       if (images == (Image *) NULL)
00462         {
00463           XSetCursorState(display,windows,MagickFalse);
00464           ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
00465           return((Image *) NULL);
00466         }
00467       nexus=GetFirstImageInList(images);
00468       *state|=ExitState;
00469       break;
00470     }
00471     case PlayCommand:
00472     {
00473       char
00474         basename[MaxTextExtent];
00475 
00476       int
00477         status;
00478 
00479       /*
00480         Window name is the base of the filename.
00481       */
00482       *state|=PlayAnimationState;
00483       *state&=(~AutoReverseAnimationState);
00484       GetPathComponent((*image)->magick_filename,BasePath,basename);
00485       (void) FormatMagickString(windows->image.name,MaxTextExtent,
00486         "ImageMagick: %s",basename);
00487       if (resource_info->title != (char *) NULL)
00488         {
00489           char
00490             *title;
00491 
00492           title=InterpretImageProperties(resource_info->image_info,*image,
00493             resource_info->title);
00494           (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
00495           title=DestroyString(title);
00496         }
00497       status=XStringListToTextProperty(&windows->image.name,1,&window_name);
00498       if (status == 0)
00499         break;
00500       XSetWMName(display,windows->image.id,&window_name);
00501       (void) XFree((void *) window_name.value);
00502       break;
00503     }
00504     case StepCommand:
00505     case StepBackwardCommand:
00506     case StepForwardCommand:
00507     {
00508       *state|=StepAnimationState;
00509       *state&=(~PlayAnimationState);
00510       if (command_type == StepBackwardCommand)
00511         *state&=(~ForwardAnimationState);
00512       if (command_type == StepForwardCommand)
00513         *state|=ForwardAnimationState;
00514       if (resource_info->title != (char *) NULL)
00515         break;
00516       break;
00517     }
00518     case RepeatCommand:
00519     {
00520       *state|=RepeatAnimationState;
00521       *state&=(~AutoReverseAnimationState);
00522       *state|=PlayAnimationState;
00523       break;
00524     }
00525     case AutoReverseCommand:
00526     {
00527       *state|=AutoReverseAnimationState;
00528       *state&=(~RepeatAnimationState);
00529       *state|=PlayAnimationState;
00530       break;
00531     }
00532     case SaveCommand:
00533     {
00534       /*
00535         Save image.
00536       */
00537       status=XSaveImage(display,resource_info,windows,*image);
00538       if (status == MagickFalse)
00539         {
00540           XNoticeWidget(display,windows,"Unable to write X image:",
00541             (*image)->filename);
00542           break;
00543         }
00544       break;
00545     }
00546     case SlowerCommand:
00547     {
00548       resource_info->delay++;
00549       break;
00550     }
00551     case FasterCommand:
00552     {
00553       if (resource_info->delay == 0)
00554         break;
00555       resource_info->delay--;
00556       break;
00557     }
00558     case ForwardCommand:
00559     {
00560       *state=ForwardAnimationState;
00561       *state&=(~AutoReverseAnimationState);
00562       break;
00563     }
00564     case ReverseCommand:
00565     {
00566       *state&=(~ForwardAnimationState);
00567       *state&=(~AutoReverseAnimationState);
00568       break;
00569     }
00570     case InfoCommand:
00571     {
00572       XDisplayImageInfo(display,resource_info,windows,(Image *) NULL,*image);
00573       break;
00574     }
00575     case HelpCommand:
00576     {
00577       /*
00578         User requested help.
00579       */
00580       XTextViewWidget(display,resource_info,windows,MagickFalse,
00581         "Help Viewer - Animate",AnimateHelp);
00582       break;
00583     }
00584     case BrowseDocumentationCommand:
00585     {
00586       Atom
00587         mozilla_atom;
00588 
00589       Window
00590         mozilla_window,
00591         root_window;
00592 
00593       /*
00594         Browse the ImageMagick documentation.
00595       */
00596       root_window=XRootWindow(display,XDefaultScreen(display));
00597       mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
00598       mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
00599       if (mozilla_window != (Window) NULL)
00600         {
00601           char
00602             command[MaxTextExtent],
00603             *url;
00604 
00605           /*
00606             Display documentation using Netscape remote control.
00607           */
00608           url=GetMagickHomeURL();
00609           (void) FormatMagickString(command,MaxTextExtent,
00610             "openurl(%s,new-tab)",url);
00611           url=DestroyString(url);
00612           mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
00613           (void) XChangeProperty(display,mozilla_window,mozilla_atom,
00614             XA_STRING,8,PropModeReplace,(unsigned char *) command,
00615             (int) strlen(command));
00616           XSetCursorState(display,windows,MagickFalse);
00617           break;
00618         }
00619       XSetCursorState(display,windows,MagickTrue);
00620       XCheckRefreshWindows(display,windows);
00621       status=InvokeDelegate(resource_info->image_info,*image,"browse",
00622         (char *) NULL,&(*image)->exception);
00623       if (status == MagickFalse)
00624         XNoticeWidget(display,windows,"Unable to browse documentation",
00625           (char *) NULL);
00626       XDelay(display,1500);
00627       XSetCursorState(display,windows,MagickFalse);
00628       break;
00629     }
00630     case VersionCommand:
00631     {
00632       XNoticeWidget(display,windows,GetMagickVersion((unsigned long *) NULL),
00633         GetMagickCopyright());
00634       break;
00635     }
00636     case QuitCommand:
00637     {
00638       /*
00639         exit program
00640       */
00641       if (resource_info->confirm_exit == MagickFalse)
00642         XClientMessage(display,windows->image.id,windows->im_protocols,
00643           windows->im_exit,CurrentTime);
00644       else
00645         {
00646           int
00647             status;
00648 
00649           /*
00650             Confirm program exit.
00651           */
00652           status=XConfirmWidget(display,windows,"Do you really want to exit",
00653             resource_info->client_name);
00654           if (status != 0)
00655             XClientMessage(display,windows->image.id,windows->im_protocols,
00656               windows->im_exit,CurrentTime);
00657         }
00658       break;
00659     }
00660     default:
00661       break;
00662   }
00663   return(nexus);
00664 }
00665 
00666 /*
00667 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00668 %                                                                             %
00669 %                                                                             %
00670 %                                                                             %
00671 +   X A n i m a t e B a c k g r o u n d I m a g e                             %
00672 %                                                                             %
00673 %                                                                             %
00674 %                                                                             %
00675 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00676 %
00677 %  XAnimateBackgroundImage() animates an image sequence in the background of
00678 %  a window.
00679 %
00680 %  The format of the XAnimateBackgroundImage method is:
00681 %
00682 %      void XAnimateBackgroundImage(Display *display,
00683 %        XResourceInfo *resource_info,Image *images)
00684 %
00685 %  A description of each parameter follows:
00686 %
00687 %    o display: Specifies a connection to an X server;  returned from
00688 %      XOpenDisplay.
00689 %
00690 %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
00691 %
00692 %    o images: the image list.
00693 %
00694 */
00695 
00696 static inline long MagickMax(const long x,const long y)
00697 {
00698   if (x > y)
00699     return(x);
00700   return(y);
00701 }
00702 
00703 #if defined(__cplusplus) || defined(c_plusplus)
00704 extern "C" {
00705 #endif
00706 
00707 static int SceneCompare(const void *x,const void *y)
00708 {
00709   const Image
00710     **image_1,
00711     **image_2;
00712 
00713   image_1=(const Image **) x;
00714   image_2=(const Image **) y;
00715   return((int) ((*image_1)->scene-(*image_2)->scene));
00716 }
00717 
00718 #if defined(__cplusplus) || defined(c_plusplus)
00719 }
00720 #endif
00721 
00722 MagickExport void XAnimateBackgroundImage(Display *display,
00723   XResourceInfo *resource_info,Image *images)
00724 {
00725   char
00726     geometry[MaxTextExtent],
00727     visual_type[MaxTextExtent];
00728 
00729   Image
00730     *coalesce_image,
00731     *display_image,
00732     **image_list;
00733 
00734   int
00735     scene;
00736 
00737   MagickStatusType
00738     status;
00739 
00740   RectangleInfo
00741     geometry_info;
00742 
00743   register long
00744     i;
00745 
00746   size_t
00747     number_scenes;
00748 
00749   static XPixelInfo
00750     pixel;
00751 
00752   static XStandardColormap
00753     *map_info;
00754 
00755   static XVisualInfo
00756     *visual_info = (XVisualInfo *) NULL;
00757 
00758   static XWindowInfo
00759     window_info;
00760 
00761   unsigned int
00762     height,
00763     width;
00764 
00765   unsigned long
00766     delay;
00767 
00768   Window
00769     root_window;
00770 
00771   XEvent
00772     event;
00773 
00774   XGCValues
00775     context_values;
00776 
00777   XResourceInfo
00778     resources;
00779 
00780   XWindowAttributes
00781     window_attributes;
00782 
00783   /*
00784     Determine target window.
00785   */
00786   assert(images != (Image *) NULL);
00787   assert(images->signature == MagickSignature);
00788   if (images->debug != MagickFalse)
00789     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
00790   resources=(*resource_info);
00791   window_info.id=(Window) NULL;
00792   root_window=XRootWindow(display,XDefaultScreen(display));
00793   if (LocaleCompare(resources.window_id,"root") == 0)
00794     window_info.id=root_window;
00795   else
00796     {
00797       if (isdigit((int) ((unsigned char) *resources.window_id)) != 0)
00798         window_info.id=XWindowByID(display,root_window,
00799           (Window) strtol((char *) resources.window_id,(char **) NULL,0));
00800       if (window_info.id == (Window) NULL)
00801         window_info.id=
00802           XWindowByName(display,root_window,resources.window_id);
00803     }
00804   if (window_info.id == (Window) NULL)
00805     {
00806       ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists",
00807         resources.window_id);
00808       return;
00809     }
00810   /*
00811     Determine window visual id.
00812   */
00813   window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
00814   window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
00815   (void) CopyMagickString(visual_type,"default",MaxTextExtent);
00816   status=XGetWindowAttributes(display,window_info.id,&window_attributes) != 0 ?
00817     MagickTrue : MagickFalse;
00818   if (status != MagickFalse)
00819     (void) FormatMagickString(visual_type,MaxTextExtent,"0x%lx",
00820       XVisualIDFromVisual(window_attributes.visual));
00821   if (visual_info == (XVisualInfo *) NULL)
00822     {
00823       /*
00824         Allocate standard colormap.
00825       */
00826       map_info=XAllocStandardColormap();
00827       if (map_info == (XStandardColormap *) NULL)
00828         ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
00829           images->filename);
00830       map_info->colormap=(Colormap) NULL;
00831       pixel.pixels=(unsigned long *) NULL;
00832       /*
00833         Initialize visual info.
00834       */
00835       resources.map_type=(char *) NULL;
00836       resources.visual_type=visual_type;
00837       visual_info=XBestVisualInfo(display,map_info,&resources);
00838       if (visual_info == (XVisualInfo *) NULL)
00839         ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
00840           images->filename);
00841       /*
00842         Initialize window info.
00843       */
00844       window_info.ximage=(XImage *) NULL;
00845       window_info.matte_image=(XImage *) NULL;
00846       window_info.pixmap=(Pixmap) NULL;
00847       window_info.matte_pixmap=(Pixmap) NULL;
00848     }
00849   /*
00850     Free previous root colors.
00851   */
00852   if (window_info.id == root_window)
00853     XDestroyWindowColors(display,root_window);
00854   coalesce_image=CoalesceImages(images,&images->exception);
00855   if (coalesce_image == (Image *) NULL)
00856     ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
00857       images->filename);
00858   images=coalesce_image;
00859   if (resources.map_type == (char *) NULL)
00860     if ((visual_info->klass != TrueColor) &&
00861         (visual_info->klass != DirectColor))
00862       {
00863         Image
00864           *next;
00865 
00866         /*
00867           Determine if the sequence of images has the identical colormap.
00868         */
00869         for (next=images; next != (Image *) NULL; )
00870         {
00871           next->matte=MagickFalse;
00872           if ((next->storage_class == DirectClass) ||
00873               (next->colors != images->colors) ||
00874               (next->colors > (unsigned long) visual_info->colormap_size))
00875             break;
00876           for (i=0; i < (long) images->colors; i++)
00877             if (IsColorEqual(next->colormap+i,images->colormap+i) == MagickFalse)
00878               break;
00879           if (i < (long) images->colors)
00880             break;
00881           next=GetNextImageInList(next);
00882         }
00883         if (next != (Image *) NULL)
00884           (void) RemapImages(resources.quantize_info,images,(Image *) NULL);
00885       }
00886   /*
00887     Sort images by increasing scene number.
00888   */
00889   number_scenes=GetImageListLength(images);
00890   image_list=ImageListToArray(images,&images->exception);
00891   if (image_list == (Image **) NULL)
00892     ThrowXWindowFatalException(ResourceLimitFatalError,
00893       "MemoryAllocationFailed",images->filename);
00894   for (i=0; i < (long) number_scenes; i++)
00895     if (image_list[i]->scene == 0)
00896       break;
00897   if (i == (long) number_scenes)
00898     qsort((void *) image_list,number_scenes,sizeof(Image *),SceneCompare);
00899   /*
00900     Initialize Standard Colormap.
00901   */
00902   resources.colormap=SharedColormap;
00903   display_image=image_list[0];
00904   for (scene=0; scene < (int) number_scenes; scene++)
00905   {
00906     if ((resource_info->map_type != (char *) NULL) ||
00907         (visual_info->klass == TrueColor) ||
00908         (visual_info->klass == DirectColor))
00909       (void) SetImageType(image_list[scene],image_list[scene]->matte ==
00910         MagickFalse ? TrueColorType : TrueColorMatteType);
00911     if ((display_image->columns < image_list[scene]->columns) &&
00912         (display_image->rows < image_list[scene]->rows))
00913       display_image=image_list[scene];
00914   }
00915   if ((resource_info->map_type != (char *) NULL) ||
00916       (visual_info->klass == TrueColor) || (visual_info->klass == DirectColor))
00917     (void) SetImageType(display_image,display_image->matte == MagickFalse ?
00918       TrueColorType : TrueColorMatteType);
00919   XMakeStandardColormap(display,visual_info,&resources,display_image,map_info,
00920     &pixel);
00921   /*
00922     Graphic context superclass.
00923   */
00924   context_values.background=pixel.background_color.pixel;
00925   context_values.foreground=pixel.foreground_color.pixel;
00926   pixel.annotate_context=XCreateGC(display,window_info.id,(unsigned long)
00927     GCBackground | GCForeground,&context_values);
00928   if (pixel.annotate_context == (GC) NULL)
00929     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
00930       images->filename);
00931   /*
00932     Initialize Image window attributes.
00933   */
00934   XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
00935     &resources,&window_info);
00936   /*
00937     Create the X image.
00938   */
00939   window_info.width=(unsigned int) image_list[0]->columns;
00940   window_info.height=(unsigned int) image_list[0]->rows;
00941   (void) FormatMagickString(geometry,MaxTextExtent,"%ux%u+0+0>",
00942     window_attributes.width,window_attributes.height);
00943   geometry_info.width=window_info.width;
00944   geometry_info.height=window_info.height;
00945   geometry_info.x=window_info.x;
00946   geometry_info.y=window_info.y;
00947   (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
00948     &geometry_info.width,&geometry_info.height);
00949   window_info.width=(unsigned int) geometry_info.width;
00950   window_info.height=(unsigned int) geometry_info.height;
00951   window_info.x=(int) geometry_info.x;
00952   window_info.y=(int) geometry_info.y;
00953   status=XMakeImage(display,&resources,&window_info,image_list[0],
00954     window_info.width,window_info.height);
00955   if (status == MagickFalse)
00956     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
00957       images->filename);
00958   window_info.x=0;
00959   window_info.y=0;
00960   if (display_image->debug != MagickFalse)
00961     {
00962       (void) LogMagickEvent(X11Event,GetMagickModule(),
00963         "Image: %s[%lu] %lux%lu ",image_list[0]->filename,
00964         image_list[0]->scene,image_list[0]->columns,image_list[0]->rows);
00965       if (image_list[0]->colors != 0)
00966         (void) LogMagickEvent(X11Event,GetMagickModule(),"%luc ",
00967           image_list[0]->colors);
00968       (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
00969         image_list[0]->magick);
00970     }
00971   /*
00972     Adjust image dimensions as specified by backdrop or geometry options.
00973   */
00974   width=window_info.width;
00975   height=window_info.height;
00976   if (resources.backdrop != MagickFalse)
00977     {
00978       /*
00979         Center image on window.
00980       */
00981       window_info.x=(int) (window_attributes.width/2)-
00982         (window_info.ximage->width/2);
00983       window_info.y=(int) (window_attributes.height/2)-
00984         (window_info.ximage->height/2);
00985       width=(unsigned int) window_attributes.width;
00986       height=(unsigned int) window_attributes.height;
00987     }
00988   if (resources.image_geometry != (char *) NULL)
00989     {
00990       char
00991         default_geometry[MaxTextExtent];
00992 
00993       int
00994         flags,
00995         gravity;
00996 
00997       XSizeHints
00998         *size_hints;
00999 
01000       /*
01001         User specified geometry.
01002       */
01003       size_hints=XAllocSizeHints();
01004       if (size_hints == (XSizeHints *) NULL)
01005         ThrowXWindowFatalException(ResourceLimitFatalError,
01006           "MemoryAllocationFailed",images->filename);
01007       size_hints->flags=0L;
01008       (void) FormatMagickString(default_geometry,MaxTextExtent,"%ux%u",width,
01009         height);
01010       flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
01011         default_geometry,window_info.border_width,size_hints,&window_info.x,
01012         &window_info.y,(int *) &width,(int *) &height,&gravity);
01013       if (((flags & (XValue | YValue))) != 0)
01014         {
01015           width=(unsigned int) window_attributes.width;
01016           height=(unsigned int) window_attributes.height;
01017         }
01018       (void) XFree((void *) size_hints);
01019     }
01020   /*
01021     Create the X pixmap.
01022   */
01023   window_info.pixmap=XCreatePixmap(display,window_info.id,(unsigned int) width,
01024     (unsigned int) height,window_info.depth);
01025   if (window_info.pixmap == (Pixmap) NULL)
01026     ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
01027       images->filename);
01028   /*
01029     Display pixmap on the window.
01030   */
01031   if (((unsigned int) width > window_info.width) ||
01032       ((unsigned int) height > window_info.height))
01033     (void) XFillRectangle(display,window_info.pixmap,
01034       window_info.annotate_context,0,0,(unsigned int) width,
01035       (unsigned int) height);
01036   (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
01037     window_info.ximage,0,0,window_info.x,window_info.y,window_info.width,
01038     window_info.height);
01039   (void) XSetWindowBackgroundPixmap(display,window_info.id,window_info.pixmap);
01040   (void) XClearWindow(display,window_info.id);
01041   /*
01042     Initialize image pixmaps structure.
01043   */
01044   window_info.pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
01045     sizeof(*window_info.pixmaps));
01046   window_info.matte_pixmaps=(Pixmap *) AcquireQuantumMemory(number_scenes,
01047     sizeof(*window_info.matte_pixmaps));
01048   if ((window_info.pixmaps == (Pixmap *) NULL) ||
01049       (window_info.matte_pixmaps == (Pixmap *) NULL))
01050     ThrowXWindowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
01051       images->filename);
01052   window_info.pixmaps[0]=window_info.pixmap;
01053   window_info.matte_pixmaps[0]=window_info.pixmap;
01054   for (scene=1; scene < (int) number_scenes; scene++)
01055   {
01056     /*
01057       Create X image.
01058     */
01059     window_info.pixmap=(Pixmap) NULL;
01060     window_info.matte_pixmap=(Pixmap) NULL;
01061     if ((resources.map_type != (char *) NULL) ||
01062         (visual_info->klass == TrueColor) ||
01063         (visual_info->klass == DirectColor))
01064       if (image_list[scene]->storage_class == PseudoClass)
01065         XGetPixelPacket(display,visual_info,map_info,&resources,
01066           image_list[scene],window_info.pixel_info);
01067     status=XMakeImage(display,&resources,&window_info,image_list[scene],
01068       (unsigned int) image_list[scene]->columns,
01069       (unsigned int) image_list[scene]->rows);
01070     if (status == MagickFalse)
01071       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
01072         images->filename);
01073     if (display_image->debug != MagickFalse)
01074       {
01075         (void) LogMagickEvent(X11Event,GetMagickModule(),
01076           "Image: [%lu] %s %lux%lu ",image_list[scene]->scene,
01077           image_list[scene]->filename,image_list[scene]->columns,
01078           image_list[scene]->rows);
01079         if (image_list[scene]->colors != 0)
01080           (void) LogMagickEvent(X11Event,GetMagickModule(),"%luc ",
01081             image_list[scene]->colors);
01082         (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
01083           image_list[scene]->magick);
01084       }
01085     /*
01086       Create the X pixmap.
01087     */
01088     window_info.pixmap=XCreatePixmap(display,window_info.id,
01089       (unsigned int) width,(unsigned int) height,window_info.depth);
01090     if (window_info.pixmap == (Pixmap) NULL)
01091       ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXPixmap",
01092         images->filename);
01093     /*
01094       Display pixmap on the window.
01095     */
01096     if (((unsigned int) width > window_info.width) ||
01097         ((unsigned int) height > window_info.height))
01098       (void) XFillRectangle(display,window_info.pixmap,
01099         window_info.annotate_context,0,0,(unsigned int) width,
01100         (unsigned int) height);
01101     (void) XPutImage(display,window_info.pixmap,window_info.annotate_context,
01102       window_info.ximage,0,0,window_info.x,window_info.y,window_info.width,
01103       window_info.height);
01104     (void) XSetWindowBackgroundPixmap(display,window_info.id,
01105       window_info.pixmap);
01106     (void) XClearWindow(display,window_info.id);
01107     window_info.pixmaps[scene]=window_info.pixmap;
01108     window_info.matte_pixmaps[scene]=window_info.matte_pixmap;
01109     if (image_list[scene]->matte)
01110       (void) XClearWindow(display,window_info.id);
01111     delay=1000*image_list[scene]->delay/MagickMax(
01112       image_list[scene]->ticks_per_second,1L);
01113     XDelay(display,resources.delay*(delay == 0 ? 10 : delay));
01114   }
01115   window_info.pixel_info=(&pixel);
01116   /*
01117     Display pixmap on the window.
01118   */
01119   (void) XSelectInput(display,window_info.id,SubstructureNotifyMask);
01120   event.type=Expose;
01121   do
01122   {
01123     for (scene=0; scene < (int) number_scenes; scene++)
01124     {
01125       if (XEventsQueued(display,QueuedAfterFlush) > 0)
01126         {
01127           (void) XNextEvent(display,&event);
01128           if (event.type == DestroyNotify)
01129             break;
01130         }
01131       window_info.pixmap=window_info.pixmaps[scene];
01132       window_info.matte_pixmap=window_info.matte_pixmaps[scene];
01133       (void) XSetWindowBackgroundPixmap(display,window_info.id,
01134         window_info.pixmap);
01135       (void) XClearWindow(display,window_info.id);
01136       (void) XSync(display,MagickFalse);
01137       delay=1000*image_list[scene]->delay/MagickMax(
01138         image_list[scene]->ticks_per_second,1L);
01139       XDelay(display,resources.delay*(delay == 0 ? 10 : delay));
01140     }
01141   } while (event.type != DestroyNotify);
01142   (void) XSync(display,MagickFalse);
01143   image_list=(Image **) RelinquishMagickMemory(image_list);
01144   images=DestroyImageList(images);
01145 }
01146 
01147 /*
01148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01149 %                                                                             %
01150 %                                                                             %
01151 %                                                                             %
01152 +   X A n i m a t e I m a g e s                                               %
01153 %                                                                             %
01154 %                                                                             %
01155 %                                                                             %
01156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01157 %
01158 %  XAnimateImages() displays an image via X11.
01159 %
01160 %  The format of the XAnimateImages method is:
01161 %
01162 %      Image *XAnimateImages(Display *display,XResourceInfo *resource_info,
01163 %        char **argv,const int argc,Image *images)
01164 %
01165 %  A description of each parameter follows:
01166 %
01167 %    o display: Specifies a connection to an X server;  returned from
01168 %      XOpenDisplay.
01169 %
01170 %    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
01171 %
01172 %    o argv: Specifies the application's argument list.
01173 %
01174 %    o argc: Specifies the number of arguments.
01175 %
01176 %    o images: the image list.
01177 %
01178 */
01179 MagickExport Image *XAnimateImages(Display *display,
01180   XResourceInfo *resource_info,char **argv,const int argc,Image *images)
01181 {
01182 #define MagickMenus  4
01183 #define MaXWindows  8
01184 #define MagickTitle  "Commands"
01185 
01186   static const char
01187     *CommandMenu[]=
01188     {
01189       "Animate",
01190       "Speed",
01191       "Direction",
01192       "Help",
01193       "Image Info",
01194       "Quit",
01195       (char *) NULL
01196     },
01197     *AnimateMenu[]=
01198     {
01199       "Open...",
01200       "Play",
01201       "Step",
01202       "Repeat",
01203       "Auto Reverse",
01204       "Save...",
01205       (char *) NULL
01206     },
01207     *SpeedMenu[]=
01208     {
01209       "Faster",
01210       "Slower",
01211       (char *) NULL
01212     },
01213     *DirectionMenu[]=
01214     {
01215       "Forward",
01216       "Reverse",
01217       (char *) NULL
01218     },
01219     *HelpMenu[]=
01220     {
01221       "Overview",
01222       "Browse Documentation",
01223       "About Animate",
01224       (char *) NULL
01225     };
01226 
01227 
01228   static const char
01229     **Menus[MagickMenus]=
01230     {
01231       AnimateMenu,
01232       SpeedMenu,
01233       DirectionMenu,
01234       HelpMenu
01235     };
01236 
01237   static const CommandType
01238     CommandMenus[]=
01239     {
01240       NullCommand,
01241       NullCommand,
01242       NullCommand,
01243       NullCommand,
01244       InfoCommand,
01245       QuitCommand
01246     },
01247     CommandTypes[]=
01248     {
01249       OpenCommand,
01250       PlayCommand,
01251       StepCommand,
01252       RepeatCommand,
01253       AutoReverseCommand,
01254       SaveCommand
01255     },
01256     SpeedCommands[]=
01257     {
01258       FasterCommand,
01259       SlowerCommand
01260     },
01261     DirectionCommands[]=
01262     {
01263       ForwardCommand,
01264       ReverseCommand
01265     },
01266     HelpCommands[]=
01267     {
01268       HelpCommand,
01269       BrowseDocumentationCommand,
01270       VersionCommand
01271     };
01272 
01273   static const CommandType
01274     *Commands[MagickMenus]=
01275     {
01276       CommandTypes,
01277       SpeedCommands,
01278       DirectionCommands,
01279       HelpCommands
01280     };
01281 
01282   char
01283     command[MaxTextExtent],
01284     geometry[MaxTextExtent],
01285     resource_name[MaxTextExtent];
01286 
01287   CommandType
01288     command_type;
01289 
0