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