]> granicus.if.org Git - imagemagick/blob - magick/attribute.c
(no commit message)
[imagemagick] / magick / 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-2010 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 "magick/studio.h"
44 #include "magick/attribute.h"
45 #include "magick/blob.h"
46 #include "magick/blob-private.h"
47 #include "magick/cache.h"
48 #include "magick/cache-view.h"
49 #include "magick/client.h"
50 #include "magick/color.h"
51 #include "magick/color-private.h"
52 #include "magick/colormap.h"
53 #include "magick/colormap-private.h"
54 #include "magick/colorspace.h"
55 #include "magick/composite.h"
56 #include "magick/composite-private.h"
57 #include "magick/constitute.h"
58 #include "magick/deprecate.h"
59 #include "magick/draw.h"
60 #include "magick/draw-private.h"
61 #include "magick/effect.h"
62 #include "magick/enhance.h"
63 #include "magick/exception.h"
64 #include "magick/exception-private.h"
65 #include "magick/geometry.h"
66 #include "magick/histogram.h"
67 #include "magick/identify.h"
68 #include "magick/image.h"
69 #include "magick/image-private.h"
70 #include "magick/list.h"
71 #include "magick/log.h"
72 #include "magick/memory_.h"
73 #include "magick/magick.h"
74 #include "magick/monitor.h"
75 #include "magick/monitor-private.h"
76 #include "magick/paint.h"
77 #include "magick/pixel.h"
78 #include "magick/pixel-private.h"
79 #include "magick/property.h"
80 #include "magick/quantize.h"
81 #include "magick/random_.h"
82 #include "magick/resource_.h"
83 #include "magick/semaphore.h"
84 #include "magick/segment.h"
85 #include "magick/splay-tree.h"
86 #include "magick/string_.h"
87 #include "magick/thread-private.h"
88 #include "magick/threshold.h"
89 #include "magick/transform.h"
90 #include "magick/utility.h"
91 \f
92 /*
93 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94 %                                                                             %
95 %                                                                             %
96 %                                                                             %
97 +   G e t I m a g e B o u n d i n g B o x                                     %
98 %                                                                             %
99 %                                                                             %
100 %                                                                             %
101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
102 %
103 %  GetImageBoundingBox() returns the bounding box of an image canvas.
104 %
105 %  The format of the GetImageBoundingBox method is:
106 %
107 %      RectangleInfo GetImageBoundingBox(const Image *image,
108 %        ExceptionInfo *exception)
109 %
110 %  A description of each parameter follows:
111 %
112 %    o bounds: Method GetImageBoundingBox returns the bounding box of an
113 %      image canvas.
114 %
115 %    o image: the image.
116 %
117 %    o exception: return any errors or warnings in this structure.
118 %
119 */
120 MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
121   ExceptionInfo *exception)
122 {
123   CacheView
124     *image_view;
125
126   long
127     y;
128
129   MagickBooleanType
130     status;
131
132   MagickPixelPacket
133     target[3],
134     zero;
135
136   RectangleInfo
137     bounds;
138
139   register const PixelPacket
140     *p;
141
142   assert(image != (Image *) NULL);
143   assert(image->signature == MagickSignature);
144   if (image->debug != MagickFalse)
145     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
146   bounds.width=0;
147   bounds.height=0;
148   bounds.x=(long) image->columns;
149   bounds.y=(long) image->rows;
150   GetMagickPixelPacket(image,&target[0]);
151   image_view=AcquireCacheView(image);
152   p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
153   if (p == (const PixelPacket *) NULL)
154     {
155       image_view=DestroyCacheView(image_view);
156       return(bounds);
157     }
158   SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
159     &target[0]);
160   GetMagickPixelPacket(image,&target[1]);
161   p=GetCacheViewVirtualPixels(image_view,(long) image->columns-1,0,1,1,
162     exception);
163   SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
164     &target[1]);
165   GetMagickPixelPacket(image,&target[2]);
166   p=GetCacheViewVirtualPixels(image_view,0,(long) image->rows-1,1,1,exception);
167   SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
168     &target[2]);
169   status=MagickTrue;
170   GetMagickPixelPacket(image,&zero);
171 #if defined(MAGICKCORE_OPENMP_SUPPORT)
172   #pragma omp parallel for schedule(dynamic,4) shared(status)
173 #endif
174   for (y=0; y < (long) image->rows; y++)
175   {
176     MagickPixelPacket
177       pixel;
178
179     RectangleInfo
180       bounding_box;
181
182     register const IndexPacket
183       *restrict indexes;
184
185     register const PixelPacket
186       *restrict p;
187
188     register long
189       x;
190
191     if (status == MagickFalse)
192       continue;
193 #if defined(MAGICKCORE_OPENMP_SUPPORT)
194 #  pragma omp critical (MagickCore_GetImageBoundingBox)
195 #endif
196     bounding_box=bounds;
197     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
198     if (p == (const PixelPacket *) NULL)
199       {
200         status=MagickFalse;
201         continue;
202       }
203     indexes=GetCacheViewVirtualIndexQueue(image_view);
204     pixel=zero;
205     for (x=0; x < (long) image->columns; x++)
206     {
207       SetMagickPixelPacket(image,p,indexes+x,&pixel);
208       if ((x < bounding_box.x) &&
209           (IsMagickColorSimilar(&pixel,&target[0]) == MagickFalse))
210         bounding_box.x=x;
211       if ((x > (long) bounding_box.width) &&
212           (IsMagickColorSimilar(&pixel,&target[1]) == MagickFalse))
213         bounding_box.width=(unsigned long) x;
214       if ((y < bounding_box.y) &&
215           (IsMagickColorSimilar(&pixel,&target[0]) == MagickFalse))
216         bounding_box.y=y;
217       if ((y > (long) bounding_box.height) &&
218           (IsMagickColorSimilar(&pixel,&target[2]) == MagickFalse))
219         bounding_box.height=(unsigned long) y;
220       p++;
221     }
222 #if defined(MAGICKCORE_OPENMP_SUPPORT)
223 #  pragma omp critical (MagickCore_GetImageBoundingBox)
224 #endif
225     {
226       if (bounding_box.x < bounds.x)
227         bounds.x=bounding_box.x;
228       if (bounding_box.y < bounds.y)
229         bounds.y=bounding_box.y;
230       if (bounding_box.width > bounds.width)
231         bounds.width=bounding_box.width;
232       if (bounding_box.height > bounds.height)
233         bounds.height=bounding_box.height;
234     }
235   }
236   image_view=DestroyCacheView(image_view);
237   if ((bounds.width == 0) || (bounds.height == 0))
238     (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
239       "GeometryDoesNotContainImage","`%s'",image->filename);
240   else
241     {
242       bounds.width-=(bounds.x-1);
243       bounds.height-=(bounds.y-1);
244     }
245   return(bounds);
246 }
247 \f
248 /*
249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250 %                                                                             %
251 %                                                                             %
252 %                                                                             %
253 %   G e t I m a g e C h a n n e l D e p t h                                   %
254 %                                                                             %
255 %                                                                             %
256 %                                                                             %
257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
258 %
259 %  GetImageChannelDepth() returns the depth of a particular image channel.
260 %
261 %  The format of the GetImageChannelDepth method is:
262 %
263 %      unsigned long GetImageDepth(const Image *image,ExceptionInfo *exception)
264 %      unsigned long GetImageChannelDepth(const Image *image,
265 %        const ChannelType channel,ExceptionInfo *exception)
266 %
267 %  A description of each parameter follows:
268 %
269 %    o image: the image.
270 %
271 %    o channel: the channel.
272 %
273 %    o exception: return any errors or warnings in this structure.
274 %
275 */
276
277 MagickExport unsigned long GetImageDepth(const Image *image,
278   ExceptionInfo *exception)
279 {
280   return(GetImageChannelDepth(image,AllChannels,exception));
281 }
282
283 MagickExport unsigned long GetImageChannelDepth(const Image *image,
284   const ChannelType channel,ExceptionInfo *exception)
285 {
286   CacheView
287     *image_view;
288
289   long
290     y;
291
292   MagickBooleanType
293     status;
294
295   register long
296     id;
297
298   unsigned long
299     *current_depth,
300     depth,
301     number_threads;
302
303   /*
304     Compute image depth.
305   */
306   assert(image != (Image *) NULL);
307   assert(image->signature == MagickSignature);
308   if (image->debug != MagickFalse)
309     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
310   number_threads=GetOpenMPMaximumThreads();
311   current_depth=(unsigned long *) AcquireQuantumMemory(number_threads,
312     sizeof(*current_depth));
313   if (current_depth == (unsigned long *) NULL)
314     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
315   status=MagickTrue;
316   for (id=0; id < (long) number_threads; id++)
317     current_depth[id]=1;
318   if ((image->storage_class == PseudoClass) && (image->matte == MagickFalse))
319     {
320       register const PixelPacket
321         *restrict p;
322
323       register long
324         i;
325
326       p=image->colormap;
327 #if defined(MAGICKCORE_OPENMP_SUPPORT)
328   #pragma omp parallel for schedule(dynamic,4) shared(status)
329 #endif
330       for (i=0; i < (long) image->colors; i++)
331       {
332         if (status == MagickFalse)
333           continue;
334         id=GetOpenMPThreadId();
335         while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
336         {
337           MagickStatusType
338             status;
339
340           QuantumAny
341             range;
342
343           status=0;
344           range=GetQuantumRange(current_depth[id]);
345           if ((channel & RedChannel) != 0)
346             status|=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,
347               range),range);
348           if ((channel & GreenChannel) != 0)
349             status|=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
350               range),range);
351           if ((channel & BlueChannel) != 0)
352             status|=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
353               range),range);
354           if (status == 0)
355             break;
356           current_depth[id]++;
357         }
358         p++;
359       }
360       depth=current_depth[0];
361       for (id=1; id < (long) number_threads; id++)
362         if (depth < current_depth[id])
363           depth=current_depth[id];
364       current_depth=(unsigned long *) RelinquishMagickMemory(current_depth);
365       return(depth);
366     }
367   image_view=AcquireCacheView(image);
368 #if defined(MAGICKCORE_OPENMP_SUPPORT)
369   #pragma omp parallel for schedule(dynamic,4) shared(status)
370 #endif
371   for (y=0; y < (long) image->rows; y++)
372   {
373     register const IndexPacket
374       *restrict indexes;
375
376     register const PixelPacket
377       *restrict p;
378
379     register long
380       id,
381       x;
382
383     if (status == MagickFalse)
384       continue;
385     id=GetOpenMPThreadId();
386     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
387     if (p == (const PixelPacket *) NULL)
388       continue;
389     indexes=GetCacheViewVirtualIndexQueue(image_view);
390     for (x=0; x < (long) image->columns; x++)
391     {
392       while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
393       {
394         MagickStatusType
395           status;
396
397         QuantumAny
398           range;
399
400         status=0;
401         range=GetQuantumRange(current_depth[id]);
402         if ((channel & RedChannel) != 0)
403           status|=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,range),
404             range);
405         if ((channel & GreenChannel) != 0)
406           status|=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
407             range),range);
408         if ((channel & BlueChannel) != 0)
409           status|=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,range),
410             range);
411         if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
412           status|=p->opacity != ScaleAnyToQuantum(ScaleQuantumToAny(p->opacity,
413             range),range);
414         if (((channel & IndexChannel) != 0) &&
415             (image->colorspace == CMYKColorspace))
416           status|=indexes[x] != ScaleAnyToQuantum(ScaleQuantumToAny(indexes[x],
417             range),range);
418         if (status == 0)
419           break;
420         current_depth[id]++;
421       }
422       p++;
423     }
424     if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
425       status=MagickFalse;
426   }
427   image_view=DestroyCacheView(image_view);
428   depth=current_depth[0];
429   for (id=1; id < (long) number_threads; id++)
430     if (depth < current_depth[id])
431       depth=current_depth[id];
432   current_depth=(unsigned long *) RelinquishMagickMemory(current_depth);
433   return(depth);
434 }
435 \f
436 /*
437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
438 %                                                                             %
439 %                                                                             %
440 %                                                                             %
441 %   G e t I m a g e Q u a n t u m D e p t h                                   %
442 %                                                                             %
443 %                                                                             %
444 %                                                                             %
445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
446 %
447 %  GetImageQuantumDepth() returns the depth of the image rounded to a legal
448 %  quantum depth: 8, 16, or 32.
449 %
450 %  The format of the GetImageQuantumDepth method is:
451 %
452 %      unsigned long GetImageQuantumDepth(const Image *image,
453 %        const MagickBooleanType constrain)
454 %
455 %  A description of each parameter follows:
456 %
457 %    o image: the image.
458 %
459 %    o constrain: A value other than MagickFalse, constrains the depth to
460 %      a maximum of MAGICKCORE_QUANTUM_DEPTH.
461 %
462 */
463
464 static inline double MagickMin(const double x,const double y)
465 {
466   if (x < y)
467     return(x);
468   return(y);
469 }
470
471 MagickExport unsigned long GetImageQuantumDepth(const Image *image,
472   const MagickBooleanType constrain)
473 {
474   unsigned long
475     depth;
476
477   depth=image->depth;
478   if (depth <= 8)
479     depth=8;
480   else
481     if (depth <= 16)
482       depth=16;
483     else
484       if (depth <= 32)
485         depth=32;
486       else
487         if (depth <= 64)
488           depth=64;
489   if (constrain != MagickFalse)
490     depth=(unsigned long) MagickMin((double) depth,(double)
491       MAGICKCORE_QUANTUM_DEPTH);
492   return(depth);
493 }
494 \f
495 /*
496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
497 %                                                                             %
498 %                                                                             %
499 %                                                                             %
500 %   G e t I m a g e T y p e                                                   %
501 %                                                                             %
502 %                                                                             %
503 %                                                                             %
504 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
505 %
506 %  GetImageType() returns the potential type of image:
507 %
508 %        Bilevel         Grayscale        GrayscaleMatte
509 %        Palette         PaletteMatte     TrueColor
510 %        TrueColorMatte  ColorSeparation  ColorSeparationMatte
511 %
512 %  To ensure the image type matches its potential, use SetImageType():
513 %
514 %    (void) SetImageType(image,GetImageType(image));
515 %
516 %  The format of the GetImageType method is:
517 %
518 %      ImageType GetImageType(const Image *image,ExceptionInfo *exception)
519 %
520 %  A description of each parameter follows:
521 %
522 %    o image: the image.
523 %
524 %    o exception: return any errors or warnings in this structure.
525 %
526 */
527 MagickExport ImageType GetImageType(const Image *image,ExceptionInfo *exception)
528 {
529   assert(image != (Image *) NULL);
530   assert(image->signature == MagickSignature);
531   if (image->debug != MagickFalse)
532     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
533   if (image->colorspace == CMYKColorspace)
534     {
535       if (image->matte == MagickFalse)
536         return(ColorSeparationType);
537       return(ColorSeparationMatteType);
538     }
539   if (IsMonochromeImage(image,exception) != MagickFalse)
540     return(BilevelType);
541   if (IsGrayImage(image,exception) != MagickFalse)
542     {
543       if (image->matte != MagickFalse)
544         return(GrayscaleMatteType);
545       return(GrayscaleType);
546     }
547   if (IsPaletteImage(image,exception) != MagickFalse)
548     {
549       if (image->matte != MagickFalse)
550         return(PaletteMatteType);
551       return(PaletteType);
552     }
553   if (image->matte != MagickFalse)
554     return(TrueColorMatteType);
555   return(TrueColorType);
556 }
557 \f
558 /*
559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
560 %                                                                             %
561 %                                                                             %
562 %                                                                             %
563 %     I s G r a y I m a g e                                                   %
564 %                                                                             %
565 %                                                                             %
566 %                                                                             %
567 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
568 %
569 %  IsGrayImage() returns MagickTrue if all the pixels in the image have the
570 %  same red, green, and blue intensities.
571 %
572 %  The format of the IsGrayImage method is:
573 %
574 %      MagickBooleanType IsGrayImage(const Image *image,
575 %        ExceptionInfo *exception)
576 %
577 %  A description of each parameter follows:
578 %
579 %    o image: the image.
580 %
581 %    o exception: return any errors or warnings in this structure.
582 %
583 */
584 MagickExport MagickBooleanType IsGrayImage(const Image *image,
585   ExceptionInfo *exception)
586 {
587   ImageType
588     type;
589
590   register const PixelPacket
591     *p;
592
593   assert(image != (Image *) NULL);
594   assert(image->signature == MagickSignature);
595   if (image->debug != MagickFalse)
596     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
597   if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
598       (image->type == GrayscaleMatteType))
599     return(MagickTrue);
600   if (image->colorspace == CMYKColorspace)
601     return(MagickFalse);
602   type=BilevelType;
603   switch (image->storage_class)
604   {
605     case DirectClass:
606     case UndefinedClass:
607     {
608       long
609         y;
610
611       register long
612         x;
613
614       CacheView
615         *image_view;
616
617       image_view=AcquireCacheView(image);
618       for (y=0; y < (long) image->rows; y++)
619       {
620         p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
621         if (p == (const PixelPacket *) NULL)
622           break;
623         for (x=0; x < (long) image->columns; x++)
624         {
625           if (IsGrayPixel(p) == MagickFalse)
626             {
627               type=UndefinedType;
628               break;
629             }
630           if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
631             type=GrayscaleType;
632           p++;
633         }
634         if (type == UndefinedType)
635           break;
636       }
637       image_view=DestroyCacheView(image_view);
638       break;
639     }
640     case PseudoClass:
641     {
642       register long
643         i;
644
645       p=image->colormap;
646       for (i=0; i < (long) image->colors; i++)
647       {
648         if (IsGrayPixel(p) == MagickFalse)
649           {
650             type=UndefinedType;
651             break;
652           }
653         if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
654           type=GrayscaleType;
655         p++;
656       }
657       break;
658     }
659   }
660   if (type == UndefinedType)
661     return(MagickFalse);
662   ((Image *) image)->type=type;
663   if ((type == GrayscaleType) && (image->matte != MagickFalse))
664     ((Image *) image)->type=GrayscaleMatteType;
665   return(MagickTrue);
666 }
667 \f
668 /*
669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670 %                                                                             %
671 %                                                                             %
672 %                                                                             %
673 %   I s M o n o c h r o m e I m a g e                                         %
674 %                                                                             %
675 %                                                                             %
676 %                                                                             %
677 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678 %
679 %  IsMonochromeImage() returns MagickTrue if all the pixels in the image have
680 %  the same red, green, and blue intensities and the intensity is either
681 %  0 or QuantumRange.
682 %
683 %  The format of the IsMonochromeImage method is:
684 %
685 %      MagickBooleanType IsMonochromeImage(const Image *image,
686 %        ExceptionInfo *exception)
687 %
688 %  A description of each parameter follows:
689 %
690 %    o image: the image.
691 %
692 %    o exception: return any errors or warnings in this structure.
693 %
694 */
695 MagickExport MagickBooleanType IsMonochromeImage(const Image *image,
696   ExceptionInfo *exception)
697 {
698   ImageType
699     type;
700
701   register const PixelPacket
702     *p;
703
704   assert(image != (Image *) NULL);
705   assert(image->signature == MagickSignature);
706   if (image->debug != MagickFalse)
707     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
708   if (image->type == BilevelType)
709     return(MagickTrue);
710   if (image->colorspace == CMYKColorspace)
711     return(MagickFalse);
712   type=BilevelType;
713   switch (image->storage_class)
714   {
715     case DirectClass:
716     case UndefinedClass:
717     {
718       long
719         y;
720
721       register long
722         x;
723
724       CacheView
725         *image_view;
726
727       image_view=AcquireCacheView(image);
728       for (y=0; y < (long) image->rows; y++)
729       {
730         p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
731         if (p == (const PixelPacket *) NULL)
732           break;
733         for (x=0; x < (long) image->columns; x++)
734         {
735           if (IsMonochromePixel(p) == MagickFalse)
736             {
737               type=UndefinedType;
738               break;
739             }
740           p++;
741         }
742         if (type == UndefinedType)
743           break;
744       }
745       image_view=DestroyCacheView(image_view);
746       if (y == (long) image->rows)
747         ((Image *) image)->type=BilevelType;
748       break;
749     }
750     case PseudoClass:
751     {
752       register long
753         i;
754
755       p=image->colormap;
756       for (i=0; i < (long) image->colors; i++)
757       {
758         if (IsMonochromePixel(p) == MagickFalse)
759           {
760             type=UndefinedType;
761             break;
762           }
763         p++;
764       }
765       break;
766     }
767   }
768   if (type == UndefinedType)
769     return(MagickFalse);
770   ((Image *) image)->type=type;
771   return(MagickTrue);
772 }
773 \f
774 /*
775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
776 %                                                                             %
777 %                                                                             %
778 %                                                                             %
779 %     I s O p a q u e I m a g e                                               %
780 %                                                                             %
781 %                                                                             %
782 %                                                                             %
783 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
784 %
785 %  IsOpaqueImage() returns MagickTrue if none of the pixels in the image have
786 %  an opacity value other than opaque (0).
787 %
788 %  The format of the IsOpaqueImage method is:
789 %
790 %      MagickBooleanType IsOpaqueImage(const Image *image,
791 %        ExceptionInfo *exception)
792 %
793 %  A description of each parameter follows:
794 %
795 %    o image: the image.
796 %
797 %    o exception: return any errors or warnings in this structure.
798 %
799 */
800 MagickExport MagickBooleanType IsOpaqueImage(const Image *image,
801   ExceptionInfo *exception)
802 {
803   CacheView
804     *image_view;
805
806   long
807     y;
808
809   register const PixelPacket
810     *p;
811
812   register long
813     x;
814
815   /*
816     Determine if image is opaque.
817   */
818   assert(image != (Image *) NULL);
819   assert(image->signature == MagickSignature);
820   if (image->debug != MagickFalse)
821     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
822   if (image->matte == MagickFalse)
823     return(MagickTrue);
824   image_view=AcquireCacheView(image);
825   for (y=0; y < (long) image->rows; y++)
826   {
827     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
828     if (p == (const PixelPacket *) NULL)
829       break;
830     for (x=0; x < (long) image->columns; x++)
831     {
832       if (p->opacity != OpaqueOpacity)
833         break;
834       p++;
835     }
836     if (x < (long) image->columns)
837      break;
838   }
839   image_view=DestroyCacheView(image_view);
840   return(y < (long) image->rows ? MagickFalse : MagickTrue);
841 }
842 \f
843 /*
844 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
845 %                                                                             %
846 %                                                                             %
847 %                                                                             %
848 %   S e t I m a g e C h a n n e l D e p t h                                   %
849 %                                                                             %
850 %                                                                             %
851 %                                                                             %
852 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
853 %
854 %  SetImageChannelDepth() sets the depth of the image.
855 %
856 %  The format of the SetImageChannelDepth method is:
857 %
858 %      MagickBooleanType SetImageDepth(Image *image,const unsigned long depth)
859 %      MagickBooleanType SetImageChannelDepth(Image *image,
860 %        const ChannelType channel,const unsigned long depth)
861 %
862 %  A description of each parameter follows:
863 %
864 %    o image: the image.
865 %
866 %    o channel: the channel.
867 %
868 %    o depth: the image depth.
869 %
870 */
871
872 MagickExport MagickBooleanType SetImageDepth(Image *image,
873   const unsigned long depth)
874 {
875   return(SetImageChannelDepth(image,AllChannels,depth));
876 }
877
878 MagickExport MagickBooleanType SetImageChannelDepth(Image *image,
879   const ChannelType channel,const unsigned long depth)
880 {
881   CacheView
882     *image_view;
883
884   ExceptionInfo
885     *exception;
886
887   long
888     y;
889
890   MagickBooleanType
891     status;
892
893   QuantumAny
894     range;
895
896   assert(image != (Image *) NULL);
897   if (image->debug != MagickFalse)
898     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
899   assert(image->signature == MagickSignature);
900   if (GetImageDepth(image,&image->exception) <= (unsigned long)
901       MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH))
902     {
903       image->depth=depth;
904       return(MagickTrue);
905     }
906   /*
907     Scale pixels to desired depth.
908   */
909   status=MagickTrue;
910   range=GetQuantumRange(depth);
911   exception=(&image->exception);
912   image_view=AcquireCacheView(image);
913 #if defined(MAGICKCORE_OPENMP_SUPPORT)
914   #pragma omp parallel for schedule(dynamic,4) shared(status)
915 #endif
916   for (y=0; y < (long) image->rows; y++)
917   {
918     register IndexPacket
919       *restrict indexes;
920
921     register long
922       x;
923
924     register PixelPacket
925       *restrict q;
926
927     if (status == MagickFalse)
928       continue;
929     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
930       exception);
931     if (q == (PixelPacket *) NULL)
932       {
933         status=MagickFalse;
934         continue;
935       }
936     indexes=GetCacheViewAuthenticIndexQueue(image_view);
937     for (x=0; x < (long) image->columns; x++)
938     {
939       if ((channel & RedChannel) != 0)
940         q->red=ScaleAnyToQuantum(ScaleQuantumToAny(q->red,range),range);
941       if ((channel & GreenChannel) != 0)
942         q->green=ScaleAnyToQuantum(ScaleQuantumToAny(q->green,range),range);
943       if ((channel & BlueChannel) != 0)
944         q->blue=ScaleAnyToQuantum(ScaleQuantumToAny(q->blue,range),range);
945       if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
946         q->opacity=ScaleAnyToQuantum(ScaleQuantumToAny(q->opacity,range),range);
947       if (((channel & IndexChannel) != 0) &&
948           (image->colorspace == CMYKColorspace))
949         indexes[x]=ScaleAnyToQuantum(ScaleQuantumToAny(indexes[x],range),range);
950       q++;
951     }
952     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
953       {
954         status=MagickFalse;
955         continue;
956       }
957   }
958   image_view=DestroyCacheView(image_view);
959   if (image->storage_class == PseudoClass)
960     {
961       QuantumAny
962         range;
963
964       register long
965         i;
966
967       register PixelPacket
968         *restrict p;
969
970       p=image->colormap;
971       range=GetQuantumRange(depth);
972 #if defined(MAGICKCORE_OPENMP_SUPPORT)
973   #pragma omp parallel for schedule(dynamic,4) shared(status)
974 #endif
975       for (i=0; i < (long) image->colors; i++)
976       {
977         if ((channel & RedChannel) != 0)
978           p->red=ScaleAnyToQuantum(ScaleQuantumToAny(p->red,range),range);
979         if ((channel & GreenChannel) != 0)
980           p->green=ScaleAnyToQuantum(ScaleQuantumToAny(p->green,range),range);
981         if ((channel & BlueChannel) != 0)
982           p->blue=ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,range),range);
983         if ((channel & OpacityChannel) != 0)
984           p->opacity=ScaleAnyToQuantum(ScaleQuantumToAny(p->opacity,range),
985             range);
986         p++;
987       }
988     }
989   image->depth=depth;
990   return(status);
991 }