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