blob: 5bb0989e0c8305abca8cc90953e060e4d339d62c [file] [log] [blame]
cristyda06ed12009-10-14 18:36:54 +00001/*
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% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
cristyda06ed12009-10-14 18:36:54 +000021% 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
40/*
41 Include declarations.
42*/
cristy4c08aed2011-07-01 19:47:50 +000043#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"
cristycca1bfa2011-09-12 12:39:53 +000055#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000056#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"
cristyda06ed12009-10-14 18:36:54 +000092
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*/
121MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
122 ExceptionInfo *exception)
123{
cristyc4c8d132010-01-07 01:58:38 +0000124 CacheView
125 *image_view;
126
cristyda06ed12009-10-14 18:36:54 +0000127 MagickBooleanType
128 status;
129
cristy4c08aed2011-07-01 19:47:50 +0000130 PixelInfo
cristyda06ed12009-10-14 18:36:54 +0000131 target[3],
132 zero;
133
134 RectangleInfo
135 bounds;
136
cristy4c08aed2011-07-01 19:47:50 +0000137 register const Quantum
cristyda06ed12009-10-14 18:36:54 +0000138 *p;
139
cristy9d314ff2011-03-09 01:30:28 +0000140 ssize_t
141 y;
142
cristyda06ed12009-10-14 18:36:54 +0000143 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;
cristybb503372010-05-27 20:51:26 +0000149 bounds.x=(ssize_t) image->columns;
150 bounds.y=(ssize_t) image->rows;
cristy4c08aed2011-07-01 19:47:50 +0000151 GetPixelInfo(image,&target[0]);
cristyda06ed12009-10-14 18:36:54 +0000152 image_view=AcquireCacheView(image);
153 p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000154 if (p == (const Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000155 {
156 image_view=DestroyCacheView(image_view);
157 return(bounds);
158 }
cristy803640d2011-11-17 02:11:32 +0000159 GetPixelInfoPixel(image,p,&target[0]);
cristy4c08aed2011-07-01 19:47:50 +0000160 GetPixelInfo(image,&target[1]);
cristybb503372010-05-27 20:51:26 +0000161 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,0,1,1,
cristyda06ed12009-10-14 18:36:54 +0000162 exception);
cristy803640d2011-11-17 02:11:32 +0000163 GetPixelInfoPixel(image,p,&target[1]);
cristy4c08aed2011-07-01 19:47:50 +0000164 GetPixelInfo(image,&target[2]);
cristy4cb39ab2010-06-07 13:59:16 +0000165 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-1,1,1,
166 exception);
cristy803640d2011-11-17 02:11:32 +0000167 GetPixelInfoPixel(image,p,&target[2]);
cristyda06ed12009-10-14 18:36:54 +0000168 status=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +0000169 GetPixelInfo(image,&zero);
cristyb5d5f722009-11-04 03:03:49 +0000170#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristye6178502011-12-23 17:02:29 +0000171 #pragma omp parallel for schedule(static,4) shared(status)
cristyda06ed12009-10-14 18:36:54 +0000172#endif
cristybb503372010-05-27 20:51:26 +0000173 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000174 {
cristy4c08aed2011-07-01 19:47:50 +0000175 PixelInfo
cristyda06ed12009-10-14 18:36:54 +0000176 pixel;
177
178 RectangleInfo
179 bounding_box;
180
cristy4c08aed2011-07-01 19:47:50 +0000181 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000182 *restrict p;
cristyda06ed12009-10-14 18:36:54 +0000183
cristybb503372010-05-27 20:51:26 +0000184 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000185 x;
186
187 if (status == MagickFalse)
188 continue;
cristyb5d5f722009-11-04 03:03:49 +0000189#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyda06ed12009-10-14 18:36:54 +0000190# pragma omp critical (MagickCore_GetImageBoundingBox)
191#endif
192 bounding_box=bounds;
193 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000194 if (p == (const Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000195 {
196 status=MagickFalse;
197 continue;
198 }
cristyda06ed12009-10-14 18:36:54 +0000199 pixel=zero;
cristybb503372010-05-27 20:51:26 +0000200 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000201 {
cristy803640d2011-11-17 02:11:32 +0000202 GetPixelInfoPixel(image,p,&pixel);
cristyda06ed12009-10-14 18:36:54 +0000203 if ((x < bounding_box.x) &&
cristy4c08aed2011-07-01 19:47:50 +0000204 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
cristyda06ed12009-10-14 18:36:54 +0000205 bounding_box.x=x;
cristybb503372010-05-27 20:51:26 +0000206 if ((x > (ssize_t) bounding_box.width) &&
cristy4c08aed2011-07-01 19:47:50 +0000207 (IsFuzzyEquivalencePixelInfo(&pixel,&target[1]) == MagickFalse))
cristybb503372010-05-27 20:51:26 +0000208 bounding_box.width=(size_t) x;
cristyda06ed12009-10-14 18:36:54 +0000209 if ((y < bounding_box.y) &&
cristy4c08aed2011-07-01 19:47:50 +0000210 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
cristyda06ed12009-10-14 18:36:54 +0000211 bounding_box.y=y;
cristybb503372010-05-27 20:51:26 +0000212 if ((y > (ssize_t) bounding_box.height) &&
cristy4c08aed2011-07-01 19:47:50 +0000213 (IsFuzzyEquivalencePixelInfo(&pixel,&target[2]) == MagickFalse))
cristybb503372010-05-27 20:51:26 +0000214 bounding_box.height=(size_t) y;
cristyed231572011-07-14 02:18:59 +0000215 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000216 }
cristyb5d5f722009-11-04 03:03:49 +0000217#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyda06ed12009-10-14 18:36:54 +0000218# 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
243/*
244%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245% %
246% %
247% %
cristyfefab1b2011-07-05 00:33:22 +0000248% G e t I m a g e D e p t h %
cristyda06ed12009-10-14 18:36:54 +0000249% %
250% %
251% %
252%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
253%
cristyfefab1b2011-07-05 00:33:22 +0000254% GetImageDepth() returns the depth of a particular image channel.
cristyda06ed12009-10-14 18:36:54 +0000255%
cristyfefab1b2011-07-05 00:33:22 +0000256% The format of the GetImageDepth method is:
cristyda06ed12009-10-14 18:36:54 +0000257%
cristybb503372010-05-27 20:51:26 +0000258% size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
cristyda06ed12009-10-14 18:36:54 +0000259%
260% A description of each parameter follows:
261%
262% o image: the image.
263%
cristyda06ed12009-10-14 18:36:54 +0000264% o exception: return any errors or warnings in this structure.
265%
266*/
cristy0aa82c12012-01-08 18:22:09 +0000267MagickExport size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
cristyda06ed12009-10-14 18:36:54 +0000268{
cristyc4c8d132010-01-07 01:58:38 +0000269 CacheView
270 *image_view;
271
cristyda06ed12009-10-14 18:36:54 +0000272 MagickBooleanType
273 status;
274
cristybb503372010-05-27 20:51:26 +0000275 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000276 id;
277
cristybb503372010-05-27 20:51:26 +0000278 size_t
cristyda06ed12009-10-14 18:36:54 +0000279 *current_depth,
280 depth,
281 number_threads;
282
cristy9d314ff2011-03-09 01:30:28 +0000283 ssize_t
284 y;
285
cristyda06ed12009-10-14 18:36:54 +0000286 /*
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();
cristybb503372010-05-27 20:51:26 +0000294 current_depth=(size_t *) AcquireQuantumMemory(number_threads,
cristyda06ed12009-10-14 18:36:54 +0000295 sizeof(*current_depth));
cristybb503372010-05-27 20:51:26 +0000296 if (current_depth == (size_t *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000297 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
298 status=MagickTrue;
cristybb503372010-05-27 20:51:26 +0000299 for (id=0; id < (ssize_t) number_threads; id++)
cristyda06ed12009-10-14 18:36:54 +0000300 current_depth[id]=1;
301 if ((image->storage_class == PseudoClass) && (image->matte == MagickFalse))
302 {
cristybb503372010-05-27 20:51:26 +0000303 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000304 i;
305
cristyb5d5f722009-11-04 03:03:49 +0000306#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy13868012012-01-08 21:44:07 +0000307 #pragma omp parallel for schedule(static) shared(status)
cristyda06ed12009-10-14 18:36:54 +0000308#endif
cristybb503372010-05-27 20:51:26 +0000309 for (i=0; i < (ssize_t) image->colors; i++)
cristyda06ed12009-10-14 18:36:54 +0000310 {
cristy5c9e6f22010-09-17 17:31:01 +0000311 const int
312 id = GetOpenMPThreadId();
313
cristyda06ed12009-10-14 18:36:54 +0000314 if (status == MagickFalse)
315 continue;
cristyda06ed12009-10-14 18:36:54 +0000316 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
317 {
318 MagickStatusType
319 status;
320
321 QuantumAny
cristyb6d6f7c2010-06-09 13:17:57 +0000322 range;
cristyda06ed12009-10-14 18:36:54 +0000323
324 status=0;
cristyb6d6f7c2010-06-09 13:17:57 +0000325 range=GetQuantumRange(current_depth[id]);
cristyed231572011-07-14 02:18:59 +0000326 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000327 status|=ClampToQuantum(image->colormap[i].red) !=
328 ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
329 image->colormap[i].red),range),range);
cristyed231572011-07-14 02:18:59 +0000330 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000331 status|=ClampToQuantum(image->colormap[i].green) !=
332 ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
333 image->colormap[i].green),range),range);
cristyed231572011-07-14 02:18:59 +0000334 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000335 status|=ClampToQuantum(image->colormap[i].blue) !=
336 ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
337 image->colormap[i].blue),range),range);
cristyda06ed12009-10-14 18:36:54 +0000338 if (status == 0)
339 break;
340 current_depth[id]++;
341 }
cristyda06ed12009-10-14 18:36:54 +0000342 }
343 depth=current_depth[0];
cristybb503372010-05-27 20:51:26 +0000344 for (id=1; id < (ssize_t) number_threads; id++)
cristyda06ed12009-10-14 18:36:54 +0000345 if (depth < current_depth[id])
346 depth=current_depth[id];
cristybb503372010-05-27 20:51:26 +0000347 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
cristyda06ed12009-10-14 18:36:54 +0000348 return(depth);
349 }
cristy13868012012-01-08 21:44:07 +0000350 image_view=AcquireCacheView(image);
cristy52936202012-01-12 12:07:45 +0000351#if !defined(MAGICKCORE_HDRI_SUPPORT)
352 if (QuantumRange <= MaxMap)
cristy13868012012-01-08 21:44:07 +0000353 {
cristy13868012012-01-08 21:44:07 +0000354 register ssize_t
cristy52936202012-01-12 12:07:45 +0000355 i;
cristy13868012012-01-08 21:44:07 +0000356
cristy52936202012-01-12 12:07:45 +0000357 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++)
cristy13868012012-01-08 21:44:07 +0000367 {
cristy52936202012-01-12 12:07:45 +0000368 unsigned int
369 depth;
cristy13868012012-01-08 21:44:07 +0000370
cristy52936202012-01-12 12:07:45 +0000371 for (depth=1; depth < MAGICKCORE_QUANTUM_DEPTH; depth++)
cristy13868012012-01-08 21:44:07 +0000372 {
cristy52936202012-01-12 12:07:45 +0000373 Quantum
374 pixel;
cristy13868012012-01-08 21:44:07 +0000375
cristy52936202012-01-12 12:07:45 +0000376 QuantumAny
377 range;
cristy13868012012-01-08 21:44:07 +0000378
cristy52936202012-01-12 12:07:45 +0000379 range=GetQuantumRange(depth);
380 pixel=(Quantum) i;
381 if (pixel == ScaleAnyToQuantum(ScaleQuantumToAny(pixel,range),range))
382 break;
cristy13868012012-01-08 21:44:07 +0000383 }
cristy52936202012-01-12 12:07:45 +0000384 depth_map[i]=depth;
cristy13868012012-01-08 21:44:07 +0000385 }
cristy52936202012-01-12 12:07:45 +0000386#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
cristy10a6c612012-01-29 21:41:05 +0000410 if (GetPixelMask(image,p) != 0)
411 {
412 p+=GetPixelChannels(image);
413 continue;
414 }
cristy52936202012-01-12 12:07:45 +0000415 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) ||
cristy10a6c612012-01-29 21:41:05 +0000426 (channel == IndexPixelChannel) || (channel == MaskPixelChannel))
cristy52936202012-01-12 12:07:45 +0000427 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);
cristy13868012012-01-08 21:44:07 +0000444 }
cristy13868012012-01-08 21:44:07 +0000445#endif
cristy0aa82c12012-01-08 18:22:09 +0000446 /*
447 Compute pixel depth.
448 */
cristyb5d5f722009-11-04 03:03:49 +0000449#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristye6178502011-12-23 17:02:29 +0000450 #pragma omp parallel for schedule(static,4) shared(status)
cristyda06ed12009-10-14 18:36:54 +0000451#endif
cristybb503372010-05-27 20:51:26 +0000452 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000453 {
cristy5c9e6f22010-09-17 17:31:01 +0000454 const int
455 id = GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +0000456
cristy4c08aed2011-07-01 19:47:50 +0000457 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000458 *restrict p;
cristyda06ed12009-10-14 18:36:54 +0000459
cristybb503372010-05-27 20:51:26 +0000460 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000461 x;
462
463 if (status == MagickFalse)
464 continue;
cristyda06ed12009-10-14 18:36:54 +0000465 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000466 if (p == (const Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000467 continue;
cristybb503372010-05-27 20:51:26 +0000468 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000469 {
cristy8a11cb12011-10-19 23:53:34 +0000470 register ssize_t
471 i;
472
cristy10a6c612012-01-29 21:41:05 +0000473 if (GetPixelMask(image,p) != 0)
474 {
475 p+=GetPixelChannels(image);
476 continue;
477 }
cristy8a11cb12011-10-19 23:53:34 +0000478 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
cristyda06ed12009-10-14 18:36:54 +0000479 {
cristyabace412011-12-11 15:56:53 +0000480 PixelChannel
481 channel;
482
cristy8a11cb12011-10-19 23:53:34 +0000483 PixelTrait
484 traits;
cristyda06ed12009-10-14 18:36:54 +0000485
cristyabace412011-12-11 15:56:53 +0000486 channel=GetPixelChannelMapChannel(image,i);
487 traits=GetPixelChannelMapTraits(image,channel);
cristy10a6c612012-01-29 21:41:05 +0000488 if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
489 (channel == MaskPixelChannel))
cristy8a11cb12011-10-19 23:53:34 +0000490 continue;
491 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
492 {
cristy8a11cb12011-10-19 23:53:34 +0000493 QuantumAny
494 range;
495
cristy8a11cb12011-10-19 23:53:34 +0000496 range=GetQuantumRange(current_depth[id]);
cristy3b2b1712012-01-08 21:52:15 +0000497 if (p[i] == ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),range))
cristy8a11cb12011-10-19 23:53:34 +0000498 break;
499 current_depth[id]++;
500 }
cristyda06ed12009-10-14 18:36:54 +0000501 }
cristyed231572011-07-14 02:18:59 +0000502 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000503 }
504 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
505 status=MagickFalse;
506 }
507 image_view=DestroyCacheView(image_view);
508 depth=current_depth[0];
cristybb503372010-05-27 20:51:26 +0000509 for (id=1; id < (ssize_t) number_threads; id++)
cristyda06ed12009-10-14 18:36:54 +0000510 if (depth < current_depth[id])
511 depth=current_depth[id];
cristybb503372010-05-27 20:51:26 +0000512 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
cristyda06ed12009-10-14 18:36:54 +0000513 return(depth);
514}
515
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%
cristybb503372010-05-27 20:51:26 +0000532% size_t GetImageQuantumDepth(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000533% 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
544static inline double MagickMin(const double x,const double y)
545{
546 if (x < y)
547 return(x);
548 return(y);
549}
550
cristybb503372010-05-27 20:51:26 +0000551MagickExport size_t GetImageQuantumDepth(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000552 const MagickBooleanType constrain)
553{
cristybb503372010-05-27 20:51:26 +0000554 size_t
cristyda06ed12009-10-14 18:36:54 +0000555 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)
cristy9e940dd2011-12-13 01:22:25 +0000570 depth=(size_t) MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH);
cristyda06ed12009-10-14 18:36:54 +0000571 return(depth);
572}
573
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*/
606MagickExport 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 }
cristy4c08aed2011-07-01 19:47:50 +0000618 if (IsImageMonochrome(image,exception) != MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000619 return(BilevelType);
cristy4c08aed2011-07-01 19:47:50 +0000620 if (IsImageGray(image,exception) != MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000621 {
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
637/*
638%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
639% %
640% %
641% %
cristy4c08aed2011-07-01 19:47:50 +0000642% I s I m a g e G r a y %
cristyda06ed12009-10-14 18:36:54 +0000643% %
644% %
645% %
646%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
647%
cristy4c08aed2011-07-01 19:47:50 +0000648% IsImageGray() returns MagickTrue if all the pixels in the image have the
cristyda06ed12009-10-14 18:36:54 +0000649% same red, green, and blue intensities.
650%
cristy4c08aed2011-07-01 19:47:50 +0000651% The format of the IsImageGray method is:
cristyda06ed12009-10-14 18:36:54 +0000652%
cristy4c08aed2011-07-01 19:47:50 +0000653% MagickBooleanType IsImageGray(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000654% 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*/
cristy4c08aed2011-07-01 19:47:50 +0000663MagickExport MagickBooleanType IsImageGray(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000664 ExceptionInfo *exception)
665{
cristy0910f242010-04-01 18:55:09 +0000666 CacheView
667 *image_view;
668
cristyda06ed12009-10-14 18:36:54 +0000669 ImageType
670 type;
671
cristy4c08aed2011-07-01 19:47:50 +0000672 register const Quantum
cristyda06ed12009-10-14 18:36:54 +0000673 *p;
674
cristybb503372010-05-27 20:51:26 +0000675 register ssize_t
cristy0910f242010-04-01 18:55:09 +0000676 x;
677
cristy95802a72010-09-05 19:07:17 +0000678 ssize_t
679 y;
680
cristyda06ed12009-10-14 18:36:54 +0000681 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);
cristycca1bfa2011-09-12 12:39:53 +0000688 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000689 return(MagickFalse);
690 type=BilevelType;
cristy0910f242010-04-01 18:55:09 +0000691 image_view=AcquireCacheView(image);
cristybb503372010-05-27 20:51:26 +0000692 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000693 {
cristy0910f242010-04-01 18:55:09 +0000694 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000695 if (p == (const Quantum *) NULL)
cristy0910f242010-04-01 18:55:09 +0000696 break;
cristybb503372010-05-27 20:51:26 +0000697 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000698 {
cristy4c08aed2011-07-01 19:47:50 +0000699 if (IsPixelGray(image,p) == MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000700 {
cristy5f1c1ff2010-12-23 21:38:06 +0000701 type=UndefinedType;
cristyda06ed12009-10-14 18:36:54 +0000702 break;
cristy0910f242010-04-01 18:55:09 +0000703 }
cristybd5a96c2011-08-21 00:04:26 +0000704 if ((type == BilevelType) &&
705 (IsPixelMonochrome(image,p) == MagickFalse))
cristy0910f242010-04-01 18:55:09 +0000706 type=GrayscaleType;
cristyed231572011-07-14 02:18:59 +0000707 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000708 }
cristy5f1c1ff2010-12-23 21:38:06 +0000709 if (type == UndefinedType)
cristyda06ed12009-10-14 18:36:54 +0000710 break;
cristyda06ed12009-10-14 18:36:54 +0000711 }
cristy0910f242010-04-01 18:55:09 +0000712 image_view=DestroyCacheView(image_view);
cristy5f1c1ff2010-12-23 21:38:06 +0000713 if (type == UndefinedType)
cristyda06ed12009-10-14 18:36:54 +0000714 return(MagickFalse);
715 ((Image *) image)->type=type;
716 if ((type == GrayscaleType) && (image->matte != MagickFalse))
717 ((Image *) image)->type=GrayscaleMatteType;
718 return(MagickTrue);
719}
720
721/*
722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
723% %
724% %
725% %
cristy4c08aed2011-07-01 19:47:50 +0000726% I s I m a g e M o n o c h r o m e %
cristyda06ed12009-10-14 18:36:54 +0000727% %
728% %
729% %
730%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
731%
cristy4c08aed2011-07-01 19:47:50 +0000732% IsImageMonochrome() returns MagickTrue if all the pixels in the image have
cristyda06ed12009-10-14 18:36:54 +0000733% the same red, green, and blue intensities and the intensity is either
734% 0 or QuantumRange.
735%
cristy4c08aed2011-07-01 19:47:50 +0000736% The format of the IsImageMonochrome method is:
cristyda06ed12009-10-14 18:36:54 +0000737%
cristy4c08aed2011-07-01 19:47:50 +0000738% MagickBooleanType IsImageMonochrome(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000739% 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*/
cristy4c08aed2011-07-01 19:47:50 +0000748MagickExport MagickBooleanType IsImageMonochrome(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000749 ExceptionInfo *exception)
750{
cristy0910f242010-04-01 18:55:09 +0000751 CacheView
752 *image_view;
753
cristyda06ed12009-10-14 18:36:54 +0000754 ImageType
755 type;
756
cristybb503372010-05-27 20:51:26 +0000757 register ssize_t
cristy0910f242010-04-01 18:55:09 +0000758 x;
759
cristy4c08aed2011-07-01 19:47:50 +0000760 register const Quantum
cristyda06ed12009-10-14 18:36:54 +0000761 *p;
762
cristy9d314ff2011-03-09 01:30:28 +0000763 ssize_t
764 y;
765
cristyda06ed12009-10-14 18:36:54 +0000766 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);
cristycca1bfa2011-09-12 12:39:53 +0000772 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000773 return(MagickFalse);
774 type=BilevelType;
cristy0910f242010-04-01 18:55:09 +0000775 image_view=AcquireCacheView(image);
cristybb503372010-05-27 20:51:26 +0000776 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000777 {
cristy0910f242010-04-01 18:55:09 +0000778 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000779 if (p == (const Quantum *) NULL)
cristy0910f242010-04-01 18:55:09 +0000780 break;
cristybb503372010-05-27 20:51:26 +0000781 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000782 {
cristy4c08aed2011-07-01 19:47:50 +0000783 if (IsPixelMonochrome(image,p) == MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000784 {
cristy5f1c1ff2010-12-23 21:38:06 +0000785 type=UndefinedType;
cristyda06ed12009-10-14 18:36:54 +0000786 break;
cristy0910f242010-04-01 18:55:09 +0000787 }
cristyed231572011-07-14 02:18:59 +0000788 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000789 }
cristy5f1c1ff2010-12-23 21:38:06 +0000790 if (type == UndefinedType)
cristyda06ed12009-10-14 18:36:54 +0000791 break;
cristyda06ed12009-10-14 18:36:54 +0000792 }
cristy0910f242010-04-01 18:55:09 +0000793 image_view=DestroyCacheView(image_view);
cristy5f1c1ff2010-12-23 21:38:06 +0000794 if (type == UndefinedType)
cristyda06ed12009-10-14 18:36:54 +0000795 return(MagickFalse);
796 ((Image *) image)->type=type;
797 return(MagickTrue);
798}
799
800/*
801%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
802% %
803% %
804% %
cristy4c08aed2011-07-01 19:47:50 +0000805% I s I m a g e O p a q u e %
cristyda06ed12009-10-14 18:36:54 +0000806% %
807% %
808% %
809%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
810%
cristy4c08aed2011-07-01 19:47:50 +0000811% IsImageOpaque() returns MagickTrue if none of the pixels in the image have
cristyda06ed12009-10-14 18:36:54 +0000812% an opacity value other than opaque (0).
813%
cristy4c08aed2011-07-01 19:47:50 +0000814% The format of the IsImageOpaque method is:
cristyda06ed12009-10-14 18:36:54 +0000815%
cristy4c08aed2011-07-01 19:47:50 +0000816% MagickBooleanType IsImageOpaque(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000817% 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*/
cristy4c08aed2011-07-01 19:47:50 +0000826MagickExport MagickBooleanType IsImageOpaque(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000827 ExceptionInfo *exception)
828{
cristyc4c8d132010-01-07 01:58:38 +0000829 CacheView
830 *image_view;
831
cristy4c08aed2011-07-01 19:47:50 +0000832 register const Quantum
cristyda06ed12009-10-14 18:36:54 +0000833 *p;
834
cristybb503372010-05-27 20:51:26 +0000835 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000836 x;
837
cristy9d314ff2011-03-09 01:30:28 +0000838 ssize_t
839 y;
840
cristyda06ed12009-10-14 18:36:54 +0000841 /*
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=AcquireCacheView(image);
cristybb503372010-05-27 20:51:26 +0000851 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000852 {
853 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000854 if (p == (const Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000855 break;
cristybb503372010-05-27 20:51:26 +0000856 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000857 {
cristy4c08aed2011-07-01 19:47:50 +0000858 if (GetPixelAlpha(image,p) != OpaqueAlpha)
cristyda06ed12009-10-14 18:36:54 +0000859 break;
cristyed231572011-07-14 02:18:59 +0000860 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000861 }
cristybb503372010-05-27 20:51:26 +0000862 if (x < (ssize_t) image->columns)
cristyda06ed12009-10-14 18:36:54 +0000863 break;
864 }
865 image_view=DestroyCacheView(image_view);
cristybb503372010-05-27 20:51:26 +0000866 return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
cristyda06ed12009-10-14 18:36:54 +0000867}
868
869/*
870%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
871% %
872% %
873% %
cristyfefab1b2011-07-05 00:33:22 +0000874% S e t I m a g e D e p t h %
cristyda06ed12009-10-14 18:36:54 +0000875% %
876% %
877% %
878%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
879%
cristyfefab1b2011-07-05 00:33:22 +0000880% SetImageDepth() sets the depth of the image.
cristyda06ed12009-10-14 18:36:54 +0000881%
cristyfefab1b2011-07-05 00:33:22 +0000882% The format of the SetImageDepth method is:
cristyda06ed12009-10-14 18:36:54 +0000883%
cristy8a11cb12011-10-19 23:53:34 +0000884% MagickBooleanType SetImageDepth(Image *image,const size_t depth,
885% ExceptionInfo *exception)
cristyda06ed12009-10-14 18:36:54 +0000886%
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%
cristy8a11cb12011-10-19 23:53:34 +0000895% o exception: return any errors or warnings in this structure.
896%
cristyda06ed12009-10-14 18:36:54 +0000897*/
cristyda06ed12009-10-14 18:36:54 +0000898MagickExport MagickBooleanType SetImageDepth(Image *image,
cristy8a11cb12011-10-19 23:53:34 +0000899 const size_t depth,ExceptionInfo *exception)
cristyda06ed12009-10-14 18:36:54 +0000900{
cristyc4c8d132010-01-07 01:58:38 +0000901 CacheView
902 *image_view;
903
cristyda06ed12009-10-14 18:36:54 +0000904 MagickBooleanType
905 status;
906
907 QuantumAny
cristyb6d6f7c2010-06-09 13:17:57 +0000908 range;
cristyda06ed12009-10-14 18:36:54 +0000909
cristy9d314ff2011-03-09 01:30:28 +0000910 ssize_t
911 y;
912
cristyda06ed12009-10-14 18:36:54 +0000913 assert(image != (Image *) NULL);
914 if (image->debug != MagickFalse)
915 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
916 assert(image->signature == MagickSignature);
cristy0aa82c12012-01-08 18:22:09 +0000917 if (depth >= MAGICKCORE_QUANTUM_DEPTH)
cristyda06ed12009-10-14 18:36:54 +0000918 {
cristy0aa82c12012-01-08 18:22:09 +0000919 image->depth=MAGICKCORE_QUANTUM_DEPTH;
cristyda06ed12009-10-14 18:36:54 +0000920 return(MagickTrue);
921 }
cristy5d6f7ed2012-01-08 02:53:08 +0000922 range=GetQuantumRange(depth);
923 if (image->storage_class == PseudoClass)
924 {
cristy5d6f7ed2012-01-08 02:53:08 +0000925 register ssize_t
926 i;
927
cristy5d6f7ed2012-01-08 02:53:08 +0000928#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy0aa82c12012-01-08 18:22:09 +0000929 #pragma omp parallel for schedule(static) shared(status)
cristy5d6f7ed2012-01-08 02:53:08 +0000930#endif
931 for (i=0; i < (ssize_t) image->colors; i++)
932 {
933 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000934 image->colormap[i].red=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
935 ClampToQuantum(image->colormap[i].red),range),range);
cristy5d6f7ed2012-01-08 02:53:08 +0000936 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000937 image->colormap[i].green=(double) ScaleAnyToQuantum(ScaleQuantumToAny( ClampToQuantum(image->colormap[i].green),range),range);
cristy5d6f7ed2012-01-08 02:53:08 +0000938 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000939 image->colormap[i].blue=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
940 ClampToQuantum(image->colormap[i].blue),range),range);
cristy5d6f7ed2012-01-08 02:53:08 +0000941 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000942 image->colormap[i].alpha=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
943 ClampToQuantum(image->colormap[i].alpha),range),range);
cristy5d6f7ed2012-01-08 02:53:08 +0000944 }
945 status=SyncImage(image,exception);
946 if (status != MagickFalse)
947 image->depth=depth;
948 return(status);
949 }
cristy0aa82c12012-01-08 18:22:09 +0000950 status=MagickTrue;
951 image_view=AcquireCacheView(image);
cristy52936202012-01-12 12:07:45 +0000952#if !defined(MAGICKCORE_HDRI_SUPPORT)
953 if (QuantumRange <= MaxMap)
cristy0aa82c12012-01-08 18:22:09 +0000954 {
cristy52936202012-01-12 12:07:45 +0000955 Quantum
956 *depth_map;
957
cristy0aa82c12012-01-08 18:22:09 +0000958 register ssize_t
cristy52936202012-01-12 12:07:45 +0000959 i;
cristy0aa82c12012-01-08 18:22:09 +0000960
cristy52936202012-01-12 12:07:45 +0000961 /*
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++)
cristy0aa82c12012-01-08 18:22:09 +0000974 {
cristy52936202012-01-12 12:07:45 +0000975 register ssize_t
976 x;
cristy0aa82c12012-01-08 18:22:09 +0000977
cristy52936202012-01-12 12:07:45 +0000978 register Quantum
979 *restrict q;
cristy0aa82c12012-01-08 18:22:09 +0000980
cristy52936202012-01-12 12:07:45 +0000981 if (status == MagickFalse)
cristy0aa82c12012-01-08 18:22:09 +0000982 continue;
cristy52936202012-01-12 12:07:45 +0000983 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 {
cristyaa874e12012-01-20 21:00:51 +0000992 register ssize_t
993 i;
994
cristy10a6c612012-01-29 21:41:05 +0000995 if (GetPixelMask(image,q) != 0)
996 {
997 q+=GetPixelChannels(image);
998 continue;
999 }
cristy52936202012-01-12 12:07:45 +00001000 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) ||
cristy10a6c612012-01-29 21:41:05 +00001011 (channel == IndexPixelChannel) || (channel == MaskPixelChannel))
cristy52936202012-01-12 12:07:45 +00001012 continue;
1013 q[i]=depth_map[ScaleQuantumToMap(q[i])];
1014 }
1015 q+=GetPixelChannels(image);
cristy0aa82c12012-01-08 18:22:09 +00001016 }
cristy52936202012-01-12 12:07:45 +00001017 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);
cristy0aa82c12012-01-08 18:22:09 +00001028 }
cristy0aa82c12012-01-08 18:22:09 +00001029#endif
cristyda06ed12009-10-14 18:36:54 +00001030 /*
1031 Scale pixels to desired depth.
1032 */
cristyb5d5f722009-11-04 03:03:49 +00001033#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristye6178502011-12-23 17:02:29 +00001034 #pragma omp parallel for schedule(static,4) shared(status)
cristyda06ed12009-10-14 18:36:54 +00001035#endif
cristybb503372010-05-27 20:51:26 +00001036 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +00001037 {
cristybb503372010-05-27 20:51:26 +00001038 register ssize_t
cristyda06ed12009-10-14 18:36:54 +00001039 x;
1040
cristy4c08aed2011-07-01 19:47:50 +00001041 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001042 *restrict q;
cristyda06ed12009-10-14 18:36:54 +00001043
1044 if (status == MagickFalse)
1045 continue;
cristy8a11cb12011-10-19 23:53:34 +00001046 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00001047 if (q == (Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +00001048 {
1049 status=MagickFalse;
1050 continue;
1051 }
cristybb503372010-05-27 20:51:26 +00001052 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +00001053 {
cristy8a11cb12011-10-19 23:53:34 +00001054 register ssize_t
1055 i;
1056
cristy10a6c612012-01-29 21:41:05 +00001057 if (GetPixelMask(image,q) != 0)
1058 {
1059 q+=GetPixelChannels(image);
1060 continue;
1061 }
cristy8a11cb12011-10-19 23:53:34 +00001062 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1063 {
cristyabace412011-12-11 15:56:53 +00001064 PixelChannel
1065 channel;
1066
cristy8a11cb12011-10-19 23:53:34 +00001067 PixelTrait
1068 traits;
1069
cristyabace412011-12-11 15:56:53 +00001070 channel=GetPixelChannelMapChannel(image,i);
1071 traits=GetPixelChannelMapTraits(image,channel);
cristy10a6c612012-01-29 21:41:05 +00001072 if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
1073 (channel == MaskPixelChannel))
cristy8a11cb12011-10-19 23:53:34 +00001074 continue;
cristy0aa82c12012-01-08 18:22:09 +00001075 q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(q[i],range),range);
cristy8a11cb12011-10-19 23:53:34 +00001076 }
cristyed231572011-07-14 02:18:59 +00001077 q+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +00001078 }
1079 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1080 {
1081 status=MagickFalse;
1082 continue;
1083 }
1084 }
1085 image_view=DestroyCacheView(image_view);
cristy5d6f7ed2012-01-08 02:53:08 +00001086 if (status != MagickFalse)
1087 image->depth=depth;
cristyda06ed12009-10-14 18:36:54 +00001088 return(status);
1089}