]> granicus.if.org Git - imagemagick/blob - MagickCore/attribute.c
Add RobidouxSharp filter depreciate Bessel Filter and Static Gravity
[imagemagick] / MagickCore / attribute.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %         AAA   TTTTT  TTTTT  RRRR   IIIII  BBBB   U   U  TTTTT  EEEEE        %
7 %        A   A    T      T    R   R    I    B   B  U   U    T    E            %
8 %        AAAAA    T      T    RRRR     I    BBBB   U   U    T    EEE          %
9 %        A   A    T      T    R R      I    B   B  U   U    T    E            %
10 %        A   A    T      T    R  R   IIIII  BBBB    UUU     T    EEEEE        %
11 %                                                                             %
12 %                                                                             %
13 %                    MagickCore Get / Set Image Attributes                    %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                October 2002                                 %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39 \f
40 /*
41   Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/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=AcquireVirtualCacheView(image,exception);
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   GetPixelInfoPixel(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   GetPixelInfoPixel(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   GetPixelInfoPixel(image,p,&target[2]);
168   status=MagickTrue;
169   GetPixelInfo(image,&zero);
170 #if defined(MAGICKCORE_OPENMP_SUPPORT)
171   #pragma omp parallel for schedule(static,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       GetPixelInfoPixel(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,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 ssize_t
304         i;
305
306 #if defined(MAGICKCORE_OPENMP_SUPPORT)
307       #pragma omp parallel for schedule(static) shared(status)
308 #endif
309       for (i=0; i < (ssize_t) image->colors; i++)
310       {
311         const int
312           id = GetOpenMPThreadId();
313
314         if (status == MagickFalse)
315           continue;
316         while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
317         {
318           MagickStatusType
319             status;
320
321           QuantumAny
322             range;
323
324           status=0;
325           range=GetQuantumRange(current_depth[id]);
326           if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
327             status|=ClampToQuantum(image->colormap[i].red) !=
328               ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
329               image->colormap[i].red),range),range);
330           if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
331             status|=ClampToQuantum(image->colormap[i].green) !=
332               ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
333               image->colormap[i].green),range),range);
334           if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
335             status|=ClampToQuantum(image->colormap[i].blue) !=
336               ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
337               image->colormap[i].blue),range),range);
338           if (status == 0)
339             break;
340           current_depth[id]++;
341         }
342       }
343       depth=current_depth[0];
344       for (id=1; id < (ssize_t) number_threads; id++)
345         if (depth < current_depth[id])
346           depth=current_depth[id];
347       current_depth=(size_t *) RelinquishMagickMemory(current_depth);
348       return(depth);
349     }
350   image_view=AcquireVirtualCacheView(image,exception);
351 #if !defined(MAGICKCORE_HDRI_SUPPORT)
352   if (QuantumRange <= MaxMap)
353     {
354       register ssize_t
355         i;
356
357       size_t
358         *depth_map;
359
360       /*
361         Scale pixels to desired (optimized with depth map).
362       */
363       depth_map=(size_t *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
364       if (depth_map == (size_t *) NULL)
365         ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
366       for (i=0; i <= (ssize_t) MaxMap; i++)
367       {
368         unsigned int
369           depth;
370
371         for (depth=1; depth < MAGICKCORE_QUANTUM_DEPTH; depth++)
372         {
373           Quantum
374             pixel;
375
376           QuantumAny
377             range;
378
379           range=GetQuantumRange(depth);
380           pixel=(Quantum) i;
381           if (pixel == ScaleAnyToQuantum(ScaleQuantumToAny(pixel,range),range))
382             break;
383         }
384         depth_map[i]=depth;
385       }
386 #if defined(MAGICKCORE_OPENMP_SUPPORT)
387       #pragma omp parallel for schedule(static,4) shared(status)
388 #endif
389       for (y=0; y < (ssize_t) image->rows; y++)
390       {
391         const int
392           id = GetOpenMPThreadId();
393
394         register const Quantum
395           *restrict p;
396
397         register ssize_t
398           x;
399
400         if (status == MagickFalse)
401           continue;
402         p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
403         if (p == (const Quantum *) NULL)
404           continue;
405         for (x=0; x < (ssize_t) image->columns; x++)
406         {
407           register ssize_t
408             i;
409
410           if (GetPixelMask(image,p) != 0)
411             {
412               p+=GetPixelChannels(image);
413               continue;
414             }
415           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
416           {
417             PixelChannel
418               channel;
419
420             PixelTrait
421               traits;
422
423             channel=GetPixelChannelMapChannel(image,i);
424             traits=GetPixelChannelMapTraits(image,channel);
425             if ((traits == UndefinedPixelTrait) ||
426                 (channel == IndexPixelChannel) || (channel == MaskPixelChannel))
427               continue;
428             if (depth_map[ScaleQuantumToMap(p[i])] > current_depth[id])
429               current_depth[id]=depth_map[ScaleQuantumToMap(p[i])];
430           }
431           p+=GetPixelChannels(image);
432         }
433         if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
434           status=MagickFalse;
435       }
436       image_view=DestroyCacheView(image_view);
437       depth=current_depth[0];
438       for (id=1; id < (ssize_t) number_threads; id++)
439         if (depth < current_depth[id])
440           depth=current_depth[id];
441       depth_map=(size_t *) RelinquishMagickMemory(depth_map);
442       current_depth=(size_t *) RelinquishMagickMemory(current_depth);
443       return(depth);
444     }
445 #endif
446   /*
447     Compute pixel depth.
448   */
449 #if defined(MAGICKCORE_OPENMP_SUPPORT)
450   #pragma omp parallel for schedule(static,4) shared(status)
451 #endif
452   for (y=0; y < (ssize_t) image->rows; y++)
453   {
454     const int
455       id = GetOpenMPThreadId();
456
457     register const Quantum
458       *restrict p;
459
460     register ssize_t
461       x;
462
463     if (status == MagickFalse)
464       continue;
465     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
466     if (p == (const Quantum *) NULL)
467       continue;
468     for (x=0; x < (ssize_t) image->columns; x++)
469     {
470       register ssize_t
471         i;
472
473       if (GetPixelMask(image,p) != 0)
474         {
475           p+=GetPixelChannels(image);
476           continue;
477         }
478       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
479       {
480         PixelChannel
481           channel;
482
483         PixelTrait
484           traits;
485
486         channel=GetPixelChannelMapChannel(image,i);
487         traits=GetPixelChannelMapTraits(image,channel);
488         if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
489             (channel == MaskPixelChannel))
490           continue;
491         while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
492         {
493           QuantumAny
494             range;
495
496           range=GetQuantumRange(current_depth[id]);
497           if (p[i] == ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),range))
498             break;
499           current_depth[id]++;
500         }
501       }
502       p+=GetPixelChannels(image);
503     }
504     if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
505       status=MagickFalse;
506   }
507   image_view=DestroyCacheView(image_view);
508   depth=current_depth[0];
509   for (id=1; id < (ssize_t) number_threads; id++)
510     if (depth < current_depth[id])
511       depth=current_depth[id];
512   current_depth=(size_t *) RelinquishMagickMemory(current_depth);
513   return(depth);
514 }
515 \f
516 /*
517 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
518 %                                                                             %
519 %                                                                             %
520 %                                                                             %
521 %   G e t I m a g e Q u a n t u m D e p t h                                   %
522 %                                                                             %
523 %                                                                             %
524 %                                                                             %
525 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
526 %
527 %  GetImageQuantumDepth() returns the depth of the image rounded to a legal
528 %  quantum depth: 8, 16, or 32.
529 %
530 %  The format of the GetImageQuantumDepth method is:
531 %
532 %      size_t GetImageQuantumDepth(const Image *image,
533 %        const MagickBooleanType constrain)
534 %
535 %  A description of each parameter follows:
536 %
537 %    o image: the image.
538 %
539 %    o constrain: A value other than MagickFalse, constrains the depth to
540 %      a maximum of MAGICKCORE_QUANTUM_DEPTH.
541 %
542 */
543
544 static inline double MagickMin(const double x,const double y)
545 {
546   if (x < y)
547     return(x);
548   return(y);
549 }
550
551 MagickExport size_t GetImageQuantumDepth(const Image *image,
552   const MagickBooleanType constrain)
553 {
554   size_t
555     depth;
556
557   depth=image->depth;
558   if (depth <= 8)
559     depth=8;
560   else
561     if (depth <= 16)
562       depth=16;
563     else
564       if (depth <= 32)
565         depth=32;
566       else
567         if (depth <= 64)
568           depth=64;
569   if (constrain != MagickFalse)
570     depth=(size_t) MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH);
571   return(depth);
572 }
573 \f
574 /*
575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
576 %                                                                             %
577 %                                                                             %
578 %                                                                             %
579 %   G e t I m a g e T y p e                                                   %
580 %                                                                             %
581 %                                                                             %
582 %                                                                             %
583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
584 %
585 %  GetImageType() returns the potential type of image:
586 %
587 %        Bilevel         Grayscale        GrayscaleMatte
588 %        Palette         PaletteMatte     TrueColor
589 %        TrueColorMatte  ColorSeparation  ColorSeparationMatte
590 %
591 %  To ensure the image type matches its potential, use SetImageType():
592 %
593 %    (void) SetImageType(image,GetImageType(image));
594 %
595 %  The format of the GetImageType method is:
596 %
597 %      ImageType GetImageType(const Image *image,ExceptionInfo *exception)
598 %
599 %  A description of each parameter follows:
600 %
601 %    o image: the image.
602 %
603 %    o exception: return any errors or warnings in this structure.
604 %
605 */
606 MagickExport ImageType GetImageType(const Image *image,ExceptionInfo *exception)
607 {
608   assert(image != (Image *) NULL);
609   assert(image->signature == MagickSignature);
610   if (image->debug != MagickFalse)
611     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
612   if (image->colorspace == CMYKColorspace)
613     {
614       if (image->matte == MagickFalse)
615         return(ColorSeparationType);
616       return(ColorSeparationMatteType);
617     }
618   if (IsImageMonochrome(image,exception) != MagickFalse)
619     return(BilevelType);
620   if (IsImageGray(image,exception) != MagickFalse)
621     {
622       if (image->matte != MagickFalse)
623         return(GrayscaleMatteType);
624       return(GrayscaleType);
625     }
626   if (IsPaletteImage(image,exception) != MagickFalse)
627     {
628       if (image->matte != MagickFalse)
629         return(PaletteMatteType);
630       return(PaletteType);
631     }
632   if (image->matte != MagickFalse)
633     return(TrueColorMatteType);
634   return(TrueColorType);
635 }
636 \f
637 /*
638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
639 %                                                                             %
640 %                                                                             %
641 %                                                                             %
642 %     I s I m a g e G r a y                                                   %
643 %                                                                             %
644 %                                                                             %
645 %                                                                             %
646 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
647 %
648 %  IsImageGray() returns MagickTrue if all the pixels in the image have the
649 %  same red, green, and blue intensities.
650 %
651 %  The format of the IsImageGray method is:
652 %
653 %      MagickBooleanType IsImageGray(const Image *image,
654 %        ExceptionInfo *exception)
655 %
656 %  A description of each parameter follows:
657 %
658 %    o image: the image.
659 %
660 %    o exception: return any errors or warnings in this structure.
661 %
662 */
663 MagickExport MagickBooleanType IsImageGray(const Image *image,
664   ExceptionInfo *exception)
665 {
666   CacheView
667     *image_view;
668
669   ImageType
670     type;
671
672   register const Quantum
673     *p;
674
675   register ssize_t
676     x;
677
678   ssize_t
679     y;
680
681   assert(image != (Image *) NULL);
682   assert(image->signature == MagickSignature);
683   if (image->debug != MagickFalse)
684     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
685   if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
686       (image->type == GrayscaleMatteType))
687     return(MagickTrue);
688   if (IssRGBColorspace(image->colorspace) == MagickFalse)
689     return(MagickFalse);
690   type=BilevelType;
691   image_view=AcquireVirtualCacheView(image,exception);
692   for (y=0; y < (ssize_t) image->rows; y++)
693   {
694     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
695     if (p == (const Quantum *) NULL)
696       break;
697     for (x=0; x < (ssize_t) image->columns; x++)
698     {
699       if (IsPixelGray(image,p) == MagickFalse)
700         {
701           type=UndefinedType;
702           break;
703         }
704       if ((type == BilevelType) &&
705           (IsPixelMonochrome(image,p) == MagickFalse))
706         type=GrayscaleType;
707       p+=GetPixelChannels(image);
708     }
709     if (type == UndefinedType)
710       break;
711   }
712   image_view=DestroyCacheView(image_view);
713   if (type == UndefinedType)
714     return(MagickFalse);
715   ((Image *) image)->type=type;
716   if ((type == GrayscaleType) && (image->matte != MagickFalse))
717     ((Image *) image)->type=GrayscaleMatteType;
718   return(MagickTrue);
719 }
720 \f
721 /*
722 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
723 %                                                                             %
724 %                                                                             %
725 %                                                                             %
726 %   I s I m a g e M o n o c h r o m e                                         %
727 %                                                                             %
728 %                                                                             %
729 %                                                                             %
730 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
731 %
732 %  IsImageMonochrome() returns MagickTrue if all the pixels in the image have
733 %  the same red, green, and blue intensities and the intensity is either
734 %  0 or QuantumRange.
735 %
736 %  The format of the IsImageMonochrome method is:
737 %
738 %      MagickBooleanType IsImageMonochrome(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 IsImageMonochrome(const Image *image,
749   ExceptionInfo *exception)
750 {
751   CacheView
752     *image_view;
753
754   ImageType
755     type;
756
757   register ssize_t
758     x;
759
760   register const Quantum
761     *p;
762
763   ssize_t
764     y;
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->type == BilevelType)
771     return(MagickTrue);
772   if (IssRGBColorspace(image->colorspace) == MagickFalse)
773     return(MagickFalse);
774   type=BilevelType;
775   image_view=AcquireVirtualCacheView(image,exception);
776   for (y=0; y < (ssize_t) image->rows; y++)
777   {
778     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
779     if (p == (const Quantum *) NULL)
780       break;
781     for (x=0; x < (ssize_t) image->columns; x++)
782     {
783       if (IsPixelMonochrome(image,p) == MagickFalse)
784         {
785           type=UndefinedType;
786           break;
787         }
788       p+=GetPixelChannels(image);
789     }
790     if (type == UndefinedType)
791       break;
792   }
793   image_view=DestroyCacheView(image_view);
794   if (type == UndefinedType)
795     return(MagickFalse);
796   ((Image *) image)->type=type;
797   return(MagickTrue);
798 }
799 \f
800 /*
801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
802 %                                                                             %
803 %                                                                             %
804 %                                                                             %
805 %     I s I m a g e O p a q u e                                               %
806 %                                                                             %
807 %                                                                             %
808 %                                                                             %
809 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
810 %
811 %  IsImageOpaque() returns MagickTrue if none of the pixels in the image have
812 %  an opacity value other than opaque (0).
813 %
814 %  The format of the IsImageOpaque method is:
815 %
816 %      MagickBooleanType IsImageOpaque(const Image *image,
817 %        ExceptionInfo *exception)
818 %
819 %  A description of each parameter follows:
820 %
821 %    o image: the image.
822 %
823 %    o exception: return any errors or warnings in this structure.
824 %
825 */
826 MagickExport MagickBooleanType IsImageOpaque(const Image *image,
827   ExceptionInfo *exception)
828 {
829   CacheView
830     *image_view;
831
832   register const Quantum
833     *p;
834
835   register ssize_t
836     x;
837
838   ssize_t
839     y;
840
841   /*
842     Determine if image is opaque.
843   */
844   assert(image != (Image *) NULL);
845   assert(image->signature == MagickSignature);
846   if (image->debug != MagickFalse)
847     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
848   if (image->matte == MagickFalse)
849     return(MagickTrue);
850   image_view=AcquireVirtualCacheView(image,exception);
851   for (y=0; y < (ssize_t) image->rows; y++)
852   {
853     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
854     if (p == (const Quantum *) NULL)
855       break;
856     for (x=0; x < (ssize_t) image->columns; x++)
857     {
858       if (GetPixelAlpha(image,p) != OpaqueAlpha)
859         break;
860       p+=GetPixelChannels(image);
861     }
862     if (x < (ssize_t) image->columns)
863      break;
864   }
865   image_view=DestroyCacheView(image_view);
866   return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
867 }
868 \f
869 /*
870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
871 %                                                                             %
872 %                                                                             %
873 %                                                                             %
874 %   S e t I m a g e D e p t h                                                 %
875 %                                                                             %
876 %                                                                             %
877 %                                                                             %
878 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
879 %
880 %  SetImageDepth() sets the depth of the image.
881 %
882 %  The format of the SetImageDepth method is:
883 %
884 %      MagickBooleanType SetImageDepth(Image *image,const size_t depth,
885 %        ExceptionInfo *exception)
886 %
887 %  A description of each parameter follows:
888 %
889 %    o image: the image.
890 %
891 %    o channel: the channel.
892 %
893 %    o depth: the image depth.
894 %
895 %    o exception: return any errors or warnings in this structure.
896 %
897 */
898 MagickExport MagickBooleanType SetImageDepth(Image *image,
899   const size_t depth,ExceptionInfo *exception)
900 {
901   CacheView
902     *image_view;
903
904   MagickBooleanType
905     status;
906
907   QuantumAny
908     range;
909
910   ssize_t
911     y;
912
913   assert(image != (Image *) NULL);
914   if (image->debug != MagickFalse)
915     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
916   assert(image->signature == MagickSignature);
917   if (depth >= MAGICKCORE_QUANTUM_DEPTH)
918     {
919       image->depth=MAGICKCORE_QUANTUM_DEPTH;
920       return(MagickTrue);
921     }
922   range=GetQuantumRange(depth);
923   if (image->storage_class == PseudoClass)
924     {
925       register ssize_t
926         i;
927
928 #if defined(MAGICKCORE_OPENMP_SUPPORT)
929       #pragma omp parallel for schedule(static) shared(status)
930 #endif
931       for (i=0; i < (ssize_t) image->colors; i++)
932       {
933         if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
934           image->colormap[i].red=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
935             ClampToQuantum(image->colormap[i].red),range),range);
936         if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
937           image->colormap[i].green=(double) ScaleAnyToQuantum(ScaleQuantumToAny(            ClampToQuantum(image->colormap[i].green),range),range);
938         if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
939           image->colormap[i].blue=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
940             ClampToQuantum(image->colormap[i].blue),range),range);
941         if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
942           image->colormap[i].alpha=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
943             ClampToQuantum(image->colormap[i].alpha),range),range);
944       }
945       status=SyncImage(image,exception);
946       if (status != MagickFalse)
947         image->depth=depth;
948       return(status);
949     }
950   status=MagickTrue;
951   image_view=AcquireAuthenticCacheView(image,exception);
952 #if !defined(MAGICKCORE_HDRI_SUPPORT)
953   if (QuantumRange <= MaxMap)
954     {
955       Quantum
956         *depth_map;
957
958       register ssize_t
959         i;
960
961       /*
962         Scale pixels to desired (optimized with depth map).
963       */
964       depth_map=(Quantum *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
965       if (depth_map == (Quantum *) NULL)
966         ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
967       for (i=0; i <= (ssize_t) MaxMap; i++)
968         depth_map[i]=ScaleAnyToQuantum(ScaleQuantumToAny((Quantum) i,range),
969           range);
970 #if defined(MAGICKCORE_OPENMP_SUPPORT)
971       #pragma omp parallel for schedule(static,4) shared(status)
972 #endif
973       for (y=0; y < (ssize_t) image->rows; y++)
974       {
975         register ssize_t
976           x;
977
978         register Quantum
979           *restrict q;
980
981         if (status == MagickFalse)
982           continue;
983         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
984           exception);
985         if (q == (Quantum *) NULL)
986           {
987             status=MagickFalse;
988             continue;
989           }
990         for (x=0; x < (ssize_t) image->columns; x++)
991         {
992           register ssize_t
993             i;
994
995           if (GetPixelMask(image,q) != 0)
996             {
997               q+=GetPixelChannels(image);
998               continue;
999             }
1000           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1001           {
1002             PixelChannel
1003               channel;
1004
1005             PixelTrait
1006               traits;
1007
1008             channel=GetPixelChannelMapChannel(image,i);
1009             traits=GetPixelChannelMapTraits(image,channel);
1010             if ((traits == UndefinedPixelTrait) ||
1011                 (channel == IndexPixelChannel) || (channel == MaskPixelChannel))
1012               continue;
1013             q[i]=depth_map[ScaleQuantumToMap(q[i])];
1014           }
1015           q+=GetPixelChannels(image);
1016         }
1017         if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1018           {
1019             status=MagickFalse;
1020             continue;
1021           }
1022       }
1023       image_view=DestroyCacheView(image_view);
1024       depth_map=(Quantum *) RelinquishMagickMemory(depth_map);
1025       if (status != MagickFalse)
1026         image->depth=depth;
1027       return(status);
1028     }
1029 #endif
1030   /*
1031     Scale pixels to desired depth.
1032   */
1033 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1034   #pragma omp parallel for schedule(static,4) shared(status)
1035 #endif
1036   for (y=0; y < (ssize_t) image->rows; y++)
1037   {
1038     register ssize_t
1039       x;
1040
1041     register Quantum
1042       *restrict q;
1043
1044     if (status == MagickFalse)
1045       continue;
1046     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1047     if (q == (Quantum *) NULL)
1048       {
1049         status=MagickFalse;
1050         continue;
1051       }
1052     for (x=0; x < (ssize_t) image->columns; x++)
1053     {
1054       register ssize_t
1055         i;
1056
1057       if (GetPixelMask(image,q) != 0)
1058         {
1059           q+=GetPixelChannels(image);
1060           continue;
1061         }
1062       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1063       {
1064         PixelChannel
1065           channel;
1066
1067         PixelTrait
1068           traits;
1069
1070         channel=GetPixelChannelMapChannel(image,i);
1071         traits=GetPixelChannelMapTraits(image,channel);
1072         if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
1073             (channel == MaskPixelChannel))
1074           continue;
1075         q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(q[i],range),range);
1076       }
1077       q+=GetPixelChannels(image);
1078     }
1079     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1080       {
1081         status=MagickFalse;
1082         continue;
1083       }
1084   }
1085   image_view=DestroyCacheView(image_view);
1086   if (status != MagickFalse)
1087     image->depth=depth;
1088   return(status);
1089 }