root / ImageMagick / trunk / magick / animate.c

Revision 12114, 99.3 kB (checked in by cristy, 10 days ago)
Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                AAA   N   N  IIIII  M   M   AAA   TTTTT  EEEEE               %
7%               A   A  NN  N    I    MM MM  A   A    T    E                   %
8%               AAAAA  N N N    I    M M M  AAAAA    T    EEE                 %
9%               A   A  N  NN    I    M   M  A   A    T    E                   %
10%               A   A  N   N  IIIII  M   M  A   A    T    EEEEE               %
11%                                                                             %
12%                                                                             %
13%              Methods to Interactively Animate an Image Sequence             %
14%                                                                             %
15%                             Software Design                                 %
16%                               John Cristy                                   %
17%                                July 1992                                    %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40  Include declarations.
41*/
42#include "magick/studio.h"
43#include "magick/animate.h"
44#include "magick/animate-private.h"
45#include "magick/client.h"
46#include "magick/color.h"
47#include "magick/color-private.h"
48#include "magick/colorspace.h"
49#include "magick/constitute.h"
50#include "magick/delegate.h"
51#include "magick/exception.h"
52#include "magick/exception-private.h"
53#include "magick/geometry.h"
54#include "magick/image-private.h"
55#include "magick/layer.h"
56#include "magick/list.h"
57#include "magick/log.h"
58#include "magick/image.h"
59#include "magick/memory_.h"
60#include "magick/monitor.h"
61#include "magick/monitor-private.h"
62#include "magick/option.h"
63#include "magick/property.h"
64#include "magick/resource_.h"
65#include "magick/string_.h"
66#include "magick/transform.h"
67#include "magick/utility.h"
68#include "magick/version.h"
69#include "magick/widget.h"
70#include "magick/xwindow-private.h"
71
72#if defined(MAGICKCORE_X11_DELEGATE)
73/*
74  Animate state declarations.
75*/
76#define AutoReverseAnimationState 0x0004
77#define ForwardAnimationState 0x0008
78#define HighlightState  0x0010
79#define PlayAnimationState 0x0020
80#define RepeatAnimationState 0x0040
81#define StepAnimationState 0x0080
82
83/*
84  Static declarations.
85*/
86static const char
87  *AnimateHelp[]=
88  {
89    "BUTTONS",
90    "",
91    "  Press any button to map or unmap the Command widget.",
92    "",
93    "COMMAND WIDGET",
94    "  The Command widget lists a number of sub-menus and commands.",
95    "  They are",
96    "",
97    "    Animate",
98    "      Open...",
99    "      Save...",
100    "      Play",
101    "      Step",
102    "      Repeat",
103    "      Auto Reverse",
104    "    Speed",
105    "      Slower",
106    "      Faster",
107    "    Direction",
108    "      Forward",
109    "      Reverse",
110    "      Help",
111    "        Overview",
112    "        Browse Documentation",
113    "        About Animate",
114    "    Image Info",
115    "    Quit",
116    "",
117    "  Menu items with a indented triangle have a sub-menu.  They",
118    "  are represented above as the indented items.  To access a",
119    "  sub-menu item, move the pointer to the appropriate menu and",
120    "  press a button and drag.  When you find the desired sub-menu",
121    "  item, release the button and the command is executed.  Move",
122    "  the pointer away from the sub-menu if you decide not to",
123    "  execute a particular command.",
124    "",
125    "KEYBOARD ACCELERATORS",
126    "  Accelerators are one or two key presses that effect a",
127    "  particular command.  The keyboard accelerators that",
128    "  animate(1) understands is:",
129    "",
130    "  Ctl+O  Press to open an image from a file.",
131    "",
132    "  space  Press to display the next image in the sequence.",
133    "",
134    "  <      Press to speed-up the display of the images.  Refer to",
135    "         -delay for more information.",
136    "",
137    "  >      Press to slow the display of the images.  Refer to",
138    "         -delay for more information.",
139    "",
140    "  F1     Press to display helpful information about animate(1).",
141    "",
142    "  Find   Press to browse documentation about ImageMagick.",
143    "",
144    "  ?      Press to display information about the image.  Press",
145    "         any key or button to erase the information.",
146    "",
147    "         This information is printed: image name;  image size;",
148    "         and the total number of unique colors in the image.",
149    "",
150    "  Ctl-q  Press to discard all images and exit program.",
151    (char *) NULL
152  };
153
154/*
155  Constant declarations.
156*/
157static const char
158  *PageSizes[]=
159  {
160    "Letter",
161    "Tabloid",
162    "Ledger",
163    "Legal",
164    "Statement",
165    "Executive",
166    "A3",
167    "A4",
168    "A5",
169    "B4",
170    "B5",
171    "Folio",
172    "Quarto",
173    "10x14",
174    (char *) NULL
175  };
176
177static const unsigned char
178  HighlightBitmap[8] =
179  {
180    (unsigned char) 0xaa,
181    (unsigned char) 0x55,
182    (unsigned char) 0xaa,
183    (unsigned char) 0x55,
184    (unsigned char) 0xaa,
185    (unsigned char) 0x55,
186    (unsigned char) 0xaa,
187    (unsigned char) 0x55
188  },
189  ShadowBitmap[8] =
190  {
191    (unsigned char) 0x00,
192    (unsigned char) 0x00,
193    (unsigned char) 0x00,
194    (unsigned char) 0x00,
195    (unsigned char) 0x00,
196    (unsigned char) 0x00,
197    (unsigned char) 0x00,
198    (unsigned char) 0x00
199  };
200
201/*
202  Enumeration declarations.
203*/
204typedef enum
205{
206  OpenCommand,
207  SaveCommand,
208  PlayCommand,
209  StepCommand,
210  RepeatCommand,
211  AutoReverseCommand,
212  SlowerCommand,
213  FasterCommand,
214  ForwardCommand,
215  ReverseCommand,
216  HelpCommand,
217  BrowseDocumentationCommand,
218  VersionCommand,
219  InfoCommand,
220  QuitCommand,
221  StepBackwardCommand,
222  StepForwardCommand,
223  NullCommand
224} CommandType;
225
226/*
227  Stipples.
228*/
229#define HighlightWidth  8
230#define HighlightHeight  8
231#define ShadowWidth  8
232#define ShadowHeight  8
233
234/*
235  Forward declarations.
236*/
237static Image
238  *XMagickCommand(Display *,XResourceInfo *,XWindows *,const CommandType,
239    Image **,MagickStatusType *);
240
241static MagickBooleanType
242  XSaveImage(Display *,XResourceInfo *,XWindows *,Image *);
243
244/*
245%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
246%                                                                             %
247%                                                                             %
248%                                                                             %
249%   A n i m a t e I m a g e s                                                 %
250%                                                                             %
251%                                                                             %
252%                                                                             %
253%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
254%
255%  AnimateImages() repeatedly displays an image sequence to any X window
256%  screen.  It returns a value other than 0 if successful.  Check the
257%  exception member of image to determine the reason for any failure.
258%
259%  The format of the AnimateImages method is:
260%
261%      MagickBooleanType AnimateImages(const ImageInfo *image_info,
262%        Image *images)
263%
264%  A description of each parameter follows:
265%
266%    o image_info: the image info.
267%
268%    o image: the image.
269%
270*/
271MagickExport MagickBooleanType AnimateImages(const ImageInfo *image_info,
272  Image *images)
273{
274  char
275    *argv[1];
276
277  Display
278    *display;
279
280  MagickStatusType
281    status;
282
283  XrmDatabase
284    resource_database;
285
286  XResourceInfo
287    resource_info;
288
289  assert(image_info != (const ImageInfo *) NULL);
290  assert(image_info->signature == MagickSignature);
291  assert(images != (Image *) NULL);
292  assert(images->signature == MagickSignature);
293  if (images->debug != MagickFalse)
294    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
295  display=XOpenDisplay(image_info->server_name);
296  if (display == (Display *) NULL)
297    {
298      (void) ThrowMagickException(&images->exception,GetMagickModule(),
299        XServerError,"UnableToOpenXServer","`%s'",XDisplayName(
300        image_info->server_name));
301      return(MagickFalse);
302    }
303  if (images->exception.severity != UndefinedException)
304    CatchException(&images->exception);
305  (void) XSetErrorHandler(XError);
306  resource_database=XGetResourceDatabase(display,GetClientName());
307  (void) ResetMagickMemory(&resource_info,0,sizeof(XResourceInfo));
308  XGetResourceInfo(image_info,resource_database,GetClientName(),&resource_info);
309  if (image_info->page != (char *) NULL)
310    resource_info.image_geometry=AcquireString(image_info->page);
311  resource_info.immutable=MagickTrue;
312  argv[0]=AcquireString(GetClientName());
313  (void) XAnimateImages(display,&resource_info,argv,1,images);
314  argv[0]=DestroyString(argv[0]);
315  (void) XCloseDisplay(display);
316  XDestroyResourceInfo(&resource_info);
317  status=images->exception.severity == UndefinedException ?
318    MagickTrue : MagickFalse;
319  return(status != 0 ? MagickTrue : MagickFalse);
320}
321
322/*
323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
324%                                                                             %
325%                                                                             %
326%                                                                             %
327+   X M a g i c k C o m m a n d                                               %
328%                                                                             %
329%                                                                             %
330%                                                                             %
331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332%
333%  XMagickCommand() makes a transform to the image or Image window as specified
334%  by a user menu button or keyboard command.
335%
336%  The format of the XMagickCommand method is:
337%
338%      Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
339%        XWindows *windows,const CommandType command_type,Image **image,
340%        MagickStatusType *state)
341%
342%  A description of each parameter follows:
343%
344%    o display: Specifies a connection to an X server; returned from
345%      XOpenDisplay.
346%
347%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
348%
349%    o windows: Specifies a pointer to a XWindows structure.
350%
351%    o image: the image;  XMagickCommand
352%      may transform the image and return a new image pointer.
353%
354%    o state: Specifies a MagickStatusType;  XMagickCommand may return a
355%      modified state.
356%
357%
358*/
359static Image *XMagickCommand(Display *display,XResourceInfo *resource_info,
360  XWindows *windows,const CommandType command_type,Image **image,
361  MagickStatusType *state)
362{
363  Image
364    *nexus;
365
366  MagickBooleanType
367    proceed;
368
369  MagickStatusType
370    status;
371
372  XTextProperty
373    window_name;
374
375  /*
376    Process user command.
377  */
378  nexus=NewImageList();
379  switch (command_type)
380  {
381    case OpenCommand:
382    {
383      char
384        **filelist;
385
386      ExceptionInfo
387        *exception;
388
389      Image
390        *images,
391        *next;
392
393      ImageInfo
394        *read_info;
395
396      int
397        number_files;
398
399      register int
400        i;
401
402      static char
403        filenames[MaxTextExtent] = "*";
404
405      if (resource_info->immutable != MagickFalse)
406        break;
407      /*
408        Request file name from user.
409      */
410      XFileBrowserWidget(display,windows,"Animate",filenames);
411      if (*filenames == '\0')
412        return((Image *) NULL);
413      /*
414        Expand the filenames.
415      */
416      filelist=(char **) AcquireMagickMemory(sizeof(char *));
417      if (filelist == (char **) NULL)
418        {
419          ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
420            filenames);
421          return((Image *) NULL);
422        }
423      number_files=1;
424      filelist[0]=filenames;
425      status=ExpandFilenames(&number_files,&filelist);
426      if ((status == MagickFalse) || (number_files == 0))
427        {
428          if (number_files == 0)
429            {
430              ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
431             return((Image *) NULL);
432            }
433          ThrowXWindowException(ResourceLimitError,"MemoryAllocationFailed",
434            filenames);
435          return((Image *) NULL);
436        }
437      read_info=CloneImageInfo(resource_info->image_info);
438      exception=AcquireExceptionInfo();
439      images=NewImageList();
440      XSetCursorState(display,windows,MagickTrue);
441      XCheckRefreshWindows(display,windows);
442      for (i=0; i < number_files; i++)
443      {
444        (void) CopyMagickString(read_info->filename,filelist[i],MaxTextExtent);
445        filelist[i]=DestroyString(filelist[i]);
446        *read_info->magick='\0';
447        next=ReadImage(read_info,exception);
448        CatchException(exception);
449        if (next != (Image *) NULL)
450          AppendImageToList(&images,next);
451        if (number_files <= 5)
452          continue;
453        proceed=SetImageProgress(images,LoadImageTag,i,number_files);
454        if (proceed == MagickFalse)
455          break;
456      }
457      filelist=(char **) RelinquishMagickMemory(filelist);
458      exception=DestroyExceptionInfo(exception);
459      read_info=DestroyImageInfo(read_info);
460      if (images == (Image *) NULL)
461        {
462          XSetCursorState(display,windows,MagickFalse);
463          ThrowXWindowException(ImageError,"NoImagesWereLoaded",filenames);
464          return((Image *) NULL);
465        }
466      nexus=GetFirstImageInList(images);
467      *state|=ExitState;
468      break;
469    }
470    case PlayCommand:
471    {
472      char
473        basename[MaxTextExtent];
474
475      int
476        status;
477
478      /*
479        Window name is the base of the filename.
480      */
481      *state|=PlayAnimationState;
482      *state&=(~AutoReverseAnimationState);
483      GetPathComponent((*image)->magick_filename,BasePath,basename);
484      (void) FormatMagickString(windows->image.name,MaxTextExtent,
485        "ImageMagick: %s",basename);
486      if (resource_info->title != (char *) NULL)
487        {
488          char
489            *title;
490
491          title=InterpretImageProperties(resource_info->image_info,*image,
492            resource_info->title);
493          (void) CopyMagickString(windows->image.name,title,MaxTextExtent);
494          title=DestroyString(title);
495        }
496      status=XStringListToTextProperty(&windows->image.name,1,&window_name);
497      if (status == 0)
498        break;
499      XSetWMName(display,windows->image.id,&window_name);
500      (void) XFree((void *) window_name.value);
501      break;
502    }
503    case StepCommand:
504    case StepBackwardCommand:
505    case StepForwardCommand:
506    {
507      *state|=StepAnimationState;
508      *state&=(~PlayAnimationState);
509      if (command_type == StepBackwardCommand)
510        *state&=(~ForwardAnimationState);
511      if (command_type == StepForwardCommand)
512        *state|=ForwardAnimationState;
513      if (resource_info->title != (char *) NULL)
514        break;
515      break;
516    }
517    case RepeatCommand:
518    {
519      *state|=RepeatAnimationState;
520      *state&=(~AutoReverseAnimationState);
521      *state|=PlayAnimationState;
522      break;
523    }
524    case AutoReverseCommand:
525    {
526      *state|=AutoReverseAnimationState;
527      *state&=(~RepeatAnimationState);
528      *state|=PlayAnimationState;
529      break;
530    }
531    case SaveCommand:
532    {
533      /*
534        Save image.
535      */
536      status=XSaveImage(display,resource_info,windows,*image);
537      if (status == MagickFalse)
538        {
539          XNoticeWidget(display,windows,"Unable to write X image:",
540            (*image)->filename);
541          break;
542        }
543      break;
544    }
545    case SlowerCommand:
546    {
547      resource_info->delay++;
548      break;
549    }
550    case FasterCommand:
551    {
552      if (resource_info->delay == 0)
553        break;
554      resource_info->delay--;
555      break;
556    }
557    case ForwardCommand:
558    {
559      *state=ForwardAnimationState;
560      *state&=(~AutoReverseAnimationState);
561      break;
562    }
563    case ReverseCommand:
564    {
565      *state&=(~ForwardAnimationState);
566      *state&=(~AutoReverseAnimationState);
567      break;
568    }
569    case InfoCommand:
570    {
571      XDisplayImageInfo(display,resource_info,windows,(Image *) NULL,*image);
572      break;
573    }
574    case HelpCommand:
575    {
576      /*
577        User requested help.
578      */
579      XTextViewWidget(display,resource_info,windows,MagickFalse,
580        "Help Viewer - Animate",AnimateHelp);
581      break;
582    }
583    case BrowseDocumentationCommand:
584    {
585      Atom
586        mozilla_atom;
587
588      Window
589        mozilla_window,
590        root_window;
591
592      /*
593        Browse the ImageMagick documentation.
594      */
595      root_window=XRootWindow(display,XDefaultScreen(display));
596      mozilla_atom=XInternAtom(display,"_MOZILLA_VERSION",MagickFalse);
597      mozilla_window=XWindowByProperty(display,root_window,mozilla_atom);
598      if (mozilla_window != (Window) NULL)
599        {
600          char
601            command[MaxTextExtent],
602            *url;
603
604          /*
605            Display documentation using Netscape remote control.
606          */
607          url=GetMagickHomeURL();
608          (void) FormatMagickString(command,MaxTextExtent,
609            "openurl(%s,new-tab)",url);
610          url=DestroyString(url);
611          mozilla_atom=XInternAtom(display,"_MOZILLA_COMMAND",MagickFalse);
612          (void) XChangeProperty(display,mozilla_window,mozilla_atom,
613            XA_STRING,8,PropModeReplace,(unsigned char *) command,
614            (int) strlen(command));
615          XSetCursorState(display,windows,MagickFalse);
616          break;
617        }
618      XSetCursorState(display,windows,MagickTrue);
619      XCheckRefreshWindows(display,windows);
620      status=InvokeDelegate(resource_info->image_info,*image,"browse",
621        (char *) NULL,&(*image)->exception);
622      if (status == MagickFalse)
623        XNoticeWidget(display,windows,"Unable to browse documentation",
624          (char *) NULL);
625      XDelay(display,1500);
626      XSetCursorState(display,windows,MagickFalse);
627      break;
628    }
629    case VersionCommand:
630    {
631      XNoticeWidget(display,windows,GetMagickVersion((unsigned long *) NULL),
632        GetMagickCopyright());
633      break;
634    }
635    case QuitCommand:
636    {
637      /*
638        exit program
639      */
640      if (resource_info->confirm_exit == MagickFalse)
641        XClientMessage(display,windows->image.id,windows->im_protocols,
642          windows->im_exit,CurrentTime);
643      else
644        {
645          int
646            status;
647
648          /*
649            Confirm program exit.
650          */
651          status=XConfirmWidget(display,windows,"Do you really want to exit",
652            resource_info->client_name);
653          if (status != 0)
654            XClientMessage(display,windows->image.id,windows->im_protocols,
655              windows->im_exit,CurrentTime);
656        }
657      break;
658    }
659    default:
660      break;
661  }
662  return(nexus);
663}
664
665/*
666%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
667%                                                                             %
668%                                                                             %
669%                                                                             %
670+   X A n i m a t e B a c k g r o u n d I m a g e                             %
671%                                                                             %
672%                                                                             %
673%                                                                             %
674%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
675%
676%  XAnimateBackgroundImage() animates an image sequence in the background of
677%  a window.
678%
679%  The format of the XAnimateBackgroundImage method is:
680%
681%      void XAnimateBackgroundImage(Display *display,
682%        XResourceInfo *resource_info,Image *images)
683%
684%  A description of each parameter follows:
685%
686%    o display: Specifies a connection to an X server;  returned from
687%      XOpenDisplay.
688%
689%    o resource_info: Specifies a pointer to a X11 XResourceInfo structure.
690%
691%    o images: the image list.
692%
693*/
694
695static inline long MagickMax(const long x,const long y)
696{
697  if (x > y)
698    return(x);
699  return(y);
700}
701
702#if defined(__cplusplus) || defined(c_plusplus)
703extern "C" {
704#endif
705
706static int SceneCompare(const void *x,const void *y)
707{
708  const Image
709    **image_1,
710    **image_2;
711
712  image_1=(const Image **) x;
713  image_2=(const Image **) y;
714  return((int) ((*image_1)->scene-(*image_2)->scene));
715}
716
717#if defined(__cplusplus) || defined(c_plusplus)
718}
719#endif
720
721MagickExport void XAnimateBackgroundImage(Display *display,
722  XResourceInfo *resource_info,Image *images)
723{
724  char
725    geometry[MaxTextExtent],
726    visual_type[MaxTextExtent];
727
728  Image
729    *coalesce_image,
730    *display_image,
731    **image_list;
732
733  int
734    scene;
735
736  MagickStatusType
737    status;
738
739  RectangleInfo
740    geometry_info;
741
742  register long
743    i;
744
745  size_t
746    number_scenes;
747
748  static XPixelInfo
749    pixel;
750
751  static XStandardColormap
752    *map_info;
753
754  static XVisualInfo
755    *visual_info = (XVisualInfo *) NULL;
756
757  static XWindowInfo
758    window_info;
759
760  unsigned int
761    height,
762    width;
763
764  unsigned long
765    delay;
766
767  Window
768    root_window;
769
770  XEvent
771    event;
772
773  XGCValues
774    context_values;
775
776  XResourceInfo
777    resources;
778
779  XWindowAttributes
780    window_attributes;
781
782  /*
783    Determine target window.
784  */
785  assert(images != (Image *) NULL);
786  assert(images->signature == MagickSignature);
787  if (images->debug != MagickFalse)
788    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
789  resources=(*resource_info);
790  window_info.id=(Window) NULL;
791  root_window=XRootWindow(display,XDefaultScreen(display));
792  if (LocaleCompare(resources.window_id,"root") == 0)
793    window_info.id=root_window;
794  else
795    {
796      if (isdigit((int) ((unsigned char) *resources.window_id)) != 0)
797        window_info.id=XWindowByID(display,root_window,
798          (Window) strtol((char *) resources.window_id,(char **) NULL,0));
799      if (window_info.id == (Window) NULL)
800        window_info.id=
801          XWindowByName(display,root_window,resources.window_id);
802    }
803  if (window_info.id == (Window) NULL)
804    {
805      ThrowXWindowException(XServerError,"NoWindowWithSpecifiedIDExists",
806        resources.window_id);
807      return;
808    }
809  /*
810    Determine window visual id.
811  */
812  window_attributes.width=XDisplayWidth(display,XDefaultScreen(display));
813  window_attributes.height=XDisplayHeight(display,XDefaultScreen(display));
814  (void) CopyMagickString(visual_type,"default",MaxTextExtent);
815  status=XGetWindowAttributes(display,window_info.id,&window_attributes) != 0 ?
816    MagickTrue : MagickFalse;
817  if (status != MagickFalse)
818    (void) FormatMagickString(visual_type,MaxTextExtent,"0x%lx",
819      XVisualIDFromVisual(window_attributes.visual));
820  if (visual_info == (XVisualInfo *) NULL)
821    {
822      /*
823        Allocate standard colormap.
824      */
825      map_info=XAllocStandardColormap();
826      if (map_info == (XStandardColormap *) NULL)
827        ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
828          images->filename);
829      map_info->colormap=(Colormap) NULL;
830      pixel.pixels=(unsigned long *) NULL;
831      /*
832        Initialize visual info.
833      */
834      resources.map_type=(char *) NULL;
835      resources.visual_type=visual_type;
836      visual_info=XBestVisualInfo(display,map_info,&resources);
837      if (visual_info == (XVisualInfo *) NULL)
838        ThrowXWindowFatalException(XServerFatalError,"UnableToGetVisual",
839          images->filename);
840      /*
841        Initialize window info.
842      */
843      window_info.ximage=(XImage *) NULL;
844      window_info.matte_image=(XImage *) NULL;
845      window_info.pixmap=(Pixmap) NULL;
846      window_info.matte_pixmap=(Pixmap) NULL;
847    }
848  /*
849    Free previous root colors.
850  */
851  if (window_info.id == root_window)
852    XDestroyWindowColors(display,root_window);
853  coalesce_image=CoalesceImages(images,&images->exception);
854  if (coalesce_image == (Image *) NULL)
855    ThrowXWindowFatalException(ResourceLimitError,"MemoryAllocationFailed",
856      images->filename);
857  images=coalesce_image;
858  if (resources.map_type == (char *) NULL)
859    if ((visual_info->klass != TrueColor) &&
860        (visual_info->klass != DirectColor))
861      {
862        Image
863          *next;
864
865        /*
866          Determine if the sequence of images has the identical colormap.
867        */
868        for (next=images; next != (Image *) NULL; )
869        {
870          next->matte=MagickFalse;
871          if ((next->storage_class == DirectClass) ||
872              (next->colors != images->colors) ||
873              (next->colors > (unsigned long) visual_info->colormap_size))
874            break;
875          for (i=0; i < (long) images->colors; i++)
876            if (IsColorEqual(next->colormap+i,images->colormap+i) == MagickFalse)
877              break;
878          if (i < (long) images->colors)
879            break;
880          next=GetNextImageInList(next);
881        }
882        if (next != (Image *) NULL)
883          (void) AffinityImages(resources.quantize_info,images,(Image *) NULL);
884      }
885  /*
886    Sort images by increasing scene number.
887  */
888  number_scenes=GetImageListLength(images);
889  image_list=ImageListToArray(images,&images->exception);
890  if (image_list == (Image **) NULL)
891    ThrowXWindowFatalException(ResourceLimitFatalError,
892      "MemoryAllocationFailed",images->filename);
893  for (i=0; i < (long) number_scenes; i++)
894    if (image_list[i]->scene == 0)
895      break;
896  if (i == (long) number_scenes)
897    qsort((void *) image_list,number_scenes,sizeof(Image *),SceneCompare);
898  /*
899    Initialize Standard Colormap.
900  */
901  resources.colormap=SharedColormap;
902  display_image=image_list[0];
903  for (scene=0; scene < (int) number_scenes; scene++)
904  {
905    if ((resource_info->map_type != (char *) NULL) ||
906        (visual_info->klass == TrueColor) ||
907        (visual_info->klass == DirectColor))
908      (void) SetImageType(image_list[scene],image_list[scene]->matte ==
909        MagickFalse ? TrueColorType : TrueColorMatteType);
910    if ((display_image->columns < image_list[scene]->columns) &&
911        (display_image->rows < image_list[scene]->rows))
912      display_image=image_list[scene];
913  }
914  if ((resource_info->map_type != (char *) NULL) ||
915      (visual_info->klass == TrueColor) || (visual_info->klass == DirectColor))
916    (void) SetImageType(display_image,display_image->matte == MagickFalse ?
917      TrueColorType : TrueColorMatteType);
918  XMakeStandardColormap(display,visual_info,&resources,display_image,map_info,
919    &pixel);
920  /*
921    Graphic context superclass.
922  */
923  context_values.background=pixel.background_color.pixel;
924  context_values.foreground=pixel.foreground_color.pixel;
925  pixel.annotate_context=XCreateGC(display,window_info.id,(unsigned long)
926    GCBackground | GCForeground,&context_values);
927  if (pixel.annotate_context == (GC) NULL)
928    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateGraphicContext",
929      images->filename);
930  /*
931    Initialize Image window attributes.
932  */
933  XGetWindowInfo(display,visual_info,map_info,&pixel,(XFontStruct *) NULL,
934    &resources,&window_info);
935  /*
936    Create the X image.
937  */
938  window_info.width=(unsigned int) image_list[0]->columns;
939  window_info.height=(unsigned int) image_list[0]->rows;
940  (void) FormatMagickString(geometry,MaxTextExtent,"%ux%u+0+0>",
941    window_attributes.width,window_attributes.height);
942  geometry_info.width=window_info.width;
943  geometry_info.height=window_info.height;
944  geometry_info.x=window_info.x;
945  geometry_info.y=window_info.y;
946  (void) ParseMetaGeometry(geometry,&geometry_info.x,&geometry_info.y,
947    &geometry_info.width,&geometry_info.height);
948  window_info.width=(unsigned int) geometry_info.width;
949  window_info.height=(unsigned int) geometry_info.height;
950  window_info.x=(int) geometry_info.x;
951  window_info.y=(int) geometry_info.y;
952  status=XMakeImage(display,&resources,&window_info,image_list[0],
953    window_info.width,window_info.height);
954  if (status == MagickFalse)
955    ThrowXWindowFatalException(XServerFatalError,"UnableToCreateXImage",
956      images->filename);
957  window_info.x=0;
958  window_info.y=0;
959  if (display_image->debug != MagickFalse)
960    {
961      (void) LogMagickEvent(X11Event,GetMagickModule(),
962        "Image: %s[%lu] %lux%lu ",image_list[0]->filename,
963        image_list[0]->scene,image_list[0]->columns,image_list[0]->rows);
964      if (image_list[0]->colors != 0)
965        (void) LogMagickEvent(X11Event,GetMagickModule(),"%luc ",
966          image_list[0]->colors);
967      (void) LogMagickEvent(X11Event,GetMagickModule(),"%s",
968        image_list[0]->magick);
969    }
970  /*
971    Adjust image dimensions as specified by backdrop or geometry options.
972  */
973  width=window_info.width;
974  height=window_info.height;
975  if (resources.backdrop != MagickFalse)
976    {
977      /*
978        Center image on window.
979      */
980      window_info.x=(int) (window_attributes.width/2)-
981        (window_info.ximage->width/2);
982      window_info.y=(int) (window_attributes.height/2)-
983        (window_info.ximage->height/2);
984      width=(unsigned int) window_attributes.width;
985      height=(unsigned int) window_attributes.height;
986    }
987  if (resources.image_geometry != (char *) NULL)
988    {
989      char
990        default_geometry[MaxTextExtent];
991
992      int
993        flags,
994        gravity;
995
996      XSizeHints
997        *size_hints;
998
999      /*
1000        User specified geometry.
1001      */
1002      size_hints=XAllocSizeHints();
1003      if (size_hints == (XSizeHints *) NULL)
1004        ThrowXWindowFatalException(ResourceLimitFatalError,
1005          "MemoryAllocationFailed",images->filename);
1006      size_hints->flags=0L;
1007      (void) FormatMagickString(default_geometry,MaxTextExtent,"%ux%u",width,
1008        height);
1009      flags=XWMGeometry(display,visual_info->screen,resources.image_geometry,
1010        default_geometry,window_info.border_width,size_hints,&window_info.x,
1011        &window_info.y,(int *) &width,(int *) &height,&gravity);
1012      if (((flags & (XValue | YValue))) != 0)
1013        {
1014          width=(unsigned int) window_attributes.width;
1015          height=(unsigned int) window_attributes.height;