]> granicus.if.org Git - imagemagick/blob - MagickCore/attribute.c
https://github.com/ImageMagick/ImageMagick/issues/616
[imagemagick] / MagickCore / attribute.c
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-2017 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 %    https://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 \f
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 \f
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 */
125 MagickExport 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 \f
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 */
274 MagickExport 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(ClampToQuantum(image->colormap[i].red),range) == MagickFalse)
334               atDepth=MagickFalse;
335           if ((atDepth != MagickFalse) &&
336               (GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
337             if (IsPixelAtDepth(ClampToQuantum(image->colormap[i].green),range) == MagickFalse)
338               atDepth=MagickFalse;
339           if ((atDepth != MagickFalse) &&
340               (GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
341             if (IsPixelAtDepth(ClampToQuantum(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 ((1UL*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 (GetPixelWriteMask(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 (GetPixelWriteMask(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 \f
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 */
537 MagickExport 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 \f
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 */
586 MagickExport 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 \f
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 */
641 MagickExport 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 \f
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 */
723 MagickExport 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 \f
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 */
806 MagickExport 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 \f
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 */
861 MagickExport 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 \f
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 */
893 MagickExport 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 \f
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 */
930 MagickExport 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 \f
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 */
1002 MagickExport 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 ((1UL*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 (GetPixelWriteMask(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 (GetPixelWriteMask(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((MagickRealType)
1181           q[i]),range),range);
1182       }
1183       q+=GetPixelChannels(image);
1184     }
1185     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1186       {
1187         status=MagickFalse;
1188         continue;
1189       }
1190   }
1191   image_view=DestroyCacheView(image_view);
1192   if (status != MagickFalse)
1193     image->depth=depth;
1194   return(status);
1195 }
1196 \f
1197 /*
1198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1199 %                                                                             %
1200 %                                                                             %
1201 %                                                                             %
1202 %   S e t I m a g e T y p e                                                   %
1203 %                                                                             %
1204 %                                                                             %
1205 %                                                                             %
1206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1207 %
1208 %  SetImageType() sets the type of image.  Choose from these types:
1209 %
1210 %        Bilevel        Grayscale       GrayscaleMatte
1211 %        Palette        PaletteMatte    TrueColor
1212 %        TrueColorMatte ColorSeparation ColorSeparationMatte
1213 %        OptimizeType
1214 %
1215 %  The format of the SetImageType method is:
1216 %
1217 %      MagickBooleanType SetImageType(Image *image,const ImageType type,
1218 %        ExceptionInfo *exception)
1219 %
1220 %  A description of each parameter follows:
1221 %
1222 %    o image: the image.
1223 %
1224 %    o type: Image type.
1225 %
1226 %    o exception: return any errors or warnings in this structure.
1227 %
1228 */
1229 MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type,
1230   ExceptionInfo *exception)
1231 {
1232   const char
1233     *artifact;
1234
1235   ImageInfo
1236     *image_info;
1237
1238   MagickBooleanType
1239     status;
1240
1241   QuantizeInfo
1242     *quantize_info;
1243
1244   assert(image != (Image *) NULL);
1245   if (image->debug != MagickFalse)
1246     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1247   assert(image->signature == MagickCoreSignature);
1248   status=MagickTrue;
1249   image_info=AcquireImageInfo();
1250   image_info->dither=image->dither;
1251   artifact=GetImageArtifact(image,"dither");
1252   if (artifact != (const char *) NULL)
1253     (void) SetImageOption(image_info,"dither",artifact);
1254   switch (type)
1255   {
1256     case BilevelType:
1257     {
1258       if (SetImageMonochrome(image,exception) == MagickFalse)
1259         {
1260           status=TransformImageColorspace(image,GRAYColorspace,exception);
1261           (void) NormalizeImage(image,exception);
1262           quantize_info=AcquireQuantizeInfo(image_info);
1263           quantize_info->number_colors=2;
1264           quantize_info->colorspace=GRAYColorspace;
1265           status=QuantizeImage(quantize_info,image,exception);
1266           quantize_info=DestroyQuantizeInfo(quantize_info);
1267         }
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 }