• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 
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 
GetEdgeBackgroundFactor(const Image * image,const CacheView * image_view,const GravityType gravity,const size_t width,const size_t height,const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo * exception)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 
GetMinEdgeBackgroundFactor(const EdgeInfo * edge)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 
GetImageBoundingBox(const Image * image,ExceptionInfo * exception)240 MagickExport RectangleInfo GetImageBoundingBox(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 /*
381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
382 %                                                                             %
383 %                                                                             %
384 %                                                                             %
385 %   G e t I m a g e D e p t h                                                 %
386 %                                                                             %
387 %                                                                             %
388 %                                                                             %
389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
390 %
391 %  GetImageDepth() returns the depth of a particular image channel.
392 %
393 %  The format of the GetImageDepth method is:
394 %
395 %      size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
396 %
397 %  A description of each parameter follows:
398 %
399 %    o image: the image.
400 %
401 %    o exception: return any errors or warnings in this structure.
402 %
403 */
GetImageDepth(const Image * image,ExceptionInfo * exception)404 MagickExport size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
405 {
406   CacheView
407     *image_view;
408 
409   MagickBooleanType
410     status;
411 
412   register ssize_t
413     i;
414 
415   size_t
416     *current_depth,
417     depth,
418     number_threads;
419 
420   ssize_t
421     y;
422 
423   /*
424     Compute image depth.
425   */
426   assert(image != (Image *) NULL);
427   assert(image->signature == MagickCoreSignature);
428   if (image->debug != MagickFalse)
429     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
430   number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
431   current_depth=(size_t *) AcquireQuantumMemory(number_threads,
432     sizeof(*current_depth));
433   if (current_depth == (size_t *) NULL)
434     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
435   status=MagickTrue;
436   for (i=0; i < (ssize_t) number_threads; i++)
437     current_depth[i]=1;
438   if ((image->storage_class == PseudoClass) &&
439       (image->alpha_trait == UndefinedPixelTrait))
440     {
441       for (i=0; i < (ssize_t) image->colors; i++)
442       {
443         const int
444           id = GetOpenMPThreadId();
445 
446         while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
447         {
448           MagickBooleanType
449             atDepth;
450 
451           QuantumAny
452             range;
453 
454           atDepth=MagickTrue;
455           range=GetQuantumRange(current_depth[id]);
456           if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
457             if (IsPixelAtDepth(ClampToQuantum(image->colormap[i].red),range) == MagickFalse)
458               atDepth=MagickFalse;
459           if ((atDepth != MagickFalse) &&
460               (GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
461             if (IsPixelAtDepth(ClampToQuantum(image->colormap[i].green),range) == MagickFalse)
462               atDepth=MagickFalse;
463           if ((atDepth != MagickFalse) &&
464               (GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
465             if (IsPixelAtDepth(ClampToQuantum(image->colormap[i].blue),range) == MagickFalse)
466               atDepth=MagickFalse;
467           if ((atDepth != MagickFalse))
468             break;
469           current_depth[id]++;
470         }
471       }
472       depth=current_depth[0];
473       for (i=1; i < (ssize_t) number_threads; i++)
474         if (depth < current_depth[i])
475           depth=current_depth[i];
476       current_depth=(size_t *) RelinquishMagickMemory(current_depth);
477       return(depth);
478     }
479   image_view=AcquireVirtualCacheView(image,exception);
480 #if !defined(MAGICKCORE_HDRI_SUPPORT)
481   if ((1UL*QuantumRange) <= MaxMap)
482     {
483       size_t
484         *depth_map;
485 
486       /*
487         Scale pixels to desired (optimized with depth map).
488       */
489       depth_map=(size_t *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
490       if (depth_map == (size_t *) NULL)
491         ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
492       for (i=0; i <= (ssize_t) MaxMap; i++)
493       {
494         unsigned int
495           depth;
496 
497         for (depth=1; depth < MAGICKCORE_QUANTUM_DEPTH; depth++)
498         {
499           Quantum
500             pixel;
501 
502           QuantumAny
503             range;
504 
505           range=GetQuantumRange(depth);
506           pixel=(Quantum) i;
507           if (pixel == ScaleAnyToQuantum(ScaleQuantumToAny(pixel,range),range))
508             break;
509         }
510         depth_map[i]=depth;
511       }
512 #if defined(MAGICKCORE_OPENMP_SUPPORT)
513       #pragma omp parallel for schedule(static) shared(status) \
514         magick_number_threads(image,image,image->rows,1)
515 #endif
516       for (y=0; y < (ssize_t) image->rows; y++)
517       {
518         const int
519           id = GetOpenMPThreadId();
520 
521         register const Quantum
522           *magick_restrict p;
523 
524         register ssize_t
525           x;
526 
527         if (status == MagickFalse)
528           continue;
529         p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
530         if (p == (const Quantum *) NULL)
531           continue;
532         for (x=0; x < (ssize_t) image->columns; x++)
533         {
534           register ssize_t
535             i;
536 
537           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
538           {
539             PixelChannel channel = GetPixelChannelChannel(image,i);
540             PixelTrait traits = GetPixelChannelTraits(image,channel);
541             if ((traits & UpdatePixelTrait) == 0)
542               continue;
543             if (depth_map[ScaleQuantumToMap(p[i])] > current_depth[id])
544               current_depth[id]=depth_map[ScaleQuantumToMap(p[i])];
545           }
546           p+=GetPixelChannels(image);
547         }
548         if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
549           status=MagickFalse;
550       }
551       image_view=DestroyCacheView(image_view);
552       depth=current_depth[0];
553       for (i=1; i < (ssize_t) number_threads; i++)
554         if (depth < current_depth[i])
555           depth=current_depth[i];
556       depth_map=(size_t *) RelinquishMagickMemory(depth_map);
557       current_depth=(size_t *) RelinquishMagickMemory(current_depth);
558       return(depth);
559     }
560 #endif
561   /*
562     Compute pixel depth.
563   */
564 #if defined(MAGICKCORE_OPENMP_SUPPORT)
565   #pragma omp parallel for schedule(static) shared(status) \
566     magick_number_threads(image,image,image->rows,1)
567 #endif
568   for (y=0; y < (ssize_t) image->rows; y++)
569   {
570     const int
571       id = GetOpenMPThreadId();
572 
573     register const Quantum
574       *magick_restrict p;
575 
576     register ssize_t
577       x;
578 
579     if (status == MagickFalse)
580       continue;
581     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
582     if (p == (const Quantum *) NULL)
583       continue;
584     for (x=0; x < (ssize_t) image->columns; x++)
585     {
586       register ssize_t
587         i;
588 
589       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
590       {
591         PixelChannel
592           channel;
593 
594         PixelTrait
595           traits;
596 
597         channel=GetPixelChannelChannel(image,i);
598         traits=GetPixelChannelTraits(image,channel);
599         if ((traits & UpdatePixelTrait) == 0)
600           continue;
601         while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
602         {
603           QuantumAny
604             range;
605 
606           range=GetQuantumRange(current_depth[id]);
607           if (p[i] == ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),range))
608             break;
609           current_depth[id]++;
610         }
611       }
612       p+=GetPixelChannels(image);
613     }
614     if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
615       status=MagickFalse;
616   }
617   image_view=DestroyCacheView(image_view);
618   depth=current_depth[0];
619   for (i=1; i < (ssize_t) number_threads; i++)
620     if (depth < current_depth[i])
621       depth=current_depth[i];
622   current_depth=(size_t *) RelinquishMagickMemory(current_depth);
623   return(depth);
624 }
625 
626 /*
627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628 %                                                                             %
629 %                                                                             %
630 %                                                                             %
631 %   G e t I m a g e Q u a n t u m D e p t h                                   %
632 %                                                                             %
633 %                                                                             %
634 %                                                                             %
635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636 %
637 %  GetImageQuantumDepth() returns the depth of the image rounded to a legal
638 %  quantum depth: 8, 16, or 32.
639 %
640 %  The format of the GetImageQuantumDepth method is:
641 %
642 %      size_t GetImageQuantumDepth(const Image *image,
643 %        const MagickBooleanType constrain)
644 %
645 %  A description of each parameter follows:
646 %
647 %    o image: the image.
648 %
649 %    o constrain: A value other than MagickFalse, constrains the depth to
650 %      a maximum of MAGICKCORE_QUANTUM_DEPTH.
651 %
652 */
GetImageQuantumDepth(const Image * image,const MagickBooleanType constrain)653 MagickExport size_t GetImageQuantumDepth(const Image *image,
654   const MagickBooleanType constrain)
655 {
656   size_t
657     depth;
658 
659   depth=image->depth;
660   if (depth <= 8)
661     depth=8;
662   else
663     if (depth <= 16)
664       depth=16;
665     else
666       if (depth <= 32)
667         depth=32;
668       else
669         if (depth <= 64)
670           depth=64;
671   if (constrain != MagickFalse)
672     depth=(size_t) MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH);
673   return(depth);
674 }
675 
676 /*
677 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678 %                                                                             %
679 %                                                                             %
680 %                                                                             %
681 %   G e t I m a g e T y p e                                                   %
682 %                                                                             %
683 %                                                                             %
684 %                                                                             %
685 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
686 %
687 %  GetImageType() returns the type of image:
688 %
689 %        Bilevel         Grayscale        GrayscaleMatte
690 %        Palette         PaletteMatte     TrueColor
691 %        TrueColorMatte  ColorSeparation  ColorSeparationMatte
692 %
693 %  The format of the GetImageType method is:
694 %
695 %      ImageType GetImageType(const Image *image)
696 %
697 %  A description of each parameter follows:
698 %
699 %    o image: the image.
700 %
701 */
GetImageType(const Image * image)702 MagickExport ImageType GetImageType(const Image *image)
703 {
704   assert(image != (Image *) NULL);
705   assert(image->signature == MagickCoreSignature);
706   if (image->colorspace == CMYKColorspace)
707     {
708       if (image->alpha_trait == UndefinedPixelTrait)
709         return(ColorSeparationType);
710       return(ColorSeparationAlphaType);
711     }
712   if (IsImageMonochrome(image) != MagickFalse)
713     return(BilevelType);
714   if (IsImageGray(image) != MagickFalse)
715     {
716       if (image->alpha_trait != UndefinedPixelTrait)
717         return(GrayscaleAlphaType);
718       return(GrayscaleType);
719     }
720   if (IsPaletteImage(image) != MagickFalse)
721     {
722       if (image->alpha_trait != UndefinedPixelTrait)
723         return(PaletteAlphaType);
724       return(PaletteType);
725     }
726   if (image->alpha_trait != UndefinedPixelTrait)
727     return(TrueColorAlphaType);
728   return(TrueColorType);
729 }
730 
731 /*
732 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
733 %                                                                             %
734 %                                                                             %
735 %                                                                             %
736 %     I d e n t i f y I m a g e G r a y                                       %
737 %                                                                             %
738 %                                                                             %
739 %                                                                             %
740 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
741 %
742 %  IdentifyImageGray() returns grayscale if all the pixels in the image have
743 %  the same red, green, and blue intensities, and bi-level is the intensity is
744 %  either 0 or QuantumRange. Otherwise undefined is returned.
745 %
746 %  The format of the IdentifyImageGray method is:
747 %
748 %      ImageType IdentifyImageGray(const Image *image,ExceptionInfo *exception)
749 %
750 %  A description of each parameter follows:
751 %
752 %    o image: the image.
753 %
754 %    o exception: return any errors or warnings in this structure.
755 %
756 */
IdentifyImageGray(const Image * image,ExceptionInfo * exception)757 MagickExport ImageType IdentifyImageGray(const Image *image,
758   ExceptionInfo *exception)
759 {
760   CacheView
761     *image_view;
762 
763   ImageType
764     type;
765 
766   register const Quantum
767     *p;
768 
769   register ssize_t
770     x;
771 
772   ssize_t
773     y;
774 
775   assert(image != (Image *) NULL);
776   assert(image->signature == MagickCoreSignature);
777   if (image->debug != MagickFalse)
778     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
779   if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
780       (image->type == GrayscaleAlphaType))
781     return(image->type);
782   if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
783     return(UndefinedType);
784   type=BilevelType;
785   image_view=AcquireVirtualCacheView(image,exception);
786   for (y=0; y < (ssize_t) image->rows; y++)
787   {
788     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
789     if (p == (const Quantum *) NULL)
790       break;
791     for (x=0; x < (ssize_t) image->columns; x++)
792     {
793       if (IsPixelGray(image,p) == MagickFalse)
794         {
795           type=UndefinedType;
796           break;
797         }
798       if ((type == BilevelType) &&
799           (IsPixelMonochrome(image,p) == MagickFalse))
800         type=GrayscaleType;
801       p+=GetPixelChannels(image);
802     }
803     if (type == UndefinedType)
804       break;
805   }
806   image_view=DestroyCacheView(image_view);
807   if ((type == GrayscaleType) && (image->alpha_trait != UndefinedPixelTrait))
808     type=GrayscaleAlphaType;
809   return(type);
810 }
811 
812 /*
813 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
814 %                                                                             %
815 %                                                                             %
816 %                                                                             %
817 %   I d e n t i f y I m a g e M o n o c h r o m e                             %
818 %                                                                             %
819 %                                                                             %
820 %                                                                             %
821 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
822 %
823 %  IdentifyImageMonochrome() returns MagickTrue if all the pixels in the image
824 %  have the same red, green, and blue intensities and the intensity is either
825 %  0 or QuantumRange.
826 %
827 %  The format of the IdentifyImageMonochrome method is:
828 %
829 %      MagickBooleanType IdentifyImageMonochrome(const Image *image,
830 %        ExceptionInfo *exception)
831 %
832 %  A description of each parameter follows:
833 %
834 %    o image: the image.
835 %
836 %    o exception: return any errors or warnings in this structure.
837 %
838 */
IdentifyImageMonochrome(const Image * image,ExceptionInfo * exception)839 MagickExport MagickBooleanType IdentifyImageMonochrome(const Image *image,
840   ExceptionInfo *exception)
841 {
842   CacheView
843     *image_view;
844 
845   MagickBooleanType
846     bilevel;
847 
848   register ssize_t
849     x;
850 
851   register const Quantum
852     *p;
853 
854   ssize_t
855     y;
856 
857   assert(image != (Image *) NULL);
858   assert(image->signature == MagickCoreSignature);
859   if (image->debug != MagickFalse)
860     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
861   if (image->type == BilevelType)
862     return(MagickTrue);
863   if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
864     return(MagickFalse);
865   bilevel=MagickTrue;
866   image_view=AcquireVirtualCacheView(image,exception);
867   for (y=0; y < (ssize_t) image->rows; y++)
868   {
869     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
870     if (p == (const Quantum *) NULL)
871       break;
872     for (x=0; x < (ssize_t) image->columns; x++)
873     {
874       if (IsPixelMonochrome(image,p) == MagickFalse)
875         {
876           bilevel=MagickFalse;
877           break;
878         }
879       p+=GetPixelChannels(image);
880     }
881     if (bilevel == MagickFalse)
882       break;
883   }
884   image_view=DestroyCacheView(image_view);
885   return(bilevel);
886 }
887 
888 /*
889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
890 %                                                                             %
891 %                                                                             %
892 %                                                                             %
893 %   I d e n t i f y I m a g e T y p e                                         %
894 %                                                                             %
895 %                                                                             %
896 %                                                                             %
897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
898 %
899 %  IdentifyImageType() returns the potential type of image:
900 %
901 %        Bilevel         Grayscale        GrayscaleMatte
902 %        Palette         PaletteMatte     TrueColor
903 %        TrueColorMatte  ColorSeparation  ColorSeparationMatte
904 %
905 %  To ensure the image type matches its potential, use SetImageType():
906 %
907 %    (void) SetImageType(image,IdentifyImageType(image,exception),exception);
908 %
909 %  The format of the IdentifyImageType method is:
910 %
911 %      ImageType IdentifyImageType(const Image *image,ExceptionInfo *exception)
912 %
913 %  A description of each parameter follows:
914 %
915 %    o image: the image.
916 %
917 %    o exception: return any errors or warnings in this structure.
918 %
919 */
IdentifyImageType(const Image * image,ExceptionInfo * exception)920 MagickExport ImageType IdentifyImageType(const Image *image,
921   ExceptionInfo *exception)
922 {
923   assert(image != (Image *) NULL);
924   assert(image->signature == MagickCoreSignature);
925   if (image->debug != MagickFalse)
926     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
927   if (image->colorspace == CMYKColorspace)
928     {
929       if (image->alpha_trait == UndefinedPixelTrait)
930         return(ColorSeparationType);
931       return(ColorSeparationAlphaType);
932     }
933   if (IdentifyImageMonochrome(image,exception) != MagickFalse)
934     return(BilevelType);
935   if (IdentifyImageGray(image,exception) != UndefinedType)
936     {
937       if (image->alpha_trait != UndefinedPixelTrait)
938         return(GrayscaleAlphaType);
939       return(GrayscaleType);
940     }
941   if (IdentifyPaletteImage(image,exception) != MagickFalse)
942     {
943       if (image->alpha_trait != UndefinedPixelTrait)
944         return(PaletteAlphaType);
945       return(PaletteType);
946     }
947   if (image->alpha_trait != UndefinedPixelTrait)
948     return(TrueColorAlphaType);
949   return(TrueColorType);
950 }
951 
952 /*
953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
954 %                                                                             %
955 %                                                                             %
956 %                                                                             %
957 %     I s I m a g e G r a y                                                   %
958 %                                                                             %
959 %                                                                             %
960 %                                                                             %
961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
962 %
963 %  IsImageGray() returns MagickTrue if the type of the image is grayscale or
964 %  bi-level.
965 %
966 %  The format of the IsImageGray method is:
967 %
968 %      MagickBooleanType IsImageGray(const Image *image)
969 %
970 %  A description of each parameter follows:
971 %
972 %    o image: the image.
973 %
974 */
IsImageGray(const Image * image)975 MagickExport MagickBooleanType IsImageGray(const Image *image)
976 {
977   assert(image != (Image *) NULL);
978   assert(image->signature == MagickCoreSignature);
979   if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
980       (image->type == GrayscaleAlphaType))
981     return(MagickTrue);
982   return(MagickFalse);
983 }
984 
985 /*
986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
987 %                                                                             %
988 %                                                                             %
989 %                                                                             %
990 %   I s I m a g e M o n o c h r o m e                                         %
991 %                                                                             %
992 %                                                                             %
993 %                                                                             %
994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
995 %
996 %  IsImageMonochrome() returns MagickTrue if type of the image is bi-level.
997 %
998 %  The format of the IsImageMonochrome method is:
999 %
1000 %      MagickBooleanType IsImageMonochrome(const Image *image)
1001 %
1002 %  A description of each parameter follows:
1003 %
1004 %    o image: the image.
1005 %
1006 */
IsImageMonochrome(const Image * image)1007 MagickExport MagickBooleanType IsImageMonochrome(const Image *image)
1008 {
1009   assert(image != (Image *) NULL);
1010   assert(image->signature == MagickCoreSignature);
1011   if (image->type == BilevelType)
1012     return(MagickTrue);
1013   return(MagickFalse);
1014 }
1015 
1016 /*
1017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1018 %                                                                             %
1019 %                                                                             %
1020 %                                                                             %
1021 %     I s I m a g e O p a q u e                                               %
1022 %                                                                             %
1023 %                                                                             %
1024 %                                                                             %
1025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1026 %
1027 %  IsImageOpaque() returns MagickTrue if none of the pixels in the image have
1028 %  an alpha value other than OpaqueAlpha (QuantumRange).
1029 %
1030 %  Will return true immediatally is alpha channel is not available.
1031 %
1032 %  The format of the IsImageOpaque method is:
1033 %
1034 %      MagickBooleanType IsImageOpaque(const Image *image,
1035 %        ExceptionInfo *exception)
1036 %
1037 %  A description of each parameter follows:
1038 %
1039 %    o image: the image.
1040 %
1041 %    o exception: return any errors or warnings in this structure.
1042 %
1043 */
IsImageOpaque(const Image * image,ExceptionInfo * exception)1044 MagickExport MagickBooleanType IsImageOpaque(const Image *image,
1045   ExceptionInfo *exception)
1046 {
1047   CacheView
1048     *image_view;
1049 
1050   register const Quantum
1051     *p;
1052 
1053   register ssize_t
1054     x;
1055 
1056   ssize_t
1057     y;
1058 
1059   /*
1060     Determine if image is opaque.
1061   */
1062   assert(image != (Image *) NULL);
1063   assert(image->signature == MagickCoreSignature);
1064   if (image->debug != MagickFalse)
1065     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1066   if (image->alpha_trait == UndefinedPixelTrait)
1067     return(MagickTrue);
1068   image_view=AcquireVirtualCacheView(image,exception);
1069   for (y=0; y < (ssize_t) image->rows; y++)
1070   {
1071     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1072     if (p == (const Quantum *) NULL)
1073       break;
1074     for (x=0; x < (ssize_t) image->columns; x++)
1075     {
1076       if (GetPixelAlpha(image,p) != OpaqueAlpha)
1077         break;
1078       p+=GetPixelChannels(image);
1079     }
1080     if (x < (ssize_t) image->columns)
1081       break;
1082   }
1083   image_view=DestroyCacheView(image_view);
1084   return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
1085 }
1086 
1087 /*
1088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1089 %                                                                             %
1090 %                                                                             %
1091 %                                                                             %
1092 %   S e t I m a g e D e p t h                                                 %
1093 %                                                                             %
1094 %                                                                             %
1095 %                                                                             %
1096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1097 %
1098 %  SetImageDepth() sets the depth of the image.
1099 %
1100 %  The format of the SetImageDepth method is:
1101 %
1102 %      MagickBooleanType SetImageDepth(Image *image,const size_t depth,
1103 %        ExceptionInfo *exception)
1104 %
1105 %  A description of each parameter follows:
1106 %
1107 %    o image: the image.
1108 %
1109 %    o channel: the channel.
1110 %
1111 %    o depth: the image depth.
1112 %
1113 %    o exception: return any errors or warnings in this structure.
1114 %
1115 */
SetImageDepth(Image * image,const size_t depth,ExceptionInfo * exception)1116 MagickExport MagickBooleanType SetImageDepth(Image *image,
1117   const size_t depth,ExceptionInfo *exception)
1118 {
1119   CacheView
1120     *image_view;
1121 
1122   MagickBooleanType
1123     status;
1124 
1125   QuantumAny
1126     range;
1127 
1128   ssize_t
1129     y;
1130 
1131   assert(image != (Image *) NULL);
1132   if (image->debug != MagickFalse)
1133     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1134   assert(image->signature == MagickCoreSignature);
1135   if (depth >= MAGICKCORE_QUANTUM_DEPTH)
1136     {
1137       image->depth=depth;
1138       return(MagickTrue);
1139     }
1140   range=GetQuantumRange(depth);
1141   if (image->storage_class == PseudoClass)
1142     {
1143       register ssize_t
1144         i;
1145 
1146 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1147       #pragma omp parallel for schedule(static) shared(status) \
1148         magick_number_threads(image,image,image->colors,1)
1149 #endif
1150       for (i=0; i < (ssize_t) image->colors; i++)
1151       {
1152         if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
1153           image->colormap[i].red=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
1154             ClampPixel(image->colormap[i].red),range),range);
1155         if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
1156           image->colormap[i].green=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
1157             ClampPixel(image->colormap[i].green),range),range);
1158         if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
1159           image->colormap[i].blue=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
1160             ClampPixel(image->colormap[i].blue),range),range);
1161         if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
1162           image->colormap[i].alpha=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
1163             ClampPixel(image->colormap[i].alpha),range),range);
1164       }
1165     }
1166   status=MagickTrue;
1167   image_view=AcquireAuthenticCacheView(image,exception);
1168 #if !defined(MAGICKCORE_HDRI_SUPPORT)
1169   if ((1UL*QuantumRange) <= MaxMap)
1170     {
1171       Quantum
1172         *depth_map;
1173 
1174       register ssize_t
1175         i;
1176 
1177       /*
1178         Scale pixels to desired (optimized with depth map).
1179       */
1180       depth_map=(Quantum *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
1181       if (depth_map == (Quantum *) NULL)
1182         ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1183       for (i=0; i <= (ssize_t) MaxMap; i++)
1184         depth_map[i]=ScaleAnyToQuantum(ScaleQuantumToAny((Quantum) i,range),
1185           range);
1186 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1187       #pragma omp parallel for schedule(static) shared(status) \
1188         magick_number_threads(image,image,image->rows,1)
1189 #endif
1190       for (y=0; y < (ssize_t) image->rows; y++)
1191       {
1192         register ssize_t
1193           x;
1194 
1195         register Quantum
1196           *magick_restrict q;
1197 
1198         if (status == MagickFalse)
1199           continue;
1200         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1201           exception);
1202         if (q == (Quantum *) NULL)
1203           {
1204             status=MagickFalse;
1205             continue;
1206           }
1207         for (x=0; x < (ssize_t) image->columns; x++)
1208         {
1209           register ssize_t
1210             i;
1211 
1212           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1213           {
1214             PixelChannel
1215               channel;
1216 
1217             PixelTrait
1218               traits;
1219 
1220             channel=GetPixelChannelChannel(image,i);
1221             traits=GetPixelChannelTraits(image,channel);
1222             if ((traits & UpdatePixelTrait) == 0)
1223               continue;
1224             q[i]=depth_map[ScaleQuantumToMap(q[i])];
1225           }
1226           q+=GetPixelChannels(image);
1227         }
1228         if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1229           {
1230             status=MagickFalse;
1231             continue;
1232           }
1233       }
1234       image_view=DestroyCacheView(image_view);
1235       depth_map=(Quantum *) RelinquishMagickMemory(depth_map);
1236       if (status != MagickFalse)
1237         image->depth=depth;
1238       return(status);
1239     }
1240 #endif
1241   /*
1242     Scale pixels to desired depth.
1243   */
1244 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1245   #pragma omp parallel for schedule(static) shared(status) \
1246     magick_number_threads(image,image,image->rows,1)
1247 #endif
1248   for (y=0; y < (ssize_t) image->rows; y++)
1249   {
1250     register ssize_t
1251       x;
1252 
1253     register Quantum
1254       *magick_restrict q;
1255 
1256     if (status == MagickFalse)
1257       continue;
1258     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1259     if (q == (Quantum *) NULL)
1260       {
1261         status=MagickFalse;
1262         continue;
1263       }
1264     for (x=0; x < (ssize_t) image->columns; x++)
1265     {
1266       register ssize_t
1267         i;
1268 
1269       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1270       {
1271         PixelChannel
1272           channel;
1273 
1274         PixelTrait
1275           traits;
1276 
1277         channel=GetPixelChannelChannel(image,i);
1278         traits=GetPixelChannelTraits(image,channel);
1279         if ((traits & UpdatePixelTrait) == 0)
1280           continue;
1281         q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(ClampPixel((MagickRealType)
1282           q[i]),range),range);
1283       }
1284       q+=GetPixelChannels(image);
1285     }
1286     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1287       {
1288         status=MagickFalse;
1289         continue;
1290       }
1291   }
1292   image_view=DestroyCacheView(image_view);
1293   if (status != MagickFalse)
1294     image->depth=depth;
1295   return(status);
1296 }
1297 
1298 /*
1299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1300 %                                                                             %
1301 %                                                                             %
1302 %                                                                             %
1303 %   S e t I m a g e T y p e                                                   %
1304 %                                                                             %
1305 %                                                                             %
1306 %                                                                             %
1307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1308 %
1309 %  SetImageType() sets the type of image.  Choose from these types:
1310 %
1311 %        Bilevel        Grayscale       GrayscaleMatte
1312 %        Palette        PaletteMatte    TrueColor
1313 %        TrueColorMatte ColorSeparation ColorSeparationMatte
1314 %        OptimizeType
1315 %
1316 %  The format of the SetImageType method is:
1317 %
1318 %      MagickBooleanType SetImageType(Image *image,const ImageType type,
1319 %        ExceptionInfo *exception)
1320 %
1321 %  A description of each parameter follows:
1322 %
1323 %    o image: the image.
1324 %
1325 %    o type: Image type.
1326 %
1327 %    o exception: return any errors or warnings in this structure.
1328 %
1329 */
SetImageType(Image * image,const ImageType type,ExceptionInfo * exception)1330 MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type,
1331   ExceptionInfo *exception)
1332 {
1333   const char
1334     *artifact;
1335 
1336   ImageInfo
1337     *image_info;
1338 
1339   MagickBooleanType
1340     status;
1341 
1342   QuantizeInfo
1343     *quantize_info;
1344 
1345   assert(image != (Image *) NULL);
1346   if (image->debug != MagickFalse)
1347     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1348   assert(image->signature == MagickCoreSignature);
1349   status=MagickTrue;
1350   image_info=AcquireImageInfo();
1351   image_info->dither=image->dither;
1352   artifact=GetImageArtifact(image,"dither");
1353   if (artifact != (const char *) NULL)
1354     (void) SetImageOption(image_info,"dither",artifact);
1355   switch (type)
1356   {
1357     case BilevelType:
1358     {
1359       status=TransformImageColorspace(image,GRAYColorspace,exception);
1360       (void) NormalizeImage(image,exception);
1361       quantize_info=AcquireQuantizeInfo(image_info);
1362       quantize_info->number_colors=2;
1363       quantize_info->colorspace=GRAYColorspace;
1364       status=QuantizeImage(quantize_info,image,exception);
1365       quantize_info=DestroyQuantizeInfo(quantize_info);
1366       image->alpha_trait=UndefinedPixelTrait;
1367       break;
1368     }
1369     case GrayscaleType:
1370     {
1371       status=TransformImageColorspace(image,GRAYColorspace,exception);
1372       image->alpha_trait=UndefinedPixelTrait;
1373       break;
1374     }
1375     case GrayscaleAlphaType:
1376     {
1377       status=TransformImageColorspace(image,GRAYColorspace,exception);
1378       if (image->alpha_trait == UndefinedPixelTrait)
1379         (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1380       break;
1381     }
1382     case PaletteType:
1383     {
1384       status=TransformImageColorspace(image,sRGBColorspace,exception);
1385       if ((image->storage_class == DirectClass) || (image->colors > 256))
1386         {
1387           quantize_info=AcquireQuantizeInfo(image_info);
1388           quantize_info->number_colors=256;
1389           status=QuantizeImage(quantize_info,image,exception);
1390           quantize_info=DestroyQuantizeInfo(quantize_info);
1391         }
1392       image->alpha_trait=UndefinedPixelTrait;
1393       break;
1394     }
1395     case PaletteBilevelAlphaType:
1396     {
1397       ChannelType
1398         channel_mask;
1399 
1400       status=TransformImageColorspace(image,sRGBColorspace,exception);
1401       if (image->alpha_trait == UndefinedPixelTrait)
1402         (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1403       channel_mask=SetImageChannelMask(image,AlphaChannel);
1404       (void) BilevelImage(image,(double) QuantumRange/2.0,exception);
1405       (void) SetImageChannelMask(image,channel_mask);
1406       quantize_info=AcquireQuantizeInfo(image_info);
1407       status=QuantizeImage(quantize_info,image,exception);
1408       quantize_info=DestroyQuantizeInfo(quantize_info);
1409       break;
1410     }
1411     case PaletteAlphaType:
1412     {
1413       status=TransformImageColorspace(image,sRGBColorspace,exception);
1414       if (image->alpha_trait == UndefinedPixelTrait)
1415         (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1416       quantize_info=AcquireQuantizeInfo(image_info);
1417       quantize_info->colorspace=TransparentColorspace;
1418       status=QuantizeImage(quantize_info,image,exception);
1419       quantize_info=DestroyQuantizeInfo(quantize_info);
1420       break;
1421     }
1422     case TrueColorType:
1423     {
1424       status=TransformImageColorspace(image,sRGBColorspace,exception);
1425       if (image->storage_class != DirectClass)
1426         status=SetImageStorageClass(image,DirectClass,exception);
1427       image->alpha_trait=UndefinedPixelTrait;
1428       break;
1429     }
1430     case TrueColorAlphaType:
1431     {
1432       status=TransformImageColorspace(image,sRGBColorspace,exception);
1433       if (image->storage_class != DirectClass)
1434         status=SetImageStorageClass(image,DirectClass,exception);
1435       if (image->alpha_trait == UndefinedPixelTrait)
1436         (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1437       break;
1438     }
1439     case ColorSeparationType:
1440     {
1441       status=TransformImageColorspace(image,CMYKColorspace,exception);
1442       if (image->storage_class != DirectClass)
1443         status=SetImageStorageClass(image,DirectClass,exception);
1444       image->alpha_trait=UndefinedPixelTrait;
1445       break;
1446     }
1447     case ColorSeparationAlphaType:
1448     {
1449       status=TransformImageColorspace(image,CMYKColorspace,exception);
1450       if (image->storage_class != DirectClass)
1451         status=SetImageStorageClass(image,DirectClass,exception);
1452       if (image->alpha_trait == UndefinedPixelTrait)
1453         status=SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1454       break;
1455     }
1456     case OptimizeType:
1457     case UndefinedType:
1458       break;
1459   }
1460   image_info=DestroyImageInfo(image_info);
1461   if (status == MagickFalse)
1462     return(status);
1463   image->type=type;
1464   return(MagickTrue);
1465 }
1466