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