]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/attribute.c
(no commit message)
[imagemagick] / MagickCore / attribute.c
index b67f995d0bbd51b679d554eaa0e8ce6af765fa38..ec953ec4e2ea01dfc1b1174b70843c5c9bb24f25 100644 (file)
 %                    MagickCore Get / Set Image Attributes                    %
 %                                                                             %
 %                              Software Design                                %
-%                                John Cristy                                  %
+%                                   Cristy                                    %
 %                                October 2002                                 %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2014 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  %
   Include declarations.
 */
 #include "MagickCore/studio.h"
+#include "MagickCore/artifact.h"
 #include "MagickCore/attribute.h"
 #include "MagickCore/blob.h"
 #include "MagickCore/blob-private.h"
 #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"
@@ -73,6 +76,7 @@
 #include "MagickCore/magick.h"
 #include "MagickCore/monitor.h"
 #include "MagickCore/monitor-private.h"
+#include "MagickCore/option.h"
 #include "MagickCore/paint.h"
 #include "MagickCore/pixel.h"
 #include "MagickCore/pixel-accessor.h"
@@ -149,7 +153,7 @@ MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
   bounds.x=(ssize_t) image->columns;
   bounds.y=(ssize_t) image->rows;
   GetPixelInfo(image,&target[0]);
-  image_view=AcquireCacheView(image);
+  image_view=AcquireVirtualCacheView(image,exception);
   p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
   if (p == (const Quantum *) NULL)
     {
@@ -168,7 +172,8 @@ MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
   status=MagickTrue;
   GetPixelInfo(image,&zero);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,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++)
   {
@@ -264,8 +269,7 @@ MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
 %    o exception: return any errors or warnings in this structure.
 %
 */
-MagickExport size_t GetImageDepth(const Image *image,
-  ExceptionInfo *exception)
+MagickExport size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
 {
   CacheView
     *image_view;
@@ -274,7 +278,7 @@ MagickExport size_t GetImageDepth(const Image *image,
     status;
 
   register ssize_t
-    id;
+    i;
 
   size_t
     *current_depth,
@@ -291,68 +295,153 @@ MagickExport size_t GetImageDepth(const Image *image,
   assert(image->signature == MagickSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  number_threads=GetOpenMPMaximumThreads();
+  number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
   current_depth=(size_t *) AcquireQuantumMemory(number_threads,
     sizeof(*current_depth));
   if (current_depth == (size_t *) NULL)
     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
   status=MagickTrue;
-  for (id=0; id < (ssize_t) number_threads; id++)
-    current_depth[id]=1;
-  if ((image->storage_class == PseudoClass) && (image->matte == MagickFalse))
+  for (i=0; i < (ssize_t) number_threads; i++)
+    current_depth[i]=1;
+  if ((image->storage_class == PseudoClass) && (image->alpha_trait != BlendPixelTrait))
     {
-      register const PixelInfo
-        *restrict p;
-
-      register ssize_t
-        i;
-
-      p=image->colormap;
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(status)
+      #pragma omp parallel for schedule(static,4) shared(status) \
+        if ((image->colors) > 256) \
+          num_threads(GetMagickResourceLimit(ThreadResource))
 #endif
       for (i=0; i < (ssize_t) image->colors; i++)
       {
         const int
           id = GetOpenMPThreadId();
 
-        if (status == MagickFalse)
-          continue;
         while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
         {
-          MagickStatusType
-            status;
+          MagickBooleanType
+            atDepth;
 
           QuantumAny
             range;
 
-          status=0;
+          atDepth=MagickTrue;
           range=GetQuantumRange(current_depth[id]);
-          if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-            status|=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,
-              range),range);
-          if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-            status|=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
-              range),range);
-          if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-            status|=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
-              range),range);
-          if (status == 0)
+          if ((atDepth != MagickFalse) &&
+              (GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
+            if (IsPixelAtDepth(image->colormap[i].red,range) == MagickFalse)
+              atDepth=MagickFalse;
+          if ((atDepth != MagickFalse) &&
+              (GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
+            if (IsPixelAtDepth(image->colormap[i].green,range) == MagickFalse)
+              atDepth=MagickFalse;
+          if ((atDepth != MagickFalse) &&
+              (GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
+            if (IsPixelAtDepth(image->colormap[i].blue,range) == MagickFalse)
+              atDepth=MagickFalse;
+          if ((atDepth != MagickFalse))
             break;
           current_depth[id]++;
         }
-        p++;
       }
       depth=current_depth[0];
-      for (id=1; id < (ssize_t) number_threads; id++)
-        if (depth < current_depth[id])
-          depth=current_depth[id];
+      for (i=1; i < (ssize_t) number_threads; i++)
+        if (depth < current_depth[i])
+          depth=current_depth[i];
+      current_depth=(size_t *) RelinquishMagickMemory(current_depth);
+      return(depth);
+    }
+  image_view=AcquireVirtualCacheView(image,exception);
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  if (QuantumRange <= MaxMap)
+    {
+      size_t
+        *depth_map;
+
+      /*
+        Scale pixels to desired (optimized with depth map).
+      */
+      depth_map=(size_t *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
+      if (depth_map == (size_t *) NULL)
+        ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+      {
+        unsigned int
+          depth;
+
+        for (depth=1; depth < MAGICKCORE_QUANTUM_DEPTH; depth++)
+        {
+          Quantum
+            pixel;
+
+          QuantumAny
+            range;
+
+          range=GetQuantumRange(depth);
+          pixel=(Quantum) i;
+          if (pixel == ScaleAnyToQuantum(ScaleQuantumToAny(pixel,range),range))
+            break;
+        }
+        depth_map[i]=depth;
+      }
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+      #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++)
+      {
+        const int
+          id = GetOpenMPThreadId();
+
+        register const Quantum
+          *restrict p;
+
+        register ssize_t
+          x;
+
+        if (status == MagickFalse)
+          continue;
+        p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
+        if (p == (const Quantum *) NULL)
+          continue;
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          if (GetPixelReadMask(image,p) == 0)
+            {
+              p+=GetPixelChannels(image);
+              continue;
+            }
+          for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+          {
+            PixelChannel channel=GetPixelChannelChannel(image,i);
+            PixelTrait traits=GetPixelChannelTraits(image,channel);
+            if ((traits == UndefinedPixelTrait) ||
+                (channel == IndexPixelChannel) ||
+                (channel == ReadMaskPixelChannel) ||
+                (channel == MetaPixelChannel))
+              continue;
+            if (depth_map[ScaleQuantumToMap(p[i])] > current_depth[id])
+              current_depth[id]=depth_map[ScaleQuantumToMap(p[i])];
+          }
+          p+=GetPixelChannels(image);
+        }
+        if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      depth=current_depth[0];
+      for (i=1; i < (ssize_t) number_threads; i++)
+        if (depth < current_depth[i])
+          depth=current_depth[i];
+      depth_map=(size_t *) RelinquishMagickMemory(depth_map);
       current_depth=(size_t *) RelinquishMagickMemory(current_depth);
       return(depth);
     }
-  image_view=AcquireCacheView(image);
+#endif
+  /*
+    Compute pixel depth.
+  */
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,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++)
   {
@@ -372,9 +461,11 @@ MagickExport size_t GetImageDepth(const Image *image,
       continue;
     for (x=0; x < (ssize_t) image->columns; x++)
     {
-      register ssize_t
-        i;
-
+      if (GetPixelReadMask(image,p) == 0)
+        {
+          p+=GetPixelChannels(image);
+          continue;
+        }
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
         PixelChannel
@@ -383,23 +474,18 @@ MagickExport size_t GetImageDepth(const Image *image,
         PixelTrait
           traits;
 
-        channel=GetPixelChannelMapChannel(image,i);
-        traits=GetPixelChannelMapTraits(image,channel);
-        if (traits == UndefinedPixelTrait)
+        channel=GetPixelChannelChannel(image,i);
+        traits=GetPixelChannelTraits(image,channel);
+        if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
+            (channel == ReadMaskPixelChannel))
           continue;
         while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
         {
-          MagickStatusType
-            status;
-
           QuantumAny
             range;
 
-          status=0;
           range=GetQuantumRange(current_depth[id]);
-          status|=p[i] != ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),
-            range);
-          if (status == 0)
+          if (p[i] == ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),range))
             break;
           current_depth[id]++;
         }
@@ -411,9 +497,9 @@ MagickExport size_t GetImageDepth(const Image *image,
   }
   image_view=DestroyCacheView(image_view);
   depth=current_depth[0];
-  for (id=1; id < (ssize_t) number_threads; id++)
-    if (depth < current_depth[id])
-      depth=current_depth[id];
+  for (i=1; i < (ssize_t) number_threads; i++)
+    if (depth < current_depth[i])
+      depth=current_depth[i];
   current_depth=(size_t *) RelinquishMagickMemory(current_depth);
   return(depth);
 }
@@ -516,7 +602,7 @@ MagickExport ImageType GetImageType(const Image *image,ExceptionInfo *exception)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   if (image->colorspace == CMYKColorspace)
     {
-      if (image->matte == MagickFalse)
+      if (image->alpha_trait != BlendPixelTrait)
         return(ColorSeparationType);
       return(ColorSeparationMatteType);
     }
@@ -524,17 +610,17 @@ MagickExport ImageType GetImageType(const Image *image,ExceptionInfo *exception)
     return(BilevelType);
   if (IsImageGray(image,exception) != MagickFalse)
     {
-      if (image->matte != MagickFalse)
+      if (image->alpha_trait == BlendPixelTrait)
         return(GrayscaleMatteType);
       return(GrayscaleType);
     }
   if (IsPaletteImage(image,exception) != MagickFalse)
     {
-      if (image->matte != MagickFalse)
+      if (image->alpha_trait == BlendPixelTrait)
         return(PaletteMatteType);
       return(PaletteType);
     }
-  if (image->matte != MagickFalse)
+  if (image->alpha_trait == BlendPixelTrait)
     return(TrueColorMatteType);
   return(TrueColorType);
 }
@@ -590,10 +676,11 @@ MagickExport MagickBooleanType IsImageGray(const Image *image,
   if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
       (image->type == GrayscaleMatteType))
     return(MagickTrue);
-  if (IsRGBColorspace(image->colorspace) == MagickFalse)
+  if ((IsGrayColorspace(image->colorspace) == MagickFalse) &&
+      (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse))
     return(MagickFalse);
   type=BilevelType;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireVirtualCacheView(image,exception);
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
@@ -617,8 +704,11 @@ MagickExport MagickBooleanType IsImageGray(const Image *image,
   image_view=DestroyCacheView(image_view);
   if (type == UndefinedType)
     return(MagickFalse);
+  ((Image *) image)->colorspace=GRAYColorspace;
+  if (SyncImagePixelCache((Image *) image,exception) == MagickFalse)
+    return(MagickFalse);
   ((Image *) image)->type=type;
-  if ((type == GrayscaleType) && (image->matte != MagickFalse))
+  if ((type == GrayscaleType) && (image->alpha_trait == BlendPixelTrait))
     ((Image *) image)->type=GrayscaleMatteType;
   return(MagickTrue);
 }
@@ -674,10 +764,11 @@ MagickExport MagickBooleanType IsImageMonochrome(const Image *image,
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
   if (image->type == BilevelType)
     return(MagickTrue);
-  if (IsRGBColorspace(image->colorspace) == MagickFalse)
+  if ((IsGrayColorspace(image->colorspace) == MagickFalse) &&
+      (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse))
     return(MagickFalse);
   type=BilevelType;
-  image_view=AcquireCacheView(image);
+  image_view=AcquireVirtualCacheView(image,exception);
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
@@ -698,6 +789,9 @@ MagickExport MagickBooleanType IsImageMonochrome(const Image *image,
   image_view=DestroyCacheView(image_view);
   if (type == UndefinedType)
     return(MagickFalse);
+  ((Image *) image)->colorspace=GRAYColorspace;
+  if (SyncImagePixelCache((Image *) image,exception) == MagickFalse)
+    return(MagickFalse);
   ((Image *) image)->type=type;
   return(MagickTrue);
 }
@@ -714,7 +808,9 @@ MagickExport MagickBooleanType IsImageMonochrome(const Image *image,
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
 %  IsImageOpaque() returns MagickTrue if none of the pixels in the image have
-%  an opacity value other than opaque (0).
+%  an alpha value other than OpaqueAlpha (QuantumRange).
+%
+%  Will return true immediatally is alpha channel is not available.
 %
 %  The format of the IsImageOpaque method is:
 %
@@ -750,9 +846,9 @@ MagickExport MagickBooleanType IsImageOpaque(const Image *image,
   assert(image->signature == MagickSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  if (image->matte == MagickFalse)
+  if (image->alpha_trait != BlendPixelTrait)
     return(MagickTrue);
-  image_view=AcquireCacheView(image);
+  image_view=AcquireVirtualCacheView(image,exception);
   for (y=0; y < (ssize_t) image->rows; y++)
   {
     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
@@ -800,6 +896,20 @@ MagickExport MagickBooleanType IsImageOpaque(const Image *image,
 %    o exception: return any errors or warnings in this structure.
 %
 */
+
+static inline Quantum ClampPixel(const MagickRealType value)
+{
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  return((Quantum) value);
+#else
+  if (value < 0.0f)
+    return(0.0f);
+  if (value >= (MagickRealType) QuantumRange)
+    return((Quantum) QuantumRange);
+  return(value);
+#endif
+}
+
 MagickExport MagickBooleanType SetImageDepth(Image *image,
   const size_t depth,ExceptionInfo *exception)
 {
@@ -819,20 +929,125 @@ MagickExport MagickBooleanType SetImageDepth(Image *image,
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
   assert(image->signature == MagickSignature);
-  if (GetImageDepth(image,exception) <= (size_t)
-      MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH))
+  if (depth >= MAGICKCORE_QUANTUM_DEPTH)
     {
       image->depth=depth;
       return(MagickTrue);
     }
+  range=GetQuantumRange(depth);
+  if (image->storage_class == PseudoClass)
+    {
+      register ssize_t
+        i;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+      #pragma omp parallel for schedule(static,4) shared(status) \
+        magick_threads(image,image,1,1)
+#endif
+      for (i=0; i < (ssize_t) image->colors; i++)
+      {
+        if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
+          image->colormap[i].red=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
+            ClampPixel(image->colormap[i].red),range),range);
+        if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
+          image->colormap[i].green=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
+            ClampPixel(image->colormap[i].green),range),range);
+        if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
+          image->colormap[i].blue=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
+            ClampPixel(image->colormap[i].blue),range),range);
+        if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
+          image->colormap[i].alpha=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
+            ClampPixel(image->colormap[i].alpha),range),range);
+      }
+    }
+  status=MagickTrue;
+  image_view=AcquireAuthenticCacheView(image,exception);
+#if !defined(MAGICKCORE_HDRI_SUPPORT)
+  if (QuantumRange <= MaxMap)
+    {
+      Quantum
+        *depth_map;
+
+      register ssize_t
+        i;
+
+      /*
+        Scale pixels to desired (optimized with depth map).
+      */
+      depth_map=(Quantum *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
+      if (depth_map == (Quantum *) NULL)
+        ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
+      for (i=0; i <= (ssize_t) MaxMap; i++)
+        depth_map[i]=ScaleAnyToQuantum(ScaleQuantumToAny((Quantum) i,range),
+          range);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+      #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++)
+      {
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        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++)
+        {
+          register ssize_t
+            i;
+
+          if (GetPixelReadMask(image,q) == 0)
+            {
+              q+=GetPixelChannels(image);
+              continue;
+            }
+          for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
+          {
+            PixelChannel
+              channel;
+
+            PixelTrait
+              traits;
+
+            channel=GetPixelChannelChannel(image,i);
+            traits=GetPixelChannelTraits(image,channel);
+            if ((traits == UndefinedPixelTrait) ||
+                (channel == IndexPixelChannel) ||
+                (channel == ReadMaskPixelChannel))
+              continue;
+            q[i]=depth_map[ScaleQuantumToMap(q[i])];
+          }
+          q+=GetPixelChannels(image);
+        }
+        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+          {
+            status=MagickFalse;
+            continue;
+          }
+      }
+      image_view=DestroyCacheView(image_view);
+      depth_map=(Quantum *) RelinquishMagickMemory(depth_map);
+      if (status != MagickFalse)
+        image->depth=depth;
+      return(status);
+    }
+#endif
   /*
     Scale pixels to desired depth.
   */
-  status=MagickTrue;
-  range=GetQuantumRange(depth);
-  image_view=AcquireCacheView(image);
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,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++)
   {
@@ -855,6 +1070,11 @@ MagickExport MagickBooleanType SetImageDepth(Image *image,
       register ssize_t
         i;
 
+      if (GetPixelReadMask(image,q) == 0)
+        {
+          q+=GetPixelChannels(image);
+          continue;
+        }
       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
       {
         PixelChannel
@@ -863,11 +1083,12 @@ MagickExport MagickBooleanType SetImageDepth(Image *image,
         PixelTrait
           traits;
 
-        channel=GetPixelChannelMapChannel(image,i);
-        traits=GetPixelChannelMapTraits(image,channel);
-        if (traits == UndefinedPixelTrait)
+        channel=GetPixelChannelChannel(image,i);
+        traits=GetPixelChannelTraits(image,channel);
+        if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
+            (channel == ReadMaskPixelChannel))
           continue;
-        q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(q[i],range),range);
+        q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(ClampPixel(q[i]),range),range);
       }
       q+=GetPixelChannels(image);
     }
@@ -878,31 +1099,197 @@ MagickExport MagickBooleanType SetImageDepth(Image *image,
       }
   }
   image_view=DestroyCacheView(image_view);
-  if (image->storage_class == PseudoClass)
-    {
-      register PixelInfo
-        *restrict p;
+  if (status != MagickFalse)
+    image->depth=depth;
+  return(status);
+}
+\f
+/*
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%                                                                             %
+%                                                                             %
+%                                                                             %
+%   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;
 
-      register ssize_t
-        i;
+  ImageInfo
+    *image_info;
 
-      p=image->colormap;
-#if defined(MAGICKCORE_OPENMP_SUPPORT)
-  #pragma omp parallel for schedule(dynamic,4) shared(status)
-#endif
-      for (i=0; i < (ssize_t) image->colors; i++)
-      {
-        if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
-          p->red=ScaleAnyToQuantum(ScaleQuantumToAny(p->red,range),range);
-        if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
-          p->green=ScaleAnyToQuantum(ScaleQuantumToAny(p->green,range),range);
-        if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
-          p->blue=ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,range),range);
-        if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
-          p->alpha=ScaleAnyToQuantum(ScaleQuantumToAny(p->alpha,range),range);
-        p++;
-      }
+  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 (IsImageGray(image,exception) == MagickFalse)
+        status=TransformImageColorspace(image,GRAYColorspace,exception);
+      (void) NormalizeImage(image,exception);
+      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->alpha_trait=UndefinedPixelTrait;
+      break;
     }
-  image->depth=depth;
-  return(status);
+    case GrayscaleType:
+    {
+      if (IsImageGray(image,exception) == MagickFalse)
+        status=TransformImageColorspace(image,GRAYColorspace,exception);
+      image->alpha_trait=UndefinedPixelTrait;
+      break;
+    }
+    case GrayscaleMatteType:
+    {
+      if (IsImageGray(image,exception) == MagickFalse)
+        status=TransformImageColorspace(image,GRAYColorspace,exception);
+      if (image->alpha_trait != BlendPixelTrait)
+        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
+      break;
+    }
+    case PaletteType:
+    {
+      if (IssRGBCompatibleColorspace(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->alpha_trait=UndefinedPixelTrait;
+      break;
+    }
+    case PaletteBilevelMatteType:
+    {
+      ChannelType
+        channel_mask;
+
+      if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
+        status=TransformImageColorspace(image,sRGBColorspace,exception);
+      if (image->alpha_trait != BlendPixelTrait)
+        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
+      channel_mask=SetImageChannelMask(image,AlphaChannel);
+      (void) BilevelImage(image,(double) QuantumRange/2.0,exception);
+      (void) SetImageChannelMask(image,channel_mask);
+      quantize_info=AcquireQuantizeInfo(image_info);
+      status=QuantizeImage(quantize_info,image,exception);
+      quantize_info=DestroyQuantizeInfo(quantize_info);
+      break;
+    }
+    case PaletteMatteType:
+    {
+      if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
+        status=TransformImageColorspace(image,sRGBColorspace,exception);
+      if (image->alpha_trait != BlendPixelTrait)
+        (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 (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
+        status=TransformImageColorspace(image,sRGBColorspace,exception);
+      if (image->storage_class != DirectClass)
+        status=SetImageStorageClass(image,DirectClass,exception);
+      image->alpha_trait=UndefinedPixelTrait;
+      break;
+    }
+    case TrueColorMatteType:
+    {
+      if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
+        status=TransformImageColorspace(image,sRGBColorspace,exception);
+      if (image->storage_class != DirectClass)
+        status=SetImageStorageClass(image,DirectClass,exception);
+      if (image->alpha_trait != BlendPixelTrait)
+        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
+      break;
+    }
+    case ColorSeparationType:
+    {
+      if (image->colorspace != CMYKColorspace)
+        {
+          if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
+            status=TransformImageColorspace(image,sRGBColorspace,exception);
+          status=TransformImageColorspace(image,CMYKColorspace,exception);
+        }
+      if (image->storage_class != DirectClass)
+        status=SetImageStorageClass(image,DirectClass,exception);
+      image->alpha_trait=UndefinedPixelTrait;
+      break;
+    }
+    case ColorSeparationMatteType:
+    {
+      if (image->colorspace != CMYKColorspace)
+        {
+          if (IssRGBCompatibleColorspace(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->alpha_trait != BlendPixelTrait)
+        status=SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
+      break;
+    }
+    case OptimizeType:
+    case UndefinedType:
+      break;
+  }
+  image_info=DestroyImageInfo(image_info);
+  if (status == MagickFalse)
+    return(status);
+  image->type=type;
+  return(MagickTrue);
 }