MagickCore  6.7.5
attribute.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %         AAA   TTTTT  TTTTT  RRRR   IIIII  BBBB   U   U  TTTTT  EEEEE        %
00007 %        A   A    T      T    R   R    I    B   B  U   U    T    E            %
00008 %        AAAAA    T      T    RRRR     I    BBBB   U   U    T    EEE          %
00009 %        A   A    T      T    R R      I    B   B  U   U    T    E            %
00010 %        A   A    T      T    R  R   IIIII  BBBB    UUU     T    EEEEE        %
00011 %                                                                             %
00012 %                                                                             %
00013 %                    MagickCore Get / Set Image Attributes                    %
00014 %                                                                             %
00015 %                              Software Design                                %
00016 %                                John Cristy                                  %
00017 %                                October 2002                                 %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 %
00038 */
00039 
00040 /*
00041   Include declarations.
00042 */
00043 #include "MagickCore/studio.h"
00044 #include "MagickCore/attribute.h"
00045 #include "MagickCore/blob.h"
00046 #include "MagickCore/blob-private.h"
00047 #include "MagickCore/cache.h"
00048 #include "MagickCore/cache-view.h"
00049 #include "MagickCore/client.h"
00050 #include "MagickCore/color.h"
00051 #include "MagickCore/color-private.h"
00052 #include "MagickCore/colormap.h"
00053 #include "MagickCore/colormap-private.h"
00054 #include "MagickCore/colorspace.h"
00055 #include "MagickCore/colorspace-private.h"
00056 #include "MagickCore/composite.h"
00057 #include "MagickCore/composite-private.h"
00058 #include "MagickCore/constitute.h"
00059 #include "MagickCore/draw.h"
00060 #include "MagickCore/draw-private.h"
00061 #include "MagickCore/effect.h"
00062 #include "MagickCore/enhance.h"
00063 #include "MagickCore/exception.h"
00064 #include "MagickCore/exception-private.h"
00065 #include "MagickCore/geometry.h"
00066 #include "MagickCore/histogram.h"
00067 #include "MagickCore/identify.h"
00068 #include "MagickCore/image.h"
00069 #include "MagickCore/image-private.h"
00070 #include "MagickCore/list.h"
00071 #include "MagickCore/log.h"
00072 #include "MagickCore/memory_.h"
00073 #include "MagickCore/magick.h"
00074 #include "MagickCore/monitor.h"
00075 #include "MagickCore/monitor-private.h"
00076 #include "MagickCore/paint.h"
00077 #include "MagickCore/pixel.h"
00078 #include "MagickCore/pixel-accessor.h"
00079 #include "MagickCore/property.h"
00080 #include "MagickCore/quantize.h"
00081 #include "MagickCore/quantum-private.h"
00082 #include "MagickCore/random_.h"
00083 #include "MagickCore/resource_.h"
00084 #include "MagickCore/semaphore.h"
00085 #include "MagickCore/segment.h"
00086 #include "MagickCore/splay-tree.h"
00087 #include "MagickCore/string_.h"
00088 #include "MagickCore/thread-private.h"
00089 #include "MagickCore/threshold.h"
00090 #include "MagickCore/transform.h"
00091 #include "MagickCore/utility.h"
00092 
00093 /*
00094 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00095 %                                                                             %
00096 %                                                                             %
00097 %                                                                             %
00098 +   G e t I m a g e B o u n d i n g B o x                                     %
00099 %                                                                             %
00100 %                                                                             %
00101 %                                                                             %
00102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00103 %
00104 %  GetImageBoundingBox() returns the bounding box of an image canvas.
00105 %
00106 %  The format of the GetImageBoundingBox method is:
00107 %
00108 %      RectangleInfo GetImageBoundingBox(const Image *image,
00109 %        ExceptionInfo *exception)
00110 %
00111 %  A description of each parameter follows:
00112 %
00113 %    o bounds: Method GetImageBoundingBox returns the bounding box of an
00114 %      image canvas.
00115 %
00116 %    o image: the image.
00117 %
00118 %    o exception: return any errors or warnings in this structure.
00119 %
00120 */
00121 MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
00122   ExceptionInfo *exception)
00123 {
00124   CacheView
00125     *image_view;
00126 
00127   MagickBooleanType
00128     status;
00129 
00130   PixelInfo
00131     target[3],
00132     zero;
00133 
00134   RectangleInfo
00135     bounds;
00136 
00137   register const Quantum
00138     *p;
00139 
00140   ssize_t
00141     y;
00142 
00143   assert(image != (Image *) NULL);
00144   assert(image->signature == MagickSignature);
00145   if (image->debug != MagickFalse)
00146     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00147   bounds.width=0;
00148   bounds.height=0;
00149   bounds.x=(ssize_t) image->columns;
00150   bounds.y=(ssize_t) image->rows;
00151   GetPixelInfo(image,&target[0]);
00152   image_view=AcquireCacheView(image);
00153   p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
00154   if (p == (const Quantum *) NULL)
00155     {
00156       image_view=DestroyCacheView(image_view);
00157       return(bounds);
00158     }
00159   GetPixelInfoPixel(image,p,&target[0]);
00160   GetPixelInfo(image,&target[1]);
00161   p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,0,1,1,
00162     exception);
00163   GetPixelInfoPixel(image,p,&target[1]);
00164   GetPixelInfo(image,&target[2]);
00165   p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-1,1,1,
00166     exception);
00167   GetPixelInfoPixel(image,p,&target[2]);
00168   status=MagickTrue;
00169   GetPixelInfo(image,&zero);
00170 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00171   #pragma omp parallel for schedule(static,4) shared(status)
00172 #endif
00173   for (y=0; y < (ssize_t) image->rows; y++)
00174   {
00175     PixelInfo
00176       pixel;
00177 
00178     RectangleInfo
00179       bounding_box;
00180 
00181     register const Quantum
00182       *restrict p;
00183 
00184     register ssize_t
00185       x;
00186 
00187     if (status == MagickFalse)
00188       continue;
00189 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00190 #  pragma omp critical (MagickCore_GetImageBoundingBox)
00191 #endif
00192     bounding_box=bounds;
00193     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00194     if (p == (const Quantum *) NULL)
00195       {
00196         status=MagickFalse;
00197         continue;
00198       }
00199     pixel=zero;
00200     for (x=0; x < (ssize_t) image->columns; x++)
00201     {
00202       GetPixelInfoPixel(image,p,&pixel);
00203       if ((x < bounding_box.x) &&
00204           (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
00205         bounding_box.x=x;
00206       if ((x > (ssize_t) bounding_box.width) &&
00207           (IsFuzzyEquivalencePixelInfo(&pixel,&target[1]) == MagickFalse))
00208         bounding_box.width=(size_t) x;
00209       if ((y < bounding_box.y) &&
00210           (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
00211         bounding_box.y=y;
00212       if ((y > (ssize_t) bounding_box.height) &&
00213           (IsFuzzyEquivalencePixelInfo(&pixel,&target[2]) == MagickFalse))
00214         bounding_box.height=(size_t) y;
00215       p+=GetPixelChannels(image);
00216     }
00217 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00218 #  pragma omp critical (MagickCore_GetImageBoundingBox)
00219 #endif
00220     {
00221       if (bounding_box.x < bounds.x)
00222         bounds.x=bounding_box.x;
00223       if (bounding_box.y < bounds.y)
00224         bounds.y=bounding_box.y;
00225       if (bounding_box.width > bounds.width)
00226         bounds.width=bounding_box.width;
00227       if (bounding_box.height > bounds.height)
00228         bounds.height=bounding_box.height;
00229     }
00230   }
00231   image_view=DestroyCacheView(image_view);
00232   if ((bounds.width == 0) || (bounds.height == 0))
00233     (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
00234       "GeometryDoesNotContainImage","`%s'",image->filename);
00235   else
00236     {
00237       bounds.width-=(bounds.x-1);
00238       bounds.height-=(bounds.y-1);
00239     }
00240   return(bounds);
00241 }
00242 
00243 /*
00244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00245 %                                                                             %
00246 %                                                                             %
00247 %                                                                             %
00248 %   G e t I m a g e D e p t h                                                 %
00249 %                                                                             %
00250 %                                                                             %
00251 %                                                                             %
00252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00253 %
00254 %  GetImageDepth() returns the depth of a particular image channel.
00255 %
00256 %  The format of the GetImageDepth method is:
00257 %
00258 %      size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
00259 %
00260 %  A description of each parameter follows:
00261 %
00262 %    o image: the image.
00263 %
00264 %    o exception: return any errors or warnings in this structure.
00265 %
00266 */
00267 MagickExport size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
00268 {
00269   CacheView
00270     *image_view;
00271 
00272   MagickBooleanType
00273     status;
00274 
00275   register ssize_t
00276     id;
00277 
00278   size_t
00279     *current_depth,
00280     depth,
00281     number_threads;
00282 
00283   ssize_t
00284     y;
00285 
00286   /*
00287     Compute image depth.
00288   */
00289   assert(image != (Image *) NULL);
00290   assert(image->signature == MagickSignature);
00291   if (image->debug != MagickFalse)
00292     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00293   number_threads=GetOpenMPMaximumThreads();
00294   current_depth=(size_t *) AcquireQuantumMemory(number_threads,
00295     sizeof(*current_depth));
00296   if (current_depth == (size_t *) NULL)
00297     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00298   status=MagickTrue;
00299   for (id=0; id < (ssize_t) number_threads; id++)
00300     current_depth[id]=1;
00301   if ((image->storage_class == PseudoClass) && (image->matte == MagickFalse))
00302     {
00303       register ssize_t
00304         i;
00305 
00306 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00307       #pragma omp parallel for schedule(static) shared(status)
00308 #endif
00309       for (i=0; i < (ssize_t) image->colors; i++)
00310       {
00311         const int
00312           id = GetOpenMPThreadId();
00313 
00314         if (status == MagickFalse)
00315           continue;
00316         while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
00317         {
00318           MagickStatusType
00319             status;
00320 
00321           QuantumAny
00322             range;
00323 
00324           status=0;
00325           range=GetQuantumRange(current_depth[id]);
00326           if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
00327             status|=ClampToQuantum(image->colormap[i].red) !=
00328               ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
00329               image->colormap[i].red),range),range);
00330           if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
00331             status|=ClampToQuantum(image->colormap[i].green) !=
00332               ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
00333               image->colormap[i].green),range),range);
00334           if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
00335             status|=ClampToQuantum(image->colormap[i].blue) !=
00336               ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
00337               image->colormap[i].blue),range),range);
00338           if (status == 0)
00339             break;
00340           current_depth[id]++;
00341         }
00342       }
00343       depth=current_depth[0];
00344       for (id=1; id < (ssize_t) number_threads; id++)
00345         if (depth < current_depth[id])
00346           depth=current_depth[id];
00347       current_depth=(size_t *) RelinquishMagickMemory(current_depth);
00348       return(depth);
00349     }
00350   image_view=AcquireCacheView(image);
00351 #if !defined(MAGICKCORE_HDRI_SUPPORT)
00352   if (QuantumRange <= MaxMap)
00353     {
00354       register ssize_t
00355         i;
00356 
00357       size_t
00358         *depth_map;
00359 
00360       /*
00361         Scale pixels to desired (optimized with depth map).
00362       */
00363       depth_map=(size_t *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
00364       if (depth_map == (size_t *) NULL)
00365         ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00366       for (i=0; i <= (ssize_t) MaxMap; i++)
00367       {
00368         unsigned int
00369           depth;
00370 
00371         for (depth=1; depth < MAGICKCORE_QUANTUM_DEPTH; depth++)
00372         {
00373           Quantum
00374             pixel;
00375 
00376           QuantumAny
00377             range;
00378 
00379           range=GetQuantumRange(depth);
00380           pixel=(Quantum) i;
00381           if (pixel == ScaleAnyToQuantum(ScaleQuantumToAny(pixel,range),range))
00382             break;
00383         }
00384         depth_map[i]=depth;
00385       }
00386 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00387       #pragma omp parallel for schedule(static,4) shared(status)
00388 #endif
00389       for (y=0; y < (ssize_t) image->rows; y++)
00390       {
00391         const int
00392           id = GetOpenMPThreadId();
00393 
00394         register const Quantum
00395           *restrict p;
00396 
00397         register ssize_t
00398           x;
00399 
00400         if (status == MagickFalse)
00401           continue;
00402         p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00403         if (p == (const Quantum *) NULL)
00404           continue;
00405         for (x=0; x < (ssize_t) image->columns; x++)
00406         {
00407           register ssize_t
00408             i;
00409 
00410           if (GetPixelMask(image,p) != 0)
00411             {
00412               p+=GetPixelChannels(image);
00413               continue;
00414             }
00415           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
00416           {
00417             PixelChannel
00418               channel;
00419 
00420             PixelTrait
00421               traits;
00422 
00423             channel=GetPixelChannelMapChannel(image,i);
00424             traits=GetPixelChannelMapTraits(image,channel);
00425             if ((traits == UndefinedPixelTrait) ||
00426                 (channel == IndexPixelChannel) || (channel == MaskPixelChannel))
00427               continue;
00428             if (depth_map[ScaleQuantumToMap(p[i])] > current_depth[id])
00429               current_depth[id]=depth_map[ScaleQuantumToMap(p[i])];
00430           }
00431           p+=GetPixelChannels(image);
00432         }
00433         if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
00434           status=MagickFalse;
00435       }
00436       image_view=DestroyCacheView(image_view);
00437       depth=current_depth[0];
00438       for (id=1; id < (ssize_t) number_threads; id++)
00439         if (depth < current_depth[id])
00440           depth=current_depth[id];
00441       depth_map=(size_t *) RelinquishMagickMemory(depth_map);
00442       current_depth=(size_t *) RelinquishMagickMemory(current_depth);
00443       return(depth);
00444     }
00445 #endif
00446   /*
00447     Compute pixel depth.
00448   */
00449 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00450   #pragma omp parallel for schedule(static,4) shared(status)
00451 #endif
00452   for (y=0; y < (ssize_t) image->rows; y++)
00453   {
00454     const int
00455       id = GetOpenMPThreadId();
00456 
00457     register const Quantum
00458       *restrict p;
00459 
00460     register ssize_t
00461       x;
00462 
00463     if (status == MagickFalse)
00464       continue;
00465     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00466     if (p == (const Quantum *) NULL)
00467       continue;
00468     for (x=0; x < (ssize_t) image->columns; x++)
00469     {
00470       register ssize_t
00471         i;
00472 
00473       if (GetPixelMask(image,p) != 0)
00474         {
00475           p+=GetPixelChannels(image);
00476           continue;
00477         }
00478       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
00479       {
00480         PixelChannel
00481           channel;
00482 
00483         PixelTrait
00484           traits;
00485 
00486         channel=GetPixelChannelMapChannel(image,i);
00487         traits=GetPixelChannelMapTraits(image,channel);
00488         if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
00489             (channel == MaskPixelChannel))
00490           continue;
00491         while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
00492         {
00493           QuantumAny
00494             range;
00495 
00496           range=GetQuantumRange(current_depth[id]);
00497           if (p[i] == ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),range))
00498             break;
00499           current_depth[id]++;
00500         }
00501       }
00502       p+=GetPixelChannels(image);
00503     }
00504     if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
00505       status=MagickFalse;
00506   }
00507   image_view=DestroyCacheView(image_view);
00508   depth=current_depth[0];
00509   for (id=1; id < (ssize_t) number_threads; id++)
00510     if (depth < current_depth[id])
00511       depth=current_depth[id];
00512   current_depth=(size_t *) RelinquishMagickMemory(current_depth);
00513   return(depth);
00514 }
00515 
00516 /*
00517 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00518 %                                                                             %
00519 %                                                                             %
00520 %                                                                             %
00521 %   G e t I m a g e Q u a n t u m D e p t h                                   %
00522 %                                                                             %
00523 %                                                                             %
00524 %                                                                             %
00525 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00526 %
00527 %  GetImageQuantumDepth() returns the depth of the image rounded to a legal
00528 %  quantum depth: 8, 16, or 32.
00529 %
00530 %  The format of the GetImageQuantumDepth method is:
00531 %
00532 %      size_t GetImageQuantumDepth(const Image *image,
00533 %        const MagickBooleanType constrain)
00534 %
00535 %  A description of each parameter follows:
00536 %
00537 %    o image: the image.
00538 %
00539 %    o constrain: A value other than MagickFalse, constrains the depth to
00540 %      a maximum of MAGICKCORE_QUANTUM_DEPTH.
00541 %
00542 */
00543 
00544 static inline double MagickMin(const double x,const double y)
00545 {
00546   if (x < y)
00547     return(x);
00548   return(y);
00549 }
00550 
00551 MagickExport size_t GetImageQuantumDepth(const Image *image,
00552   const MagickBooleanType constrain)
00553 {
00554   size_t
00555     depth;
00556 
00557   depth=image->depth;
00558   if (depth <= 8)
00559     depth=8;
00560   else
00561     if (depth <= 16)
00562       depth=16;
00563     else
00564       if (depth <= 32)
00565         depth=32;
00566       else
00567         if (depth <= 64)
00568           depth=64;
00569   if (constrain != MagickFalse)
00570     depth=(size_t) MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH);
00571   return(depth);
00572 }
00573 
00574 /*
00575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00576 %                                                                             %
00577 %                                                                             %
00578 %                                                                             %
00579 %   G e t I m a g e T y p e                                                   %
00580 %                                                                             %
00581 %                                                                             %
00582 %                                                                             %
00583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00584 %
00585 %  GetImageType() returns the potential type of image:
00586 %
00587 %        Bilevel         Grayscale        GrayscaleMatte
00588 %        Palette         PaletteMatte     TrueColor
00589 %        TrueColorMatte  ColorSeparation  ColorSeparationMatte
00590 %
00591 %  To ensure the image type matches its potential, use SetImageType():
00592 %
00593 %    (void) SetImageType(image,GetImageType(image));
00594 %
00595 %  The format of the GetImageType method is:
00596 %
00597 %      ImageType GetImageType(const Image *image,ExceptionInfo *exception)
00598 %
00599 %  A description of each parameter follows:
00600 %
00601 %    o image: the image.
00602 %
00603 %    o exception: return any errors or warnings in this structure.
00604 %
00605 */
00606 MagickExport ImageType GetImageType(const Image *image,ExceptionInfo *exception)
00607 {
00608   assert(image != (Image *) NULL);
00609   assert(image->signature == MagickSignature);
00610   if (image->debug != MagickFalse)
00611     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00612   if (image->colorspace == CMYKColorspace)
00613     {
00614       if (image->matte == MagickFalse)
00615         return(ColorSeparationType);
00616       return(ColorSeparationMatteType);
00617     }
00618   if (IsImageMonochrome(image,exception) != MagickFalse)
00619     return(BilevelType);
00620   if (IsImageGray(image,exception) != MagickFalse)
00621     {
00622       if (image->matte != MagickFalse)
00623         return(GrayscaleMatteType);
00624       return(GrayscaleType);
00625     }
00626   if (IsPaletteImage(image,exception) != MagickFalse)
00627     {
00628       if (image->matte != MagickFalse)
00629         return(PaletteMatteType);
00630       return(PaletteType);
00631     }
00632   if (image->matte != MagickFalse)
00633     return(TrueColorMatteType);
00634   return(TrueColorType);
00635 }
00636 
00637 /*
00638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00639 %                                                                             %
00640 %                                                                             %
00641 %                                                                             %
00642 %     I s I m a g e G r a y                                                   %
00643 %                                                                             %
00644 %                                                                             %
00645 %                                                                             %
00646 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00647 %
00648 %  IsImageGray() returns MagickTrue if all the pixels in the image have the
00649 %  same red, green, and blue intensities.
00650 %
00651 %  The format of the IsImageGray method is:
00652 %
00653 %      MagickBooleanType IsImageGray(const Image *image,
00654 %        ExceptionInfo *exception)
00655 %
00656 %  A description of each parameter follows:
00657 %
00658 %    o image: the image.
00659 %
00660 %    o exception: return any errors or warnings in this structure.
00661 %
00662 */
00663 MagickExport MagickBooleanType IsImageGray(const Image *image,
00664   ExceptionInfo *exception)
00665 {
00666   CacheView
00667     *image_view;
00668 
00669   ImageType
00670     type;
00671 
00672   register const Quantum
00673     *p;
00674 
00675   register ssize_t
00676     x;
00677 
00678   ssize_t
00679     y;
00680 
00681   assert(image != (Image *) NULL);
00682   assert(image->signature == MagickSignature);
00683   if (image->debug != MagickFalse)
00684     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00685   if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
00686       (image->type == GrayscaleMatteType))
00687     return(MagickTrue);
00688   if (IsRGBColorspace(image->colorspace) == MagickFalse)
00689     return(MagickFalse);
00690   type=BilevelType;
00691   image_view=AcquireCacheView(image);
00692   for (y=0; y < (ssize_t) image->rows; y++)
00693   {
00694     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00695     if (p == (const Quantum *) NULL)
00696       break;
00697     for (x=0; x < (ssize_t) image->columns; x++)
00698     {
00699       if (IsPixelGray(image,p) == MagickFalse)
00700         {
00701           type=UndefinedType;
00702           break;
00703         }
00704       if ((type == BilevelType) &&
00705           (IsPixelMonochrome(image,p) == MagickFalse))
00706         type=GrayscaleType;
00707       p+=GetPixelChannels(image);
00708     }
00709     if (type == UndefinedType)
00710       break;
00711   }
00712   image_view=DestroyCacheView(image_view);
00713   if (type == UndefinedType)
00714     return(MagickFalse);
00715   ((Image *) image)->type=type;
00716   if ((type == GrayscaleType) && (image->matte != MagickFalse))
00717     ((Image *) image)->type=GrayscaleMatteType;
00718   return(MagickTrue);
00719 }
00720 
00721 /*
00722 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00723 %                                                                             %
00724 %                                                                             %
00725 %                                                                             %
00726 %   I s I m a g e M o n o c h r o m e                                         %
00727 %                                                                             %
00728 %                                                                             %
00729 %                                                                             %
00730 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00731 %
00732 %  IsImageMonochrome() returns MagickTrue if all the pixels in the image have
00733 %  the same red, green, and blue intensities and the intensity is either
00734 %  0 or QuantumRange.
00735 %
00736 %  The format of the IsImageMonochrome method is:
00737 %
00738 %      MagickBooleanType IsImageMonochrome(const Image *image,
00739 %        ExceptionInfo *exception)
00740 %
00741 %  A description of each parameter follows:
00742 %
00743 %    o image: the image.
00744 %
00745 %    o exception: return any errors or warnings in this structure.
00746 %
00747 */
00748 MagickExport MagickBooleanType IsImageMonochrome(const Image *image,
00749   ExceptionInfo *exception)
00750 {
00751   CacheView
00752     *image_view;
00753 
00754   ImageType
00755     type;
00756 
00757   register ssize_t
00758     x;
00759 
00760   register const Quantum
00761     *p;
00762 
00763   ssize_t
00764     y;
00765 
00766   assert(image != (Image *) NULL);
00767   assert(image->signature == MagickSignature);
00768   if (image->debug != MagickFalse)
00769     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00770   if (image->type == BilevelType)
00771     return(MagickTrue);
00772   if (IsRGBColorspace(image->colorspace) == MagickFalse)
00773     return(MagickFalse);
00774   type=BilevelType;
00775   image_view=AcquireCacheView(image);
00776   for (y=0; y < (ssize_t) image->rows; y++)
00777   {
00778     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00779     if (p == (const Quantum *) NULL)
00780       break;
00781     for (x=0; x < (ssize_t) image->columns; x++)
00782     {
00783       if (IsPixelMonochrome(image,p) == MagickFalse)
00784         {
00785           type=UndefinedType;
00786           break;
00787         }
00788       p+=GetPixelChannels(image);
00789     }
00790     if (type == UndefinedType)
00791       break;
00792   }
00793   image_view=DestroyCacheView(image_view);
00794   if (type == UndefinedType)
00795     return(MagickFalse);
00796   ((Image *) image)->type=type;
00797   return(MagickTrue);
00798 }
00799 
00800 /*
00801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00802 %                                                                             %
00803 %                                                                             %
00804 %                                                                             %
00805 %     I s I m a g e O p a q u e                                               %
00806 %                                                                             %
00807 %                                                                             %
00808 %                                                                             %
00809 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00810 %
00811 %  IsImageOpaque() returns MagickTrue if none of the pixels in the image have
00812 %  an opacity value other than opaque (0).
00813 %
00814 %  The format of the IsImageOpaque method is:
00815 %
00816 %      MagickBooleanType IsImageOpaque(const Image *image,
00817 %        ExceptionInfo *exception)
00818 %
00819 %  A description of each parameter follows:
00820 %
00821 %    o image: the image.
00822 %
00823 %    o exception: return any errors or warnings in this structure.
00824 %
00825 */
00826 MagickExport MagickBooleanType IsImageOpaque(const Image *image,
00827   ExceptionInfo *exception)
00828 {
00829   CacheView
00830     *image_view;
00831 
00832   register const Quantum
00833     *p;
00834 
00835   register ssize_t
00836     x;
00837 
00838   ssize_t
00839     y;
00840 
00841   /*
00842     Determine if image is opaque.
00843   */
00844   assert(image != (Image *) NULL);
00845   assert(image->signature == MagickSignature);
00846   if (image->debug != MagickFalse)
00847     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00848   if (image->matte == MagickFalse)
00849     return(MagickTrue);
00850   image_view=AcquireCacheView(image);
00851   for (y=0; y < (ssize_t) image->rows; y++)
00852   {
00853     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
00854     if (p == (const Quantum *) NULL)
00855       break;
00856     for (x=0; x < (ssize_t) image->columns; x++)
00857     {
00858       if (GetPixelAlpha(image,p) != OpaqueAlpha)
00859         break;
00860       p+=GetPixelChannels(image);
00861     }
00862     if (x < (ssize_t) image->columns)
00863      break;
00864   }
00865   image_view=DestroyCacheView(image_view);
00866   return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
00867 }
00868 
00869 /*
00870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00871 %                                                                             %
00872 %                                                                             %
00873 %                                                                             %
00874 %   S e t I m a g e D e p t h                                                 %
00875 %                                                                             %
00876 %                                                                             %
00877 %                                                                             %
00878 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00879 %
00880 %  SetImageDepth() sets the depth of the image.
00881 %
00882 %  The format of the SetImageDepth method is:
00883 %
00884 %      MagickBooleanType SetImageDepth(Image *image,const size_t depth,
00885 %        ExceptionInfo *exception)
00886 %
00887 %  A description of each parameter follows:
00888 %
00889 %    o image: the image.
00890 %
00891 %    o channel: the channel.
00892 %
00893 %    o depth: the image depth.
00894 %
00895 %    o exception: return any errors or warnings in this structure.
00896 %
00897 */
00898 MagickExport MagickBooleanType SetImageDepth(Image *image,
00899   const size_t depth,ExceptionInfo *exception)
00900 {
00901   CacheView
00902     *image_view;
00903 
00904   MagickBooleanType
00905     status;
00906 
00907   QuantumAny
00908     range;
00909 
00910   ssize_t
00911     y;
00912 
00913   assert(image != (Image *) NULL);
00914   if (image->debug != MagickFalse)
00915     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
00916   assert(image->signature == MagickSignature);
00917   if (depth >= MAGICKCORE_QUANTUM_DEPTH)
00918     {
00919       image->depth=MAGICKCORE_QUANTUM_DEPTH;
00920       return(MagickTrue);
00921     }
00922   range=GetQuantumRange(depth);
00923   if (image->storage_class == PseudoClass)
00924     {
00925       register ssize_t
00926         i;
00927 
00928 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00929       #pragma omp parallel for schedule(static) shared(status)
00930 #endif
00931       for (i=0; i < (ssize_t) image->colors; i++)
00932       {
00933         if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
00934           image->colormap[i].red=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
00935             ClampToQuantum(image->colormap[i].red),range),range);
00936         if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
00937           image->colormap[i].green=(double) ScaleAnyToQuantum(ScaleQuantumToAny(            ClampToQuantum(image->colormap[i].green),range),range);
00938         if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
00939           image->colormap[i].blue=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
00940             ClampToQuantum(image->colormap[i].blue),range),range);
00941         if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
00942           image->colormap[i].alpha=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
00943             ClampToQuantum(image->colormap[i].alpha),range),range);
00944       }
00945       status=SyncImage(image,exception);
00946       if (status != MagickFalse)
00947         image->depth=depth;
00948       return(status);
00949     }
00950   status=MagickTrue;
00951   image_view=AcquireCacheView(image);
00952 #if !defined(MAGICKCORE_HDRI_SUPPORT)
00953   if (QuantumRange <= MaxMap)
00954     {
00955       Quantum
00956         *depth_map;
00957 
00958       register ssize_t
00959         i;
00960 
00961       /*
00962         Scale pixels to desired (optimized with depth map).
00963       */
00964       depth_map=(Quantum *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
00965       if (depth_map == (Quantum *) NULL)
00966         ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
00967       for (i=0; i <= (ssize_t) MaxMap; i++)
00968         depth_map[i]=ScaleAnyToQuantum(ScaleQuantumToAny((Quantum) i,range),
00969           range);
00970 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00971       #pragma omp parallel for schedule(static,4) shared(status)
00972 #endif
00973       for (y=0; y < (ssize_t) image->rows; y++)
00974       {
00975         register ssize_t
00976           x;
00977 
00978         register Quantum
00979           *restrict q;
00980 
00981         if (status == MagickFalse)
00982           continue;
00983         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
00984           exception);
00985         if (q == (Quantum *) NULL)
00986           {
00987             status=MagickFalse;
00988             continue;
00989           }
00990         for (x=0; x < (ssize_t) image->columns; x++)
00991         {
00992           register ssize_t
00993             i;
00994 
00995           if (GetPixelMask(image,q) != 0)
00996             {
00997               q+=GetPixelChannels(image);
00998               continue;
00999             }
01000           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
01001           {
01002             PixelChannel
01003               channel;
01004 
01005             PixelTrait
01006               traits;
01007 
01008             channel=GetPixelChannelMapChannel(image,i);
01009             traits=GetPixelChannelMapTraits(image,channel);
01010             if ((traits == UndefinedPixelTrait) ||
01011                 (channel == IndexPixelChannel) || (channel == MaskPixelChannel))
01012               continue;
01013             q[i]=depth_map[ScaleQuantumToMap(q[i])];
01014           }
01015           q+=GetPixelChannels(image);
01016         }
01017         if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
01018           {
01019             status=MagickFalse;
01020             continue;
01021           }
01022       }
01023       image_view=DestroyCacheView(image_view);
01024       depth_map=(Quantum *) RelinquishMagickMemory(depth_map);
01025       if (status != MagickFalse)
01026         image->depth=depth;
01027       return(status);
01028     }
01029 #endif
01030   /*
01031     Scale pixels to desired depth.
01032   */
01033 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01034   #pragma omp parallel for schedule(static,4) shared(status)
01035 #endif
01036   for (y=0; y < (ssize_t) image->rows; y++)
01037   {
01038     register ssize_t
01039       x;
01040 
01041     register Quantum
01042       *restrict q;
01043 
01044     if (status == MagickFalse)
01045       continue;
01046     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
01047     if (q == (Quantum *) NULL)
01048       {
01049         status=MagickFalse;
01050         continue;
01051       }
01052     for (x=0; x < (ssize_t) image->columns; x++)
01053     {
01054       register ssize_t
01055         i;
01056 
01057       if (GetPixelMask(image,q) != 0)
01058         {
01059           q+=GetPixelChannels(image);
01060           continue;
01061         }
01062       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
01063       {
01064         PixelChannel
01065           channel;
01066 
01067         PixelTrait
01068           traits;
01069 
01070         channel=GetPixelChannelMapChannel(image,i);
01071         traits=GetPixelChannelMapTraits(image,channel);
01072         if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
01073             (channel == MaskPixelChannel))
01074           continue;
01075         q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(q[i],range),range);
01076       }
01077       q+=GetPixelChannels(image);
01078     }
01079     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
01080       {
01081         status=MagickFalse;
01082         continue;
01083       }
01084   }
01085   image_view=DestroyCacheView(image_view);
01086   if (status != MagickFalse)
01087     image->depth=depth;
01088   return(status);
01089 }