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