Home | History | Annotate | Download | only in MagickCore
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                                                                             %
      6 %         AAA   TTTTT  TTTTT  RRRR   IIIII  BBBB   U   U  TTTTT  EEEEE        %
      7 %        A   A    T      T    R   R    I    B   B  U   U    T    E            %
      8 %        AAAAA    T      T    RRRR     I    BBBB   U   U    T    EEE          %
      9 %        A   A    T      T    R R      I    B   B  U   U    T    E            %
     10 %        A   A    T      T    R  R   IIIII  BBBB    UUU     T    EEEEE        %
     11 %                                                                             %
     12 %                                                                             %
     13 %                    MagickCore Get / Set Image Attributes                    %
     14 %                                                                             %
     15 %                              Software Design                                %
     16 %                                   Cristy                                    %
     17 %                                October 2002                                 %
     18 %                                                                             %
     19 %                                                                             %
     20 %  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
     21 %  dedicated to making software imaging solutions freely available.           %
     22 %                                                                             %
     23 %  You may not use this file except in compliance with the License.  You may  %
     24 %  obtain a copy of the License at                                            %
     25 %                                                                             %
     26 %    http://www.imagemagick.org/script/license.php                            %
     27 %                                                                             %
     28 %  Unless required by applicable law or agreed to in writing, software        %
     29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     31 %  See the License for the specific language governing permissions and        %
     32 %  limitations under the License.                                             %
     33 %                                                                             %
     34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     35 %
     36 %
     37 %
     38 */
     39 
     40 /*
     42   Include declarations.
     43 */
     44 #include "MagickCore/studio.h"
     45 #include "MagickCore/artifact.h"
     46 #include "MagickCore/attribute.h"
     47 #include "MagickCore/blob.h"
     48 #include "MagickCore/blob-private.h"
     49 #include "MagickCore/cache.h"
     50 #include "MagickCore/cache-private.h"
     51 #include "MagickCore/cache-view.h"
     52 #include "MagickCore/channel.h"
     53 #include "MagickCore/client.h"
     54 #include "MagickCore/color.h"
     55 #include "MagickCore/color-private.h"
     56 #include "MagickCore/colormap.h"
     57 #include "MagickCore/colormap-private.h"
     58 #include "MagickCore/colorspace.h"
     59 #include "MagickCore/colorspace-private.h"
     60 #include "MagickCore/composite.h"
     61 #include "MagickCore/composite-private.h"
     62 #include "MagickCore/constitute.h"
     63 #include "MagickCore/draw.h"
     64 #include "MagickCore/draw-private.h"
     65 #include "MagickCore/effect.h"
     66 #include "MagickCore/enhance.h"
     67 #include "MagickCore/exception.h"
     68 #include "MagickCore/exception-private.h"
     69 #include "MagickCore/geometry.h"
     70 #include "MagickCore/histogram.h"
     71 #include "MagickCore/identify.h"
     72 #include "MagickCore/image.h"
     73 #include "MagickCore/image-private.h"
     74 #include "MagickCore/list.h"
     75 #include "MagickCore/log.h"
     76 #include "MagickCore/memory_.h"
     77 #include "MagickCore/magick.h"
     78 #include "MagickCore/monitor.h"
     79 #include "MagickCore/monitor-private.h"
     80 #include "MagickCore/option.h"
     81 #include "MagickCore/paint.h"
     82 #include "MagickCore/pixel.h"
     83 #include "MagickCore/pixel-accessor.h"
     84 #include "MagickCore/property.h"
     85 #include "MagickCore/quantize.h"
     86 #include "MagickCore/quantum-private.h"
     87 #include "MagickCore/random_.h"
     88 #include "MagickCore/resource_.h"
     89 #include "MagickCore/semaphore.h"
     90 #include "MagickCore/segment.h"
     91 #include "MagickCore/splay-tree.h"
     92 #include "MagickCore/string_.h"
     93 #include "MagickCore/thread-private.h"
     94 #include "MagickCore/threshold.h"
     95 #include "MagickCore/transform.h"
     96 #include "MagickCore/utility.h"
     97 
     98 /*
    100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    101 %                                                                             %
    102 %                                                                             %
    103 %                                                                             %
    104 +   G e t I m a g e B o u n d i n g B o x                                     %
    105 %                                                                             %
    106 %                                                                             %
    107 %                                                                             %
    108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    109 %
    110 %  GetImageBoundingBox() returns the bounding box of an image canvas.
    111 %
    112 %  The format of the GetImageBoundingBox method is:
    113 %
    114 %      RectangleInfo GetImageBoundingBox(const Image *image,
    115 %        ExceptionInfo *exception)
    116 %
    117 %  A description of each parameter follows:
    118 %
    119 %    o bounds: Method GetImageBoundingBox returns the bounding box of an
    120 %      image canvas.
    121 %
    122 %    o image: the image.
    123 %
    124 %    o exception: return any errors or warnings in this structure.
    125 %
    126 */
    127 MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
    128   ExceptionInfo *exception)
    129 {
    130   CacheView
    131     *image_view;
    132 
    133   MagickBooleanType
    134     status;
    135 
    136   PixelInfo
    137     target[3],
    138     zero;
    139 
    140   RectangleInfo
    141     bounds;
    142 
    143   register const Quantum
    144     *r;
    145 
    146   ssize_t
    147     y;
    148 
    149   assert(image != (Image *) NULL);
    150   assert(image->signature == MagickCoreSignature);
    151   if (image->debug != MagickFalse)
    152     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    153   bounds.width=0;
    154   bounds.height=0;
    155   bounds.x=(ssize_t) image->columns;
    156   bounds.y=(ssize_t) image->rows;
    157   GetPixelInfo(image,&target[0]);
    158   image_view=AcquireVirtualCacheView(image,exception);
    159   r=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
    160   if (r == (const Quantum *) NULL)
    161     {
    162       image_view=DestroyCacheView(image_view);
    163       return(bounds);
    164     }
    165   GetPixelInfoPixel(image,r,&target[0]);
    166   GetPixelInfo(image,&target[1]);
    167   r=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,0,1,1,
    168     exception);
    169   if (r != (const Quantum *) NULL)
    170     GetPixelInfoPixel(image,r,&target[1]);
    171   GetPixelInfo(image,&target[2]);
    172   r=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-1,1,1,
    173     exception);
    174   if (r != (const Quantum *) NULL)
    175     GetPixelInfoPixel(image,r,&target[2]);
    176   status=MagickTrue;
    177   GetPixelInfo(image,&zero);
    178 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    179   #pragma omp parallel for schedule(static,4) shared(status) \
    180     magick_threads(image,image,image->rows,1)
    181 #endif
    182   for (y=0; y < (ssize_t) image->rows; y++)
    183   {
    184     PixelInfo
    185       pixel;
    186 
    187     RectangleInfo
    188       bounding_box;
    189 
    190     register const Quantum
    191       *magick_restrict p;
    192 
    193     register ssize_t
    194       x;
    195 
    196     if (status == MagickFalse)
    197       continue;
    198 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    199 #  pragma omp critical (MagickCore_GetImageBoundingBox)
    200 #endif
    201     bounding_box=bounds;
    202     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    203     if (p == (const Quantum *) NULL)
    204       {
    205         status=MagickFalse;
    206         continue;
    207       }
    208     pixel=zero;
    209     for (x=0; x < (ssize_t) image->columns; x++)
    210     {
    211       GetPixelInfoPixel(image,p,&pixel);
    212       if ((x < bounding_box.x) &&
    213           (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
    214         bounding_box.x=x;
    215       if ((x > (ssize_t) bounding_box.width) &&
    216           (IsFuzzyEquivalencePixelInfo(&pixel,&target[1]) == MagickFalse))
    217         bounding_box.width=(size_t) x;
    218       if ((y < bounding_box.y) &&
    219           (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
    220         bounding_box.y=y;
    221       if ((y > (ssize_t) bounding_box.height) &&
    222           (IsFuzzyEquivalencePixelInfo(&pixel,&target[2]) == MagickFalse))
    223         bounding_box.height=(size_t) y;
    224       p+=GetPixelChannels(image);
    225     }
    226 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    227 #  pragma omp critical (MagickCore_GetImageBoundingBox)
    228 #endif
    229     {
    230       if (bounding_box.x < bounds.x)
    231         bounds.x=bounding_box.x;
    232       if (bounding_box.y < bounds.y)
    233         bounds.y=bounding_box.y;
    234       if (bounding_box.width > bounds.width)
    235         bounds.width=bounding_box.width;
    236       if (bounding_box.height > bounds.height)
    237         bounds.height=bounding_box.height;
    238     }
    239   }
    240   image_view=DestroyCacheView(image_view);
    241   if ((bounds.width == 0) && (bounds.height == 0))
    242     (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
    243       "GeometryDoesNotContainImage","`%s'",image->filename);
    244   else
    245     {
    246       bounds.width-=(bounds.x-1);
    247       bounds.height-=(bounds.y-1);
    248     }
    249   return(bounds);
    250 }
    251 
    252 /*
    254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    255 %                                                                             %
    256 %                                                                             %
    257 %                                                                             %
    258 %   G e t I m a g e D e p t h                                                 %
    259 %                                                                             %
    260 %                                                                             %
    261 %                                                                             %
    262 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    263 %
    264 %  GetImageDepth() returns the depth of a particular image channel.
    265 %
    266 %  The format of the GetImageDepth method is:
    267 %
    268 %      size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
    269 %
    270 %  A description of each parameter follows:
    271 %
    272 %    o image: the image.
    273 %
    274 %    o exception: return any errors or warnings in this structure.
    275 %
    276 */
    277 MagickExport size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
    278 {
    279   CacheView
    280     *image_view;
    281 
    282   MagickBooleanType
    283     status;
    284 
    285   register ssize_t
    286     i;
    287 
    288   size_t
    289     *current_depth,
    290     depth,
    291     number_threads;
    292 
    293   ssize_t
    294     y;
    295 
    296   /*
    297     Compute image depth.
    298   */
    299   assert(image != (Image *) NULL);
    300   assert(image->signature == MagickCoreSignature);
    301   if (image->debug != MagickFalse)
    302     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    303   number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
    304   current_depth=(size_t *) AcquireQuantumMemory(number_threads,
    305     sizeof(*current_depth));
    306   if (current_depth == (size_t *) NULL)
    307     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
    308   status=MagickTrue;
    309   for (i=0; i < (ssize_t) number_threads; i++)
    310     current_depth[i]=1;
    311   if ((image->storage_class == PseudoClass) &&
    312       (image->alpha_trait == UndefinedPixelTrait))
    313     {
    314 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    315       #pragma omp parallel for schedule(static,4) shared(status) \
    316         if ((image->colors) > 256) \
    317           num_threads(GetMagickResourceLimit(ThreadResource))
    318 #endif
    319       for (i=0; i < (ssize_t) image->colors; i++)
    320       {
    321         const int
    322           id = GetOpenMPThreadId();
    323 
    324         while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
    325         {
    326           MagickBooleanType
    327             atDepth;
    328 
    329           QuantumAny
    330             range;
    331 
    332           atDepth=MagickTrue;
    333           range=GetQuantumRange(current_depth[id]);
    334           if ((atDepth != MagickFalse) &&
    335               (GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
    336             if (IsPixelAtDepth(image->colormap[i].red,range) == MagickFalse)
    337               atDepth=MagickFalse;
    338           if ((atDepth != MagickFalse) &&
    339               (GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
    340             if (IsPixelAtDepth(image->colormap[i].green,range) == MagickFalse)
    341               atDepth=MagickFalse;
    342           if ((atDepth != MagickFalse) &&
    343               (GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
    344             if (IsPixelAtDepth(image->colormap[i].blue,range) == MagickFalse)
    345               atDepth=MagickFalse;
    346           if ((atDepth != MagickFalse))
    347             break;
    348           current_depth[id]++;
    349         }
    350       }
    351       depth=current_depth[0];
    352       for (i=1; i < (ssize_t) number_threads; i++)
    353         if (depth < current_depth[i])
    354           depth=current_depth[i];
    355       current_depth=(size_t *) RelinquishMagickMemory(current_depth);
    356       return(depth);
    357     }
    358   image_view=AcquireVirtualCacheView(image,exception);
    359 #if !defined(MAGICKCORE_HDRI_SUPPORT)
    360   if (QuantumRange <= MaxMap)
    361     {
    362       size_t
    363         *depth_map;
    364 
    365       /*
    366         Scale pixels to desired (optimized with depth map).
    367       */
    368       depth_map=(size_t *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
    369       if (depth_map == (size_t *) NULL)
    370         ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
    371       for (i=0; i <= (ssize_t) MaxMap; i++)
    372       {
    373         unsigned int
    374           depth;
    375 
    376         for (depth=1; depth < MAGICKCORE_QUANTUM_DEPTH; depth++)
    377         {
    378           Quantum
    379             pixel;
    380 
    381           QuantumAny
    382             range;
    383 
    384           range=GetQuantumRange(depth);
    385           pixel=(Quantum) i;
    386           if (pixel == ScaleAnyToQuantum(ScaleQuantumToAny(pixel,range),range))
    387             break;
    388         }
    389         depth_map[i]=depth;
    390       }
    391 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    392       #pragma omp parallel for schedule(static,4) shared(status) \
    393         magick_threads(image,image,image->rows,1)
    394 #endif
    395       for (y=0; y < (ssize_t) image->rows; y++)
    396       {
    397         const int
    398           id = GetOpenMPThreadId();
    399 
    400         register const Quantum
    401           *magick_restrict p;
    402 
    403         register ssize_t
    404           x;
    405 
    406         if (status == MagickFalse)
    407           continue;
    408         p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    409         if (p == (const Quantum *) NULL)
    410           continue;
    411         for (x=0; x < (ssize_t) image->columns; x++)
    412         {
    413           if (GetPixelReadMask(image,p) == 0)
    414             {
    415               p+=GetPixelChannels(image);
    416               continue;
    417             }
    418           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
    419           {
    420             PixelChannel channel=GetPixelChannelChannel(image,i);
    421             PixelTrait traits=GetPixelChannelTraits(image,channel);
    422             if ((traits == UndefinedPixelTrait) ||
    423                 (channel == IndexPixelChannel) ||
    424                 (channel == ReadMaskPixelChannel) ||
    425                 (channel == MetaPixelChannel))
    426               continue;
    427             if (depth_map[ScaleQuantumToMap(p[i])] > current_depth[id])
    428               current_depth[id]=depth_map[ScaleQuantumToMap(p[i])];
    429           }
    430           p+=GetPixelChannels(image);
    431         }
    432         if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
    433           status=MagickFalse;
    434       }
    435       image_view=DestroyCacheView(image_view);
    436       depth=current_depth[0];
    437       for (i=1; i < (ssize_t) number_threads; i++)
    438         if (depth < current_depth[i])
    439           depth=current_depth[i];
    440       depth_map=(size_t *) RelinquishMagickMemory(depth_map);
    441       current_depth=(size_t *) RelinquishMagickMemory(current_depth);
    442       return(depth);
    443     }
    444 #endif
    445   /*
    446     Compute pixel depth.
    447   */
    448 #if defined(MAGICKCORE_OPENMP_SUPPORT)
    449   #pragma omp parallel for schedule(static,4) shared(status) \
    450     magick_threads(image,image,image->rows,1)
    451 #endif
    452   for (y=0; y < (ssize_t) image->rows; y++)
    453   {
    454     const int
    455       id = GetOpenMPThreadId();
    456 
    457     register const Quantum
    458       *magick_restrict p;
    459 
    460     register ssize_t
    461       x;
    462 
    463     if (status == MagickFalse)
    464       continue;
    465     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    466     if (p == (const Quantum *) NULL)
    467       continue;
    468     for (x=0; x < (ssize_t) image->columns; x++)
    469     {
    470       if (GetPixelReadMask(image,p) == 0)
    471         {
    472           p+=GetPixelChannels(image);
    473           continue;
    474         }
    475       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
    476       {
    477         PixelChannel
    478           channel;
    479 
    480         PixelTrait
    481           traits;
    482 
    483         channel=GetPixelChannelChannel(image,i);
    484         traits=GetPixelChannelTraits(image,channel);
    485         if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
    486             (channel == ReadMaskPixelChannel))
    487           continue;
    488         while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
    489         {
    490           QuantumAny
    491             range;
    492 
    493           range=GetQuantumRange(current_depth[id]);
    494           if (p[i] == ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),range))
    495             break;
    496           current_depth[id]++;
    497         }
    498       }
    499       p+=GetPixelChannels(image);
    500     }
    501     if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
    502       status=MagickFalse;
    503   }
    504   image_view=DestroyCacheView(image_view);
    505   depth=current_depth[0];
    506   for (i=1; i < (ssize_t) number_threads; i++)
    507     if (depth < current_depth[i])
    508       depth=current_depth[i];
    509   current_depth=(size_t *) RelinquishMagickMemory(current_depth);
    510   return(depth);
    511 }
    512 
    513 /*
    515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    516 %                                                                             %
    517 %                                                                             %
    518 %                                                                             %
    519 %   G e t I m a g e Q u a n t u m D e p t h                                   %
    520 %                                                                             %
    521 %                                                                             %
    522 %                                                                             %
    523 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    524 %
    525 %  GetImageQuantumDepth() returns the depth of the image rounded to a legal
    526 %  quantum depth: 8, 16, or 32.
    527 %
    528 %  The format of the GetImageQuantumDepth method is:
    529 %
    530 %      size_t GetImageQuantumDepth(const Image *image,
    531 %        const MagickBooleanType constrain)
    532 %
    533 %  A description of each parameter follows:
    534 %
    535 %    o image: the image.
    536 %
    537 %    o constrain: A value other than MagickFalse, constrains the depth to
    538 %      a maximum of MAGICKCORE_QUANTUM_DEPTH.
    539 %
    540 */
    541 MagickExport size_t GetImageQuantumDepth(const Image *image,
    542   const MagickBooleanType constrain)
    543 {
    544   size_t
    545     depth;
    546 
    547   depth=image->depth;
    548   if (depth <= 8)
    549     depth=8;
    550   else
    551     if (depth <= 16)
    552       depth=16;
    553     else
    554       if (depth <= 32)
    555         depth=32;
    556       else
    557         if (depth <= 64)
    558           depth=64;
    559   if (constrain != MagickFalse)
    560     depth=(size_t) MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH);
    561   return(depth);
    562 }
    563 
    564 /*
    566 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    567 %                                                                             %
    568 %                                                                             %
    569 %                                                                             %
    570 %   G e t I m a g e T y p e                                                   %
    571 %                                                                             %
    572 %                                                                             %
    573 %                                                                             %
    574 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    575 %
    576 %  GetImageType() returns the type of image:
    577 %
    578 %        Bilevel         Grayscale        GrayscaleMatte
    579 %        Palette         PaletteMatte     TrueColor
    580 %        TrueColorMatte  ColorSeparation  ColorSeparationMatte
    581 %
    582 %  The format of the GetImageType method is:
    583 %
    584 %      ImageType GetImageType(const Image *image)
    585 %
    586 %  A description of each parameter follows:
    587 %
    588 %    o image: the image.
    589 %
    590 */
    591 MagickExport ImageType GetImageType(const Image *image)
    592 {
    593   assert(image != (Image *) NULL);
    594   assert(image->signature == MagickCoreSignature);
    595   if (image->colorspace == CMYKColorspace)
    596     {
    597       if (image->alpha_trait == UndefinedPixelTrait)
    598         return(ColorSeparationType);
    599       return(ColorSeparationAlphaType);
    600     }
    601   if (IsImageMonochrome(image) != MagickFalse)
    602     return(BilevelType);
    603   if (IsImageGray(image) != MagickFalse)
    604     {
    605       if (image->alpha_trait != UndefinedPixelTrait)
    606         return(GrayscaleAlphaType);
    607       return(GrayscaleType);
    608     }
    609   if (IsPaletteImage(image) != MagickFalse)
    610     {
    611       if (image->alpha_trait != UndefinedPixelTrait)
    612         return(PaletteAlphaType);
    613       return(PaletteType);
    614     }
    615   if (image->alpha_trait != UndefinedPixelTrait)
    616     return(TrueColorAlphaType);
    617   return(TrueColorType);
    618 }
    619 
    620 /*
    622 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    623 %                                                                             %
    624 %                                                                             %
    625 %                                                                             %
    626 %     I d e n t i f y I m a g e G r a y                                       %
    627 %                                                                             %
    628 %                                                                             %
    629 %                                                                             %
    630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    631 %
    632 %  IdentifyImageGray() returns grayscale if all the pixels in the image have
    633 %  the same red, green, and blue intensities, and bi-level is the intensity is
    634 %  either 0 or QuantumRange. Otherwise undefined is returned.
    635 %
    636 %  The format of the IdentifyImageGray method is:
    637 %
    638 %      ImageType IdentifyImageGray(const Image *image,ExceptionInfo *exception)
    639 %
    640 %  A description of each parameter follows:
    641 %
    642 %    o image: the image.
    643 %
    644 %    o exception: return any errors or warnings in this structure.
    645 %
    646 */
    647 MagickExport ImageType IdentifyImageGray(const Image *image,
    648   ExceptionInfo *exception)
    649 {
    650   CacheView
    651     *image_view;
    652 
    653   ImageType
    654     type;
    655 
    656   register const Quantum
    657     *p;
    658 
    659   register ssize_t
    660     x;
    661 
    662   ssize_t
    663     y;
    664 
    665   assert(image != (Image *) NULL);
    666   assert(image->signature == MagickCoreSignature);
    667   if (image->debug != MagickFalse)
    668     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    669   if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
    670       (image->type == GrayscaleAlphaType))
    671     return(image->type);
    672   if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
    673     return(UndefinedType);
    674   type=BilevelType;
    675   image_view=AcquireVirtualCacheView(image,exception);
    676   for (y=0; y < (ssize_t) image->rows; y++)
    677   {
    678     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    679     if (p == (const Quantum *) NULL)
    680       break;
    681     for (x=0; x < (ssize_t) image->columns; x++)
    682     {
    683       if (IsPixelGray(image,p) == MagickFalse)
    684         {
    685           type=UndefinedType;
    686           break;
    687         }
    688       if ((type == BilevelType) &&
    689           (IsPixelMonochrome(image,p) == MagickFalse))
    690         type=GrayscaleType;
    691       p+=GetPixelChannels(image);
    692     }
    693     if (type == UndefinedType)
    694       break;
    695   }
    696   image_view=DestroyCacheView(image_view);
    697   if ((type == GrayscaleType) && (image->alpha_trait != UndefinedPixelTrait))
    698     type=GrayscaleAlphaType;
    699   return(type);
    700 }
    701 
    702 /*
    704 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    705 %                                                                             %
    706 %                                                                             %
    707 %                                                                             %
    708 %   I d e n t i f y I m a g e M o n o c h r o m e                             %
    709 %                                                                             %
    710 %                                                                             %
    711 %                                                                             %
    712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    713 %
    714 %  IdentifyImageMonochrome() returns MagickTrue if all the pixels in the image
    715 %  have the same red, green, and blue intensities and the intensity is either
    716 %  0 or QuantumRange.
    717 %
    718 %  The format of the IdentifyImageMonochrome method is:
    719 %
    720 %      MagickBooleanType IdentifyImageMonochrome(const Image *image,
    721 %        ExceptionInfo *exception)
    722 %
    723 %  A description of each parameter follows:
    724 %
    725 %    o image: the image.
    726 %
    727 %    o exception: return any errors or warnings in this structure.
    728 %
    729 */
    730 MagickExport MagickBooleanType IdentifyImageMonochrome(const Image *image,
    731   ExceptionInfo *exception)
    732 {
    733   CacheView
    734     *image_view;
    735 
    736   ImageType
    737     type;
    738 
    739   register ssize_t
    740     x;
    741 
    742   register const Quantum
    743     *p;
    744 
    745   ssize_t
    746     y;
    747 
    748   assert(image != (Image *) NULL);
    749   assert(image->signature == MagickCoreSignature);
    750   if (image->debug != MagickFalse)
    751     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    752   if (image->type == BilevelType)
    753     return(MagickTrue);
    754   if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
    755     return(MagickFalse);
    756   type=BilevelType;
    757   image_view=AcquireVirtualCacheView(image,exception);
    758   for (y=0; y < (ssize_t) image->rows; y++)
    759   {
    760     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    761     if (p == (const Quantum *) NULL)
    762       break;
    763     for (x=0; x < (ssize_t) image->columns; x++)
    764     {
    765       if (IsPixelMonochrome(image,p) == MagickFalse)
    766         {
    767           type=UndefinedType;
    768           break;
    769         }
    770       p+=GetPixelChannels(image);
    771     }
    772     if (type == UndefinedType)
    773       break;
    774   }
    775   image_view=DestroyCacheView(image_view);
    776   if (type == BilevelType)
    777     return(MagickTrue);
    778   return(MagickFalse);
    779 }
    780 
    781 /*
    783 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    784 %                                                                             %
    785 %                                                                             %
    786 %                                                                             %
    787 %   I d e n t i f y I m a g e T y p e                                         %
    788 %                                                                             %
    789 %                                                                             %
    790 %                                                                             %
    791 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    792 %
    793 %  IdentifyImageType() returns the potential type of image:
    794 %
    795 %        Bilevel         Grayscale        GrayscaleMatte
    796 %        Palette         PaletteMatte     TrueColor
    797 %        TrueColorMatte  ColorSeparation  ColorSeparationMatte
    798 %
    799 %  To ensure the image type matches its potential, use SetImageType():
    800 %
    801 %    (void) SetImageType(image,IdentifyImageType(image,exception),exception);
    802 %
    803 %  The format of the IdentifyImageType method is:
    804 %
    805 %      ImageType IdentifyImageType(const Image *image,ExceptionInfo *exception)
    806 %
    807 %  A description of each parameter follows:
    808 %
    809 %    o image: the image.
    810 %
    811 %    o exception: return any errors or warnings in this structure.
    812 %
    813 */
    814 MagickExport ImageType IdentifyImageType(const Image *image,
    815   ExceptionInfo *exception)
    816 {
    817   assert(image != (Image *) NULL);
    818   assert(image->signature == MagickCoreSignature);
    819   if (image->debug != MagickFalse)
    820     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    821   if (image->colorspace == CMYKColorspace)
    822     {
    823       if (image->alpha_trait == UndefinedPixelTrait)
    824         return(ColorSeparationType);
    825       return(ColorSeparationAlphaType);
    826     }
    827   if (IdentifyImageMonochrome(image,exception) != MagickFalse)
    828     return(BilevelType);
    829   if (IdentifyImageGray(image,exception) != UndefinedType)
    830     {
    831       if (image->alpha_trait != UndefinedPixelTrait)
    832         return(GrayscaleAlphaType);
    833       return(GrayscaleType);
    834     }
    835   if (IdentifyPaletteImage(image,exception) != MagickFalse)
    836     {
    837       if (image->alpha_trait != UndefinedPixelTrait)
    838         return(PaletteAlphaType);
    839       return(PaletteType);
    840     }
    841   if (image->alpha_trait != UndefinedPixelTrait)
    842     return(TrueColorAlphaType);
    843   return(TrueColorType);
    844 }
    845 
    846 /*
    848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    849 %                                                                             %
    850 %                                                                             %
    851 %                                                                             %
    852 %     I s I m a g e G r a y                                                   %
    853 %                                                                             %
    854 %                                                                             %
    855 %                                                                             %
    856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    857 %
    858 %  IsImageGray() returns MagickTrue if the type of the image is grayscale or
    859 %  bi-level.
    860 %
    861 %  The format of the IsImageGray method is:
    862 %
    863 %      MagickBooleanType IsImageGray(const Image *image)
    864 %
    865 %  A description of each parameter follows:
    866 %
    867 %    o image: the image.
    868 %
    869 */
    870 MagickExport MagickBooleanType IsImageGray(const Image *image)
    871 {
    872   assert(image != (Image *) NULL);
    873   assert(image->signature == MagickCoreSignature);
    874   if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
    875       (image->type == GrayscaleAlphaType))
    876     return(MagickTrue);
    877   return(MagickFalse);
    878 }
    879 
    880 /*
    882 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    883 %                                                                             %
    884 %                                                                             %
    885 %                                                                             %
    886 %   I s I m a g e M o n o c h r o m e                                         %
    887 %                                                                             %
    888 %                                                                             %
    889 %                                                                             %
    890 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    891 %
    892 %  IsImageMonochrome() returns MagickTrue if type of the image is bi-level.
    893 %
    894 %  The format of the IsImageMonochrome method is:
    895 %
    896 %      MagickBooleanType IsImageMonochrome(const Image *image)
    897 %
    898 %  A description of each parameter follows:
    899 %
    900 %    o image: the image.
    901 %
    902 */
    903 MagickExport MagickBooleanType IsImageMonochrome(const Image *image)
    904 {
    905   assert(image != (Image *) NULL);
    906   assert(image->signature == MagickCoreSignature);
    907   if (image->type == BilevelType)
    908     return(MagickTrue);
    909   return(MagickFalse);
    910 }
    911 
    912 /*
    914 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    915 %                                                                             %
    916 %                                                                             %
    917 %                                                                             %
    918 %     I s I m a g e O p a q u e                                               %
    919 %                                                                             %
    920 %                                                                             %
    921 %                                                                             %
    922 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    923 %
    924 %  IsImageOpaque() returns MagickTrue if none of the pixels in the image have
    925 %  an alpha value other than OpaqueAlpha (QuantumRange).
    926 %
    927 %  Will return true immediatally is alpha channel is not available.
    928 %
    929 %  The format of the IsImageOpaque method is:
    930 %
    931 %      MagickBooleanType IsImageOpaque(const Image *image,
    932 %        ExceptionInfo *exception)
    933 %
    934 %  A description of each parameter follows:
    935 %
    936 %    o image: the image.
    937 %
    938 %    o exception: return any errors or warnings in this structure.
    939 %
    940 */
    941 MagickExport MagickBooleanType IsImageOpaque(const Image *image,
    942   ExceptionInfo *exception)
    943 {
    944   CacheView
    945     *image_view;
    946 
    947   register const Quantum
    948     *p;
    949 
    950   register ssize_t
    951     x;
    952 
    953   ssize_t
    954     y;
    955 
    956   /*
    957     Determine if image is opaque.
    958   */
    959   assert(image != (Image *) NULL);
    960   assert(image->signature == MagickCoreSignature);
    961   if (image->debug != MagickFalse)
    962     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
    963   if (image->alpha_trait == UndefinedPixelTrait)
    964     return(MagickTrue);
    965   image_view=AcquireVirtualCacheView(image,exception);
    966   for (y=0; y < (ssize_t) image->rows; y++)
    967   {
    968     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
    969     if (p == (const Quantum *) NULL)
    970       break;
    971     for (x=0; x < (ssize_t) image->columns; x++)
    972     {
    973       if (GetPixelAlpha(image,p) != OpaqueAlpha)
    974         break;
    975       p+=GetPixelChannels(image);
    976     }
    977     if (x < (ssize_t) image->columns)
    978       break;
    979   }
    980   image_view=DestroyCacheView(image_view);
    981   return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
    982 }
    983 
    984 /*
    986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    987 %                                                                             %
    988 %                                                                             %
    989 %                                                                             %
    990 %   S e t I m a g e D e p t h                                                 %
    991 %                                                                             %
    992 %                                                                             %
    993 %                                                                             %
    994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    995 %
    996 %  SetImageDepth() sets the depth of the image.
    997 %
    998 %  The format of the SetImageDepth method is:
    999 %
   1000 %      MagickBooleanType SetImageDepth(Image *image,const size_t depth,
   1001 %        ExceptionInfo *exception)
   1002 %
   1003 %  A description of each parameter follows:
   1004 %
   1005 %    o image: the image.
   1006 %
   1007 %    o channel: the channel.
   1008 %
   1009 %    o depth: the image depth.
   1010 %
   1011 %    o exception: return any errors or warnings in this structure.
   1012 %
   1013 */
   1014 MagickExport MagickBooleanType SetImageDepth(Image *image,
   1015   const size_t depth,ExceptionInfo *exception)
   1016 {
   1017   CacheView
   1018     *image_view;
   1019 
   1020   MagickBooleanType
   1021     status;
   1022 
   1023   QuantumAny
   1024     range;
   1025 
   1026   ssize_t
   1027     y;
   1028 
   1029   assert(image != (Image *) NULL);
   1030   if (image->debug != MagickFalse)
   1031     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
   1032   assert(image->signature == MagickCoreSignature);
   1033   if (depth >= MAGICKCORE_QUANTUM_DEPTH)
   1034     {
   1035       image->depth=depth;
   1036       return(MagickTrue);
   1037     }
   1038   range=GetQuantumRange(depth);
   1039   if (image->storage_class == PseudoClass)
   1040     {
   1041       register ssize_t
   1042         i;
   1043 
   1044 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1045       #pragma omp parallel for schedule(static,4) shared(status) \
   1046         magick_threads(image,image,1,1)
   1047 #endif
   1048       for (i=0; i < (ssize_t) image->colors; i++)
   1049       {
   1050         if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
   1051           image->colormap[i].red=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
   1052             ClampPixel(image->colormap[i].red),range),range);
   1053         if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
   1054           image->colormap[i].green=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
   1055             ClampPixel(image->colormap[i].green),range),range);
   1056         if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
   1057           image->colormap[i].blue=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
   1058             ClampPixel(image->colormap[i].blue),range),range);
   1059         if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
   1060           image->colormap[i].alpha=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
   1061             ClampPixel(image->colormap[i].alpha),range),range);
   1062       }
   1063     }
   1064   status=MagickTrue;
   1065   image_view=AcquireAuthenticCacheView(image,exception);
   1066 #if !defined(MAGICKCORE_HDRI_SUPPORT)
   1067   if (QuantumRange <= MaxMap)
   1068     {
   1069       Quantum
   1070         *depth_map;
   1071 
   1072       register ssize_t
   1073         i;
   1074 
   1075       /*
   1076         Scale pixels to desired (optimized with depth map).
   1077       */
   1078       depth_map=(Quantum *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
   1079       if (depth_map == (Quantum *) NULL)
   1080         ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
   1081       for (i=0; i <= (ssize_t) MaxMap; i++)
   1082         depth_map[i]=ScaleAnyToQuantum(ScaleQuantumToAny((Quantum) i,range),
   1083           range);
   1084 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1085       #pragma omp parallel for schedule(static,4) shared(status) \
   1086         magick_threads(image,image,image->rows,1)
   1087 #endif
   1088       for (y=0; y < (ssize_t) image->rows; y++)
   1089       {
   1090         register ssize_t
   1091           x;
   1092 
   1093         register Quantum
   1094           *magick_restrict q;
   1095 
   1096         if (status == MagickFalse)
   1097           continue;
   1098         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
   1099           exception);
   1100         if (q == (Quantum *) NULL)
   1101           {
   1102             status=MagickFalse;
   1103             continue;
   1104           }
   1105         for (x=0; x < (ssize_t) image->columns; x++)
   1106         {
   1107           register ssize_t
   1108             i;
   1109 
   1110           if (GetPixelReadMask(image,q) == 0)
   1111             {
   1112               q+=GetPixelChannels(image);
   1113               continue;
   1114             }
   1115           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   1116           {
   1117             PixelChannel
   1118               channel;
   1119 
   1120             PixelTrait
   1121               traits;
   1122 
   1123             channel=GetPixelChannelChannel(image,i);
   1124             traits=GetPixelChannelTraits(image,channel);
   1125             if ((traits == UndefinedPixelTrait) ||
   1126                 (channel == IndexPixelChannel) ||
   1127                 (channel == ReadMaskPixelChannel))
   1128               continue;
   1129             q[i]=depth_map[ScaleQuantumToMap(q[i])];
   1130           }
   1131           q+=GetPixelChannels(image);
   1132         }
   1133         if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
   1134           {
   1135             status=MagickFalse;
   1136             continue;
   1137           }
   1138       }
   1139       image_view=DestroyCacheView(image_view);
   1140       depth_map=(Quantum *) RelinquishMagickMemory(depth_map);
   1141       if (status != MagickFalse)
   1142         image->depth=depth;
   1143       return(status);
   1144     }
   1145 #endif
   1146   /*
   1147     Scale pixels to desired depth.
   1148   */
   1149 #if defined(MAGICKCORE_OPENMP_SUPPORT)
   1150   #pragma omp parallel for schedule(static,4) shared(status) \
   1151     magick_threads(image,image,image->rows,1)
   1152 #endif
   1153   for (y=0; y < (ssize_t) image->rows; y++)
   1154   {
   1155     register ssize_t
   1156       x;
   1157 
   1158     register Quantum
   1159       *magick_restrict q;
   1160 
   1161     if (status == MagickFalse)
   1162       continue;
   1163     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
   1164     if (q == (Quantum *) NULL)
   1165       {
   1166         status=MagickFalse;
   1167         continue;
   1168       }
   1169     for (x=0; x < (ssize_t) image->columns; x++)
   1170     {
   1171       register ssize_t
   1172         i;
   1173 
   1174       if (GetPixelReadMask(image,q) == 0)
   1175         {
   1176           q+=GetPixelChannels(image);
   1177           continue;
   1178         }
   1179       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
   1180       {
   1181         PixelChannel
   1182           channel;
   1183 
   1184         PixelTrait
   1185           traits;
   1186 
   1187         channel=GetPixelChannelChannel(image,i);
   1188         traits=GetPixelChannelTraits(image,channel);
   1189         if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
   1190             (channel == ReadMaskPixelChannel))
   1191           continue;
   1192         q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(ClampPixel(q[i]),range),range);
   1193       }
   1194       q+=GetPixelChannels(image);
   1195     }
   1196     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
   1197       {
   1198         status=MagickFalse;
   1199         continue;
   1200       }
   1201   }
   1202   image_view=DestroyCacheView(image_view);
   1203   if (status != MagickFalse)
   1204     image->depth=depth;
   1205   return(status);
   1206 }
   1207 
   1208 /*
   1210 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1211 %                                                                             %
   1212 %                                                                             %
   1213 %                                                                             %
   1214 %   S e t I m a g e T y p e                                                   %
   1215 %                                                                             %
   1216 %                                                                             %
   1217 %                                                                             %
   1218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   1219 %
   1220 %  SetImageType() sets the type of image.  Choose from these types:
   1221 %
   1222 %        Bilevel        Grayscale       GrayscaleMatte
   1223 %        Palette        PaletteMatte    TrueColor
   1224 %        TrueColorMatte ColorSeparation ColorSeparationMatte
   1225 %        OptimizeType
   1226 %
   1227 %  The format of the SetImageType method is:
   1228 %
   1229 %      MagickBooleanType SetImageType(Image *image,const ImageType type,
   1230 %        ExceptionInfo *exception)
   1231 %
   1232 %  A description of each parameter follows:
   1233 %
   1234 %    o image: the image.
   1235 %
   1236 %    o type: Image type.
   1237 %
   1238 %    o exception: return any errors or warnings in this structure.
   1239 %
   1240 */
   1241 MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type,
   1242   ExceptionInfo *exception)
   1243 {
   1244   const char
   1245     *artifact;
   1246 
   1247   ImageInfo
   1248     *image_info;
   1249 
   1250   MagickBooleanType
   1251     status;
   1252 
   1253   QuantizeInfo
   1254     *quantize_info;
   1255 
   1256   assert(image != (Image *) NULL);
   1257   if (image->debug != MagickFalse)
   1258     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
   1259   assert(image->signature == MagickCoreSignature);
   1260   status=MagickTrue;
   1261   image_info=AcquireImageInfo();
   1262   image_info->dither=image->dither;
   1263   artifact=GetImageArtifact(image,"dither");
   1264   if (artifact != (const char *) NULL)
   1265     (void) SetImageOption(image_info,"dither",artifact);
   1266   switch (type)
   1267   {
   1268     case BilevelType:
   1269     {
   1270       if (SetImageMonochrome(image,exception) == MagickFalse)
   1271         {
   1272           status=TransformImageColorspace(image,GRAYColorspace,exception);
   1273           (void) NormalizeImage(image,exception);
   1274           quantize_info=AcquireQuantizeInfo(image_info);
   1275           quantize_info->number_colors=2;
   1276           quantize_info->colorspace=GRAYColorspace;
   1277           status=QuantizeImage(quantize_info,image,exception);
   1278           quantize_info=DestroyQuantizeInfo(quantize_info);
   1279         }
   1280       image->colors=2;
   1281       image->alpha_trait=UndefinedPixelTrait;
   1282       break;
   1283     }
   1284     case GrayscaleType:
   1285     {
   1286       if (SetImageGray(image,exception) == MagickFalse)
   1287         status=TransformImageColorspace(image,GRAYColorspace,exception);
   1288       image->alpha_trait=UndefinedPixelTrait;
   1289       break;
   1290     }
   1291     case GrayscaleAlphaType:
   1292     {
   1293       if (SetImageGray(image,exception) == MagickFalse)
   1294         status=TransformImageColorspace(image,GRAYColorspace,exception);
   1295       if (image->alpha_trait == UndefinedPixelTrait)
   1296         (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
   1297       break;
   1298     }
   1299     case PaletteType:
   1300     {
   1301       if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
   1302         status=TransformImageColorspace(image,sRGBColorspace,exception);
   1303       if ((image->storage_class == DirectClass) || (image->colors > 256))
   1304         {
   1305           quantize_info=AcquireQuantizeInfo(image_info);
   1306           quantize_info->number_colors=256;
   1307           status=QuantizeImage(quantize_info,image,exception);
   1308           quantize_info=DestroyQuantizeInfo(quantize_info);
   1309         }
   1310       image->alpha_trait=UndefinedPixelTrait;
   1311       break;
   1312     }
   1313     case PaletteBilevelAlphaType:
   1314     {
   1315       ChannelType
   1316         channel_mask;
   1317 
   1318       if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
   1319         status=TransformImageColorspace(image,sRGBColorspace,exception);
   1320       if (image->alpha_trait == UndefinedPixelTrait)
   1321         (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
   1322       channel_mask=SetImageChannelMask(image,AlphaChannel);
   1323       (void) BilevelImage(image,(double) QuantumRange/2.0,exception);
   1324       (void) SetImageChannelMask(image,channel_mask);
   1325       quantize_info=AcquireQuantizeInfo(image_info);
   1326       status=QuantizeImage(quantize_info,image,exception);
   1327       quantize_info=DestroyQuantizeInfo(quantize_info);
   1328       break;
   1329     }
   1330     case PaletteAlphaType:
   1331     {
   1332       if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
   1333         status=TransformImageColorspace(image,sRGBColorspace,exception);
   1334       if (image->alpha_trait == UndefinedPixelTrait)
   1335         (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
   1336       quantize_info=AcquireQuantizeInfo(image_info);
   1337       quantize_info->colorspace=TransparentColorspace;
   1338       status=QuantizeImage(quantize_info,image,exception);
   1339       quantize_info=DestroyQuantizeInfo(quantize_info);
   1340       break;
   1341     }
   1342     case TrueColorType:
   1343     {
   1344       if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
   1345         status=TransformImageColorspace(image,sRGBColorspace,exception);
   1346       if (image->storage_class != DirectClass)
   1347         status=SetImageStorageClass(image,DirectClass,exception);
   1348       image->alpha_trait=UndefinedPixelTrait;
   1349       break;
   1350     }
   1351     case TrueColorAlphaType:
   1352     {
   1353       if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
   1354         status=TransformImageColorspace(image,sRGBColorspace,exception);
   1355       if (image->storage_class != DirectClass)
   1356         status=SetImageStorageClass(image,DirectClass,exception);
   1357       if (image->alpha_trait == UndefinedPixelTrait)
   1358         (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
   1359       break;
   1360     }
   1361     case ColorSeparationType:
   1362     {
   1363       if (image->colorspace != CMYKColorspace)
   1364         {
   1365           if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
   1366             status=TransformImageColorspace(image,sRGBColorspace,exception);
   1367           status=TransformImageColorspace(image,CMYKColorspace,exception);
   1368         }
   1369       if (image->storage_class != DirectClass)
   1370         status=SetImageStorageClass(image,DirectClass,exception);
   1371       image->alpha_trait=UndefinedPixelTrait;
   1372       break;
   1373     }
   1374     case ColorSeparationAlphaType:
   1375     {
   1376       if (image->colorspace != CMYKColorspace)
   1377         {
   1378           if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
   1379             status=TransformImageColorspace(image,sRGBColorspace,exception);
   1380           status=TransformImageColorspace(image,CMYKColorspace,exception);
   1381         }
   1382       if (image->storage_class != DirectClass)
   1383         status=SetImageStorageClass(image,DirectClass,exception);
   1384       if (image->alpha_trait == UndefinedPixelTrait)
   1385         status=SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
   1386       break;
   1387     }
   1388     case OptimizeType:
   1389     case UndefinedType:
   1390       break;
   1391   }
   1392   image_info=DestroyImageInfo(image_info);
   1393   if (status == MagickFalse)
   1394     return(status);
   1395   image->type=type;
   1396   return(MagickTrue);
   1397 }
   1398