]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/image.c
(no commit message)
[imagemagick] / MagickCore / image.c
index c6fb3eed3c8f9d361d0d8e7340119505a5753a62..1050897de6367b45dc1f683d53f6cfb507295682 100644 (file)
@@ -17,7 +17,7 @@
 %                                 July 1992                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2013 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  %
@@ -83,6 +83,7 @@
 #include "MagickCore/property.h"
 #include "MagickCore/quantize.h"
 #include "MagickCore/random_.h"
+#include "MagickCore/resource_.h"
 #include "MagickCore/segment.h"
 #include "MagickCore/semaphore.h"
 #include "MagickCore/signature-private.h"
@@ -174,16 +175,20 @@ MagickExport Image *AcquireImage(const ImageInfo *image_info,
   image->storage_class=DirectClass;
   image->depth=MAGICKCORE_QUANTUM_DEPTH;
   image->colorspace=sRGBColorspace;
-  image->rendering_intent=RelativeIntent;
-  image->gamma=0.45455;
-  image->chromaticity.red_primary.x=0.6400;
-  image->chromaticity.red_primary.y=0.3300;
-  image->chromaticity.green_primary.x=0.3000;
-  image->chromaticity.green_primary.y=0.6000;
-  image->chromaticity.blue_primary.x=0.1500;
-  image->chromaticity.blue_primary.y=0.0600;
-  image->chromaticity.white_point.x=0.3127;
-  image->chromaticity.white_point.y=0.3290;
+  image->rendering_intent=PerceptualIntent;
+  image->gamma=1.000f/2.200f;
+  image->chromaticity.red_primary.x=0.6400f;
+  image->chromaticity.red_primary.y=0.3300f;
+  image->chromaticity.red_primary.z=0.0300f;
+  image->chromaticity.green_primary.x=0.3000f;
+  image->chromaticity.green_primary.y=0.6000f;
+  image->chromaticity.green_primary.z=0.1000f;
+  image->chromaticity.blue_primary.x=0.1500f;
+  image->chromaticity.blue_primary.y=0.0600f;
+  image->chromaticity.blue_primary.z=0.7900f;
+  image->chromaticity.white_point.x=0.3127f;
+  image->chromaticity.white_point.y=0.3290f;
+  image->chromaticity.white_point.z=0.3583f;
   image->interlace=NoInterlace;
   image->ticks_per_second=UndefinedTicksPerSecond;
   image->compose=OverCompositeOp;
@@ -195,14 +200,12 @@ MagickExport Image *AcquireImage(const ImageInfo *image_info,
     exception);
   (void) QueryColorCompliance(TransparentColor,AllCompliance,
     &image->transparent_color,exception);
-  image->resolution.x=DefaultResolution;
-  image->resolution.y=DefaultResolution;
-  image->units=PixelsPerInchResolution;
   GetTimerInfo(&image->timer);
   image->cache=AcquirePixelCache(0);
   image->channel_mask=DefaultChannels;
   image->channel_map=AcquirePixelChannelMap();
   image->blob=CloneBlobInfo((BlobInfo *) NULL);
+  image->timestamp=time((time_t *) NULL);
   image->debug=IsEventLogging();
   image->reference_count=1;
   image->semaphore=AllocateSemaphoreInfo();
@@ -278,7 +281,14 @@ MagickExport Image *AcquireImage(const ImageInfo *image_info,
   image->client_data=image_info->client_data;
   if (image_info->cache != (void *) NULL)
     ClonePixelCacheMethods(image->cache,image_info->cache);
+  /*
+    Set all global options that map to per-image settings.
+  */
   (void) SyncImageSettings(image_info,image,exception);
+  /*
+    Global options that are only set for new images.
+  */
+  image->image_info=(ImageInfo *) NULL;
   option=GetImageOption(image_info,"delay");
   if (option != (const char *) NULL)
     {
@@ -433,23 +443,20 @@ MagickExport Image *AppendImages(const Image *images,
 #define AppendImageTag  "Append/Image"
 
   CacheView
-    *append_view,
-    *image_view;
-
-  const Image
-    *image;
+    *append_view;
 
   Image
     *append_image;
 
   MagickBooleanType
-    matte,
-    proceed,
     status;
 
   MagickOffsetType
     n;
 
+  PixelTrait
+    alpha_trait;
+
   RectangleInfo
     geometry;
 
@@ -475,16 +482,15 @@ MagickExport Image *AppendImages(const Image *images,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
-  image=images;
-  matte=image->matte;
+  alpha_trait=images->alpha_trait;
   number_images=1;
-  width=image->columns;
-  height=image->rows;
-  next=GetNextImageInList(image);
+  width=images->columns;
+  height=images->rows;
+  next=GetNextImageInList(images);
   for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
   {
-    if (next->matte != MagickFalse)
-      matte=MagickTrue;
+    if (next->alpha_trait == BlendPixelTrait)
+      alpha_trait=BlendPixelTrait;
     number_images++;
     if (stack != MagickFalse)
       {
@@ -500,7 +506,7 @@ MagickExport Image *AppendImages(const Image *images,
   /*
     Append images.
   */
-  append_image=CloneImage(image,width,height,MagickTrue,exception);
+  append_image=CloneImage(images,width,height,MagickTrue,exception);
   if (append_image == (Image *) NULL)
     return((Image *) NULL);
   if (SetImageStorageClass(append_image,DirectClass,exception) == MagickFalse)
@@ -508,26 +514,38 @@ MagickExport Image *AppendImages(const Image *images,
       append_image=DestroyImage(append_image);
       return((Image *) NULL);
     }
-  append_image->matte=matte;
+  append_image->alpha_trait=alpha_trait;
   (void) SetImageBackgroundColor(append_image,exception);
   status=MagickTrue;
   x_offset=0;
   y_offset=0;
-  append_view=AcquireCacheView(append_image);
+  next=images;
+  append_view=AcquireAuthenticCacheView(append_image,exception);
   for (n=0; n < (MagickOffsetType) number_images; n++)
   {
-    if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
-        (IsGrayColorspace(append_image->colorspace) != MagickFalse))
-      (void) TransformImageColorspace(append_image,sRGBColorspace,exception);
+    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);
     if (stack != MagickFalse)
       x_offset-=geometry.x;
     else
       y_offset-=geometry.y;
-    image_view=AcquireCacheView(image);
+    image_view=AcquireVirtualCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-    #pragma omp parallel for schedule(static) shared(status)
+    #pragma omp parallel for schedule(static,4) shared(status) \
+      magick_threads(image,image,image->rows,1)
 #endif
     for (y=0; y < (ssize_t) image->rows; y++)
     {
@@ -575,9 +593,6 @@ MagickExport Image *AppendImages(const Image *images,
         status=MagickFalse;
     }
     image_view=DestroyCacheView(image_view);
-    proceed=SetImageProgress(image,AppendImageTag,n,number_images);
-    if (proceed == MagickFalse)
-      break;
     if (stack == MagickFalse)
       {
         x_offset+=(ssize_t) image->columns;
@@ -588,7 +603,11 @@ MagickExport Image *AppendImages(const Image *images,
         x_offset=0;
         y_offset+=(ssize_t) image->rows;
       }
-    image=GetNextImageInList(image);
+    image=DestroyImage(image);
+    proceed=SetImageProgress(append_image,AppendImageTag,n,number_images);
+    if (proceed == MagickFalse)
+      break;
+    next=GetNextImageInList(next);
   }
   append_view=DestroyCacheView(append_view);
   if (status == MagickFalse)
@@ -777,7 +796,7 @@ MagickExport Image *CloneImage(const Image *image,const size_t columns,
   Image
     *clone_image;
 
-  MagickRealType
+  double
     scale;
 
   size_t
@@ -803,7 +822,7 @@ MagickExport Image *CloneImage(const Image *image,const size_t columns,
   clone_image->metacontent_extent=image->metacontent_extent;
   clone_image->colorspace=image->colorspace;
   clone_image->mask=image->mask;
-  clone_image->matte=image->matte;
+  clone_image->alpha_trait=image->alpha_trait;
   clone_image->columns=image->columns;
   clone_image->rows=image->rows;
   clone_image->dither=image->dither;
@@ -862,11 +881,11 @@ MagickExport Image *CloneImage(const Image *image,const size_t columns,
       clone_image->cache=ReferencePixelCache(image->cache);
       return(clone_image);
     }
-  scale=(MagickRealType) columns/(MagickRealType) image->columns;
+  scale=(double) columns/(double) image->columns;
   clone_image->page.width=(size_t) floor(scale*image->page.width+0.5);
   clone_image->page.x=(ssize_t) ceil(scale*image->page.x-0.5);
   clone_image->tile_offset.x=(ssize_t) ceil(scale*image->tile_offset.x-0.5);
-  scale=(MagickRealType) rows/(MagickRealType) image->rows;
+  scale=(double) rows/(double) image->rows;
   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);
@@ -1160,7 +1179,7 @@ MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
   assert(image->signature == MagickSignature);
-  return(image->matte);
+  return(image->alpha_trait == BlendPixelTrait ? MagickTrue : MagickFalse);
 }
 \f
 /*
@@ -1187,6 +1206,9 @@ MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
 */
 MagickExport void GetImageInfo(ImageInfo *image_info)
 {
+  char
+    *synchronize;
+
   ExceptionInfo
     *exception;
 
@@ -1202,8 +1224,12 @@ MagickExport void GetImageInfo(ImageInfo *image_info)
   image_info->quality=UndefinedCompressionQuality;
   image_info->antialias=MagickTrue;
   image_info->dither=MagickTrue;
-  image_info->synchronize=IsStringTrue(GetEnvironmentValue(
-         "MAGICK_SYNCHRONIZE"));
+  synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
+  if (synchronize != (const char *) NULL)
+    {
+      image_info->synchronize=IsStringTrue(synchronize);
+      synchronize=DestroyString(synchronize);
+    }
   exception=AcquireExceptionInfo();
   (void) QueryColorCompliance(BackgroundColor,AllCompliance,
     &image_info->background_color,exception);
@@ -1293,10 +1319,10 @@ MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
   if (mask_image == (Image *) NULL)
     return((Image *) NULL);
   status=MagickTrue;
-  mask_image->colorspace=GRAYColorspace;
+  (void) SetImageColorspace(mask_image,GRAYColorspace,exception);
   mask_image->mask=MagickFalse;
-  image_view=AcquireCacheView(image);
-  mask_view=AcquireCacheView(mask_image);
+  image_view=AcquireVirtualCacheView(image,exception);
+  mask_view=AcquireAuthenticCacheView(mask_image,exception);
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register const Quantum
@@ -1329,6 +1355,8 @@ MagickExport Image *GetImageMask(const Image *image,ExceptionInfo *exception)
   }
   mask_view=DestroyCacheView(mask_view);
   image_view=DestroyCacheView(image_view);
+  if (status == MagickFalse)
+    mask_image=DestroyImage(mask_image);
   return(mask_image);
 }
 \f
@@ -1514,6 +1542,9 @@ MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
         /*
           Image option.
         */
+        /* FUTURE: Compare update with code from InterpretImageProperties()
+           Note that a 'filename:' property should not need depth recursion.
+        */
         if (strchr(p,']') == (char *) NULL)
           break;
         depth=1;
@@ -1532,15 +1563,23 @@ MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
         if (LocaleNCompare(pattern,"filename:",9) != 0)
           break;
         value=(const char *) NULL;
+#if 0
+        // FUTURE: remove this code. -- Anthony  29 Arpil 2012
+        // Removed as GetMagickProperty() will will never match a "filename:"
+        // string as this is not a 'known' image property.
+        //
         if ((image_info != (const ImageInfo *) NULL) &&
             (image != (const Image *) NULL))
           value=GetMagickProperty(image_info,image,pattern,exception);
         else
-          if (image != (Image *) NULL)
-            value=GetImageProperty(image,pattern,exception);
-          else
-            if (image_info != (ImageInfo *) NULL)
-              value=GetImageOption(image_info,pattern);
+#endif
+        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) &&
+            (image_info != (ImageInfo *) NULL))
+          value=GetImageOption(image_info,pattern);
         if (value == (const char *) NULL)
           break;
         q--;
@@ -1621,9 +1660,10 @@ MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   status=MagickTrue;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireVirtualCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(status)
+  #pragma omp parallel for schedule(static,4) shared(status) \
+    magick_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -1643,9 +1683,6 @@ MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      PixelTrait
-        traits;
-
       register ssize_t
         i;
 
@@ -1656,13 +1693,16 @@ MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
         }
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
-        MagickRealType
+        double
           pixel;
 
-        traits=GetPixelChannelMapTraits(image,i);
+        PixelTrait
+          traits;
+
+        traits=GetPixelChannelTraits(image,(PixelChannel) i);
         if (traits == UndefinedPixelTrait)
           continue;
-        pixel=(MagickRealType) p[i];
+        pixel=(double) p[i];
         if ((pixel < 0.0) || (pixel > QuantumRange) ||
             (pixel != (QuantumAny) pixel))
           break;
@@ -1871,13 +1911,14 @@ MagickExport Image *NewMagickImage(const ImageInfo *image_info,
   image->columns=width;
   image->rows=height;
   image->colorspace=background->colorspace;
-  image->matte=background->matte;
+  image->alpha_trait=background->alpha_trait;
   image->fuzz=background->fuzz;
   image->depth=background->depth;
   status=MagickTrue;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(status)
+  #pragma omp parallel for schedule(static,4) shared(status) \
+    magick_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -2030,7 +2071,7 @@ MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
 %  The format of the SetImageAlphaChannel method is:
 %
 %      MagickBooleanType SetImageAlphaChannel(Image *image,
-%        const AlphaChannelType alpha_type,ExceptionInfo *exception)
+%        const AlphaChannelOption alpha_type,ExceptionInfo *exception)
 %
 %  A description of each parameter follows:
 %
@@ -2046,10 +2087,10 @@ MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
 */
 
 static inline void FlattenPixelInfo(const Image *image,const PixelInfo *p,
-  const MagickRealType alpha,const Quantum *q,const MagickRealType beta,
+  const double alpha,const Quantum *q,const double beta,
   Quantum *composite)
 {
-  MagickRealType
+  double
     Da,
     gamma,
     Sa;
@@ -2063,43 +2104,37 @@ static inline void FlattenPixelInfo(const Image *image,const PixelInfo *p,
   Sa=QuantumScale*alpha;
   Da=QuantumScale*beta,
   gamma=Sa*(-Da)+Sa+Da;
-  gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
+  gamma=PerceptibleReciprocal(gamma);
   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   {
-    PixelChannel
-      channel;
-
-    PixelTrait
-      traits;
-
-    channel=GetPixelChannelMapChannel(image,i);
-    traits=GetPixelChannelMapTraits(image,channel);
+    PixelChannel channel=GetPixelChannelChannel(image,i);
+    PixelTrait traits=GetPixelChannelTraits(image,channel);
     if (traits == UndefinedPixelTrait)
       continue;
     switch (channel)
     {
       case RedPixelChannel:
       {
-        composite[i]=ClampToQuantum(gamma*MagickOver_((MagickRealType) q[i],
-          beta,(MagickRealType) p->red,alpha));
+        composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
+          (double) p->red,alpha));
         break;
       }
       case GreenPixelChannel:
       {
-        composite[i]=ClampToQuantum(gamma*MagickOver_((MagickRealType) q[i],
-          beta,(MagickRealType) p->green,alpha));
+        composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
+          (double) p->green,alpha));
         break;
       }
       case BluePixelChannel:
       {
-        composite[i]=ClampToQuantum(gamma*MagickOver_((MagickRealType) q[i],
-          beta,(MagickRealType) p->blue,alpha));
+        composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
+          (double) p->blue,alpha));
         break;
       }
       case BlackPixelChannel:
       {
-        composite[i]=ClampToQuantum(gamma*MagickOver_((MagickRealType) q[i],
-          beta,(MagickRealType) p->black,alpha));
+        composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
+          (double) p->black,alpha));
         break;
       }
       case AlphaPixelChannel:
@@ -2114,7 +2149,7 @@ static inline void FlattenPixelInfo(const Image *image,const PixelInfo *p,
 }
 
 MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
-  const AlphaChannelType alpha_type,ExceptionInfo *exception)
+  const AlphaChannelOption alpha_type,ExceptionInfo *exception)
 {
   MagickBooleanType
     status;
@@ -2128,7 +2163,7 @@ MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
   {
     case ActivateAlphaChannel:
     {
-      image->matte=MagickTrue;
+      image->alpha_trait=BlendPixelTrait;
       break;
     }
     case BackgroundAlphaChannel:
@@ -2142,13 +2177,14 @@ MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
       /*
         Set transparent pixels to background color.
       */
-      if (image->matte == MagickFalse)
+      if (image->alpha_trait != BlendPixelTrait)
         break;
       if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
         break;
-      image_view=AcquireCacheView(image);
+      image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-      #pragma omp parallel for schedule(static,4) shared(status)
+      #pragma omp parallel for schedule(static,4) shared(status) \
+        magick_threads(image,image,image->rows,1)
 #endif
       for (y=0; y < (ssize_t) image->rows; y++)
       {
@@ -2170,7 +2206,10 @@ MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
         for (x=0; x < (ssize_t) image->columns; x++)
         {
           if (GetPixelAlpha(image,q) == TransparentAlpha)
-            SetPixelInfoPixel(image,&image->background_color,q);
+            {
+              SetPixelInfoPixel(image,&image->background_color,q);
+              SetPixelChannel(image,AlphaPixelChannel,TransparentAlpha,q);
+            }
           q+=GetPixelChannels(image);
         }
         if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
@@ -2194,14 +2233,14 @@ MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
     }
     case DeactivateAlphaChannel:
     {
-      image->matte=MagickFalse;
+      image->alpha_trait=CopyPixelTrait;
       break;
     }
     case ExtractAlphaChannel:
     {
       status=CompositeImage(image,image,AlphaCompositeOp,MagickTrue,0,0,
         exception);
-      image->matte=MagickFalse;
+      image->alpha_trait=CopyPixelTrait;
       break;
     }
     case OpaqueAlphaChannel:
@@ -2220,13 +2259,14 @@ MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
       /*
         Remove transparency.
       */
-      if (image->matte == MagickFalse)
+      if (image->alpha_trait != BlendPixelTrait)
         break;
       if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
         break;
-      image_view=AcquireCacheView(image);
+      image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-      #pragma omp parallel for schedule(static,4) shared(status)
+      #pragma omp parallel for schedule(static,4) shared(status) \
+        magick_threads(image,image,image->rows,1)
 #endif
       for (y=0; y < (ssize_t) image->rows; y++)
       {
@@ -2248,7 +2288,7 @@ MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
         for (x=0; x < (ssize_t) image->columns; x++)
         {
           FlattenPixelInfo(image,&image->background_color,
-            image->background_color.alpha,q,(MagickRealType)
+            image->background_color.alpha,q,(double)
             GetPixelAlpha(image,q),q);
           q+=GetPixelChannels(image);
         }
@@ -2256,12 +2296,12 @@ MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
           status=MagickFalse;
       }
       image_view=DestroyCacheView(image_view);
-      image->matte=image->background_color.matte;
+      image->alpha_trait=image->background_color.alpha_trait;
       return(status);
     }
     case SetAlphaChannel:
     {
-      if (image->matte == MagickFalse)
+      if (image->alpha_trait != BlendPixelTrait)
         status=SetImageAlpha(image,OpaqueAlpha,exception);
       break;
     }
@@ -2323,17 +2363,17 @@ MagickExport MagickBooleanType SetImageBackgroundColor(Image *image,
   assert(image->signature == MagickSignature);
   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
     return(MagickFalse);
-  if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
-      (IsPixelInfoGray(&image->background_color) == MagickFalse))
+  if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
+      (IsGrayColorspace(image->colorspace) != MagickFalse))
     (void) TransformImageColorspace(image,sRGBColorspace,exception);
-  if ((image->background_color.matte != MagickFalse) &&
-      (image->matte == MagickFalse))
+  if ((image->background_color.alpha_trait == BlendPixelTrait) &&
+      (image->alpha_trait != BlendPixelTrait))
     (void) SetImageAlpha(image,OpaqueAlpha,exception);
   /*
     Set image background color.
   */
   status=MagickTrue;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register Quantum
@@ -2367,6 +2407,44 @@ MagickExport MagickBooleanType SetImageBackgroundColor(Image *image,
 %                                                                             %
 %                                                                             %
 %                                                                             %
+%   S e t I m a g e C h a n n e l M a s k                                     %
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  SetImageChannelMask() sets the image channel mask from the specified channel
+%  mask.
+%
+%  The format of the SetImageChannelMask method is:
+%
+%      ChannelType SetImageChannelMask(Image *image,
+%        const ChannelType channel_mask)
+%
+%  A description of each parameter follows:
+%
+%    o image: the image.
+%
+%    o channel_mask: the channel mask.
+%
+*/
+MagickExport ChannelType SetImageChannelMask(Image *image,
+  const ChannelType channel_mask)
+{
+  ChannelType
+    mask;
+
+  mask=image->channel_mask;
+  image->channel_mask=channel_mask;
+  SetPixelChannelMask(image,channel_mask);
+  return(mask);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
 %   S e t I m a g e C o l o r                                                 %
 %                                                                             %
 %                                                                             %
@@ -2407,13 +2485,14 @@ MagickExport MagickBooleanType SetImageColor(Image *image,
   assert(image->signature == MagickSignature);
   assert(color != (const PixelInfo *) NULL);
   image->colorspace=color->colorspace;
-  image->matte=color->matte;
+  image->alpha_trait=color->alpha_trait;
   image->fuzz=color->fuzz;
   image->depth=color->depth;
   status=MagickTrue;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(status)
+  #pragma omp parallel for schedule(static,4) shared(status) \
+    magick_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -2528,10 +2607,10 @@ MagickExport MagickBooleanType SetImageExtent(Image *image,const size_t columns,
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  SetImageInfo() initializes the `magick' field of the ImageInfo structure.
+%  SetImageInfo() initializes the 'magick' field of the ImageInfo structure.
 %  It is set to a type of image format based on the prefix or suffix of the
-%  filename.  For example, `ps:image' returns PS indicating a Postscript image.
-%  JPEG is returned for this filename: `image.jpg'.  The filename prefix has
+%  filename.  For example, 'ps:image' returns PS indicating a Postscript image.
+%  JPEG is returned for this filename: 'image.jpg'.  The filename prefix has
 %  precendence over the suffix.  Use an optional index enclosed in brackets
 %  after a file name to specify a desired scene of a multi-resolution image
 %  format like Photo CD (e.g. img0001.pcd[4]).  A True (non-zero) return value
@@ -2828,6 +2907,7 @@ MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
         }
       (void) ResetMagickMemory(magick,0,sizeof(magick));
       count=ReadBlob(image,2*MaxTextExtent,magick);
+      (void) SeekBlob(image,-((MagickOffsetType) count),SEEK_CUR);
       (void) CloseBlob(image);
       image=DestroyImage(image);
       /*
@@ -2980,12 +3060,18 @@ MagickExport MagickBooleanType SetImageMask(Image *image,const Image *mask,
   if (mask == (const Image *) NULL)
     {
       image->mask=MagickFalse;
-      return(MagickTrue);
+      return(SyncImagePixelCache(image,exception));
     }
-  status=MagickTrue;
   image->mask=MagickTrue;
-  image_view=AcquireCacheView(image);
-  mask_view=AcquireCacheView(mask);
+  if (SyncImagePixelCache(image,exception) == MagickFalse)
+    return(MagickFalse);
+  status=MagickTrue;
+  mask_view=AcquireVirtualCacheView(mask,exception);
+  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)
+#endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     register const Quantum
@@ -3008,7 +3094,7 @@ MagickExport MagickBooleanType SetImageMask(Image *image,const Image *mask,
       }
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      SetPixelMask(image,GetPixelGray(mask,p),q);
+      SetPixelMask(image,ClampToQuantum(GetPixelIntensity(mask,p)),q);
       p+=GetPixelChannels(mask);
       q+=GetPixelChannels(image);
     }
@@ -3062,11 +3148,12 @@ MagickExport MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
   assert(image->signature == MagickSignature);
-  image->matte=MagickTrue;
+  image->alpha_trait=BlendPixelTrait;
   status=MagickTrue;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(status)
+  #pragma omp parallel for schedule(static,4) shared(status) \
+    magick_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -3101,191 +3188,6 @@ MagickExport MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
 %                                                                             %
 %                                                                             %
 %                                                                             %
-%   S e t I m a g e T y p e                                                   %
-%                                                                             %
-%                                                                             %
-%                                                                             %
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-%  SetImageType() sets the type of image.  Choose from these types:
-%
-%        Bilevel        Grayscale       GrayscaleMatte
-%        Palette        PaletteMatte    TrueColor
-%        TrueColorMatte ColorSeparation ColorSeparationMatte
-%        OptimizeType
-%
-%  The format of the SetImageType method is:
-%
-%      MagickBooleanType SetImageType(Image *image,const ImageType type,
-%        ExceptionInfo *exception)
-%
-%  A description of each parameter follows:
-%
-%    o image: the image.
-%
-%    o type: Image type.
-%
-%    o exception: return any errors or warnings in this structure.
-%
-*/
-MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type,
-  ExceptionInfo *exception)
-{
-  const char
-    *artifact;
-
-  ImageInfo
-    *image_info;
-
-  MagickBooleanType
-    status;
-
-  QuantizeInfo
-    *quantize_info;
-
-  assert(image != (Image *) NULL);
-  if (image->debug != MagickFalse)
-    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
-  assert(image->signature == MagickSignature);
-  status=MagickTrue;
-  image_info=AcquireImageInfo();
-  image_info->dither=image->dither;
-  artifact=GetImageArtifact(image,"dither");
-  if (artifact != (const char *) NULL)
-    (void) SetImageOption(image_info,"dither",artifact);
-  switch (type)
-  {
-    case BilevelType:
-    {
-      if (IsImageMonochrome(image,exception) == MagickFalse)
-        {
-          quantize_info=AcquireQuantizeInfo(image_info);
-          quantize_info->number_colors=2;
-          quantize_info->colorspace=GRAYColorspace;
-          status=QuantizeImage(quantize_info,image,exception);
-          quantize_info=DestroyQuantizeInfo(quantize_info);
-        }
-      image->matte=MagickFalse;
-      break;
-    }
-    case GrayscaleType:
-    {
-      if (IsImageGray(image,exception) == MagickFalse)
-        status=TransformImageColorspace(image,GRAYColorspace,exception);
-      image->matte=MagickFalse;
-      break;
-    }
-    case GrayscaleMatteType:
-    {
-      if (IsImageGray(image,exception) == MagickFalse)
-        status=TransformImageColorspace(image,GRAYColorspace,exception);
-      if (image->matte == MagickFalse)
-        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
-      break;
-    }
-    case PaletteType:
-    {
-      if (IsRGBColorspace(image->colorspace) == MagickFalse)
-        status=TransformImageColorspace(image,sRGBColorspace,exception);
-      if ((image->storage_class == DirectClass) || (image->colors > 256))
-        {
-          quantize_info=AcquireQuantizeInfo(image_info);
-          quantize_info->number_colors=256;
-          status=QuantizeImage(quantize_info,image,exception);
-          quantize_info=DestroyQuantizeInfo(quantize_info);
-        }
-      image->matte=MagickFalse;
-      break;
-    }
-    case PaletteBilevelMatteType:
-    {
-      ChannelType
-        channel_mask;
-
-      if (IsRGBColorspace(image->colorspace) == MagickFalse)
-        status=TransformImageColorspace(image,sRGBColorspace,exception);
-      if (image->matte == MagickFalse)
-        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
-      channel_mask=SetPixelChannelMask(image,AlphaChannel);
-      (void) BilevelImage(image,(double) QuantumRange/2.0,exception);
-      (void) SetPixelChannelMask(image,channel_mask);
-      quantize_info=AcquireQuantizeInfo(image_info);
-      status=QuantizeImage(quantize_info,image,exception);
-      quantize_info=DestroyQuantizeInfo(quantize_info);
-      break;
-    }
-    case PaletteMatteType:
-    {
-      if (IsRGBColorspace(image->colorspace) == MagickFalse)
-        status=TransformImageColorspace(image,sRGBColorspace,exception);
-      if (image->matte == MagickFalse)
-        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
-      quantize_info=AcquireQuantizeInfo(image_info);
-      quantize_info->colorspace=TransparentColorspace;
-      status=QuantizeImage(quantize_info,image,exception);
-      quantize_info=DestroyQuantizeInfo(quantize_info);
-      break;
-    }
-    case TrueColorType:
-    {
-      if (IsRGBColorspace(image->colorspace) == MagickFalse)
-        status=TransformImageColorspace(image,sRGBColorspace,exception);
-      if (image->storage_class != DirectClass)
-        status=SetImageStorageClass(image,DirectClass,exception);
-      image->matte=MagickFalse;
-      break;
-    }
-    case TrueColorMatteType:
-    {
-      if (IsRGBColorspace(image->colorspace) == MagickFalse)
-        status=TransformImageColorspace(image,sRGBColorspace,exception);
-      if (image->storage_class != DirectClass)
-        status=SetImageStorageClass(image,DirectClass,exception);
-      if (image->matte == MagickFalse)
-        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
-      break;
-    }
-    case ColorSeparationType:
-    {
-      if (image->colorspace != CMYKColorspace)
-        {
-          if (IsRGBColorspace(image->colorspace) == MagickFalse)
-            status=TransformImageColorspace(image,sRGBColorspace,exception);
-          status=TransformImageColorspace(image,CMYKColorspace,exception);
-        }
-      if (image->storage_class != DirectClass)
-        status=SetImageStorageClass(image,DirectClass,exception);
-      image->matte=MagickFalse;
-      break;
-    }
-    case ColorSeparationMatteType:
-    {
-      if (image->colorspace != CMYKColorspace)
-        {
-          if (IsRGBColorspace(image->colorspace) == MagickFalse)
-            status=TransformImageColorspace(image,sRGBColorspace,exception);
-          status=TransformImageColorspace(image,CMYKColorspace,exception);
-        }
-      if (image->storage_class != DirectClass)
-        status=SetImageStorageClass(image,DirectClass,exception);
-      if (image->matte == MagickFalse)
-        status=SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
-      break;
-    }
-    case OptimizeType:
-    case UndefinedType:
-      break;
-  }
-  image->type=type;
-  image_info=DestroyImageInfo(image_info);
-  return(status);
-}
-\f
-/*
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%                                                                             %
-%                                                                             %
-%                                                                             %
 %   S e t I m a g e V i r t u a l P i x e l M e t h o d                       %
 %                                                                             %
 %                                                                             %
@@ -3394,8 +3296,8 @@ static ssize_t SmushXGap(const Image *smush_image,const Image *images,
   GravityAdjustGeometry(left_image->columns,left_image->rows,
     left_image->gravity,&left_geometry);
   gap=right_image->columns;
-  left_view=AcquireCacheView(left_image);
-  right_view=AcquireCacheView(right_image);
+  left_view=AcquireVirtualCacheView(left_image,exception);
+  right_view=AcquireVirtualCacheView(right_image,exception);
   for (y=0; y < (ssize_t) smush_image->rows; y++)
   {
     for (x=(ssize_t) left_image->columns-1; x > 0; x--)
@@ -3465,8 +3367,8 @@ static ssize_t SmushYGap(const Image *smush_image,const Image *images,
   GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
     &top_geometry);
   gap=bottom_image->rows;
-  top_view=AcquireCacheView(top_image);
-  bottom_view=AcquireCacheView(bottom_image);
+  top_view=AcquireVirtualCacheView(top_image,exception);
+  bottom_view=AcquireVirtualCacheView(bottom_image,exception);
   for (x=0; x < (ssize_t) smush_image->columns; x++)
   {
     for (y=(ssize_t) top_image->rows-1; y > 0; y--)
@@ -3502,9 +3404,6 @@ MagickExport Image *SmushImages(const Image *images,
 {
 #define SmushImageTag  "Smush/Image"
 
-  CacheView
-    *smush_view;
-
   const Image
     *image;
 
@@ -3512,13 +3411,15 @@ MagickExport Image *SmushImages(const Image *images,
     *smush_image;
 
   MagickBooleanType
-    matte,
     proceed,
     status;
 
   MagickOffsetType
     n;
 
+  PixelTrait
+    alpha_trait;
+
   RectangleInfo
     geometry;
 
@@ -3544,15 +3445,15 @@ MagickExport Image *SmushImages(const Image *images,
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
   image=images;
-  matte=image->matte;
+  alpha_trait=image->alpha_trait;
   number_images=1;
   width=image->columns;
   height=image->rows;
   next=GetNextImageInList(image);
   for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
   {
-    if (next->matte != MagickFalse)
-      matte=MagickTrue;
+    if (next->alpha_trait == BlendPixelTrait)
+      alpha_trait=BlendPixelTrait;
     number_images++;
     if (stack != MagickFalse)
       {
@@ -3580,12 +3481,11 @@ MagickExport Image *SmushImages(const Image *images,
       smush_image=DestroyImage(smush_image);
       return((Image *) NULL);
     }
-  smush_image->matte=matte;
+  smush_image->alpha_trait=alpha_trait;
   (void) SetImageBackgroundColor(smush_image,exception);
   status=MagickTrue;
   x_offset=0;
   y_offset=0;
-  smush_view=AcquireCacheView(smush_image);
   for (n=0; n < (MagickOffsetType) number_images; n++)
   {
     SetGeometry(smush_image,&geometry);
@@ -3621,7 +3521,6 @@ MagickExport Image *SmushImages(const Image *images,
     smush_image->columns=(size_t) x_offset;
   else
     smush_image->rows=(size_t) y_offset;
-  smush_view=DestroyCacheView(smush_view);
   if (status == MagickFalse)
     smush_image=DestroyImage(smush_image);
   return(smush_image);
@@ -3700,7 +3599,7 @@ static inline Quantum PushColormapIndex(Image *image,const Quantum index,
   if ((size_t) index < image->colors)
     return(index);
   *range_exception=MagickTrue;
-  return(0);
+  return((Quantum) 0);
 }
 
 MagickExport MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
@@ -3723,9 +3622,10 @@ MagickExport MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
     return(MagickFalse);
   range_exception=MagickFalse;
   status=MagickTrue;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireAuthenticCacheView(image,exception);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(static,4) shared(range_exception,status)
+  #pragma omp parallel for schedule(static,4) shared(range_exception,status) \
+    magick_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
   {
@@ -3756,7 +3656,7 @@ MagickExport MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
       status=MagickFalse;
   }
   image_view=DestroyCacheView(image_view);
-  if (range_exception != MagickFalse)
+  if ((image->ping == MagickFalse) && (range_exception != MagickFalse))
     (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
       "InvalidColormapIndex","`%s'",image->filename);
   return(status);
@@ -3773,7 +3673,14 @@ MagickExport MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
-%  SyncImageSettings() syncs the image_info options into per-image attributes.
+%  SyncImageSettings() syncs any image_info global options into per-image
+%  attributes.
+%
+%  Note: in IMv6 free form 'options' were always mapped into 'artifacts', so
+%  that operations and coders can find such settings.  In IMv7 if a desired
+%  per-image artifact is not set, then it will directly look for a global
+%  option as a fallback, as such this copy is no longer needed, only the
+%  link set up.
 %
 %  The format of the SyncImageSettings method is:
 %
@@ -3814,12 +3721,8 @@ MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
 MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
   Image *image,ExceptionInfo *exception)
 {
-  char
-    property[MaxTextExtent];
-
   const char
-    *option,
-    *value;
+    *option;
 
   GeometryInfo
     geometry_info;
@@ -3862,7 +3765,7 @@ MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
       exception);
   option=GetImageOption(image_info,"channel");
   if (option != (const char *) NULL)
-    (void) SetPixelChannelMapMask(image,(ChannelType)
+    (void) SetPixelChannelMask(image,(ChannelType)
       ParseChannelOption(option));
   /* FUTURE: do not sync compose to per-image compose setting here */
   option=GetImageOption(image_info,"compose");
@@ -4039,15 +3942,43 @@ MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
         image->chromaticity.white_point.y=image->chromaticity.white_point.x;
     }
   ResetImageOptionIterator(image_info);
-  for (option=GetNextImageOption(image_info); option != (const char *) NULL; )
+#if 0
   {
-    value=GetImageOption(image_info,option);
-    if (value != (const char *) NULL)
-      {
-        (void) FormatLocaleString(property,MaxTextExtent,"%s",option);
-        (void) SetImageArtifact(image,property,value);
-      }
-    option=GetNextImageOption(image_info);
+    /* IMv6: Copy freeform global options into per-image artifacts, so
+     * various operations and coders can access them.
+     *
+     * This has a problem, as per-image artefacts may have been set in
+     * parenthesis, but may not be unset when parenthesis ends.
+     */
+    char
+      property[MaxTextExtent];
+
+    const char
+      *value;
+
+    for (option=GetNextImageOption(image_info); option != (const char *) NULL; )
+    {
+      value=GetImageOption(image_info,option);
+      if (value != (const char *) NULL)
+        {
+          (void) FormatLocaleString(property,MaxTextExtent,"%s",option);
+          (void) SetImageArtifact(image,property,value);
+        }
+      option=GetNextImageOption(image_info);
+    }
   }
+#else
+  /* IMv7: pointer to allow the lookup of pre-image artefact will fallback to
+     a global option setting/define.  This saves a lot of duplication of
+     global options into per-image artifacts, while ensuring only specifically
+     set per-image artifacts are preverved when parenthesis ends.
+
+     This pointer is never explictally freed, as it is only used as a back
+     reference, not as the main pointer to the image_info structure.  Images
+     being removed from a image_info image list (or yet to be added to such),
+     should have this pointer reset to NULL.
+  */
+  image->image_info=image_info;
+#endif
   return(MagickTrue);
 }