]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/layer.c
Update web pages
[imagemagick] / MagickCore / layer.c
index 72594fe97a1fb72360cacb20d46c5c93126f51d1..7ddfca7af3a5cffdca0322add8a4610f4c767244 100644 (file)
 %                      MagickCore Image Layering Methods                      %
 %                                                                             %
 %                              Software Design                                %
-%                                John Cristy                                  %
+%                                   Cristy                                    %
 %                              Anthony Thyssen                                %
 %                               January 2006                                  %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
@@ -40,6 +40,7 @@
 #include "MagickCore/studio.h"
 #include "MagickCore/artifact.h"
 #include "MagickCore/cache.h"
+#include "MagickCore/channel.h"
 #include "MagickCore/color.h"
 #include "MagickCore/color-private.h"
 #include "MagickCore/composite.h"
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
 %  ClearBounds() Clear the area specified by the bounds in an image to
-%  transparency.  This typically used to handle Background Disposal
-%  for the previous frame in an animation sequence.
+%  transparency.  This typically used to handle Background Disposal for the
+%  previous frame in an animation sequence.
 %
-%  WARNING: no bounds checks are performed, except for the null or
-%  missed image, for images that don't change. in all other cases
-%  bound must fall within the image.
+%  Warning: no bounds checks are performed, except for the null or missed
+%  image, for images that don't change. in all other cases bound must fall
+%  within the image.
 %
 %  The format is:
 %
-%      void ClearBounds(Image *image,RectangleInfo *bounds
+%      void ClearBounds(Image *image,RectangleInfo *bounds,
 %        ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
@@ -104,7 +105,7 @@ static void ClearBounds(Image *image,RectangleInfo *bounds,
 
   if (bounds->x < 0)
     return;
-  if (image->alpha_trait != BlendPixelTrait)
+  if (image->alpha_trait == UndefinedPixelTrait)
     (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
   for (y=0; y < (ssize_t) bounds->height; y++)
   {
@@ -143,6 +144,10 @@ static void ClearBounds(Image *image,RectangleInfo *bounds,
 %  to check if a proposed disposal method will work successfully to generate
 %  the second frame image from the first disposed form of the previous frame.
 %
+%  Warning: no bounds checks are performed, except for the null or missed
+%  image, for images that don't change. in all other cases bound must fall
+%  within the image.
+%
 %  The format is:
 %
 %      MagickBooleanType IsBoundsCleared(const Image *image1,
@@ -156,21 +161,17 @@ static void ClearBounds(Image *image,RectangleInfo *bounds,
 %
 %    o exception: return any errors or warnings in this structure.
 %
-%  WARNING: no bounds checks are performed, except for the null or
-%  missed image, for images that don't change. in all other cases
-%  bound must fall within the image.
-%
 */
 static MagickBooleanType IsBoundsCleared(const Image *image1,
   const Image *image2,RectangleInfo *bounds,ExceptionInfo *exception)
 {
-  register ssize_t
-    x;
-
   register const Quantum
     *p,
     *q;
 
+  register ssize_t
+    x;
+
   ssize_t
     y;
 
@@ -184,11 +185,11 @@ static MagickBooleanType IsBoundsCleared(const Image *image1,
       break;
     for (x=0; x < (ssize_t) bounds->width; x++)
     {
-      if ((GetPixelAlpha(image1,p) <= (Quantum) (QuantumRange/2)) &&
-          (GetPixelAlpha(image1,q) > (Quantum) (QuantumRange/2)))
+      if ((GetPixelAlpha(image1,p) >= (Quantum) (QuantumRange/2)) &&
+          (GetPixelAlpha(image2,q) < (Quantum) (QuantumRange/2)))
         break;
       p+=GetPixelChannels(image1);
-      q++;
+      q+=GetPixelChannels(image2);
     }
     if (x < (ssize_t) bounds->width)
       break;
@@ -242,11 +243,11 @@ MagickExport Image *CoalesceImages(const Image *image,ExceptionInfo *exception)
     Coalesce the image sequence.
   */
   assert(image != (Image *) NULL);
-  assert(image->signature == MagickSignature);
+  assert(image->signature == MagickCoreSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
+  assert(exception->signature == MagickCoreSignature);
   next=GetFirstImageInList(image);
   bounds=next->page;
   if (bounds.width == 0)
@@ -267,6 +268,7 @@ MagickExport Image *CoalesceImages(const Image *image,ExceptionInfo *exception)
     exception);
   if (coalesce_image == (Image *) NULL)
     return((Image *) NULL);
+  coalesce_image->background_color.alpha=(Quantum) TransparentAlpha;
   (void) SetImageBackgroundColor(coalesce_image,exception);
   coalesce_image->alpha_trait=next->alpha_trait;
   coalesce_image->page=bounds;
@@ -327,7 +329,7 @@ MagickExport Image *CoalesceImages(const Image *image,ExceptionInfo *exception)
     previous=coalesce_image;
     coalesce_image=GetNextImageInList(coalesce_image);
     (void) CompositeImage(coalesce_image,next,
-      next->alpha_trait == BlendPixelTrait ? OverCompositeOp : CopyCompositeOp,
+      next->alpha_trait != UndefinedPixelTrait ? OverCompositeOp : CopyCompositeOp,
       MagickTrue,next->page.x,next->page.y,exception);
     (void) CloneImageProfiles(coalesce_image,next);
     (void) CloneImageProperties(coalesce_image,next);
@@ -336,7 +338,7 @@ MagickExport Image *CoalesceImages(const Image *image,ExceptionInfo *exception)
     /*
       If a pixel goes opaque to transparent, use background dispose.
     */
-    if (IsBoundsCleared(previous,coalesce_image,&bounds,exception))
+    if (IsBoundsCleared(previous,coalesce_image,&bounds,exception) != MagickFalse)
       coalesce_image->dispose=BackgroundDispose;
     else
       coalesce_image->dispose=NoneDispose;
@@ -358,8 +360,8 @@ MagickExport Image *CoalesceImages(const Image *image,ExceptionInfo *exception)
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
 %  DisposeImages() returns the coalesced frames of a GIF animation as it would
-%  appear after the GIF dispose method of that frame has been applied.  That
-%  is it returned the appearance of each frame before the next is overlaid.
+%  appear after the GIF dispose method of that frame has been applied.  That is
+%  it returned the appearance of each frame before the next is overlaid.
 %
 %  The format of the DisposeImages method is:
 %
@@ -378,22 +380,22 @@ MagickExport Image *DisposeImages(const Image *images,ExceptionInfo *exception)
     *dispose_image,
     *dispose_images;
 
+  RectangleInfo
+    bounds;
+
   register Image
     *image,
     *next;
 
-  RectangleInfo
-    bounds;
-
   /*
     Run the image through the animation sequence
   */
   assert(images != (Image *) NULL);
-  assert(images->signature == MagickSignature);
+  assert(images->signature == MagickCoreSignature);
   if (images->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
   assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
+  assert(exception->signature == MagickCoreSignature);
   image=GetFirstImageInList(images);
   dispose_image=CloneImage(image,image->page.width,image->page.height,
     MagickTrue,exception);
@@ -422,7 +424,7 @@ MagickExport Image *DisposeImages(const Image *images,ExceptionInfo *exception)
         return((Image *) NULL);
       }
     (void) CompositeImage(current_image,next,
-      next->alpha_trait == BlendPixelTrait ? OverCompositeOp : CopyCompositeOp,
+      next->alpha_trait != UndefinedPixelTrait ? OverCompositeOp : CopyCompositeOp,
       MagickTrue,next->page.x,next->page.y,exception);
     /*
       Handle Background dispose: image is displayed for the delay period.
@@ -457,7 +459,7 @@ MagickExport Image *DisposeImages(const Image *images,ExceptionInfo *exception)
       {
         dispose_image=DestroyImage(dispose_image);
         dispose_image=current_image;
-        current_image=(Image *)NULL;
+        current_image=(Image *) NULL;
       }
     /*
       Save the dispose image just calculated for return.
@@ -530,8 +532,8 @@ static MagickBooleanType ComparePixels(const LayerMethod method,
   if (method == CompareAnyLayer)
     return((MagickBooleanType)(IsFuzzyEquivalencePixelInfo(p,q) == MagickFalse));
 
-  o1 = (p->alpha_trait == BlendPixelTrait) ? p->alpha : OpaqueAlpha;
-  o2 = (q->alpha_trait == BlendPixelTrait) ? q->alpha : OpaqueAlpha;
+  o1 = (p->alpha_trait != UndefinedPixelTrait) ? p->alpha : OpaqueAlpha;
+  o2 = (q->alpha_trait != UndefinedPixelTrait) ? q->alpha : OpaqueAlpha;
   /*
     Pixel goes from opaque to transprency.
   */
@@ -624,7 +626,7 @@ static RectangleInfo CompareImagesBounds(const Image *image1,
       if (ComparePixels(method,&pixel1,&pixel2))
         break;
       p+=GetPixelChannels(image1);
-      q++;
+      q+=GetPixelChannels(image2);
     }
     if (y < (ssize_t) image1->rows)
       break;
@@ -655,7 +657,7 @@ static RectangleInfo CompareImagesBounds(const Image *image1,
       if (ComparePixels(method,&pixel1,&pixel2))
         break;
       p+=GetPixelChannels(image1);
-      q++;
+      q+=GetPixelChannels(image2);
     }
     if (y < (ssize_t) image1->rows)
       break;
@@ -675,7 +677,7 @@ static RectangleInfo CompareImagesBounds(const Image *image1,
       if (ComparePixels(method,&pixel1,&pixel2))
         break;
       p+=GetPixelChannels(image1);
-      q++;
+      q+=GetPixelChannels(image2);
     }
     if (x < (ssize_t) image1->columns)
       break;
@@ -695,7 +697,7 @@ static RectangleInfo CompareImagesBounds(const Image *image1,
       if (ComparePixels(method,&pixel1,&pixel2))
         break;
       p+=GetPixelChannels(image1);
-      q++;
+      q+=GetPixelChannels(image2);
     }
     if (x < (ssize_t) image1->columns)
       break;
@@ -760,11 +762,11 @@ MagickExport Image *CompareImagesLayers(const Image *image,
     i;
 
   assert(image != (const Image *) NULL);
-  assert(image->signature == MagickSignature);
+  assert(image->signature == MagickCoreSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
+  assert(exception->signature == MagickCoreSignature);
   assert((method == CompareAnyLayer) ||
          (method == CompareClearLayer) ||
          (method == CompareOverlayLayer));
@@ -831,6 +833,16 @@ MagickExport Image *CompareImagesLayers(const Image *image,
   next=GetNextImageInList(next);
   for ( ; next != (const Image *) NULL; next=GetNextImageInList(next))
   {
+    if ((bounds[i].x == -1) && (bounds[i].y == -1) &&
+        (bounds[i].width == 1) && (bounds[i].height == 1))
+      {
+        /*
+          An empty frame is returned from CompareImageBounds(), which means the
+          current frame is identical to the previous frame.
+        */
+        i++;
+        continue;
+      }
     image_a=CloneImage(next,0,0,MagickTrue,exception);
     if (image_a == (Image *) NULL)
       break;
@@ -934,11 +946,11 @@ static Image *OptimizeLayerFrames(const Image *image,
     i;
 
   assert(image != (const Image *) NULL);
-  assert(image->signature == MagickSignature);
+  assert(image->signature == MagickCoreSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
+  assert(exception->signature == MagickCoreSignature);
   assert(method == OptimizeLayer ||
          method == OptimizeImageLayer ||
          method == OptimizePlusLayer);
@@ -1013,8 +1025,8 @@ static Image *OptimizeLayerFrames(const Image *image,
     Compute the bounding box of changes for each pair of images.
   */
   i=1;
-  bgnd_image=(Image *)NULL;
-  dup_image=(Image *)NULL;
+  bgnd_image=(Image *) NULL;
+  dup_image=(Image *) NULL;
   dup_bounds.width=0;
   dup_bounds.height=0;
   dup_bounds.x=0;
@@ -1267,7 +1279,7 @@ static Image *OptimizeLayerFrames(const Image *image,
         if ( disposals[i-1] != PreviousDispose )
           prev_image=DestroyImage(prev_image);
         if ( disposals[i-1] == BackgroundDispose )
-          prev_image=bgnd_image,  bgnd_image=(Image *)NULL;
+          prev_image=bgnd_image,  bgnd_image=(Image *) NULL;
         if (bgnd_image != (Image *) NULL)
           bgnd_image=DestroyImage(bgnd_image);
         if ( disposals[i-1] == NoneDispose )
@@ -1462,11 +1474,11 @@ MagickExport void OptimizeImageTransparency(const Image *image,
     Run the image through the animation sequence
   */
   assert(image != (Image *) NULL);
-  assert(image->signature == MagickSignature);
+  assert(image->signature == MagickCoreSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
+  assert(exception->signature == MagickCoreSignature);
   next=GetFirstImageInList(image);
   dispose_image=CloneImage(next,next->page.width,next->page.height,
     MagickTrue,exception);
@@ -1493,7 +1505,7 @@ MagickExport void OptimizeImageTransparency(const Image *image,
         dispose_image=DestroyImage(dispose_image);
         return;
       }
-    (void) CompositeImage(current_image,next,next->alpha_trait == BlendPixelTrait ?
+    (void) CompositeImage(current_image,next,next->alpha_trait != UndefinedPixelTrait ?
       OverCompositeOp : CopyCompositeOp,MagickTrue,next->page.x,next->page.y,
       exception);
     /*
@@ -1587,11 +1599,11 @@ MagickExport void RemoveDuplicateLayers(Image **images,
     bounds;
 
   assert((*images) != (const Image *) NULL);
-  assert((*images)->signature == MagickSignature);
+  assert((*images)->signature == MagickCoreSignature);
   if ((*images)->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*images)->filename);
   assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
+  assert(exception->signature == MagickCoreSignature);
 
   curr=GetFirstImageInList(*images);
   for (; (next=GetNextImageInList(curr)) != (Image *) NULL; curr=next)
@@ -1664,11 +1676,11 @@ MagickExport void RemoveZeroDelayLayers(Image **images,
     *i;
 
   assert((*images) != (const Image *) NULL);
-  assert((*images)->signature == MagickSignature);
+  assert((*images)->signature == MagickCoreSignature);
   if ((*images)->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*images)->filename);
   assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
+  assert(exception->signature == MagickCoreSignature);
 
   i=GetFirstImageInList(*images);
   for ( ; i != (Image *) NULL; i=GetNextImageInList(i))
@@ -1762,11 +1774,11 @@ MagickExport void CompositeLayers(Image *destination,
   const ssize_t y_offset,ExceptionInfo *exception)
 {
   assert(destination != (Image *) NULL);
-  assert(destination->signature == MagickSignature);
+  assert(destination->signature == MagickCoreSignature);
   assert(source != (Image *) NULL);
-  assert(source->signature == MagickSignature);
+  assert(source->signature == MagickCoreSignature);
   assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
+  assert(exception->signature == MagickCoreSignature);
   if (source->debug != MagickFalse || destination->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s - %s",
       source->filename, destination->filename);
@@ -1911,11 +1923,11 @@ MagickExport Image *MergeImageLayers(Image *image,const LayerMethod method,
     scene;
 
   assert(image != (Image *) NULL);
-  assert(image->signature == MagickSignature);
+  assert(image->signature == MagickCoreSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
+  assert(exception->signature == MagickCoreSignature);
   /*
     Determine canvas image size, and its virtual canvas size and offset
   */
@@ -1942,7 +1954,7 @@ MagickExport Image *MergeImageLayers(Image *image,const LayerMethod method,
             page.y=next->page.y;
           }
         if ((ssize_t) width < (next->page.x+(ssize_t) next->columns-page.x))
-          width=(size_t) next->page.x+(ssize_t)next->columns-page.x;
+          width=(size_t) next->page.x+(ssize_t) next->columns-page.x;
         if ((ssize_t) height < (next->page.y+(ssize_t) next->rows-page.y))
           height=(size_t) next->page.y+(ssize_t) next->rows-page.y;
       }