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