2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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 %
13 % MagickCore Get / Set Image Attributes %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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"
94 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98 + G e t I m a g e B o u n d i n g B o x %
102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
104 % GetImageBoundingBox() returns the bounding box of an image canvas.
106 % The format of the GetImageBoundingBox method is:
108 % RectangleInfo GetImageBoundingBox(const Image *image,
109 % ExceptionInfo *exception)
111 % A description of each parameter follows:
113 % o bounds: Method GetImageBoundingBox returns the bounding box of an
116 % o image: the image.
118 % o exception: return any errors or warnings in this structure.
121 MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
122 ExceptionInfo *exception)
137 register const Quantum
143 assert(image != (Image *) NULL);
144 assert(image->signature == MagickSignature);
145 if (image->debug != MagickFalse)
146 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
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)
156 image_view=DestroyCacheView(image_view);
159 GetPixelInfoPixel(image,p,&target[0]);
160 GetPixelInfo(image,&target[1]);
161 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,0,1,1,
163 GetPixelInfoPixel(image,p,&target[1]);
164 GetPixelInfo(image,&target[2]);
165 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-1,1,1,
167 GetPixelInfoPixel(image,p,&target[2]);
169 GetPixelInfo(image,&zero);
170 #if defined(MAGICKCORE_OPENMP_SUPPORT)
171 #pragma omp parallel for schedule(static,4) shared(status) \
172 dynamic_number_threads(image,image->columns,image->rows,1)
174 for (y=0; y < (ssize_t) image->rows; y++)
182 register const Quantum
188 if (status == MagickFalse)
190 #if defined(MAGICKCORE_OPENMP_SUPPORT)
191 # pragma omp critical (MagickCore_GetImageBoundingBox)
194 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
195 if (p == (const Quantum *) NULL)
201 for (x=0; x < (ssize_t) image->columns; x++)
203 GetPixelInfoPixel(image,p,&pixel);
204 if ((x < bounding_box.x) &&
205 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
207 if ((x > (ssize_t) bounding_box.width) &&
208 (IsFuzzyEquivalencePixelInfo(&pixel,&target[1]) == MagickFalse))
209 bounding_box.width=(size_t) x;
210 if ((y < bounding_box.y) &&
211 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
213 if ((y > (ssize_t) bounding_box.height) &&
214 (IsFuzzyEquivalencePixelInfo(&pixel,&target[2]) == MagickFalse))
215 bounding_box.height=(size_t) y;
216 p+=GetPixelChannels(image);
218 #if defined(MAGICKCORE_OPENMP_SUPPORT)
219 # pragma omp critical (MagickCore_GetImageBoundingBox)
222 if (bounding_box.x < bounds.x)
223 bounds.x=bounding_box.x;
224 if (bounding_box.y < bounds.y)
225 bounds.y=bounding_box.y;
226 if (bounding_box.width > bounds.width)
227 bounds.width=bounding_box.width;
228 if (bounding_box.height > bounds.height)
229 bounds.height=bounding_box.height;
232 image_view=DestroyCacheView(image_view);
233 if ((bounds.width == 0) || (bounds.height == 0))
234 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
235 "GeometryDoesNotContainImage","'%s'",image->filename);
238 bounds.width-=(bounds.x-1);
239 bounds.height-=(bounds.y-1);
245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
249 % G e t I m a g e D e p t h %
253 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
255 % GetImageDepth() returns the depth of a particular image channel.
257 % The format of the GetImageDepth method is:
259 % size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
261 % A description of each parameter follows:
263 % o image: the image.
265 % o exception: return any errors or warnings in this structure.
268 MagickExport size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
290 assert(image != (Image *) NULL);
291 assert(image->signature == MagickSignature);
292 if (image->debug != MagickFalse)
293 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
294 number_threads=GetOpenMPMaximumThreads();
295 current_depth=(size_t *) AcquireQuantumMemory(number_threads,
296 sizeof(*current_depth));
297 if (current_depth == (size_t *) NULL)
298 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
300 for (id=0; id < (ssize_t) number_threads; id++)
302 if ((image->storage_class == PseudoClass) && (image->matte == MagickFalse))
307 #if defined(MAGICKCORE_OPENMP_SUPPORT)
308 #pragma omp parallel for schedule(static) shared(status) \
309 if ((image->colors) > 256) \
310 num_threads(GetMagickResourceLimit(ThreadResource))
312 for (i=0; i < (ssize_t) image->colors; i++)
315 id = GetOpenMPThreadId();
317 if (status == MagickFalse)
319 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
328 range=GetQuantumRange(current_depth[id]);
329 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
330 status|=ClampToQuantum(image->colormap[i].red) !=
331 ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
332 image->colormap[i].red),range),range);
333 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
334 status|=ClampToQuantum(image->colormap[i].green) !=
335 ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
336 image->colormap[i].green),range),range);
337 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
338 status|=ClampToQuantum(image->colormap[i].blue) !=
339 ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
340 image->colormap[i].blue),range),range);
346 depth=current_depth[0];
347 for (id=1; id < (ssize_t) number_threads; id++)
348 if (depth < current_depth[id])
349 depth=current_depth[id];
350 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
353 image_view=AcquireVirtualCacheView(image,exception);
354 #if !defined(MAGICKCORE_HDRI_SUPPORT)
355 if (QuantumRange <= MaxMap)
364 Scale pixels to desired (optimized with depth map).
366 depth_map=(size_t *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
367 if (depth_map == (size_t *) NULL)
368 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
369 for (i=0; i <= (ssize_t) MaxMap; i++)
374 for (depth=1; depth < MAGICKCORE_QUANTUM_DEPTH; depth++)
382 range=GetQuantumRange(depth);
384 if (pixel == ScaleAnyToQuantum(ScaleQuantumToAny(pixel,range),range))
389 #if defined(MAGICKCORE_OPENMP_SUPPORT)
390 #pragma omp parallel for schedule(static,4) shared(status) \
391 dynamic_number_threads(image,image->columns,image->rows,1)
393 for (y=0; y < (ssize_t) image->rows; y++)
396 id = GetOpenMPThreadId();
398 register const Quantum
404 if (status == MagickFalse)
406 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
407 if (p == (const Quantum *) NULL)
409 for (x=0; x < (ssize_t) image->columns; x++)
414 if (GetPixelMask(image,p) != 0)
416 p+=GetPixelChannels(image);
419 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
427 channel=GetPixelChannelMapChannel(image,i);
428 traits=GetPixelChannelMapTraits(image,channel);
429 if ((traits == UndefinedPixelTrait) ||
430 (channel == IndexPixelChannel) || (channel == MaskPixelChannel))
432 if (depth_map[ScaleQuantumToMap(p[i])] > current_depth[id])
433 current_depth[id]=depth_map[ScaleQuantumToMap(p[i])];
435 p+=GetPixelChannels(image);
437 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
440 image_view=DestroyCacheView(image_view);
441 depth=current_depth[0];
442 for (id=1; id < (ssize_t) number_threads; id++)
443 if (depth < current_depth[id])
444 depth=current_depth[id];
445 depth_map=(size_t *) RelinquishMagickMemory(depth_map);
446 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
453 #if defined(MAGICKCORE_OPENMP_SUPPORT)
454 #pragma omp parallel for schedule(static,4) shared(status) \
455 dynamic_number_threads(image,image->columns,image->rows,1)
457 for (y=0; y < (ssize_t) image->rows; y++)
460 id = GetOpenMPThreadId();
462 register const Quantum
468 if (status == MagickFalse)
470 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
471 if (p == (const Quantum *) NULL)
473 for (x=0; x < (ssize_t) image->columns; x++)
478 if (GetPixelMask(image,p) != 0)
480 p+=GetPixelChannels(image);
483 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
491 channel=GetPixelChannelMapChannel(image,i);
492 traits=GetPixelChannelMapTraits(image,channel);
493 if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
494 (channel == MaskPixelChannel))
496 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
501 range=GetQuantumRange(current_depth[id]);
502 if (p[i] == ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),range))
507 p+=GetPixelChannels(image);
509 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
512 image_view=DestroyCacheView(image_view);
513 depth=current_depth[0];
514 for (id=1; id < (ssize_t) number_threads; id++)
515 if (depth < current_depth[id])
516 depth=current_depth[id];
517 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
522 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
526 % G e t I m a g e Q u a n t u m D e p t h %
530 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
532 % GetImageQuantumDepth() returns the depth of the image rounded to a legal
533 % quantum depth: 8, 16, or 32.
535 % The format of the GetImageQuantumDepth method is:
537 % size_t GetImageQuantumDepth(const Image *image,
538 % const MagickBooleanType constrain)
540 % A description of each parameter follows:
542 % o image: the image.
544 % o constrain: A value other than MagickFalse, constrains the depth to
545 % a maximum of MAGICKCORE_QUANTUM_DEPTH.
549 static inline double MagickMin(const double x,const double y)
556 MagickExport size_t GetImageQuantumDepth(const Image *image,
557 const MagickBooleanType constrain)
574 if (constrain != MagickFalse)
575 depth=(size_t) MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH);
580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
584 % G e t I m a g e T y p e %
588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
590 % GetImageType() returns the potential type of image:
592 % Bilevel Grayscale GrayscaleMatte
593 % Palette PaletteMatte TrueColor
594 % TrueColorMatte ColorSeparation ColorSeparationMatte
596 % To ensure the image type matches its potential, use SetImageType():
598 % (void) SetImageType(image,GetImageType(image));
600 % The format of the GetImageType method is:
602 % ImageType GetImageType(const Image *image,ExceptionInfo *exception)
604 % A description of each parameter follows:
606 % o image: the image.
608 % o exception: return any errors or warnings in this structure.
611 MagickExport ImageType GetImageType(const Image *image,ExceptionInfo *exception)
613 assert(image != (Image *) NULL);
614 assert(image->signature == MagickSignature);
615 if (image->debug != MagickFalse)
616 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
617 if (image->colorspace == CMYKColorspace)
619 if (image->matte == MagickFalse)
620 return(ColorSeparationType);
621 return(ColorSeparationMatteType);
623 if (IsImageMonochrome(image,exception) != MagickFalse)
625 if (IsImageGray(image,exception) != MagickFalse)
627 if (image->matte != MagickFalse)
628 return(GrayscaleMatteType);
629 return(GrayscaleType);
631 if (IsPaletteImage(image,exception) != MagickFalse)
633 if (image->matte != MagickFalse)
634 return(PaletteMatteType);
637 if (image->matte != MagickFalse)
638 return(TrueColorMatteType);
639 return(TrueColorType);
643 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
647 % I s I m a g e G r a y %
651 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
653 % IsImageGray() returns MagickTrue if all the pixels in the image have the
654 % same red, green, and blue intensities.
656 % The format of the IsImageGray method is:
658 % MagickBooleanType IsImageGray(const Image *image,
659 % ExceptionInfo *exception)
661 % A description of each parameter follows:
663 % o image: the image.
665 % o exception: return any errors or warnings in this structure.
668 MagickExport MagickBooleanType IsImageGray(const Image *image,
669 ExceptionInfo *exception)
677 register const Quantum
686 assert(image != (Image *) NULL);
687 assert(image->signature == MagickSignature);
688 if (image->debug != MagickFalse)
689 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
690 if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
691 (image->type == GrayscaleMatteType))
693 if ((IsGrayColorspace(image->colorspace) == MagickFalse) &&
694 (IssRGBColorspace(image->colorspace) == MagickFalse))
697 image_view=AcquireVirtualCacheView(image,exception);
698 for (y=0; y < (ssize_t) image->rows; y++)
700 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
701 if (p == (const Quantum *) NULL)
703 for (x=0; x < (ssize_t) image->columns; x++)
705 if (IsPixelGray(image,p) == MagickFalse)
710 if ((type == BilevelType) &&
711 (IsPixelMonochrome(image,p) == MagickFalse))
713 p+=GetPixelChannels(image);
715 if (type == UndefinedType)
718 image_view=DestroyCacheView(image_view);
719 if (type == UndefinedType)
721 ((Image *) image)->type=type;
722 if ((type == GrayscaleType) && (image->matte != MagickFalse))
723 ((Image *) image)->type=GrayscaleMatteType;
728 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
732 % I s I m a g e M o n o c h r o m e %
736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
738 % IsImageMonochrome() returns MagickTrue if all the pixels in the image have
739 % the same red, green, and blue intensities and the intensity is either
742 % The format of the IsImageMonochrome method is:
744 % MagickBooleanType IsImageMonochrome(const Image *image,
745 % ExceptionInfo *exception)
747 % A description of each parameter follows:
749 % o image: the image.
751 % o exception: return any errors or warnings in this structure.
754 MagickExport MagickBooleanType IsImageMonochrome(const Image *image,
755 ExceptionInfo *exception)
766 register const Quantum
772 assert(image != (Image *) NULL);
773 assert(image->signature == MagickSignature);
774 if (image->debug != MagickFalse)
775 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
776 if (image->type == BilevelType)
778 if ((IsGrayColorspace(image->colorspace) == MagickFalse) &&
779 (IssRGBColorspace(image->colorspace) == MagickFalse))
782 image_view=AcquireVirtualCacheView(image,exception);
783 for (y=0; y < (ssize_t) image->rows; y++)
785 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
786 if (p == (const Quantum *) NULL)
788 for (x=0; x < (ssize_t) image->columns; x++)
790 if (IsPixelMonochrome(image,p) == MagickFalse)
795 p+=GetPixelChannels(image);
797 if (type == UndefinedType)
800 image_view=DestroyCacheView(image_view);
801 if (type == UndefinedType)
803 ((Image *) image)->type=type;
808 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
812 % I s I m a g e O p a q u e %
816 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
818 % IsImageOpaque() returns MagickTrue if none of the pixels in the image have
819 % an alpha value other than OpaqueAlpha (QuantumRange).
821 % Will return true immediatally is alpha channel is not available.
823 % The format of the IsImageOpaque method is:
825 % MagickBooleanType IsImageOpaque(const Image *image,
826 % ExceptionInfo *exception)
828 % A description of each parameter follows:
830 % o image: the image.
832 % o exception: return any errors or warnings in this structure.
835 MagickExport MagickBooleanType IsImageOpaque(const Image *image,
836 ExceptionInfo *exception)
841 register const Quantum
851 Determine if image is opaque.
853 assert(image != (Image *) NULL);
854 assert(image->signature == MagickSignature);
855 if (image->debug != MagickFalse)
856 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
857 if (image->matte == MagickFalse)
859 image_view=AcquireVirtualCacheView(image,exception);
860 for (y=0; y < (ssize_t) image->rows; y++)
862 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
863 if (p == (const Quantum *) NULL)
865 for (x=0; x < (ssize_t) image->columns; x++)
867 if (GetPixelAlpha(image,p) != OpaqueAlpha)
869 p+=GetPixelChannels(image);
871 if (x < (ssize_t) image->columns)
874 image_view=DestroyCacheView(image_view);
875 return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
879 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
883 % S e t I m a g e D e p t h %
887 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
889 % SetImageDepth() sets the depth of the image.
891 % The format of the SetImageDepth method is:
893 % MagickBooleanType SetImageDepth(Image *image,const size_t depth,
894 % ExceptionInfo *exception)
896 % A description of each parameter follows:
898 % o image: the image.
900 % o channel: the channel.
902 % o depth: the image depth.
904 % o exception: return any errors or warnings in this structure.
907 MagickExport MagickBooleanType SetImageDepth(Image *image,
908 const size_t depth,ExceptionInfo *exception)
922 assert(image != (Image *) NULL);
923 if (image->debug != MagickFalse)
924 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
925 assert(image->signature == MagickSignature);
926 if (depth >= MAGICKCORE_QUANTUM_DEPTH)
928 image->depth=MAGICKCORE_QUANTUM_DEPTH;
931 range=GetQuantumRange(depth);
932 if (image->storage_class == PseudoClass)
937 #if defined(MAGICKCORE_OPENMP_SUPPORT)
938 #pragma omp parallel for schedule(static) shared(status) \
939 dynamic_number_threads(image,image->columns,1,1)
941 for (i=0; i < (ssize_t) image->colors; i++)
943 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
944 image->colormap[i].red=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
945 ClampToQuantum(image->colormap[i].red),range),range);
946 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
947 image->colormap[i].green=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
948 ClampToQuantum(image->colormap[i].green),range),range);
949 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
950 image->colormap[i].blue=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
951 ClampToQuantum(image->colormap[i].blue),range),range);
952 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
953 image->colormap[i].alpha=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
954 ClampToQuantum(image->colormap[i].alpha),range),range);
956 status=SyncImage(image,exception);
957 if (status != MagickFalse)
962 image_view=AcquireAuthenticCacheView(image,exception);
963 #if !defined(MAGICKCORE_HDRI_SUPPORT)
964 if (QuantumRange <= MaxMap)
973 Scale pixels to desired (optimized with depth map).
975 depth_map=(Quantum *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
976 if (depth_map == (Quantum *) NULL)
977 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
978 for (i=0; i <= (ssize_t) MaxMap; i++)
979 depth_map[i]=ScaleAnyToQuantum(ScaleQuantumToAny((Quantum) i,range),
981 #if defined(MAGICKCORE_OPENMP_SUPPORT)
982 #pragma omp parallel for schedule(static,4) shared(status) \
983 dynamic_number_threads(image,image->columns,image->rows,1)
985 for (y=0; y < (ssize_t) image->rows; y++)
993 if (status == MagickFalse)
995 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
997 if (q == (Quantum *) NULL)
1002 for (x=0; x < (ssize_t) image->columns; x++)
1007 if (GetPixelMask(image,q) != 0)
1009 q+=GetPixelChannels(image);
1012 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1020 channel=GetPixelChannelMapChannel(image,i);
1021 traits=GetPixelChannelMapTraits(image,channel);
1022 if ((traits == UndefinedPixelTrait) ||
1023 (channel == IndexPixelChannel) || (channel == MaskPixelChannel))
1025 q[i]=depth_map[ScaleQuantumToMap(q[i])];
1027 q+=GetPixelChannels(image);
1029 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1035 image_view=DestroyCacheView(image_view);
1036 depth_map=(Quantum *) RelinquishMagickMemory(depth_map);
1037 if (status != MagickFalse)
1043 Scale pixels to desired depth.
1045 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1046 #pragma omp parallel for schedule(static,4) shared(status) \
1047 dynamic_number_threads(image,image->columns,image->rows,1)
1049 for (y=0; y < (ssize_t) image->rows; y++)
1057 if (status == MagickFalse)
1059 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1060 if (q == (Quantum *) NULL)
1065 for (x=0; x < (ssize_t) image->columns; x++)
1070 if (GetPixelMask(image,q) != 0)
1072 q+=GetPixelChannels(image);
1075 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1083 channel=GetPixelChannelMapChannel(image,i);
1084 traits=GetPixelChannelMapTraits(image,channel);
1085 if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
1086 (channel == MaskPixelChannel))
1088 q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(q[i],range),range);
1090 q+=GetPixelChannels(image);
1092 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1098 image_view=DestroyCacheView(image_view);
1099 if (status != MagickFalse)