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