]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/image.c
...
[imagemagick] / MagickCore / image.c
index c71a84e567526dbc21761e8d42199ba833114560..44a2f12bc6481d309cfe571796bb8f9ac68af6aa 100644 (file)
 %                                 July 1992                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2017 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  %
 %  obtain a copy of the License at                                            %
 %                                                                             %
-%    http://www.imagemagick.org/script/license.php                            %
+%    https://www.imagemagick.org/script/license.php                           %
 %                                                                             %
 %  Unless required by applicable law or agreed to in writing, software        %
 %  distributed under the License is distributed on an "AS IS" BASIS,          %
@@ -49,6 +49,7 @@
 #include "MagickCore/cache.h"
 #include "MagickCore/cache-private.h"
 #include "MagickCore/cache-view.h"
+#include "MagickCore/channel.h"
 #include "MagickCore/client.h"
 #include "MagickCore/color.h"
 #include "MagickCore/color-private.h"
@@ -59,6 +60,7 @@
 #include "MagickCore/composite-private.h"
 #include "MagickCore/compress.h"
 #include "MagickCore/constitute.h"
+#include "MagickCore/delegate.h"
 #include "MagickCore/display.h"
 #include "MagickCore/draw.h"
 #include "MagickCore/enhance.h"
@@ -192,12 +194,12 @@ MagickExport Image *AcquireImage(const ImageInfo *image_info,
   image->interlace=NoInterlace;
   image->ticks_per_second=UndefinedTicksPerSecond;
   image->compose=OverCompositeOp;
+  (void) QueryColorCompliance(MatteColor,AllCompliance,&image->matte_color,
+    exception);
   (void) QueryColorCompliance(BackgroundColor,AllCompliance,
     &image->background_color,exception);
   (void) QueryColorCompliance(BorderColor,AllCompliance,&image->border_color,
     exception);
-  (void) QueryColorCompliance(MatteColor,AllCompliance,&image->matte_color,
-    exception);
   (void) QueryColorCompliance(TransparentColor,AllCompliance,
     &image->transparent_color,exception);
   GetTimerInfo(&image->timer);
@@ -273,9 +275,9 @@ MagickExport Image *AcquireImage(const ImageInfo *image_info,
   if (image_info->depth != 0)
     image->depth=image_info->depth;
   image->dither=image_info->dither;
+  image->matte_color=image_info->matte_color;
   image->background_color=image_info->background_color;
   image->border_color=image_info->border_color;
-  image->matte_color=image_info->matte_color;
   image->transparent_color=image_info->transparent_color;
   image->ping=image_info->ping;
   image->progress_monitor=image_info->progress_monitor;
@@ -449,6 +451,7 @@ MagickExport Image *AppendImages(const Image *images,
     *append_image;
 
   MagickBooleanType
+    homogeneous_colorspace,
     status;
 
   MagickOffsetType
@@ -464,6 +467,7 @@ MagickExport Image *AppendImages(const Image *images,
     *next;
 
   size_t
+    depth,
     height,
     number_images,
     width;
@@ -486,9 +490,15 @@ MagickExport Image *AppendImages(const Image *images,
   number_images=1;
   width=images->columns;
   height=images->rows;
+  depth=images->depth;
+  homogeneous_colorspace=MagickTrue;
   next=GetNextImageInList(images);
   for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
   {
+    if (next->depth > depth)
+      depth=next->depth;
+    if (next->colorspace != images->colorspace)
+      homogeneous_colorspace=MagickFalse;
     if (next->alpha_trait != UndefinedPixelTrait)
       alpha_trait=BlendPixelTrait;
     number_images++;
@@ -514,7 +524,11 @@ MagickExport Image *AppendImages(const Image *images,
       append_image=DestroyImage(append_image);
       return((Image *) NULL);
     }
+  if (homogeneous_colorspace == MagickFalse)
+    (void) SetImageColorspace(append_image,sRGBColorspace,exception);
+  append_image->depth=depth;
   append_image->alpha_trait=alpha_trait;
+  append_image->page=images->page;
   (void) SetImageBackgroundColor(append_image,exception);
   status=MagickTrue;
   x_offset=0;
@@ -526,28 +540,21 @@ MagickExport Image *AppendImages(const Image *images,
     CacheView
       *image_view;
 
-    Image
-      *image;
-
     MagickBooleanType
       proceed;
 
-    image=CloneImage(next,0,0,MagickTrue,exception);
-    if (image == (Image *) NULL)
-      break;
-    (void) TransformImageColorspace(image,append_image->colorspace,exception);
     SetGeometry(append_image,&geometry);
-    GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
+    GravityAdjustGeometry(next->columns,next->rows,next->gravity,&geometry);
     if (stack != MagickFalse)
       x_offset-=geometry.x;
     else
       y_offset-=geometry.y;
-    image_view=AcquireVirtualCacheView(image,exception);
+    image_view=AcquireVirtualCacheView(next,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
     #pragma omp parallel for schedule(static,4) shared(status) \
-      magick_threads(image,image,image->rows,1)
+      magick_number_threads(next,next,next->rows,1)
 #endif
-    for (y=0; y < (ssize_t) image->rows; y++)
+    for (y=0; y < (ssize_t) next->rows; y++)
     {
       MagickBooleanType
         sync;
@@ -556,37 +563,37 @@ MagickExport Image *AppendImages(const Image *images,
         pixel;
 
       register const Quantum
-        *restrict p;
+        *magick_restrict p;
 
       register Quantum
-        *restrict q;
+        *magick_restrict q;
 
       register ssize_t
         x;
 
       if (status == MagickFalse)
         continue;
-      p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+      p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
       q=QueueCacheViewAuthenticPixels(append_view,x_offset,y+y_offset,
-        image->columns,1,exception);
+        next->columns,1,exception);
       if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
         {
           status=MagickFalse;
           continue;
         }
-      GetPixelInfo(image,&pixel);
-      for (x=0; x < (ssize_t) image->columns; x++)
+      GetPixelInfo(next,&pixel);
+      for (x=0; x < (ssize_t) next->columns; x++)
       {
-        if (GetPixelReadMask(image,p) == 0)
+        if (GetPixelWriteMask(next,p) <= (QuantumRange/2))
           {
             SetPixelBackgoundColor(append_image,q);
-            p+=GetPixelChannels(image);
+            p+=GetPixelChannels(next);
             q+=GetPixelChannels(append_image);
             continue;
           }
-        GetPixelInfoPixel(image,p,&pixel);
+        GetPixelInfoPixel(next,p,&pixel);
         SetPixelViaPixelInfo(append_image,&pixel,q);
-        p+=GetPixelChannels(image);
+        p+=GetPixelChannels(next);
         q+=GetPixelChannels(append_image);
       }
       sync=SyncCacheViewAuthenticPixels(append_view,exception);
@@ -596,15 +603,14 @@ MagickExport Image *AppendImages(const Image *images,
     image_view=DestroyCacheView(image_view);
     if (stack == MagickFalse)
       {
-        x_offset+=(ssize_t) image->columns;
+        x_offset+=(ssize_t) next->columns;
         y_offset=0;
       }
     else
       {
         x_offset=0;
-        y_offset+=(ssize_t) image->rows;
+        y_offset+=(ssize_t) next->rows;
       }
-    image=DestroyImage(image);
     proceed=SetImageProgress(append_image,AppendImageTag,n,number_images);
     if (proceed == MagickFalse)
       break;
@@ -745,11 +751,11 @@ MagickExport MagickBooleanType ClipImagePath(Image *image,const char *pathname,
       if (SetImageStorageClass(clip_mask,DirectClass,exception) == MagickFalse)
         return(MagickFalse);
     }
-  if (inside == MagickFalse)
+  if (inside != MagickFalse)
     (void) NegateImage(clip_mask,MagickFalse,exception);
   (void) FormatLocaleString(clip_mask->magick_filename,MagickPathExtent,
     "8BIM:1999,2998:%s\nPS",pathname);
-  (void) SetImageMask(image,ReadPixelMask,clip_mask,exception);
+  (void) SetImageMask(image,WritePixelMask,clip_mask,exception);
   clip_mask=DestroyImage(clip_mask);
   return(MagickTrue);
 }
@@ -836,20 +842,6 @@ MagickExport Image *CloneImage(const Image *image,const size_t columns,
   clone_image->columns=image->columns;
   clone_image->rows=image->rows;
   clone_image->dither=image->dither;
-  if (image->colormap != (PixelInfo *) NULL)
-    {
-      /*
-        Allocate and copy the image colormap.
-      */
-      clone_image->colors=image->colors;
-      length=(size_t) image->colors;
-      clone_image->colormap=(PixelInfo *) AcquireQuantumMemory(length,
-        sizeof(*clone_image->colormap));
-      if (clone_image->colormap == (PixelInfo *) NULL)
-        ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
-      (void) CopyMagickMemory(clone_image->colormap,image->colormap,length*
-        sizeof(*clone_image->colormap));
-    }
   clone_image->image_info=CloneImageInfo(image->image_info);
   (void) CloneImageProfiles(clone_image,image);
   (void) CloneImageProperties(clone_image,image);
@@ -884,6 +876,23 @@ MagickExport Image *CloneImage(const Image *image,const size_t columns,
   clone_image->ping=image->ping;
   clone_image->debug=IsEventLogging();
   clone_image->semaphore=AcquireSemaphoreInfo();
+  if (image->colormap != (PixelInfo *) NULL)
+    {
+      /*
+        Allocate and copy the image colormap.
+      */
+      clone_image->colors=image->colors;
+      length=(size_t) image->colors;
+      clone_image->colormap=(PixelInfo *) AcquireQuantumMemory(length+1,
+        sizeof(*clone_image->colormap));
+      if (clone_image->colormap == (PixelInfo *) NULL)
+        {
+          clone_image=DestroyImage(clone_image);
+          ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+        }
+      (void) CopyMagickMemory(clone_image->colormap,image->colormap,length*
+        sizeof(*clone_image->colormap));
+    }
   if ((columns == 0) || (rows == 0))
     {
       if (image->montage != (char *) NULL)
@@ -905,9 +914,9 @@ MagickExport Image *CloneImage(const Image *image,const size_t columns,
   clone_image->page.height=(size_t) floor(scale*image->page.height+0.5);
   clone_image->page.y=(ssize_t) ceil(scale*image->page.y-0.5);
   clone_image->tile_offset.y=(ssize_t) ceil(scale*image->tile_offset.y-0.5);
-  clone_image->columns=columns;
-  clone_image->rows=rows;
   clone_image->cache=ClonePixelCache(image->cache);
+  if (SetImageExtent(clone_image,columns,rows,exception) == MagickFalse)
+    clone_image=DestroyImage(clone_image);
   return(clone_image);
 }
 \f
@@ -941,8 +950,6 @@ MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
     *clone_info;
 
   clone_info=AcquireImageInfo();
-  if (image_info == (ImageInfo *) NULL)
-    return(clone_info);
   clone_info->compression=image_info->compression;
   clone_info->temporary=image_info->temporary;
   clone_info->adjoin=image_info->adjoin;
@@ -950,35 +957,42 @@ MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
   clone_info->scene=image_info->scene;
   clone_info->number_scenes=image_info->number_scenes;
   clone_info->depth=image_info->depth;
-  (void) CloneString(&clone_info->size,image_info->size);
-  (void) CloneString(&clone_info->extract,image_info->extract);
-  (void) CloneString(&clone_info->scenes,image_info->scenes);
-  (void) CloneString(&clone_info->page,image_info->page);
+  if (image_info->size != (ImageInfo *) NULL)
+    (void) CloneString(&clone_info->size,image_info->size);
+  if (image_info->extract != (ImageInfo *) NULL)
+    (void) CloneString(&clone_info->extract,image_info->extract);
+  if (image_info->scenes != (ImageInfo *) NULL)
+    (void) CloneString(&clone_info->scenes,image_info->scenes);
+  if (image_info->page != (ImageInfo *) NULL)
+    (void) CloneString(&clone_info->page,image_info->page);
   clone_info->interlace=image_info->interlace;
   clone_info->endian=image_info->endian;
   clone_info->units=image_info->units;
   clone_info->quality=image_info->quality;
-  (void) CloneString(&clone_info->sampling_factor,image_info->sampling_factor);
-  (void) CloneString(&clone_info->server_name,image_info->server_name);
-  (void) CloneString(&clone_info->font,image_info->font);
-  (void) CloneString(&clone_info->texture,image_info->texture);
-  (void) CloneString(&clone_info->density,image_info->density);
+  if (image_info->sampling_factor != (ImageInfo *) NULL)
+    (void) CloneString(&clone_info->sampling_factor,
+      image_info->sampling_factor);
+  if (image_info->server_name != (ImageInfo *) NULL)
+    (void) CloneString(&clone_info->server_name,image_info->server_name);
+  if (image_info->font != (ImageInfo *) NULL)
+    (void) CloneString(&clone_info->font,image_info->font);
+  if (image_info->texture != (ImageInfo *) NULL)
+    (void) CloneString(&clone_info->texture,image_info->texture);
+  if (image_info->density != (ImageInfo *) NULL)
+    (void) CloneString(&clone_info->density,image_info->density);
   clone_info->pointsize=image_info->pointsize;
   clone_info->fuzz=image_info->fuzz;
+  clone_info->matte_color=image_info->matte_color;
   clone_info->background_color=image_info->background_color;
   clone_info->border_color=image_info->border_color;
-  clone_info->matte_color=image_info->matte_color;
   clone_info->transparent_color=image_info->transparent_color;
   clone_info->dither=image_info->dither;
   clone_info->monochrome=image_info->monochrome;
   clone_info->colorspace=image_info->colorspace;
   clone_info->type=image_info->type;
   clone_info->orientation=image_info->orientation;
-  clone_info->preview_type=image_info->preview_type;
-  clone_info->group=image_info->group;
   clone_info->ping=image_info->ping;
   clone_info->verbose=image_info->verbose;
-  (void) CloneString(&clone_info->view,image_info->view);
   clone_info->progress_monitor=image_info->progress_monitor;
   clone_info->client_data=image_info->client_data;
   clone_info->cache=image_info->cache;
@@ -990,11 +1004,11 @@ MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
   SetImageInfoFile(clone_info,image_info->file);
   SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
   clone_info->stream=image_info->stream;
+  clone_info->custom_stream=image_info->custom_stream;
   (void) CopyMagickString(clone_info->magick,image_info->magick,
     MagickPathExtent);
   (void) CopyMagickString(clone_info->unique,image_info->unique,
     MagickPathExtent);
-  (void) CopyMagickString(clone_info->zero,image_info->zero,MagickPathExtent);
   (void) CopyMagickString(clone_info->filename,image_info->filename,
     MagickPathExtent);
   clone_info->channel=image_info->channel;
@@ -1078,7 +1092,7 @@ MagickExport MagickBooleanType CopyImagePixels(Image *image,
   image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   #pragma omp parallel for schedule(static,4) shared(progress,status) \
-    magick_threads(image,source_image,geometry->height,1)
+    magick_number_threads(image,source_image,geometry->height,1)
 #endif
   for (y=0; y < (ssize_t) geometry->height; y++)
   {
@@ -1086,13 +1100,13 @@ MagickExport MagickBooleanType CopyImagePixels(Image *image,
       sync;
 
     register const Quantum
-      *restrict p;
+      *magick_restrict p;
 
     register ssize_t
       x;
 
     register Quantum
-      *restrict q;
+      *magick_restrict q;
 
     if (status == MagickFalse)
       continue;
@@ -1111,11 +1125,12 @@ MagickExport MagickBooleanType CopyImagePixels(Image *image,
         i;
 
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
-      { 
-        PixelChannel channel=GetPixelChannelChannel(image,i);
-        PixelTrait traits=GetPixelChannelTraits(image,channel);
+      {
+        PixelChannel channel = GetPixelChannelChannel(image,i);
+        PixelTrait traits = GetPixelChannelTraits(image,channel);
         PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
         if ((traits == UndefinedPixelTrait) ||
+            ((traits & UpdatePixelTrait) == 0) ||
             (source_traits == UndefinedPixelTrait))
           continue;
         SetPixelChannel(image,channel,p[i],q);
@@ -1265,8 +1280,6 @@ MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
     image_info->texture=DestroyString(image_info->texture);
   if (image_info->density != (char *) NULL)
     image_info->density=DestroyString(image_info->density);
-  if (image_info->view != (char *) NULL)
-    image_info->view=DestroyString(image_info->view);
   if (image_info->cache != (void *) NULL)
     image_info->cache=DestroyPixelCache(image_info->cache);
   if (image_info->profile != (StringInfo *) NULL)
@@ -1415,14 +1428,18 @@ MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
 %
 %  The format of the GetImageMask method is:
 %
-%      Image *GetImageMask(const Image *image,ExceptionInfo *exception)
+%      Image *GetImageMask(const Image *image,const PixelMask type,
+%        ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
+%    o type: the mask type, ReadPixelMask or WritePixelMask.
+%
 */
-MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
+MagickExport Image *GetImageMask(const Image *image,const PixelMask type,
+  ExceptionInfo *exception)
 {
   CacheView
     *mask_view,
@@ -1448,6 +1465,7 @@ MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
   if (mask_image == (Image *) NULL)
     return((Image *) NULL);
   status=MagickTrue;
+  mask_image->alpha_trait=UndefinedPixelTrait;
   (void) SetImageColorspace(mask_image,GRAYColorspace,exception);
   mask_image->read_mask=MagickFalse;
   image_view=AcquireVirtualCacheView(image,exception);
@@ -1455,10 +1473,10 @@ MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register const Quantum
-      *restrict p;
+      *magick_restrict p;
 
     register Quantum
-      *restrict q;
+      *magick_restrict q;
 
     register ssize_t
       x;
@@ -1475,7 +1493,19 @@ MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      SetPixelGray(mask_image,GetPixelReadMask(image,p),q);
+      switch (type)
+      {
+        case WritePixelMask:
+        {
+          SetPixelGray(mask_image,GetPixelWriteMask(image,p),q);
+          break;
+        }
+        default:
+        {
+          SetPixelGray(mask_image,GetPixelReadMask(image,p),q);
+          break;
+        }
+      }
       p+=GetPixelChannels(image);
       q+=GetPixelChannels(mask_image);
     }
@@ -1627,10 +1657,10 @@ MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
     if (*q == '0')
       {
         ssize_t
-          value;
+          foo;
 
-        value=(ssize_t) strtol(q,&q,10);
-        (void) value;
+        foo=(ssize_t) strtol(q,&q,10);
+        (void) foo;
       }
     switch (*q)
     {
@@ -1657,7 +1687,7 @@ MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
           pattern[MagickPathExtent];
 
         const char
-          *value;
+          *option;
 
         register char
           *r;
@@ -1691,20 +1721,20 @@ MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
         pattern[i]='\0';
         if (LocaleNCompare(pattern,"filename:",9) != 0)
           break;
-        value=(const char *) NULL;
+        option=(const char *) NULL;
         if (image != (Image *) NULL)
-          value=GetImageProperty(image,pattern,exception);
-        if ((value == (const char *) NULL) && (image != (Image *) NULL))
-          value=GetImageArtifact(image,pattern);
-        if ((value == (const char *) NULL) &&
+          option=GetImageProperty(image,pattern,exception);
+        if ((option == (const char *) NULL) && (image != (Image *) NULL))
+          option=GetImageArtifact(image,pattern);
+        if ((option == (const char *) NULL) &&
             (image_info != (ImageInfo *) NULL))
-          value=GetImageOption(image_info,pattern);
-        if (value == (const char *) NULL)
+          option=GetImageOption(image_info,pattern);
+        if (option == (const char *) NULL)
           break;
         q--;
         c=(*q);
         *q='\0';
-        (void) CopyMagickString(filename+(p-format-length),value,(size_t)
+        (void) CopyMagickString(filename+(p-format-length),option,(size_t)
           (MagickPathExtent-(p-format-length)));
         length+=strlen(pattern)-1;
         *q=c;
@@ -1782,7 +1812,7 @@ MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
   image_view=AcquireVirtualCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   #pragma omp parallel for schedule(static,4) shared(status) \
-    magick_threads(image,image,image->rows,1)
+    magick_number_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -1805,7 +1835,7 @@ MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
       register ssize_t
         i;
 
-      if (GetPixelReadMask(image,p) == 0)
+      if (GetPixelWriteMask(image,p) <= (QuantumRange/2))
         {
           p+=GetPixelChannels(image);
           continue;
@@ -2037,12 +2067,12 @@ MagickExport Image *NewMagickImage(const ImageInfo *image_info,
   image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   #pragma omp parallel for schedule(static,4) shared(status) \
-    magick_threads(image,image,image->rows,1)
+    magick_number_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register Quantum
-      *restrict q;
+      *magick_restrict q;
 
     register ssize_t
       x;
@@ -2178,6 +2208,84 @@ MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
 %                                                                             %
 %                                                                             %
 %                                                                             %
+%     S e t I m a g e A l p h a                                               %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageAlpha() sets the alpha levels of the image.
+%
+%  The format of the SetImageAlpha method is:
+%
+%      MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
+%        ExceptionInfo *exception)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o Alpha: the level of transparency: 0 is fully opaque and QuantumRange is
+%      fully transparent.
+%
+*/
+MagickExport MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
+  ExceptionInfo *exception)
+{
+  CacheView
+    *image_view;
+
+  MagickBooleanType
+    status;
+
+  ssize_t
+    y;
+
+  assert(image != (Image *) NULL);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
+  assert(image->signature == MagickCoreSignature);
+  image->alpha_trait=BlendPixelTrait;
+  status=MagickTrue;
+  image_view=AcquireAuthenticCacheView(image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+  #pragma omp parallel for schedule(static,4) shared(status) \
+    magick_number_threads(image,image,image->rows,1)
+#endif
+  for (y=0; y < (ssize_t) image->rows; y++)
+  {
+    register Quantum
+      *magick_restrict q;
+
+    register ssize_t
+      x;
+
+    if (status == MagickFalse)
+      continue;
+    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+    if (q == (Quantum *) NULL)
+      {
+        status=MagickFalse;
+        continue;
+      }
+    for (x=0; x < (ssize_t) image->columns; x++)
+    {
+      if (GetPixelWriteMask(image,q) > (QuantumRange/2))
+        SetPixelAlpha(image,alpha,q);
+      q+=GetPixelChannels(image);
+    }
+    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+      status=MagickFalse;
+  }
+  image_view=DestroyCacheView(image_view);
+  return(status);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 %   S e t I m a g e B a c k g r o u n d C o l o r                             %
 %                                                                             %
 %                                                                             %
@@ -2221,6 +2329,9 @@ MagickExport MagickBooleanType SetImageBackgroundColor(Image *image,
   assert(image->signature == MagickCoreSignature);
   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
+  if ((image->background_color.alpha != OpaqueAlpha) &&
+      (image->alpha_trait == UndefinedPixelTrait))
+    (void) SetImageAlphaChannel(image,OnAlphaChannel,exception);
   ConformPixelInfo(image,&image->background_color,&background,exception);
   /*
     Set image background color.
@@ -2230,7 +2341,7 @@ MagickExport MagickBooleanType SetImageBackgroundColor(Image *image,
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register Quantum
-      *restrict q;
+      *magick_restrict q;
 
     register ssize_t
       x;
@@ -2339,12 +2450,12 @@ MagickExport MagickBooleanType SetImageColor(Image *image,
   image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   #pragma omp parallel for schedule(static,4) shared(status) \
-    magick_threads(image,image,image->rows,1)
+    magick_number_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register Quantum
-      *restrict q;
+      *magick_restrict q;
 
     register ssize_t
       x;
@@ -2400,6 +2511,12 @@ MagickExport MagickBooleanType SetImageColor(Image *image,
 MagickExport MagickBooleanType SetImageStorageClass(Image *image,
   const ClassType storage_class,ExceptionInfo *exception)
 {
+  assert(image != (Image *) NULL);
+  assert(image->signature == MagickCoreSignature);
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickCoreSignature);
   image->storage_class=storage_class;
   return(SyncImagePixelCache(image,exception));
 }
@@ -2437,7 +2554,7 @@ MagickExport MagickBooleanType SetImageExtent(Image *image,const size_t columns,
   const size_t rows,ExceptionInfo *exception)
 {
   if ((columns == 0) || (rows == 0))
-    return(MagickFalse);
+    ThrowBinaryException(ImageError,"NegativeOrZeroImageSize",image->filename);
   image->columns=columns;
   image->rows=rows;
   if (image->depth > (8*sizeof(MagickSizeType)))
@@ -2606,7 +2723,6 @@ MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
           "BROWSE",
           "DCRAW",
           "EDIT",
-          "EPHEMERAL",
           "LAUNCH",
           "MPEG:DECODE",
           "MPEG:ENCODE",
@@ -2661,29 +2777,40 @@ MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
   *magic='\0';
   GetPathComponent(image_info->filename,MagickPath,magic);
   if (*magic == '\0')
-    (void) CopyMagickString(magic,image_info->magick,MagickPathExtent);
+    {
+      (void) CopyMagickString(magic,image_info->magick,MagickPathExtent);
+      magick_info=GetMagickInfo(magic,sans_exception);
+      GetPathComponent(image_info->filename,CanonicalPath,component);
+      (void) CopyMagickString(image_info->filename,component,MagickPathExtent);
+    }
   else
     {
+      const DelegateInfo
+        *delegate_info;
+
       /*
         User specified image format.
       */
       LocaleUpper(magic);
-      if (IsMagickConflict(magic) == MagickFalse)
+      magick_info=GetMagickInfo(magic,sans_exception);
+      delegate_info=GetDelegateInfo(magic,"*",sans_exception);
+      if (delegate_info == (const DelegateInfo *) NULL)
+        delegate_info=GetDelegateInfo("*",magic,sans_exception);
+      if (((magick_info != (const MagickInfo *) NULL) ||
+           (delegate_info != (const DelegateInfo *) NULL)) &&
+          (IsMagickConflict(magic) == MagickFalse))
         {
+          image_info->affirm=MagickTrue;
           (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
-          if (LocaleCompare(magic,"EPHEMERAL") != 0)
-            image_info->affirm=MagickTrue;
-          else
-            image_info->temporary=MagickTrue;
+          GetPathComponent(image_info->filename,CanonicalPath,component);
+          (void) CopyMagickString(image_info->filename,component,
+            MagickPathExtent);
         }
     }
-  magick_info=GetMagickInfo(magic,sans_exception);
   sans_exception=DestroyExceptionInfo(sans_exception);
   if ((magick_info == (const MagickInfo *) NULL) ||
       (GetMagickEndianSupport(magick_info) == MagickFalse))
     image_info->endian=UndefinedEndian;
-  GetPathComponent(image_info->filename,CanonicalPath,component);
-  (void) CopyMagickString(image_info->filename,component,MagickPathExtent);
   if ((image_info->adjoin != MagickFalse) && (frames > 1))
     {
       /*
@@ -2851,6 +2978,42 @@ MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
 %                                                                             %
 %                                                                             %
 %                                                                             %
+%   S e t I m a g e I n f o C u s t o m S t r e a m                           %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageInfoCustomStream() sets the image info custom stream handlers.
+%
+%  The format of the SetImageInfoCustomStream method is:
+%
+%      void SetImageInfoCustomStream(ImageInfo *image_info,
+%        CustomStreamInfo *custom_stream)
+%
+%  A description of each parameter follows:
+%
+%    o image_info: the image info.
+%
+%    o custom_stream: your custom stream methods.
+%
+*/
+MagickExport void SetImageInfoCustomStream(ImageInfo *image_info,
+  CustomStreamInfo *custom_stream)
+{
+  assert(image_info != (ImageInfo *) NULL);
+  assert(image_info->signature == MagickCoreSignature);
+  if (image_info->debug != MagickFalse)
+    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
+      image_info->filename);
+  image_info->custom_stream=(CustomStreamInfo *) custom_stream;
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 %   S e t I m a g e I n f o F i l e                                           %
 %                                                                             %
 %                                                                             %
@@ -2951,15 +3114,15 @@ MagickExport MagickBooleanType SetImageMask(Image *image,const PixelMask type,
   image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   #pragma omp parallel for schedule(static,4) shared(status) \
-    magick_threads(mask,image,1,1)
+    magick_number_threads(mask,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register const Quantum
-      *restrict p;
+      *magick_restrict p;
 
     register Quantum
-      *restrict q;
+      *magick_restrict q;
 
     register ssize_t
       x;
@@ -2975,16 +3138,22 @@ MagickExport MagickBooleanType SetImageMask(Image *image,const PixelMask type,
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
+      MagickRealType
+        intensity;
+
+      intensity=0;
+      if ((x < (ssize_t) mask->columns) && (y < (ssize_t) mask->rows))
+        intensity=GetPixelIntensity(mask,p);
       switch (type)
       {
         case WritePixelMask:
         {
-          SetPixelWriteMask(image,ClampToQuantum(GetPixelIntensity(mask,p)),q);
+          SetPixelWriteMask(image,ClampToQuantum(intensity),q);
           break;
         }
         default:
         {
-          SetPixelReadMask(image,ClampToQuantum(GetPixelIntensity(mask,p)),q);
+          SetPixelReadMask(image,ClampToQuantum(intensity),q);
           break;
         }
       }
@@ -3004,29 +3173,33 @@ MagickExport MagickBooleanType SetImageMask(Image *image,const PixelMask type,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-%     S e t I m a g e A l p h a                                               %
+%   S e t I m a g e R e g i o n M a s k                                       %
 %                                                                             %
 %                                                                             %
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  SetImageAlpha() sets the alpha levels of the image.
+%  SetImageRegionMask() associates a mask with the image as defined by the
+%  specified region.
 %
-%  The format of the SetImageAlpha method is:
+%  The format of the SetImageRegionMask method is:
 %
-%      MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
-%        ExceptionInfo *exception)
+%      MagickBooleanType SetImageRegionMask(Image *image,const PixelMask type,
+%        const RectangleInfo *region,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
 %    o image: the image.
 %
-%    o Alpha: the level of transparency: 0 is fully opaque and QuantumRange is
-%      fully transparent.
+%    o type: the mask type, ReadPixelMask or WritePixelMask.
+%
+%    o geometry: the mask region.
+%
+%    o exception: return any errors or warnings in this structure.
 %
 */
-MagickExport MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
-  ExceptionInfo *exception)
+MagickExport MagickBooleanType SetImageRegionMask(Image *image,
+  const PixelMask type,const RectangleInfo *region,ExceptionInfo *exception)
 {
   CacheView
     *image_view;
@@ -3037,21 +3210,39 @@ MagickExport MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
   ssize_t
     y;
 
+  /*
+    Set image mask as defined by the region.
+  */
   assert(image != (Image *) NULL);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
   assert(image->signature == MagickCoreSignature);
-  image->alpha_trait=BlendPixelTrait;
+  if (region == (const RectangleInfo *) NULL)
+    {
+      switch (type)
+      {
+        case WritePixelMask: image->write_mask=MagickFalse; break;
+        default: image->read_mask=MagickFalse; break;
+      }
+      return(SyncImagePixelCache(image,exception));
+    }
+  switch (type)
+  {
+    case WritePixelMask: image->write_mask=MagickTrue; break;
+    default: image->read_mask=MagickTrue; break;
+  }
+  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
+    return(MagickFalse);
   status=MagickTrue;
   image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   #pragma omp parallel for schedule(static,4) shared(status) \
-    magick_threads(image,image,image->rows,1)
+    magick_number_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register Quantum
-      *restrict q;
+      *magick_restrict q;
 
     register ssize_t
       x;
@@ -3066,8 +3257,26 @@ MagickExport MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      if (GetPixelReadMask(image,q) != 0)
-        SetPixelAlpha(image,alpha,q);
+      Quantum
+        pixel;
+
+      pixel=0;
+      if (((x >= region->x) && (x < (region->x+(ssize_t) region->width))) &&
+          ((y >= region->y) && (y < (region->y+(ssize_t) region->height))))
+        pixel=QuantumRange;
+      switch (type)
+      {
+        case WritePixelMask:
+        {
+          SetPixelWriteMask(image,pixel,q);
+          break;
+        }
+        default:
+        {
+          SetPixelReadMask(image,pixel,q);
+          break;
+        }
+      }
       q+=GetPixelChannels(image);
     }
     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
@@ -3458,7 +3667,7 @@ MagickExport MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
   (void) DeleteImageProperty(image,"date:create");
   (void) DeleteImageProperty(image,"date:modify");
   status=SetImageArtifact(image,"png:exclude-chunk",
-    "EXIF,iCCP,iTXt,sRGB,tEXt,zCCP,zTXt,date");
+    "bKGD,caNv,cHRM,eXIf,gAMA,iCCP,iTXt,pHYs,sRGB,tEXt,zCCP,zTXt,date");
   return(status);
 }
 \f
@@ -3514,15 +3723,18 @@ MagickExport MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
   assert(image->signature == MagickCoreSignature);
-  if (image->storage_class == DirectClass)
+  if (image->ping != MagickFalse)
+    return(MagickTrue);
+  if (image->storage_class != PseudoClass)
     return(MagickFalse);
+  assert(image->colormap != (PixelInfo *) NULL);
   range_exception=MagickFalse;
   status=MagickTrue;
   taint=image->taint;
   image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   #pragma omp parallel for schedule(static,4) shared(range_exception,status) \
-    magick_threads(image,image,image->rows,1)
+    magick_number_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -3530,7 +3742,7 @@ MagickExport MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
       index;
 
     register Quantum
-      *restrict q;
+      *magick_restrict q;
 
     register ssize_t
       x;
@@ -3555,8 +3767,8 @@ MagickExport MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
   image_view=DestroyCacheView(image_view);
   image->taint=taint;
   if ((image->ping == MagickFalse) && (range_exception != MagickFalse))
-    (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
-      "InvalidColormapIndex","`%s'",image->filename);
+    (void) ThrowMagickException(exception,GetMagickModule(),
+      CorruptImageWarning,"InvalidColormapIndex","`%s'",image->filename);
   return(status);
 }
 \f
@@ -3678,9 +3890,6 @@ MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
   option=GetImageOption(image_info,"density");
   if (option != (const char *) NULL)
     {
-      GeometryInfo
-        geometry_info;
-
       flags=ParseGeometry(option,&geometry_info);
       image->resolution.x=geometry_info.rho;
       image->resolution.y=geometry_info.sigma;
@@ -3696,7 +3905,7 @@ MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
       MagickFalse,option);
   option=GetImageOption(image_info,"filter");
   if (option != (const char *) NULL)
-    image->filter=(FilterTypes) ParseCommandOption(MagickFilterOptions,
+    image->filter=(FilterType) ParseCommandOption(MagickFilterOptions,
       MagickFalse,option);
   option=GetImageOption(image_info,"fuzz");
   if (option != (const char *) NULL)