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