]> granicus.if.org Git - imagemagick/blob - MagickCore/layer.c
(no commit message)
[imagemagick] / MagickCore / layer.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                     L       AAA   Y   Y  EEEEE  RRRR                        %
6 %                     L      A   A   Y Y   E      R   R                       %
7 %                     L      AAAAA    Y    EEE    RRRR                        %
8 %                     L      A   A    Y    E      R R                         %
9 %                     LLLLL  A   A    Y    EEEEE  R  R                        %
10 %                                                                             %
11 %                      MagickCore Image Layering Methods                      %
12 %                                                                             %
13 %                              Software Design                                %
14 %                                John Cristy                                  %
15 %                              Anthony Thyssen                                %
16 %                               January 2006                                  %
17 %                                                                             %
18 %                                                                             %
19 %  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
20 %  dedicated to making software imaging solutions freely available.           %
21 %                                                                             %
22 %  You may not use this file except in compliance with the License.  You may  %
23 %  obtain a copy of the License at                                            %
24 %                                                                             %
25 %    http://www.imagemagick.org/script/license.php                            %
26 %                                                                             %
27 %  Unless required by applicable law or agreed to in writing, software        %
28 %  distributed under the License is distributed on an "AS IS" BASIS,          %
29 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
30 %  See the License for the specific language governing permissions and        %
31 %  limitations under the License.                                             %
32 %                                                                             %
33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34 %
35 */
36 \f
37 /*
38   Include declarations.
39 */
40 #include "MagickCore/studio.h"
41 #include "MagickCore/artifact.h"
42 #include "MagickCore/cache.h"
43 #include "MagickCore/color.h"
44 #include "MagickCore/color-private.h"
45 #include "MagickCore/composite.h"
46 #include "MagickCore/effect.h"
47 #include "MagickCore/exception.h"
48 #include "MagickCore/exception-private.h"
49 #include "MagickCore/geometry.h"
50 #include "MagickCore/image.h"
51 #include "MagickCore/layer.h"
52 #include "MagickCore/list.h"
53 #include "MagickCore/memory_.h"
54 #include "MagickCore/monitor.h"
55 #include "MagickCore/monitor-private.h"
56 #include "MagickCore/option.h"
57 #include "MagickCore/pixel-accessor.h"
58 #include "MagickCore/property.h"
59 #include "MagickCore/profile.h"
60 #include "MagickCore/resource_.h"
61 #include "MagickCore/resize.h"
62 #include "MagickCore/statistic.h"
63 #include "MagickCore/string_.h"
64 #include "MagickCore/transform.h"
65 \f
66 /*
67 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
68 %                                                                             %
69 %                                                                             %
70 %                                                                             %
71 +     C l e a r B o u n d s                                                   %
72 %                                                                             %
73 %                                                                             %
74 %                                                                             %
75 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76 %
77 %  ClearBounds() Clear the area specified by the bounds in an image to
78 %  transparency.  This typically used to handle Background Disposal
79 %  for the previous frame in an animation sequence.
80 %
81 %  WARNING: no bounds checks are performed, except for the null or
82 %  missed image, for images that don't change. in all other cases
83 %  bound must fall within the image.
84 %
85 %  The format is:
86 %
87 %      void ClearBounds(Image *image,RectangleInfo *bounds)
88 %
89 %  A description of each parameter follows:
90 %
91 %    o image: the image to had the area cleared in
92 %
93 %    o bounds: the area to be clear within the imag image
94 %
95 */
96 static void ClearBounds(Image *image,RectangleInfo *bounds)
97 {
98   ExceptionInfo
99     *exception;
100
101   ssize_t
102     y;
103
104   if (bounds->x < 0)
105     return;
106   exception=(&image->exception);
107   if (image->matte == MagickFalse)
108     (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
109   for (y=0; y < (ssize_t) bounds->height; y++)
110   {
111     register ssize_t
112       x;
113
114     register Quantum
115       *restrict q;
116
117     q=GetAuthenticPixels(image,bounds->x,bounds->y+y,bounds->width,1,exception);
118     if (q == (Quantum *) NULL)
119       break;
120     for (x=0; x < (ssize_t) bounds->width; x++)
121     {
122       SetPixelAlpha(image,TransparentAlpha,q);
123       q+=GetPixelChannels(image);
124     }
125     if (SyncAuthenticPixels(image,exception) == MagickFalse)
126       break;
127   }
128 }
129 \f
130 /*
131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
132 %                                                                             %
133 %                                                                             %
134 %                                                                             %
135 +     I s B o u n d s C l e a r e d                                           %
136 %                                                                             %
137 %                                                                             %
138 %                                                                             %
139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140 %
141 %  IsBoundsCleared() tests whether any pixel in the bounds given, gets cleared
142 %  when going from the first image to the second image.  This typically used
143 %  to check if a proposed disposal method will work successfully to generate
144 %  the second frame image from the first disposed form of the previous frame.
145 %
146 %  The format is:
147 %
148 %      MagickBooleanType IsBoundsCleared(const Image *image1,
149 %        const Image *image2,RectangleInfo bounds,ExceptionInfo *exception)
150 %
151 %  A description of each parameter follows:
152 %
153 %    o image1, image 2: the images to check for cleared pixels
154 %
155 %    o bounds: the area to be clear within the imag image
156 %
157 %    o exception: return any errors or warnings in this structure.
158 %
159 %  WARNING: no bounds checks are performed, except for the null or
160 %  missed image, for images that don't change. in all other cases
161 %  bound must fall within the image.
162 %
163 */
164 static MagickBooleanType IsBoundsCleared(const Image *image1,
165   const Image *image2,RectangleInfo *bounds,ExceptionInfo *exception)
166 {
167   register ssize_t
168     x;
169
170   register const Quantum
171     *p,
172     *q;
173
174   ssize_t
175     y;
176
177   if (bounds->x < 0)
178     return(MagickFalse);
179   for (y=0; y < (ssize_t) bounds->height; y++)
180   {
181     p=GetVirtualPixels(image1,bounds->x,bounds->y+y,bounds->width,1,
182       exception);
183     q=GetVirtualPixels(image2,bounds->x,bounds->y+y,bounds->width,1,
184       exception);
185     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
186       break;
187     for (x=0; x < (ssize_t) bounds->width; x++)
188     {
189       if ((GetPixelAlpha(image1,p) <= (Quantum) (QuantumRange/2)) &&
190           (GetPixelAlpha(image1,q) > (Quantum) (QuantumRange/2)))
191         break;
192       p+=GetPixelChannels(image1);
193       q++;
194     }
195     if (x < (ssize_t) bounds->width)
196       break;
197   }
198   return(y < (ssize_t) bounds->height ? MagickTrue : MagickFalse);
199 }
200 \f
201 /*
202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
203 %                                                                             %
204 %                                                                             %
205 %                                                                             %
206 %     C o a l e s c e I m a g e s                                             %
207 %                                                                             %
208 %                                                                             %
209 %                                                                             %
210 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
211 %
212 %  CoalesceImages() composites a set of images while respecting any page
213 %  offsets and disposal methods.  GIF, MIFF, and MNG animation sequences
214 %  typically start with an image background and each subsequent image
215 %  varies in size and offset.  A new image sequence is returned with all
216 %  images the same size as the first images virtual canvas and composited
217 %  with the next image in the sequence.
218 %
219 %  The format of the CoalesceImages method is:
220 %
221 %      Image *CoalesceImages(Image *image,ExceptionInfo *exception)
222 %
223 %  A description of each parameter follows:
224 %
225 %    o image: the image sequence.
226 %
227 %    o exception: return any errors or warnings in this structure.
228 %
229 */
230 MagickExport Image *CoalesceImages(const Image *image,ExceptionInfo *exception)
231 {
232   Image
233     *coalesce_image,
234     *dispose_image,
235     *previous;
236
237   register Image
238     *next;
239
240   RectangleInfo
241     bounds;
242
243   /*
244     Coalesce the image sequence.
245   */
246   assert(image != (Image *) NULL);
247   assert(image->signature == MagickSignature);
248   if (image->debug != MagickFalse)
249     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
250   assert(exception != (ExceptionInfo *) NULL);
251   assert(exception->signature == MagickSignature);
252
253   /* initialise first image */
254   next=GetFirstImageInList(image);
255   bounds=next->page;
256   if (bounds.width == 0)
257     {
258       bounds.width=next->columns;
259       if (bounds.x > 0)
260         bounds.width+=bounds.x;
261     }
262   if (bounds.height == 0)
263     {
264       bounds.height=next->rows;
265       if (bounds.y > 0)
266         bounds.height+=bounds.y;
267     }
268   bounds.x=0;
269   bounds.y=0;
270   coalesce_image=CloneImage(next,bounds.width,bounds.height,MagickTrue,
271     exception);
272   if (coalesce_image == (Image *) NULL)
273     return((Image *) NULL);
274   coalesce_image->page=bounds;
275   coalesce_image->dispose=NoneDispose;
276   coalesce_image->background_color.alpha=(Quantum) TransparentAlpha;
277   (void) SetImageBackgroundColor(coalesce_image);
278   /*
279     Coalesce rest of the images.
280   */
281   dispose_image=CloneImage(coalesce_image,0,0,MagickTrue,exception);
282   (void) CompositeImage(coalesce_image,CopyCompositeOp,next,next->page.x,
283     next->page.y);
284   next=GetNextImageInList(next);
285   for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
286   {
287     /*
288       Determine the bounds that was overlaid in the previous image.
289     */
290     previous=GetPreviousImageInList(next);
291     bounds=previous->page;
292     bounds.width=previous->columns;
293     bounds.height=previous->rows;
294     if (bounds.x < 0)
295       {
296         bounds.width+=bounds.x;
297         bounds.x=0;
298       }
299     if ((ssize_t) (bounds.x+bounds.width) > (ssize_t) coalesce_image->columns)
300       bounds.width=coalesce_image->columns-bounds.x;
301     if (bounds.y < 0)
302       {
303         bounds.height+=bounds.y;
304         bounds.y=0;
305       }
306     if ((ssize_t) (bounds.y+bounds.height) > (ssize_t) coalesce_image->rows)
307       bounds.height=coalesce_image->rows-bounds.y;
308     /*
309       Replace the dispose image with the new coalesced image.
310     */
311     if (GetPreviousImageInList(next)->dispose != PreviousDispose)
312       {
313         dispose_image=DestroyImage(dispose_image);
314         dispose_image=CloneImage(coalesce_image,0,0,MagickTrue,exception);
315         if (dispose_image == (Image *) NULL)
316           {
317             coalesce_image=DestroyImageList(coalesce_image);
318             return((Image *) NULL);
319           }
320       }
321     /*
322       Clear the overlaid area of the coalesced bounds for background disposal
323     */
324     if (next->previous->dispose == BackgroundDispose)
325       ClearBounds(dispose_image, &bounds);
326     /*
327       Next image is the dispose image, overlaid with next frame in sequence.
328     */
329     coalesce_image->next=CloneImage(dispose_image,0,0,MagickTrue,exception);
330     coalesce_image->next->previous=coalesce_image;
331     previous=coalesce_image;
332     coalesce_image=GetNextImageInList(coalesce_image);
333     coalesce_image->matte=MagickTrue;
334     (void) CompositeImage(coalesce_image,next->matte != MagickFalse ?
335       OverCompositeOp : CopyCompositeOp,next,next->page.x,next->page.y);
336     (void) CloneImageProfiles(coalesce_image,next);
337     (void) CloneImageProperties(coalesce_image,next);
338     (void) CloneImageArtifacts(coalesce_image,next);
339     coalesce_image->page=previous->page;
340     /*
341       If a pixel goes opaque to transparent, use background dispose.
342     */
343     if (IsBoundsCleared(previous,coalesce_image,&bounds,exception))
344       coalesce_image->dispose=BackgroundDispose;
345     else
346       coalesce_image->dispose=NoneDispose;
347     previous->dispose=coalesce_image->dispose;
348   }
349   dispose_image=DestroyImage(dispose_image);
350   return(GetFirstImageInList(coalesce_image));
351 }
352 \f
353 /*
354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355 %                                                                             %
356 %                                                                             %
357 %                                                                             %
358 %     D i s p o s e I m a g e s                                               %
359 %                                                                             %
360 %                                                                             %
361 %                                                                             %
362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
363 %
364 %  DisposeImages() returns the coalesced frames of a GIF animation as it would
365 %  appear after the GIF dispose method of that frame has been applied.  That
366 %  is it returned the appearance of each frame before the next is overlaid.
367 %
368 %  The format of the DisposeImages method is:
369 %
370 %      Image *DisposeImages(Image *image,ExceptionInfo *exception)
371 %
372 %  A description of each parameter follows:
373 %
374 %    o image: the image sequence.
375 %
376 %    o exception: return any errors or warnings in this structure.
377 %
378 */
379 MagickExport Image *DisposeImages(const Image *image,ExceptionInfo *exception)
380 {
381   Image
382     *dispose_image,
383     *dispose_images;
384
385   register Image
386     *curr;
387
388   RectangleInfo
389     bounds;
390
391   /*
392     Run the image through the animation sequence
393   */
394   assert(image != (Image *) NULL);
395   assert(image->signature == MagickSignature);
396   if (image->debug != MagickFalse)
397     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
398   assert(exception != (ExceptionInfo *) NULL);
399   assert(exception->signature == MagickSignature);
400   curr=GetFirstImageInList(image);
401   dispose_image=CloneImage(curr,curr->page.width,curr->page.height,MagickTrue,
402     exception);
403   if (dispose_image == (Image *) NULL)
404     return((Image *) NULL);
405   dispose_image->page=curr->page;
406   dispose_image->page.x=0;
407   dispose_image->page.y=0;
408   dispose_image->dispose=NoneDispose;
409   dispose_image->background_color.alpha=(Quantum) TransparentAlpha;
410   (void) SetImageBackgroundColor(dispose_image);
411   dispose_images=NewImageList();
412   for ( ; curr != (Image *) NULL; curr=GetNextImageInList(curr))
413   {
414     Image
415       *current_image;
416
417     /*
418       Overlay this frame's image over the previous disposal image.
419     */
420     current_image=CloneImage(dispose_image,0,0,MagickTrue,exception);
421     if (current_image == (Image *) NULL)
422       {
423         dispose_images=DestroyImageList(dispose_images);
424         dispose_image=DestroyImage(dispose_image);
425         return((Image *) NULL);
426       }
427     (void) CompositeImage(current_image,curr->matte != MagickFalse ?
428       OverCompositeOp : CopyCompositeOp,curr,curr->page.x,curr->page.y);
429
430     /*
431       Handle Background dispose: image is displayed for the delay period.
432     */
433     if (curr->dispose == BackgroundDispose)
434       {
435         bounds=curr->page;
436         bounds.width=curr->columns;
437         bounds.height=curr->rows;
438         if (bounds.x < 0)
439           {
440             bounds.width+=bounds.x;
441             bounds.x=0;
442           }
443         if ((ssize_t) (bounds.x+bounds.width) > (ssize_t) current_image->columns)
444           bounds.width=current_image->columns-bounds.x;
445         if (bounds.y < 0)
446           {
447             bounds.height+=bounds.y;
448             bounds.y=0;
449           }
450         if ((ssize_t) (bounds.y+bounds.height) > (ssize_t) current_image->rows)
451           bounds.height=current_image->rows-bounds.y;
452         ClearBounds(current_image,&bounds);
453       }
454     /*
455       Select the appropriate previous/disposed image.
456     */
457     if (curr->dispose == PreviousDispose)
458       current_image=DestroyImage(current_image);
459     else
460       {
461         dispose_image=DestroyImage(dispose_image);
462         dispose_image=current_image;
463         current_image=(Image *)NULL;
464       }
465     /*
466       Save the dispose image just calculated for return.
467     */
468     {
469       Image
470         *dispose;
471
472       dispose=CloneImage(dispose_image,0,0,MagickTrue,exception);
473       if (dispose == (Image *) NULL)
474         {
475           dispose_images=DestroyImageList(dispose_images);
476           dispose_image=DestroyImage(dispose_image);
477           return((Image *) NULL);
478         }
479       (void) CloneImageProfiles(dispose,curr);
480       (void) CloneImageProperties(dispose,curr);
481       (void) CloneImageArtifacts(dispose,curr);
482       dispose->page.x=0;
483       dispose->page.y=0;
484       dispose->dispose=curr->dispose;
485       AppendImageToList(&dispose_images,dispose);
486     }
487   }
488   dispose_image=DestroyImage(dispose_image);
489   return(GetFirstImageInList(dispose_images));
490 }
491 \f
492 /*
493 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
494 %                                                                             %
495 %                                                                             %
496 %                                                                             %
497 +     C o m p a r e P i x e l s                                               %
498 %                                                                             %
499 %                                                                             %
500 %                                                                             %
501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
502 %
503 %  ComparePixels() Compare the two pixels and return true if the pixels
504 %  differ according to the given LayerType comparision method.
505 %
506 %  This currently only used internally by CompareImagesBounds(). It is
507 %  doubtful that this sub-routine will be useful outside this module.
508 %
509 %  The format of the ComparePixels method is:
510 %
511 %      MagickBooleanType *ComparePixels(const ImageLayerMethod method,
512 %        const PixelInfo *p,const PixelInfo *q)
513 %
514 %  A description of each parameter follows:
515 %
516 %    o method: What differences to look for. Must be one of
517 %              CompareAnyLayer, CompareClearLayer, CompareOverlayLayer.
518 %
519 %    o p, q: the pixels to test for appropriate differences.
520 %
521 */
522
523 static MagickBooleanType ComparePixels(const ImageLayerMethod method,
524   const PixelInfo *p,const PixelInfo *q)
525 {
526   MagickRealType
527     o1,
528     o2;
529
530   /*
531     Any change in pixel values
532   */
533   if (method == CompareAnyLayer)
534     return((MagickBooleanType)(IsFuzzyEquivalencePixelInfo(p,q) == MagickFalse));
535
536   o1 = (p->matte != MagickFalse) ? p->alpha : OpaqueAlpha;
537   o2 = (q->matte != MagickFalse) ? q->alpha : OpaqueAlpha;
538
539   /*
540     Pixel goes from opaque to transprency
541   */
542   if (method == CompareClearLayer)
543     return((MagickBooleanType) ( (o1 <= ((MagickRealType) QuantumRange/2.0)) &&
544       (o2 > ((MagickRealType) QuantumRange/2.0)) ) );
545
546   /*
547     overlay would change first pixel by second
548   */
549   if (method == CompareOverlayLayer)
550     {
551       if (o2 > ((MagickRealType) QuantumRange/2.0))
552         return MagickFalse;
553       return((MagickBooleanType) (IsFuzzyEquivalencePixelInfo(p,q) == MagickFalse));
554     }
555   return(MagickFalse);
556 }
557
558 \f
559 /*
560 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
561 %                                                                             %
562 %                                                                             %
563 %                                                                             %
564 +     C o m p a r e I m a g e B o u n d s                                     %
565 %                                                                             %
566 %                                                                             %
567 %                                                                             %
568 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
569 %
570 %  CompareImagesBounds() Given two images return the smallest rectangular area
571 %  by which the two images differ, accourding to the given 'Compare...'
572 %  layer method.
573 %
574 %  This currently only used internally in this module, but may eventually
575 %  be used by other modules.
576 %
577 %  The format of the CompareImagesBounds method is:
578 %
579 %      RectangleInfo *CompareImagesBounds(const ImageLayerMethod method,
580 %        const Image *image1, const Image *image2, ExceptionInfo *exception)
581 %
582 %  A description of each parameter follows:
583 %
584 %    o method: What differences to look for. Must be one of CompareAnyLayer,
585 %      CompareClearLayer, CompareOverlayLayer.
586 %
587 %    o image1, image2: the two images to compare.
588 %
589 %    o exception: return any errors or warnings in this structure.
590 %
591 */
592
593 static RectangleInfo CompareImagesBounds(const Image *image1,const Image *image2,
594   const ImageLayerMethod method,ExceptionInfo *exception)
595 {
596   RectangleInfo
597     bounds;
598
599   PixelInfo
600     pixel1,
601     pixel2;
602
603   register const Quantum
604     *p,
605     *q;
606
607   register ssize_t
608     x;
609
610   ssize_t
611     y;
612
613   /*
614     Set bounding box of the differences between images.
615   */
616   GetPixelInfo(image1,&pixel1);
617   GetPixelInfo(image2,&pixel2);
618   for (x=0; x < (ssize_t) image1->columns; x++)
619   {
620     p=GetVirtualPixels(image1,x,0,1,image1->rows,exception);
621     q=GetVirtualPixels(image2,x,0,1,image2->rows,exception);
622     if ((p == (const Quantum *) NULL) ||
623         (q == (Quantum *) NULL))
624       break;
625     for (y=0; y < (ssize_t) image1->rows; y++)
626     {
627       SetPixelInfo(image1,p,&pixel1);
628       SetPixelInfo(image2,q,&pixel2);
629       if (ComparePixels(method,&pixel1,&pixel2))
630         break;
631       p+=GetPixelChannels(image1);
632       q++;
633     }
634     if (y < (ssize_t) image1->rows)
635       break;
636   }
637   if (x >= (ssize_t) image1->columns)
638     {
639       /*
640         Images are identical, return a null image.
641       */
642       bounds.x=-1;
643       bounds.y=-1;
644       bounds.width=1;
645       bounds.height=1;
646       return(bounds);
647     }
648   bounds.x=x;
649   for (x=(ssize_t) image1->columns-1; x >= 0; x--)
650   {
651     p=GetVirtualPixels(image1,x,0,1,image1->rows,exception);
652     q=GetVirtualPixels(image2,x,0,1,image2->rows,exception);
653     if ((p == (const Quantum *) NULL) ||
654         (q == (Quantum *) NULL))
655       break;
656     for (y=0; y < (ssize_t) image1->rows; y++)
657     {
658       SetPixelInfo(image1,p,&pixel1);
659       SetPixelInfo(image2,q,&pixel2);
660       if (ComparePixels(method,&pixel1,&pixel2))
661         break;
662       p+=GetPixelChannels(image1);
663       q++;
664     }
665     if (y < (ssize_t) image1->rows)
666       break;
667   }
668   bounds.width=(size_t) (x-bounds.x+1);
669   for (y=0; y < (ssize_t) image1->rows; y++)
670   {
671     p=GetVirtualPixels(image1,0,y,image1->columns,1,exception);
672     q=GetVirtualPixels(image2,0,y,image2->columns,1,exception);
673     if ((p == (const Quantum *) NULL) ||
674         (q == (Quantum *) NULL))
675       break;
676     for (x=0; x < (ssize_t) image1->columns; x++)
677     {
678       SetPixelInfo(image1,p,&pixel1);
679       SetPixelInfo(image2,q,&pixel2);
680       if (ComparePixels(method,&pixel1,&pixel2))
681         break;
682       p+=GetPixelChannels(image1);
683       q++;
684     }
685     if (x < (ssize_t) image1->columns)
686       break;
687   }
688   bounds.y=y;
689   for (y=(ssize_t) image1->rows-1; y >= 0; y--)
690   {
691     p=GetVirtualPixels(image1,0,y,image1->columns,1,exception);
692     q=GetVirtualPixels(image2,0,y,image2->columns,1,exception);
693     if ((p == (const Quantum *) NULL) ||
694         (q == (Quantum *) NULL))
695       break;
696     for (x=0; x < (ssize_t) image1->columns; x++)
697     {
698       SetPixelInfo(image1,p,&pixel1);
699       SetPixelInfo(image2,q,&pixel2);
700       if (ComparePixels(method,&pixel1,&pixel2))
701         break;
702       p+=GetPixelChannels(image1);
703       q++;
704     }
705     if (x < (ssize_t) image1->columns)
706       break;
707   }
708   bounds.height=(size_t) (y-bounds.y+1);
709   return(bounds);
710 }
711 \f
712 /*
713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
714 %                                                                             %
715 %                                                                             %
716 %                                                                             %
717 %     C o m p a r e I m a g e L a y e r s                                     %
718 %                                                                             %
719 %                                                                             %
720 %                                                                             %
721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
722 %
723 %  CompareImagesLayers() compares each image with the next in a sequence and
724 %  returns the minimum bounding region of all the pixel differences (of the
725 %  ImageLayerMethod specified) it discovers.
726 %
727 %  Images do NOT have to be the same size, though it is best that all the
728 %  images are 'coalesced' (images are all the same size, on a flattened
729 %  canvas, so as to represent exactly how an specific frame should look).
730 %
731 %  No GIF dispose methods are applied, so GIF animations must be coalesced
732 %  before applying this image operator to find differences to them.
733 %
734 %  The format of the CompareImagesLayers method is:
735 %
736 %      Image *CompareImagesLayers(const Image *images,
737 %        const ImageLayerMethod method,ExceptionInfo *exception)
738 %
739 %  A description of each parameter follows:
740 %
741 %    o image: the image.
742 %
743 %    o method: the layers type to compare images with. Must be one of...
744 %              CompareAnyLayer, CompareClearLayer, CompareOverlayLayer.
745 %
746 %    o exception: return any errors or warnings in this structure.
747 %
748 */
749
750 MagickExport Image *CompareImagesLayers(const Image *image,
751   const ImageLayerMethod method, ExceptionInfo *exception)
752 {
753   Image
754     *image_a,
755     *image_b,
756     *layers;
757
758   RectangleInfo
759     *bounds;
760
761   register const Image
762     *next;
763
764   register ssize_t
765     i;
766
767   assert(image != (const Image *) NULL);
768   assert(image->signature == MagickSignature);
769   if (image->debug != MagickFalse)
770     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
771   assert(exception != (ExceptionInfo *) NULL);
772   assert(exception->signature == MagickSignature);
773   assert((method == CompareAnyLayer) ||
774          (method == CompareClearLayer) ||
775          (method == CompareOverlayLayer));
776   /*
777     Allocate bounds memory.
778   */
779   next=GetFirstImageInList(image);
780   bounds=(RectangleInfo *) AcquireQuantumMemory((size_t)
781     GetImageListLength(next),sizeof(*bounds));
782   if (bounds == (RectangleInfo *) NULL)
783     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
784   /*
785     Set up first comparision images.
786   */
787   image_a=CloneImage(next,next->page.width,next->page.height,
788     MagickTrue,exception);
789   if (image_a == (Image *) NULL)
790     {
791       bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
792       return((Image *) NULL);
793     }
794   image_a->background_color.alpha=(Quantum) TransparentAlpha;
795   (void) SetImageBackgroundColor(image_a);
796   image_a->page=next->page;
797   image_a->page.x=0;
798   image_a->page.y=0;
799   (void) CompositeImage(image_a,CopyCompositeOp,next,next->page.x,next->page.y);
800   /*
801     Compute the bounding box of changes for the later images
802   */
803   i=0;
804   next=GetNextImageInList(next);
805   for ( ; next != (const Image *) NULL; next=GetNextImageInList(next))
806   {
807     image_b=CloneImage(image_a,0,0,MagickTrue,exception);
808     if (image_b == (Image *) NULL)
809       {
810         image_a=DestroyImage(image_a);
811         bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
812         return((Image *) NULL);
813       }
814     (void) CompositeImage(image_a,CopyCompositeOp,next,next->page.x,
815                            next->page.y);
816     bounds[i]=CompareImagesBounds(image_b,image_a,method,exception);
817
818     image_b=DestroyImage(image_b);
819     i++;
820   }
821   image_a=DestroyImage(image_a);
822   /*
823     Clone first image in sequence.
824   */
825   next=GetFirstImageInList(image);
826   layers=CloneImage(next,0,0,MagickTrue,exception);
827   if (layers == (Image *) NULL)
828     {
829       bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
830       return((Image *) NULL);
831     }
832   /*
833     Deconstruct the image sequence.
834   */
835   i=0;
836   next=GetNextImageInList(next);
837   for ( ; next != (const Image *) NULL; next=GetNextImageInList(next))
838   {
839     image_a=CloneImage(next,0,0,MagickTrue,exception);
840     if (image_a == (Image *) NULL)
841       break;
842     image_b=CropImage(image_a,&bounds[i],exception);
843     image_a=DestroyImage(image_a);
844     if (image_b == (Image *) NULL)
845       break;
846     AppendImageToList(&layers,image_b);
847     i++;
848   }
849   bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
850   if (next != (Image *) NULL)
851     {
852       layers=DestroyImageList(layers);
853       return((Image *) NULL);
854     }
855   return(GetFirstImageInList(layers));
856 }
857 \f
858 /*
859 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
860 %                                                                             %
861 %                                                                             %
862 %                                                                             %
863 +     O p t i m i z e L a y e r F r a m e s                                   %
864 %                                                                             %
865 %                                                                             %
866 %                                                                             %
867 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
868 %
869 %  OptimizeLayerFrames() takes a coalesced GIF animation, and compares each
870 %  frame against the three different 'disposal' forms of the previous frame.
871 %  From this it then attempts to select the smallest cropped image and
872 %  disposal method needed to reproduce the resulting image.
873 %
874 %  Note that this not easy, and may require the expansion of the bounds
875 %  of previous frame, simply clear pixels for the next animation frame to
876 %  transparency according to the selected dispose method.
877 %
878 %  The format of the OptimizeLayerFrames method is:
879 %
880 %      Image *OptimizeLayerFrames(const Image *image,
881 %        const ImageLayerMethod method, ExceptionInfo *exception)
882 %
883 %  A description of each parameter follows:
884 %
885 %    o image: the image.
886 %
887 %    o method: the layers technique to optimize with. Must be one of...
888 %      OptimizeImageLayer, or  OptimizePlusLayer.  The Plus form allows
889 %      the addition of extra 'zero delay' frames to clear pixels from
890 %      the previous frame, and the removal of frames that done change,
891 %      merging the delay times together.
892 %
893 %    o exception: return any errors or warnings in this structure.
894 %
895 */
896 /*
897   Define a 'fake' dispose method where the frame is duplicated, (for
898   OptimizePlusLayer) with a extra zero time delay frame which does a
899   BackgroundDisposal to clear the pixels that need to be cleared.
900 */
901 #define DupDispose  ((DisposeType)9)
902 /*
903   Another 'fake' dispose method used to removed frames that don't change.
904 */
905 #define DelDispose  ((DisposeType)8)
906
907 #define DEBUG_OPT_FRAME 0
908
909 static Image *OptimizeLayerFrames(const Image *image,
910   const ImageLayerMethod method, ExceptionInfo *exception)
911 {
912   ExceptionInfo
913     *sans_exception;
914
915   Image
916     *prev_image,
917     *dup_image,
918     *bgnd_image,
919     *optimized_image;
920
921   RectangleInfo
922     try_bounds,
923     bgnd_bounds,
924     dup_bounds,
925     *bounds;
926
927   MagickBooleanType
928     add_frames,
929     try_cleared,
930     cleared;
931
932   DisposeType
933     *disposals;
934
935   register const Image
936     *curr;
937
938   register ssize_t
939     i;
940
941   assert(image != (const Image *) NULL);
942   assert(image->signature == MagickSignature);
943   if (image->debug != MagickFalse)
944     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
945   assert(exception != (ExceptionInfo *) NULL);
946   assert(exception->signature == MagickSignature);
947   assert(method == OptimizeLayer ||
948          method == OptimizeImageLayer ||
949          method == OptimizePlusLayer);
950
951   /*
952     Are we allowed to add/remove frames from animation
953   */
954   add_frames=method == OptimizePlusLayer ? MagickTrue : MagickFalse;
955   /*
956     Ensure  all the images are the same size
957   */
958   curr=GetFirstImageInList(image);
959   for (; curr != (Image *) NULL; curr=GetNextImageInList(curr))
960   {
961     if ((curr->columns != image->columns) || (curr->rows != image->rows))
962       ThrowImageException(OptionError,"ImagesAreNotTheSameSize");
963     /*
964       FUTURE: also check that image is also fully coalesced (full page)
965       Though as long as they are the same size it should not matter.
966     */
967   }
968   /*
969     Allocate memory (times 2 if we allow the use of frame duplications)
970   */
971   curr=GetFirstImageInList(image);
972   bounds=(RectangleInfo *) AcquireQuantumMemory((size_t)
973     GetImageListLength(curr),(add_frames != MagickFalse ? 2UL : 1UL)*
974     sizeof(*bounds));
975   if (bounds == (RectangleInfo *) NULL)
976     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
977   disposals=(DisposeType *) AcquireQuantumMemory((size_t)
978     GetImageListLength(image),(add_frames != MagickFalse ? 2UL : 1UL)*
979     sizeof(*disposals));
980   if (disposals == (DisposeType *) NULL)
981     {
982       bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
983       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
984     }
985   /*
986     Initialise Previous Image as fully transparent
987   */
988   prev_image=CloneImage(curr,curr->page.width,curr->page.height,
989     MagickTrue,exception);
990   if (prev_image == (Image *) NULL)
991     {
992       bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
993       disposals=(DisposeType *) RelinquishMagickMemory(disposals);
994       return((Image *) NULL);
995     }
996   prev_image->page=curr->page;  /* ERROR: <-- should not be need, but is! */
997   prev_image->page.x=0;
998   prev_image->page.y=0;
999   prev_image->dispose=NoneDispose;
1000
1001   prev_image->background_color.alpha=(Quantum) TransparentAlpha;
1002   (void) SetImageBackgroundColor(prev_image);
1003   /*
1004     Figure out the area of overlay of the first frame
1005     No pixel could be cleared as all pixels are already cleared.
1006   */
1007 #if DEBUG_OPT_FRAME
1008   i=0;
1009   (void) FormatLocaleFile(stderr, "frame %.20g :-\n", (double) i);
1010 #endif
1011   disposals[0]=NoneDispose;
1012   bounds[0]=CompareImagesBounds(prev_image,curr,CompareAnyLayer,exception);
1013 #if DEBUG_OPT_FRAME
1014   (void) FormatLocaleFile(stderr, "overlay: %.20gx%.20g%+.20g%+.20g\n\n",
1015     (double) bounds[i].width,(double) bounds[i].height,
1016     (double) bounds[i].x,(double) bounds[i].y );
1017 #endif
1018   /*
1019     Compute the bounding box of changes for each pair of images.
1020   */
1021   i=1;
1022   bgnd_image=(Image *)NULL;
1023   dup_image=(Image *)NULL;
1024   dup_bounds.width=0;
1025   dup_bounds.height=0;
1026   dup_bounds.x=0;
1027   dup_bounds.y=0;
1028   curr=GetNextImageInList(curr);
1029   for ( ; curr != (const Image *) NULL; curr=GetNextImageInList(curr))
1030   {
1031 #if DEBUG_OPT_FRAME
1032     (void) FormatLocaleFile(stderr, "frame %.20g :-\n", (double) i);
1033 #endif
1034     /*
1035       Assume none disposal is the best
1036     */
1037     bounds[i]=CompareImagesBounds(curr->previous,curr,CompareAnyLayer,exception);
1038     cleared=IsBoundsCleared(curr->previous,curr,&bounds[i],exception);
1039     disposals[i-1]=NoneDispose;
1040 #if DEBUG_OPT_FRAME
1041     (void) FormatLocaleFile(stderr, "overlay: %.20gx%.20g%+.20g%+.20g%s%s\n",
1042          (double) bounds[i].width,(double) bounds[i].height,
1043          (double) bounds[i].x,(double) bounds[i].y,
1044          bounds[i].x < 0?"  (unchanged)":"",
1045          cleared?"  (pixels cleared)":"");
1046 #endif
1047     if ( bounds[i].x < 0 ) {
1048       /*
1049         Image frame is exactly the same as the previous frame!
1050         If not adding frames leave it to be cropped down to a null image.
1051         Otherwise mark previous image for deleted, transfering its crop bounds
1052         to the current image.
1053       */
1054       if ( add_frames && i>=2 ) {
1055         disposals[i-1]=DelDispose;
1056         disposals[i]=NoneDispose;
1057         bounds[i]=bounds[i-1];
1058         i++;
1059         continue;
1060       }
1061     }
1062     else
1063       {
1064         /*
1065           Compare a none disposal against a previous disposal
1066         */
1067         try_bounds=CompareImagesBounds(prev_image,curr,CompareAnyLayer,exception);
1068         try_cleared=IsBoundsCleared(prev_image,curr,&try_bounds,exception);
1069 #if DEBUG_OPT_FRAME
1070     (void) FormatLocaleFile(stderr, "test_prev: %.20gx%.20g%+.20g%+.20g%s\n",
1071          (double) try_bounds.width,(double) try_bounds.height,
1072          (double) try_bounds.x,(double) try_bounds.y,
1073          try_cleared?"  (pixels were cleared)":"");
1074 #endif
1075         if ( (!try_cleared && cleared ) ||
1076                 try_bounds.width * try_bounds.height
1077                     <  bounds[i].width * bounds[i].height )
1078           {
1079             cleared=try_cleared;
1080             bounds[i]=try_bounds;
1081             disposals[i-1]=PreviousDispose;
1082 #if DEBUG_OPT_FRAME
1083             (void) FormatLocaleFile(stderr, "previous: accepted\n");
1084           } else {
1085             (void) FormatLocaleFile(stderr, "previous: rejected\n");
1086 #endif
1087           }
1088
1089         /*
1090           If we are allowed lets try a complex frame duplication.
1091           It is useless if the previous image already clears pixels correctly.
1092           This method will always clear all the pixels that need to be cleared.
1093         */
1094         dup_bounds.width=dup_bounds.height=0; /* no dup, no pixel added */
1095         if ( add_frames )
1096           {
1097             dup_image=CloneImage(curr->previous,curr->previous->page.width,
1098                 curr->previous->page.height,MagickTrue,exception);
1099             if (dup_image == (Image *) NULL)
1100               {
1101                 bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
1102                 disposals=(DisposeType *) RelinquishMagickMemory(disposals);
1103                 prev_image=DestroyImage(prev_image);
1104                 return((Image *) NULL);
1105               }
1106             dup_bounds=CompareImagesBounds(dup_image,curr,CompareClearLayer,exception);
1107             ClearBounds(dup_image,&dup_bounds);
1108             try_bounds=CompareImagesBounds(dup_image,curr,CompareAnyLayer,exception);
1109             if ( cleared ||
1110                    dup_bounds.width*dup_bounds.height
1111                       +try_bounds.width*try_bounds.height
1112                    < bounds[i].width * bounds[i].height )
1113               {
1114                 cleared=MagickFalse;
1115                 bounds[i]=try_bounds;
1116                 disposals[i-1]=DupDispose;
1117                 /* to be finalised later, if found to be optimial */
1118               }
1119             else
1120               dup_bounds.width=dup_bounds.height=0;
1121           }
1122         /*
1123           Now compare against a simple background disposal
1124         */
1125         bgnd_image=CloneImage(curr->previous,curr->previous->page.width,
1126           curr->previous->page.height,MagickTrue,exception);
1127         if (bgnd_image == (Image *) NULL)
1128           {
1129             bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
1130             disposals=(DisposeType *) RelinquishMagickMemory(disposals);
1131             prev_image=DestroyImage(prev_image);
1132             if ( dup_image != (Image *) NULL)
1133               dup_image=DestroyImage(dup_image);
1134             return((Image *) NULL);
1135           }
1136         bgnd_bounds=bounds[i-1]; /* interum bounds of the previous image */
1137         ClearBounds(bgnd_image,&bgnd_bounds);
1138         try_bounds=CompareImagesBounds(bgnd_image,curr,CompareAnyLayer,exception);
1139         try_cleared=IsBoundsCleared(bgnd_image,curr,&try_bounds,exception);
1140 #if DEBUG_OPT_FRAME
1141     (void) FormatLocaleFile(stderr, "background: %s\n",
1142          try_cleared?"(pixels cleared)":"");
1143 #endif
1144         if ( try_cleared )
1145           {
1146             /*
1147               Straight background disposal failed to clear pixels needed!
1148               Lets try expanding the disposal area of the previous frame, to
1149               include the pixels that are cleared.  This guaranteed
1150               to work, though may not be the most optimized solution.
1151             */
1152             try_bounds=CompareImagesBounds(curr->previous,curr,CompareClearLayer,exception);
1153 #if DEBUG_OPT_FRAME
1154             (void) FormatLocaleFile(stderr, "expand_clear: %.20gx%.20g%+.20g%+.20g%s\n",
1155                 (double) try_bounds.width,(double) try_bounds.height,
1156                 (double) try_bounds.x,(double) try_bounds.y,
1157                 try_bounds.x<0?"  (no expand nessary)":"");
1158 #endif
1159             if ( bgnd_bounds.x < 0 )
1160               bgnd_bounds = try_bounds;
1161             else
1162               {
1163 #if DEBUG_OPT_FRAME
1164                 (void) FormatLocaleFile(stderr, "expand_bgnd: %.20gx%.20g%+.20g%+.20g\n",
1165                     (double) bgnd_bounds.width,(double) bgnd_bounds.height,
1166                     (double) bgnd_bounds.x,(double) bgnd_bounds.y );
1167 #endif
1168                 if ( try_bounds.x < bgnd_bounds.x )
1169                   {
1170                      bgnd_bounds.width+= bgnd_bounds.x-try_bounds.x;
1171                      if ( bgnd_bounds.width < try_bounds.width )
1172                        bgnd_bounds.width = try_bounds.width;
1173                      bgnd_bounds.x = try_bounds.x;
1174                   }
1175                 else
1176                   {
1177                      try_bounds.width += try_bounds.x - bgnd_bounds.x;
1178                      if ( bgnd_bounds.width < try_bounds.width )
1179                        bgnd_bounds.width = try_bounds.width;
1180                   }
1181                 if ( try_bounds.y < bgnd_bounds.y )
1182                   {
1183                      bgnd_bounds.height += bgnd_bounds.y - try_bounds.y;
1184                      if ( bgnd_bounds.height < try_bounds.height )
1185                        bgnd_bounds.height = try_bounds.height;
1186                      bgnd_bounds.y = try_bounds.y;
1187                   }
1188                 else
1189                   {
1190                     try_bounds.height += try_bounds.y - bgnd_bounds.y;
1191                      if ( bgnd_bounds.height < try_bounds.height )
1192                        bgnd_bounds.height = try_bounds.height;
1193                   }
1194 #if DEBUG_OPT_FRAME
1195                 (void) FormatLocaleFile(stderr, "        to : %.20gx%.20g%+.20g%+.20g\n",
1196                     (double) bgnd_bounds.width,(double) bgnd_bounds.height,
1197                     (double) bgnd_bounds.x,(double) bgnd_bounds.y );
1198 #endif
1199               }
1200             ClearBounds(bgnd_image,&bgnd_bounds);
1201 #if DEBUG_OPT_FRAME
1202 /* Something strange is happening with a specific animation
1203  * CompareAnyLayers (normal method) and CompareClearLayers returns the whole
1204  * image, which is not posibly correct!  As verified by previous tests.
1205  * Something changed beyond the bgnd_bounds clearing.  But without being able
1206  * to see, or writet he image at this point it is hard to tell what is wrong!
1207  * Only CompareOverlay seemed to return something sensible.
1208  */
1209             try_bounds=CompareImagesBounds(bgnd_image,curr,CompareClearLayer,exception);
1210             (void) FormatLocaleFile(stderr, "expand_ctst: %.20gx%.20g%+.20g%+.20g\n",
1211                 (double) try_bounds.width,(double) try_bounds.height,
1212                 (double) try_bounds.x,(double) try_bounds.y );
1213             try_bounds=CompareImagesBounds(bgnd_image,curr,CompareAnyLayer,exception);
1214             try_cleared=IsBoundsCleared(bgnd_image,curr,&try_bounds,exception);
1215             (void) FormatLocaleFile(stderr, "expand_any : %.20gx%.20g%+.20g%+.20g%s\n",
1216                 (double) try_bounds.width,(double) try_bounds.height,
1217                 (double) try_bounds.x,(double) try_bounds.y,
1218                 try_cleared?"   (pixels cleared)":"");
1219 #endif
1220             try_bounds=CompareImagesBounds(bgnd_image,curr,CompareOverlayLayer,exception);
1221 #if DEBUG_OPT_FRAME
1222             try_cleared=IsBoundsCleared(bgnd_image,curr,&try_bounds,exception);
1223             (void) FormatLocaleFile(stderr, "expand_test: %.20gx%.20g%+.20g%+.20g%s\n",
1224                 (double) try_bounds.width,(double) try_bounds.height,
1225                 (double) try_bounds.x,(double) try_bounds.y,
1226                 try_cleared?"   (pixels cleared)":"");
1227 #endif
1228           }
1229         /*
1230           Test if this background dispose is smaller than any of the
1231           other methods we tryed before this (including duplicated frame)
1232         */
1233         if ( cleared ||
1234               bgnd_bounds.width*bgnd_bounds.height
1235                 +try_bounds.width*try_bounds.height
1236               < bounds[i-1].width*bounds[i-1].height
1237                   +dup_bounds.width*dup_bounds.height
1238                   +bounds[i].width*bounds[i].height )
1239           {
1240             cleared=MagickFalse;
1241             bounds[i-1]=bgnd_bounds;
1242             bounds[i]=try_bounds;
1243             if ( disposals[i-1] == DupDispose )
1244               dup_image=DestroyImage(dup_image);
1245             disposals[i-1]=BackgroundDispose;
1246 #if DEBUG_OPT_FRAME
1247     (void) FormatLocaleFile(stderr, "expand_bgnd: accepted\n");
1248           } else {
1249     (void) FormatLocaleFile(stderr, "expand_bgnd: reject\n");
1250 #endif
1251           }
1252       }
1253     /*
1254        Finalise choice of dispose, set new prev_image,
1255        and junk any extra images as appropriate,
1256     */
1257     if ( disposals[i-1] == DupDispose )
1258       {
1259          if (bgnd_image != (Image *) NULL)
1260            bgnd_image=DestroyImage(bgnd_image);
1261          prev_image=DestroyImage(prev_image);
1262          prev_image=dup_image, dup_image=(Image *) NULL;
1263          bounds[i+1]=bounds[i];
1264          bounds[i]=dup_bounds;
1265          disposals[i-1]=DupDispose;
1266          disposals[i]=BackgroundDispose;
1267          i++;
1268       }
1269     else
1270       {
1271         if ( dup_image != (Image *) NULL)
1272           dup_image=DestroyImage(dup_image);
1273         if ( disposals[i-1] != PreviousDispose )
1274           prev_image=DestroyImage(prev_image);
1275         if ( disposals[i-1] == BackgroundDispose )
1276           prev_image=bgnd_image,  bgnd_image=(Image *)NULL;
1277         if (bgnd_image != (Image *) NULL)
1278           bgnd_image=DestroyImage(bgnd_image);
1279         if ( disposals[i-1] == NoneDispose )
1280           {
1281             prev_image=CloneImage(curr->previous,curr->previous->page.width,
1282               curr->previous->page.height,MagickTrue,exception);
1283             if (prev_image == (Image *) NULL)
1284               {
1285                 bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
1286                 disposals=(DisposeType *) RelinquishMagickMemory(disposals);
1287                 return((Image *) NULL);
1288               }
1289           }
1290
1291       }
1292     assert(prev_image != (Image *) NULL);
1293     disposals[i]=disposals[i-1];
1294 #if DEBUG_OPT_FRAME
1295     (void) FormatLocaleFile(stderr, "final   %.20g : %s  %.20gx%.20g%+.20g%+.20g\n",
1296          (double) i-1,
1297          CommandOptionToMnemonic(MagickDisposeOptions, disposals[i-1]),
1298          (double) bounds[i-1].width, (double) bounds[i-1].height,
1299          (double) bounds[i-1].x, (double) bounds[i-1].y );
1300 #endif
1301 #if DEBUG_OPT_FRAME
1302     (void) FormatLocaleFile(stderr, "interum %.20g : %s  %.20gx%.20g%+.20g%+.20g\n",
1303          (double) i,
1304          CommandOptionToMnemonic(MagickDisposeOptions, disposals[i]),
1305          (double) bounds[i].width, (double) bounds[i].height,
1306          (double) bounds[i].x, (double) bounds[i].y );
1307     (void) FormatLocaleFile(stderr, "\n");
1308 #endif
1309     i++;
1310   }
1311   prev_image=DestroyImage(prev_image);
1312   /*
1313     Optimize all images in sequence.
1314   */
1315   sans_exception=AcquireExceptionInfo();
1316   i=0;
1317   curr=GetFirstImageInList(image);
1318   optimized_image=NewImageList();
1319   while ( curr != (const Image *) NULL )
1320   {
1321     prev_image=CloneImage(curr,0,0,MagickTrue,exception);
1322     if (prev_image == (Image *) NULL)
1323       break;
1324     if ( disposals[i] == DelDispose ) {
1325       size_t time = 0;
1326       while ( disposals[i] == DelDispose ) {
1327         time += curr->delay*1000/curr->ticks_per_second;
1328         curr=GetNextImageInList(curr);
1329         i++;
1330       }
1331       time += curr->delay*1000/curr->ticks_per_second;
1332       prev_image->ticks_per_second = 100L;
1333       prev_image->delay = time*prev_image->ticks_per_second/1000;
1334     }
1335     bgnd_image=CropImage(prev_image,&bounds[i],sans_exception);
1336     prev_image=DestroyImage(prev_image);
1337     if (bgnd_image == (Image *) NULL)
1338       break;
1339     bgnd_image->dispose=disposals[i];
1340     if ( disposals[i] == DupDispose ) {
1341       bgnd_image->delay=0;
1342       bgnd_image->dispose=NoneDispose;
1343     }
1344     else
1345       curr=GetNextImageInList(curr);
1346     AppendImageToList(&optimized_image,bgnd_image);
1347     i++;
1348   }
1349   sans_exception=DestroyExceptionInfo(sans_exception);
1350   bounds=(RectangleInfo *) RelinquishMagickMemory(bounds);
1351   disposals=(DisposeType *) RelinquishMagickMemory(disposals);
1352   if (curr != (Image *) NULL)
1353     {
1354       optimized_image=DestroyImageList(optimized_image);
1355       return((Image *) NULL);
1356     }
1357   return(GetFirstImageInList(optimized_image));
1358 }
1359 \f
1360 /*
1361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1362 %                                                                             %
1363 %                                                                             %
1364 %                                                                             %
1365 %     O p t i m i z e I m a g e L a y e r s                                   %
1366 %                                                                             %
1367 %                                                                             %
1368 %                                                                             %
1369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1370 %
1371 %  OptimizeImageLayers() compares each image the GIF disposed forms of the
1372 %  previous image in the sequence.  From this it attempts to select the
1373 %  smallest cropped image to replace each frame, while preserving the results
1374 %  of the GIF animation.
1375 %
1376 %  The format of the OptimizeImageLayers method is:
1377 %
1378 %      Image *OptimizeImageLayers(const Image *image,
1379 %               ExceptionInfo *exception)
1380 %
1381 %  A description of each parameter follows:
1382 %
1383 %    o image: the image.
1384 %
1385 %    o exception: return any errors or warnings in this structure.
1386 %
1387 */
1388 MagickExport Image *OptimizeImageLayers(const Image *image,
1389   ExceptionInfo *exception)
1390 {
1391   return(OptimizeLayerFrames(image,OptimizeImageLayer,exception));
1392 }
1393 \f
1394 /*
1395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1396 %                                                                             %
1397 %                                                                             %
1398 %                                                                             %
1399 %     O p t i m i z e P l u s I m a g e L a y e r s                           %
1400 %                                                                             %
1401 %                                                                             %
1402 %                                                                             %
1403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1404 %
1405 %  OptimizeImagePlusLayers() is exactly as OptimizeImageLayers(), but may
1406 %  also add or even remove extra frames in the animation, if it improves
1407 %  the total number of pixels in the resulting GIF animation.
1408 %
1409 %  The format of the OptimizePlusImageLayers method is:
1410 %
1411 %      Image *OptimizePlusImageLayers(const Image *image,
1412 %               ExceptionInfo *exception)
1413 %
1414 %  A description of each parameter follows:
1415 %
1416 %    o image: the image.
1417 %
1418 %    o exception: return any errors or warnings in this structure.
1419 %
1420 */
1421 MagickExport Image *OptimizePlusImageLayers(const Image *image,
1422   ExceptionInfo *exception)
1423 {
1424   return OptimizeLayerFrames(image, OptimizePlusLayer, exception);
1425 }
1426 \f
1427 /*
1428 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1429 %                                                                             %
1430 %                                                                             %
1431 %                                                                             %
1432 %     O p t i m i z e I m a g e T r a n s p a r e n c y                       %
1433 %                                                                             %
1434 %                                                                             %
1435 %                                                                             %
1436 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1437 %
1438 %  OptimizeImageTransparency() takes a frame optimized GIF animation, and
1439 %  compares the overlayed pixels against the disposal image resulting from all
1440 %  the previous frames in the animation.  Any pixel that does not change the
1441 %  disposal image (and thus does not effect the outcome of an overlay) is made
1442 %  transparent.
1443 %
1444 %  WARNING: This modifies the current images directly, rather than generate
1445 %  a new image sequence.
1446 %
1447 %  The format of the OptimizeImageTransperency method is:
1448 %
1449 %      void OptimizeImageTransperency(Image *image,ExceptionInfo *exception)
1450 %
1451 %  A description of each parameter follows:
1452 %
1453 %    o image: the image sequence
1454 %
1455 %    o exception: return any errors or warnings in this structure.
1456 %
1457 */
1458 MagickExport void OptimizeImageTransparency(const Image *image,
1459      ExceptionInfo *exception)
1460 {
1461   Image
1462     *dispose_image;
1463
1464   register Image
1465     *next;
1466
1467   /*
1468     Run the image through the animation sequence
1469   */
1470   assert(image != (Image *) NULL);
1471   assert(image->signature == MagickSignature);
1472   if (image->debug != MagickFalse)
1473     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1474   assert(exception != (ExceptionInfo *) NULL);
1475   assert(exception->signature == MagickSignature);
1476   next=GetFirstImageInList(image);
1477   dispose_image=CloneImage(next,next->page.width,next->page.height,
1478     MagickTrue,exception);
1479   if (dispose_image == (Image *) NULL)
1480     return;
1481   dispose_image->page=next->page;
1482   dispose_image->page.x=0;
1483   dispose_image->page.y=0;
1484   dispose_image->dispose=NoneDispose;
1485   dispose_image->background_color.alpha=(Quantum) TransparentAlpha;
1486   (void) SetImageBackgroundColor(dispose_image);
1487
1488   while ( next != (Image *) NULL )
1489   {
1490     Image
1491       *current_image;
1492
1493     /*
1494       Overlay this frame's image over the previous disposal image
1495     */
1496     current_image=CloneImage(dispose_image,0,0,MagickTrue,exception);
1497     if (current_image == (Image *) NULL)
1498       {
1499         dispose_image=DestroyImage(dispose_image);
1500         return;
1501       }
1502     (void) CompositeImage(current_image,next->matte != MagickFalse ?
1503       OverCompositeOp : CopyCompositeOp, next,next->page.x,next->page.y);
1504     /*
1505       At this point the image would be displayed, for the delay period
1506     **
1507       Work out the disposal of the previous image
1508     */
1509     if (next->dispose == BackgroundDispose)
1510       {
1511         RectangleInfo
1512           bounds=next->page;
1513
1514         bounds.width=next->columns;
1515         bounds.height=next->rows;
1516         if (bounds.x < 0)
1517           {
1518             bounds.width+=bounds.x;
1519             bounds.x=0;
1520           }
1521         if ((ssize_t) (bounds.x+bounds.width) > (ssize_t) current_image->columns)
1522           bounds.width=current_image->columns-bounds.x;
1523         if (bounds.y < 0)
1524           {
1525             bounds.height+=bounds.y;
1526             bounds.y=0;
1527           }
1528         if ((ssize_t) (bounds.y+bounds.height) > (ssize_t) current_image->rows)
1529           bounds.height=current_image->rows-bounds.y;
1530         ClearBounds(current_image, &bounds);
1531       }
1532     if (next->dispose != PreviousDispose)
1533       {
1534         dispose_image=DestroyImage(dispose_image);
1535         dispose_image=current_image;
1536       }
1537     else
1538       current_image=DestroyImage(current_image);
1539
1540     /*
1541       Optimize Transparency of the next frame (if present)
1542     */
1543     next=GetNextImageInList(next);
1544     if ( next != (Image *) NULL ) {
1545       (void) CompositeImage(next, ChangeMaskCompositeOp,
1546           dispose_image, -(next->page.x), -(next->page.y) );
1547     }
1548   }
1549   dispose_image=DestroyImage(dispose_image);
1550   return;
1551 }
1552 \f
1553 /*
1554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1555 %                                                                             %
1556 %                                                                             %
1557 %                                                                             %
1558 %     R e m o v e D u p l i c a t e L a y e r s                               %
1559 %                                                                             %
1560 %                                                                             %
1561 %                                                                             %
1562 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1563 %
1564 %  RemoveDuplicateLayers() removes any image that is exactly the same as the
1565 %  next image in the given image list.  Image size and virtual canvas offset
1566 %  must also match, though not the virtual canvas size itself.
1567 %
1568 %  No check is made with regards to image disposal setting, though it is the
1569 %  dispose setting of later image that is kept.  Also any time delays are also
1570 %  added together. As such coalesced image animations should still produce the
1571 %  same result, though with duplicte frames merged into a single frame.
1572 %
1573 %  The format of the RemoveDuplicateLayers method is:
1574 %
1575 %      void RemoveDuplicateLayers(Image **image, ExceptionInfo *exception)
1576 %
1577 %  A description of each parameter follows:
1578 %
1579 %    o images: the image list
1580 %
1581 %    o exception: return any errors or warnings in this structure.
1582 %
1583 */
1584 MagickExport void RemoveDuplicateLayers(Image **images,
1585      ExceptionInfo *exception)
1586 {
1587   register Image
1588     *curr,
1589     *next;
1590
1591   RectangleInfo
1592     bounds;
1593
1594   assert((*images) != (const Image *) NULL);
1595   assert((*images)->signature == MagickSignature);
1596   if ((*images)->debug != MagickFalse)
1597     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*images)->filename);
1598   assert(exception != (ExceptionInfo *) NULL);
1599   assert(exception->signature == MagickSignature);
1600
1601   curr=GetFirstImageInList(*images);
1602   for (; (next=GetNextImageInList(curr)) != (Image *) NULL; curr=next)
1603   {
1604     if ( curr->columns != next->columns || curr->rows != next->rows
1605          || curr->page.x != next->page.x || curr->page.y != next->page.y )
1606       continue;
1607     bounds=CompareImagesBounds(curr,next,CompareAnyLayer,exception);
1608     if ( bounds.x < 0 ) {
1609       /*
1610         the two images are the same, merge time delays and delete one.
1611       */
1612       size_t time;
1613       time = curr->delay*1000/curr->ticks_per_second;
1614       time += next->delay*1000/next->ticks_per_second;
1615       next->ticks_per_second = 100L;
1616       next->delay = time*curr->ticks_per_second/1000;
1617       next->iterations = curr->iterations;
1618       *images = curr;
1619       (void) DeleteImageFromList(images);
1620     }
1621   }
1622   *images = GetFirstImageInList(*images);
1623 }
1624 \f
1625 /*
1626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1627 %                                                                             %
1628 %                                                                             %
1629 %                                                                             %
1630 %     R e m o v e Z e r o D e l a y L a y e r s                               %
1631 %                                                                             %
1632 %                                                                             %
1633 %                                                                             %
1634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1635 %
1636 %  RemoveZeroDelayLayers() removes any image that as a zero delay time. Such
1637 %  images generally represent intermediate or partial updates in GIF
1638 %  animations used for file optimization.  They are not ment to be displayed
1639 %  to users of the animation.  Viewable images in an animation should have a
1640 %  time delay of 3 or more centi-seconds (hundredths of a second).
1641 %
1642 %  However if all the frames have a zero time delay, then either the animation
1643 %  is as yet incomplete, or it is not a GIF animation.  This a non-sensible
1644 %  situation, so no image will be removed and a 'Zero Time Animation' warning
1645 %  (exception) given.
1646 %
1647 %  No warning will be given if no image was removed because all images had an
1648 %  appropriate non-zero time delay set.
1649 %
1650 %  Due to the special requirements of GIF disposal handling, GIF animations
1651 %  should be coalesced first, before calling this function, though that is not
1652 %  a requirement.
1653 %
1654 %  The format of the RemoveZeroDelayLayers method is:
1655 %
1656 %      void RemoveZeroDelayLayers(Image **image, ExceptionInfo *exception)
1657 %
1658 %  A description of each parameter follows:
1659 %
1660 %    o images: the image list
1661 %
1662 %    o exception: return any errors or warnings in this structure.
1663 %
1664 */
1665 MagickExport void RemoveZeroDelayLayers(Image **images,
1666      ExceptionInfo *exception)
1667 {
1668   Image
1669     *i;
1670
1671   assert((*images) != (const Image *) NULL);
1672   assert((*images)->signature == MagickSignature);
1673   if ((*images)->debug != MagickFalse)
1674     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*images)->filename);
1675   assert(exception != (ExceptionInfo *) NULL);
1676   assert(exception->signature == MagickSignature);
1677
1678   i=GetFirstImageInList(*images);
1679   for ( ; i != (Image *) NULL; i=GetNextImageInList(i))
1680     if ( i->delay != 0L ) break;
1681   if ( i == (Image *) NULL ) {
1682     (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
1683        "ZeroTimeAnimation","`%s'",GetFirstImageInList(*images)->filename);
1684     return;
1685   }
1686   i=GetFirstImageInList(*images);
1687   while ( i != (Image *) NULL )
1688   {
1689     if ( i->delay == 0L ) {
1690       (void) DeleteImageFromList(&i);
1691       *images=i;
1692     }
1693     else
1694       i=GetNextImageInList(i);
1695   }
1696   *images=GetFirstImageInList(*images);
1697 }
1698 \f
1699 /*
1700 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1701 %                                                                             %
1702 %                                                                             %
1703 %                                                                             %
1704 %     C o m p o s i t e L a y e r s                                           %
1705 %                                                                             %
1706 %                                                                             %
1707 %                                                                             %
1708 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1709 %
1710 %  CompositeLayers() compose first image sequence (source) over the second
1711 %  image sequence (destination), using the given compose method and offsets.
1712 %
1713 %  The pointers to the image list does not have to be the start of that image
1714 %  list, but may start somewhere in the middle.  Each layer from the two image
1715 %  lists are composted together until the end of one of the image lists is
1716 %  reached.  The offset of each composition is also adjusted to match the
1717 %  virtual canvas offsets of each layer. As such the given offset is relative
1718 %  to the virtual canvas, and not the actual image.
1719 %
1720 %  No GIF disposal handling is performed, so GIF animations should be
1721 %  coalesced before use.  However this not a requirement, and individual
1722 %  layer images may have any size or offset, for special compositions.
1723 %
1724 %  Special case:- If one of the image sequences is just a single image that
1725 %  image is repeatally composed with all the images in the other image list.
1726 %  Either the source or destination lists may be the single image, for this
1727 %  situation.
1728 %
1729 %  The destination list will be expanded as needed to match number of source
1730 %  image overlaid (from current position to end of list).
1731 %
1732 %  The format of the CompositeLayers method is:
1733 %
1734 %      void CompositeLayers(Image *destination,
1735 %          const CompositeOperator compose, Image *source,
1736 %          const ssize_t x_offset, const ssize_t y_offset,
1737 %          ExceptionInfo *exception);
1738 %
1739 %  A description of each parameter follows:
1740 %
1741 %    o destination: the destination images and results
1742 %
1743 %    o source: source image(s) for the layer composition
1744 %
1745 %    o compose, x_offset, y_offset:  arguments passed on to CompositeImages()
1746 %
1747 %    o exception: return any errors or warnings in this structure.
1748 %
1749 */
1750 static inline void CompositeCanvas(Image *destination,
1751   const CompositeOperator compose, Image *source,ssize_t x_offset,
1752   ssize_t y_offset )
1753 {
1754   x_offset+=source->page.x-destination->page.x;
1755   y_offset+=source->page.y-destination->page.y;
1756   (void) CompositeImage(destination,compose,source,x_offset,y_offset);
1757 }
1758
1759 MagickExport void CompositeLayers(Image *destination,
1760   const CompositeOperator compose, Image *source,const ssize_t x_offset,
1761   const ssize_t y_offset,ExceptionInfo *exception)
1762 {
1763   assert(destination != (Image *) NULL);
1764   assert(destination->signature == MagickSignature);
1765   assert(source != (Image *) NULL);
1766   assert(source->signature == MagickSignature);
1767   assert(exception != (ExceptionInfo *) NULL);
1768   assert(exception->signature == MagickSignature);
1769   if (source->debug != MagickFalse || destination->debug != MagickFalse)
1770     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s - %s",
1771          source->filename, destination->filename);
1772
1773   /*
1774     Overlay single source image over destation image/list
1775   */
1776   if ( source->previous == (Image *) NULL && source->next == (Image *) NULL )
1777     while ( destination != (Image *) NULL )
1778     {
1779       CompositeCanvas(destination, compose, source, x_offset, y_offset);
1780       destination=GetNextImageInList(destination);
1781     }
1782
1783   /*
1784     Overlay source image list over single destination
1785     Generating multiple clones of destination image to match source list.
1786     Original Destination image becomes first image of generated list.
1787     As such the image list pointer does not require any change in caller.
1788     Some animation attributes however also needs coping in this case.
1789   */
1790   else if ( destination->previous == (Image *) NULL &&
1791             destination->next == (Image *) NULL )
1792   {
1793     Image *dest = CloneImage(destination,0,0,MagickTrue,exception);
1794
1795     CompositeCanvas(destination, compose, source, x_offset, y_offset);
1796     /* copy source image attributes ? */
1797     if ( source->next != (Image *) NULL )
1798       {
1799         destination->delay = source->delay;
1800         destination->iterations = source->iterations;
1801       }
1802     source=GetNextImageInList(source);
1803
1804     while ( source != (Image *) NULL )
1805     {
1806       AppendImageToList(&destination,
1807            CloneImage(dest,0,0,MagickTrue,exception));
1808       destination=GetLastImageInList(destination);
1809
1810       CompositeCanvas(destination, compose, source, x_offset, y_offset);
1811       destination->delay = source->delay;
1812       destination->iterations = source->iterations;
1813       source=GetNextImageInList(source);
1814     }
1815     dest=DestroyImage(dest);
1816   }
1817
1818   /*
1819     Overlay a source image list over a destination image list
1820     until either list runs out of images. (Does not repeat)
1821   */
1822   else
1823     while ( source != (Image *) NULL && destination != (Image *) NULL )
1824     {
1825       CompositeCanvas(destination, compose, source, x_offset, y_offset);
1826       source=GetNextImageInList(source);
1827       destination=GetNextImageInList(destination);
1828     }
1829 }
1830 \f
1831 /*
1832 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1833 %                                                                             %
1834 %                                                                             %
1835 %                                                                             %
1836 %     M e r g e I m a g e L a y e r s                                         %
1837 %                                                                             %
1838 %                                                                             %
1839 %                                                                             %
1840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1841 %
1842 %  MergeImageLayers() composes all the image layers from the current given
1843 %  image onward to produce a single image of the merged layers.
1844 %
1845 %  The inital canvas's size depends on the given ImageLayerMethod, and is
1846 %  initialized using the first images background color.  The images
1847 %  are then compositied onto that image in sequence using the given
1848 %  composition that has been assigned to each individual image.
1849 %
1850 %  The format of the MergeImageLayers is:
1851 %
1852 %      Image *MergeImageLayers(const Image *image,
1853 %        const ImageLayerMethod method, ExceptionInfo *exception)
1854 %
1855 %  A description of each parameter follows:
1856 %
1857 %    o image: the image list to be composited together
1858 %
1859 %    o method: the method of selecting the size of the initial canvas.
1860 %
1861 %        MergeLayer: Merge all layers onto a canvas just large enough
1862 %           to hold all the actual images. The virtual canvas of the
1863 %           first image is preserved but otherwise ignored.
1864 %
1865 %        FlattenLayer: Use the virtual canvas size of first image.
1866 %           Images which fall outside this canvas is clipped.
1867 %           This can be used to 'fill out' a given virtual canvas.
1868 %
1869 %        MosaicLayer: Start with the virtual canvas of the first image,
1870 %           enlarging left and right edges to contain all images.
1871 %           Images with negative offsets will be clipped.
1872 %
1873 %        TrimBoundsLayer: Determine the overall bounds of all the image
1874 %           layers just as in "MergeLayer", then adjust the the canvas
1875 %           and offsets to be relative to those bounds, without overlaying
1876 %           the images.
1877 %
1878 %           WARNING: a new image is not returned, the original image
1879 %           sequence page data is modified instead.
1880 %
1881 %    o exception: return any errors or warnings in this structure.
1882 %
1883 */
1884 MagickExport Image *MergeImageLayers(Image *image,
1885   const ImageLayerMethod method,ExceptionInfo *exception)
1886 {
1887 #define MergeLayersTag  "Merge/Layers"
1888
1889   Image
1890     *canvas;
1891
1892   MagickBooleanType
1893     proceed;
1894
1895   RectangleInfo
1896     page;
1897
1898   register const Image
1899     *next;
1900
1901   size_t
1902     number_images,
1903     height,
1904     width;
1905
1906   ssize_t
1907     scene;
1908
1909   assert(image != (Image *) NULL);
1910   assert(image->signature == MagickSignature);
1911   if (image->debug != MagickFalse)
1912     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1913   assert(exception != (ExceptionInfo *) NULL);
1914   assert(exception->signature == MagickSignature);
1915   /*
1916     Determine canvas image size, and its virtual canvas size and offset
1917   */
1918   page=image->page;
1919   width=image->columns;
1920   height=image->rows;
1921   switch (method)
1922   {
1923     case TrimBoundsLayer:
1924     case MergeLayer:
1925     default:
1926     {
1927       next = GetNextImageInList(image);
1928       for ( ; next != (Image *) NULL;  next=GetNextImageInList(next)) {
1929         if ( page.x > next->page.x ) {
1930              width += page.x-next->page.x;
1931              page.x = next->page.x;
1932         }
1933         if ( page.y > next->page.y ) {
1934              height += page.y-next->page.y;
1935              page.y = next->page.y;
1936         }
1937         if ( (ssize_t) width < (next->page.x + (ssize_t)next->columns - page.x) )
1938            width = (size_t) next->page.x + (ssize_t)next->columns - page.x;
1939         if ( (ssize_t) height < (next->page.y + (ssize_t)next->rows - page.y) )
1940            height = (size_t) next->page.y + (ssize_t)next->rows - page.y;
1941       }
1942       break;
1943     }
1944     case FlattenLayer:
1945     {
1946       if ( page.width > 0 )
1947         width=page.width;
1948       if ( page.height > 0 )
1949         height=page.height;
1950       page.x=0;
1951       page.y=0;
1952       break;
1953     }
1954     case MosaicLayer:
1955     {
1956       if ( page.width > 0 )
1957         width=page.width;
1958       if ( page.height > 0 )
1959         height=page.height;
1960       for (next=image; next != (Image *) NULL; next=GetNextImageInList(next)) {
1961         if (method == MosaicLayer) {
1962           page.x=next->page.x;
1963           page.y=next->page.y;
1964           if ( (ssize_t) width < (next->page.x + (ssize_t)next->columns) )
1965              width = (size_t) next->page.x + next->columns;
1966           if ( (ssize_t) height < (next->page.y + (ssize_t)next->rows) )
1967              height = (size_t) next->page.y + next->rows;
1968         }
1969       }
1970       page.width=width;
1971       page.height=height;
1972       page.x=0;
1973       page.y=0;
1974     }
1975     break;
1976   }
1977   /* set virtual canvas size if not defined */
1978   if ( page.width == 0 )
1979     page.width = (page.x < 0) ? width : width+page.x;
1980   if ( page.height == 0 )
1981     page.height = (page.y < 0) ? height : height+page.y;
1982
1983   /*
1984     Handle "TrimBoundsLayer" method separately to normal 'layer merge'
1985   */
1986   if ( method == TrimBoundsLayer ) {
1987     number_images=GetImageListLength(image);
1988     for (scene=0; scene < (ssize_t) number_images; scene++)
1989     {
1990       image->page.x -= page.x;
1991       image->page.y -= page.y;
1992       image->page.width = width;
1993       image->page.height = height;
1994       proceed=SetImageProgress(image,MergeLayersTag,(MagickOffsetType) scene,
1995         number_images);
1996       if (proceed == MagickFalse)
1997         break;
1998       image=GetNextImageInList(image);
1999     }
2000     return((Image *) NULL);
2001   }
2002
2003   /*
2004     Create canvas size of width and height, and background color.
2005   */
2006   canvas=CloneImage(image,width,height,MagickTrue,exception);
2007   if (canvas == (Image *) NULL)
2008     return((Image *) NULL);
2009   (void) SetImageBackgroundColor(canvas);
2010   canvas->page=page;
2011   canvas->dispose=UndefinedDispose;
2012
2013   /*
2014     Compose images onto canvas, with progress monitor
2015   */
2016   number_images=GetImageListLength(image);
2017   for (scene=0; scene < (ssize_t) number_images; scene++)
2018   {
2019     (void) CompositeImage(canvas,image->compose,image,image->page.x-
2020       canvas->page.x,image->page.y-canvas->page.y);
2021     proceed=SetImageProgress(image,MergeLayersTag,(MagickOffsetType) scene,
2022       number_images);
2023     if (proceed == MagickFalse)
2024       break;
2025     image=GetNextImageInList(image);
2026   }
2027   return(canvas);
2028 }
2029