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