blob: 8c81776aa59479d1e74c558e131e76365b07c213 [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]);
cristydb070952012-04-20 14:33:00 +0000152 image_view=AcquireVirtualCacheView(image,exception);
cristyda06ed12009-10-14 18:36:54 +0000153 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)
cristyac245f82012-05-05 17:13:57 +0000171 #pragma omp parallel for schedule(static,4) shared(status) \
cristy16881e62012-05-06 14:41:29 +0000172 IsConcurrentDos(image->columns,image->rows,64)
cristyda06ed12009-10-14 18:36:54 +0000173#endif
cristybb503372010-05-27 20:51:26 +0000174 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000175 {
cristy4c08aed2011-07-01 19:47:50 +0000176 PixelInfo
cristyda06ed12009-10-14 18:36:54 +0000177 pixel;
178
179 RectangleInfo
180 bounding_box;
181
cristy4c08aed2011-07-01 19:47:50 +0000182 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000183 *restrict p;
cristyda06ed12009-10-14 18:36:54 +0000184
cristybb503372010-05-27 20:51:26 +0000185 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000186 x;
187
188 if (status == MagickFalse)
189 continue;
cristyb5d5f722009-11-04 03:03:49 +0000190#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyda06ed12009-10-14 18:36:54 +0000191# pragma omp critical (MagickCore_GetImageBoundingBox)
192#endif
193 bounding_box=bounds;
194 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000195 if (p == (const Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000196 {
197 status=MagickFalse;
198 continue;
199 }
cristyda06ed12009-10-14 18:36:54 +0000200 pixel=zero;
cristybb503372010-05-27 20:51:26 +0000201 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000202 {
cristy803640d2011-11-17 02:11:32 +0000203 GetPixelInfoPixel(image,p,&pixel);
cristyda06ed12009-10-14 18:36:54 +0000204 if ((x < bounding_box.x) &&
cristy4c08aed2011-07-01 19:47:50 +0000205 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
cristyda06ed12009-10-14 18:36:54 +0000206 bounding_box.x=x;
cristybb503372010-05-27 20:51:26 +0000207 if ((x > (ssize_t) bounding_box.width) &&
cristy4c08aed2011-07-01 19:47:50 +0000208 (IsFuzzyEquivalencePixelInfo(&pixel,&target[1]) == MagickFalse))
cristybb503372010-05-27 20:51:26 +0000209 bounding_box.width=(size_t) x;
cristyda06ed12009-10-14 18:36:54 +0000210 if ((y < bounding_box.y) &&
cristy4c08aed2011-07-01 19:47:50 +0000211 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
cristyda06ed12009-10-14 18:36:54 +0000212 bounding_box.y=y;
cristybb503372010-05-27 20:51:26 +0000213 if ((y > (ssize_t) bounding_box.height) &&
cristy4c08aed2011-07-01 19:47:50 +0000214 (IsFuzzyEquivalencePixelInfo(&pixel,&target[2]) == MagickFalse))
cristybb503372010-05-27 20:51:26 +0000215 bounding_box.height=(size_t) y;
cristyed231572011-07-14 02:18:59 +0000216 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000217 }
cristyb5d5f722009-11-04 03:03:49 +0000218#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyda06ed12009-10-14 18:36:54 +0000219# pragma omp critical (MagickCore_GetImageBoundingBox)
220#endif
221 {
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;
230 }
231 }
232 image_view=DestroyCacheView(image_view);
233 if ((bounds.width == 0) || (bounds.height == 0))
234 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
anthonye5b39652012-04-21 05:37:29 +0000235 "GeometryDoesNotContainImage","'%s'",image->filename);
cristyda06ed12009-10-14 18:36:54 +0000236 else
237 {
238 bounds.width-=(bounds.x-1);
239 bounds.height-=(bounds.y-1);
240 }
241 return(bounds);
242}
243
244/*
245%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
246% %
247% %
248% %
cristyfefab1b2011-07-05 00:33:22 +0000249% G e t I m a g e D e p t h %
cristyda06ed12009-10-14 18:36:54 +0000250% %
251% %
252% %
253%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
254%
cristyfefab1b2011-07-05 00:33:22 +0000255% GetImageDepth() returns the depth of a particular image channel.
cristyda06ed12009-10-14 18:36:54 +0000256%
cristyfefab1b2011-07-05 00:33:22 +0000257% The format of the GetImageDepth method is:
cristyda06ed12009-10-14 18:36:54 +0000258%
cristybb503372010-05-27 20:51:26 +0000259% size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
cristyda06ed12009-10-14 18:36:54 +0000260%
261% A description of each parameter follows:
262%
263% o image: the image.
264%
cristyda06ed12009-10-14 18:36:54 +0000265% o exception: return any errors or warnings in this structure.
266%
267*/
cristy0aa82c12012-01-08 18:22:09 +0000268MagickExport size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
cristyda06ed12009-10-14 18:36:54 +0000269{
cristyc4c8d132010-01-07 01:58:38 +0000270 CacheView
271 *image_view;
272
cristyda06ed12009-10-14 18:36:54 +0000273 MagickBooleanType
274 status;
275
cristybb503372010-05-27 20:51:26 +0000276 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000277 id;
278
cristybb503372010-05-27 20:51:26 +0000279 size_t
cristyda06ed12009-10-14 18:36:54 +0000280 *current_depth,
281 depth,
282 number_threads;
283
cristy9d314ff2011-03-09 01:30:28 +0000284 ssize_t
285 y;
286
cristyda06ed12009-10-14 18:36:54 +0000287 /*
288 Compute image depth.
289 */
290 assert(image != (Image *) NULL);
291 assert(image->signature == MagickSignature);
292 if (image->debug != MagickFalse)
293 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristyac245f82012-05-05 17:13:57 +0000294 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
cristybb503372010-05-27 20:51:26 +0000295 current_depth=(size_t *) AcquireQuantumMemory(number_threads,
cristyda06ed12009-10-14 18:36:54 +0000296 sizeof(*current_depth));
cristybb503372010-05-27 20:51:26 +0000297 if (current_depth == (size_t *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000298 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
299 status=MagickTrue;
cristybb503372010-05-27 20:51:26 +0000300 for (id=0; id < (ssize_t) number_threads; id++)
cristyda06ed12009-10-14 18:36:54 +0000301 current_depth[id]=1;
302 if ((image->storage_class == PseudoClass) && (image->matte == MagickFalse))
303 {
cristybb503372010-05-27 20:51:26 +0000304 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000305 i;
306
cristyb5d5f722009-11-04 03:03:49 +0000307#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000308 #pragma omp parallel for schedule(static) shared(status) \
309 if ((image->colors) > 256) \
310 num_threads(GetMagickResourceLimit(ThreadResource))
cristyda06ed12009-10-14 18:36:54 +0000311#endif
cristybb503372010-05-27 20:51:26 +0000312 for (i=0; i < (ssize_t) image->colors; i++)
cristyda06ed12009-10-14 18:36:54 +0000313 {
cristy5c9e6f22010-09-17 17:31:01 +0000314 const int
315 id = GetOpenMPThreadId();
316
cristyda06ed12009-10-14 18:36:54 +0000317 if (status == MagickFalse)
318 continue;
cristyda06ed12009-10-14 18:36:54 +0000319 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
320 {
321 MagickStatusType
322 status;
323
324 QuantumAny
cristyb6d6f7c2010-06-09 13:17:57 +0000325 range;
cristyda06ed12009-10-14 18:36:54 +0000326
327 status=0;
cristyb6d6f7c2010-06-09 13:17:57 +0000328 range=GetQuantumRange(current_depth[id]);
cristyed231572011-07-14 02:18:59 +0000329 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000330 status|=ClampToQuantum(image->colormap[i].red) !=
331 ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
332 image->colormap[i].red),range),range);
cristyed231572011-07-14 02:18:59 +0000333 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000334 status|=ClampToQuantum(image->colormap[i].green) !=
335 ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
336 image->colormap[i].green),range),range);
cristyed231572011-07-14 02:18:59 +0000337 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000338 status|=ClampToQuantum(image->colormap[i].blue) !=
339 ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
340 image->colormap[i].blue),range),range);
cristyda06ed12009-10-14 18:36:54 +0000341 if (status == 0)
342 break;
343 current_depth[id]++;
344 }
cristyda06ed12009-10-14 18:36:54 +0000345 }
346 depth=current_depth[0];
cristybb503372010-05-27 20:51:26 +0000347 for (id=1; id < (ssize_t) number_threads; id++)
cristyda06ed12009-10-14 18:36:54 +0000348 if (depth < current_depth[id])
349 depth=current_depth[id];
cristybb503372010-05-27 20:51:26 +0000350 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
cristyda06ed12009-10-14 18:36:54 +0000351 return(depth);
352 }
cristydb070952012-04-20 14:33:00 +0000353 image_view=AcquireVirtualCacheView(image,exception);
cristy52936202012-01-12 12:07:45 +0000354#if !defined(MAGICKCORE_HDRI_SUPPORT)
355 if (QuantumRange <= MaxMap)
cristy13868012012-01-08 21:44:07 +0000356 {
cristy13868012012-01-08 21:44:07 +0000357 register ssize_t
cristy52936202012-01-12 12:07:45 +0000358 i;
cristy13868012012-01-08 21:44:07 +0000359
cristy52936202012-01-12 12:07:45 +0000360 size_t
361 *depth_map;
362
363 /*
364 Scale pixels to desired (optimized with depth map).
365 */
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++)
cristy13868012012-01-08 21:44:07 +0000370 {
cristy52936202012-01-12 12:07:45 +0000371 unsigned int
372 depth;
cristy13868012012-01-08 21:44:07 +0000373
cristy52936202012-01-12 12:07:45 +0000374 for (depth=1; depth < MAGICKCORE_QUANTUM_DEPTH; depth++)
cristy13868012012-01-08 21:44:07 +0000375 {
cristy52936202012-01-12 12:07:45 +0000376 Quantum
377 pixel;
cristy13868012012-01-08 21:44:07 +0000378
cristy52936202012-01-12 12:07:45 +0000379 QuantumAny
380 range;
cristy13868012012-01-08 21:44:07 +0000381
cristy52936202012-01-12 12:07:45 +0000382 range=GetQuantumRange(depth);
383 pixel=(Quantum) i;
384 if (pixel == ScaleAnyToQuantum(ScaleQuantumToAny(pixel,range),range))
385 break;
cristy13868012012-01-08 21:44:07 +0000386 }
cristy52936202012-01-12 12:07:45 +0000387 depth_map[i]=depth;
cristy13868012012-01-08 21:44:07 +0000388 }
cristy52936202012-01-12 12:07:45 +0000389#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000390 #pragma omp parallel for schedule(static,4) shared(status) \
cristy16881e62012-05-06 14:41:29 +0000391 IsConcurrentDos(image->columns,image->rows,64)
cristy52936202012-01-12 12:07:45 +0000392#endif
393 for (y=0; y < (ssize_t) image->rows; y++)
394 {
395 const int
396 id = GetOpenMPThreadId();
397
398 register const Quantum
399 *restrict p;
400
401 register ssize_t
402 x;
403
404 if (status == MagickFalse)
405 continue;
406 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
407 if (p == (const Quantum *) NULL)
408 continue;
409 for (x=0; x < (ssize_t) image->columns; x++)
410 {
411 register ssize_t
412 i;
413
cristy10a6c612012-01-29 21:41:05 +0000414 if (GetPixelMask(image,p) != 0)
415 {
416 p+=GetPixelChannels(image);
417 continue;
418 }
cristy52936202012-01-12 12:07:45 +0000419 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
420 {
421 PixelChannel
422 channel;
423
424 PixelTrait
425 traits;
426
427 channel=GetPixelChannelMapChannel(image,i);
428 traits=GetPixelChannelMapTraits(image,channel);
429 if ((traits == UndefinedPixelTrait) ||
cristy10a6c612012-01-29 21:41:05 +0000430 (channel == IndexPixelChannel) || (channel == MaskPixelChannel))
cristy52936202012-01-12 12:07:45 +0000431 continue;
432 if (depth_map[ScaleQuantumToMap(p[i])] > current_depth[id])
433 current_depth[id]=depth_map[ScaleQuantumToMap(p[i])];
434 }
435 p+=GetPixelChannels(image);
436 }
437 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
438 status=MagickFalse;
439 }
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);
447 return(depth);
cristy13868012012-01-08 21:44:07 +0000448 }
cristy13868012012-01-08 21:44:07 +0000449#endif
cristy0aa82c12012-01-08 18:22:09 +0000450 /*
451 Compute pixel depth.
452 */
cristyb5d5f722009-11-04 03:03:49 +0000453#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000454 #pragma omp parallel for schedule(static,4) shared(status) \
cristy16881e62012-05-06 14:41:29 +0000455 IsConcurrentDos(image->columns,image->rows,64)
cristyda06ed12009-10-14 18:36:54 +0000456#endif
cristybb503372010-05-27 20:51:26 +0000457 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000458 {
cristy5c9e6f22010-09-17 17:31:01 +0000459 const int
460 id = GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +0000461
cristy4c08aed2011-07-01 19:47:50 +0000462 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000463 *restrict p;
cristyda06ed12009-10-14 18:36:54 +0000464
cristybb503372010-05-27 20:51:26 +0000465 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000466 x;
467
468 if (status == MagickFalse)
469 continue;
cristyda06ed12009-10-14 18:36:54 +0000470 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000471 if (p == (const Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000472 continue;
cristybb503372010-05-27 20:51:26 +0000473 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000474 {
cristy8a11cb12011-10-19 23:53:34 +0000475 register ssize_t
476 i;
477
cristy10a6c612012-01-29 21:41:05 +0000478 if (GetPixelMask(image,p) != 0)
479 {
480 p+=GetPixelChannels(image);
481 continue;
482 }
cristy8a11cb12011-10-19 23:53:34 +0000483 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
cristyda06ed12009-10-14 18:36:54 +0000484 {
cristyabace412011-12-11 15:56:53 +0000485 PixelChannel
486 channel;
487
cristy8a11cb12011-10-19 23:53:34 +0000488 PixelTrait
489 traits;
cristyda06ed12009-10-14 18:36:54 +0000490
cristyabace412011-12-11 15:56:53 +0000491 channel=GetPixelChannelMapChannel(image,i);
492 traits=GetPixelChannelMapTraits(image,channel);
cristy10a6c612012-01-29 21:41:05 +0000493 if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
494 (channel == MaskPixelChannel))
cristy8a11cb12011-10-19 23:53:34 +0000495 continue;
496 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
497 {
cristy8a11cb12011-10-19 23:53:34 +0000498 QuantumAny
499 range;
500
cristy8a11cb12011-10-19 23:53:34 +0000501 range=GetQuantumRange(current_depth[id]);
cristy3b2b1712012-01-08 21:52:15 +0000502 if (p[i] == ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),range))
cristy8a11cb12011-10-19 23:53:34 +0000503 break;
504 current_depth[id]++;
505 }
cristyda06ed12009-10-14 18:36:54 +0000506 }
cristyed231572011-07-14 02:18:59 +0000507 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000508 }
509 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
510 status=MagickFalse;
511 }
512 image_view=DestroyCacheView(image_view);
513 depth=current_depth[0];
cristybb503372010-05-27 20:51:26 +0000514 for (id=1; id < (ssize_t) number_threads; id++)
cristyda06ed12009-10-14 18:36:54 +0000515 if (depth < current_depth[id])
516 depth=current_depth[id];
cristybb503372010-05-27 20:51:26 +0000517 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
cristyda06ed12009-10-14 18:36:54 +0000518 return(depth);
519}
520
521/*
522%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
523% %
524% %
525% %
526% G e t I m a g e Q u a n t u m D e p t h %
527% %
528% %
529% %
530%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
531%
532% GetImageQuantumDepth() returns the depth of the image rounded to a legal
533% quantum depth: 8, 16, or 32.
534%
535% The format of the GetImageQuantumDepth method is:
536%
cristybb503372010-05-27 20:51:26 +0000537% size_t GetImageQuantumDepth(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000538% const MagickBooleanType constrain)
539%
540% A description of each parameter follows:
541%
542% o image: the image.
543%
544% o constrain: A value other than MagickFalse, constrains the depth to
545% a maximum of MAGICKCORE_QUANTUM_DEPTH.
546%
547*/
548
549static inline double MagickMin(const double x,const double y)
550{
551 if (x < y)
552 return(x);
553 return(y);
554}
555
cristybb503372010-05-27 20:51:26 +0000556MagickExport size_t GetImageQuantumDepth(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000557 const MagickBooleanType constrain)
558{
cristybb503372010-05-27 20:51:26 +0000559 size_t
cristyda06ed12009-10-14 18:36:54 +0000560 depth;
561
562 depth=image->depth;
563 if (depth <= 8)
564 depth=8;
565 else
566 if (depth <= 16)
567 depth=16;
568 else
569 if (depth <= 32)
570 depth=32;
571 else
572 if (depth <= 64)
573 depth=64;
574 if (constrain != MagickFalse)
cristy9e940dd2011-12-13 01:22:25 +0000575 depth=(size_t) MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH);
cristyda06ed12009-10-14 18:36:54 +0000576 return(depth);
577}
578
579/*
580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
581% %
582% %
583% %
584% G e t I m a g e T y p e %
585% %
586% %
587% %
588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
589%
590% GetImageType() returns the potential type of image:
591%
592% Bilevel Grayscale GrayscaleMatte
593% Palette PaletteMatte TrueColor
594% TrueColorMatte ColorSeparation ColorSeparationMatte
595%
596% To ensure the image type matches its potential, use SetImageType():
597%
598% (void) SetImageType(image,GetImageType(image));
599%
600% The format of the GetImageType method is:
601%
602% ImageType GetImageType(const Image *image,ExceptionInfo *exception)
603%
604% A description of each parameter follows:
605%
606% o image: the image.
607%
608% o exception: return any errors or warnings in this structure.
609%
610*/
611MagickExport ImageType GetImageType(const Image *image,ExceptionInfo *exception)
612{
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)
618 {
619 if (image->matte == MagickFalse)
620 return(ColorSeparationType);
621 return(ColorSeparationMatteType);
622 }
cristy4c08aed2011-07-01 19:47:50 +0000623 if (IsImageMonochrome(image,exception) != MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000624 return(BilevelType);
cristy4c08aed2011-07-01 19:47:50 +0000625 if (IsImageGray(image,exception) != MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000626 {
627 if (image->matte != MagickFalse)
628 return(GrayscaleMatteType);
629 return(GrayscaleType);
630 }
631 if (IsPaletteImage(image,exception) != MagickFalse)
632 {
633 if (image->matte != MagickFalse)
634 return(PaletteMatteType);
635 return(PaletteType);
636 }
637 if (image->matte != MagickFalse)
638 return(TrueColorMatteType);
639 return(TrueColorType);
640}
641
642/*
643%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
644% %
645% %
646% %
cristy4c08aed2011-07-01 19:47:50 +0000647% I s I m a g e G r a y %
cristyda06ed12009-10-14 18:36:54 +0000648% %
649% %
650% %
651%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
652%
cristy4c08aed2011-07-01 19:47:50 +0000653% IsImageGray() returns MagickTrue if all the pixels in the image have the
cristyda06ed12009-10-14 18:36:54 +0000654% same red, green, and blue intensities.
655%
cristy4c08aed2011-07-01 19:47:50 +0000656% The format of the IsImageGray method is:
cristyda06ed12009-10-14 18:36:54 +0000657%
cristy4c08aed2011-07-01 19:47:50 +0000658% MagickBooleanType IsImageGray(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000659% ExceptionInfo *exception)
660%
661% A description of each parameter follows:
662%
663% o image: the image.
664%
665% o exception: return any errors or warnings in this structure.
666%
667*/
cristy4c08aed2011-07-01 19:47:50 +0000668MagickExport MagickBooleanType IsImageGray(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000669 ExceptionInfo *exception)
670{
cristy0910f242010-04-01 18:55:09 +0000671 CacheView
672 *image_view;
673
cristyda06ed12009-10-14 18:36:54 +0000674 ImageType
675 type;
676
cristy4c08aed2011-07-01 19:47:50 +0000677 register const Quantum
cristyda06ed12009-10-14 18:36:54 +0000678 *p;
679
cristybb503372010-05-27 20:51:26 +0000680 register ssize_t
cristy0910f242010-04-01 18:55:09 +0000681 x;
682
cristy95802a72010-09-05 19:07:17 +0000683 ssize_t
684 y;
685
cristyda06ed12009-10-14 18:36:54 +0000686 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))
692 return(MagickTrue);
cristy501c5592012-04-18 12:45:09 +0000693 if (IssRGBColorspace(image->colorspace) == MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000694 return(MagickFalse);
695 type=BilevelType;
cristydb070952012-04-20 14:33:00 +0000696 image_view=AcquireVirtualCacheView(image,exception);
cristybb503372010-05-27 20:51:26 +0000697 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000698 {
cristy0910f242010-04-01 18:55:09 +0000699 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000700 if (p == (const Quantum *) NULL)
cristy0910f242010-04-01 18:55:09 +0000701 break;
cristybb503372010-05-27 20:51:26 +0000702 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000703 {
cristy4c08aed2011-07-01 19:47:50 +0000704 if (IsPixelGray(image,p) == MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000705 {
cristy5f1c1ff2010-12-23 21:38:06 +0000706 type=UndefinedType;
cristyda06ed12009-10-14 18:36:54 +0000707 break;
cristy0910f242010-04-01 18:55:09 +0000708 }
cristybd5a96c2011-08-21 00:04:26 +0000709 if ((type == BilevelType) &&
710 (IsPixelMonochrome(image,p) == MagickFalse))
cristy0910f242010-04-01 18:55:09 +0000711 type=GrayscaleType;
cristyed231572011-07-14 02:18:59 +0000712 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000713 }
cristy5f1c1ff2010-12-23 21:38:06 +0000714 if (type == UndefinedType)
cristyda06ed12009-10-14 18:36:54 +0000715 break;
cristyda06ed12009-10-14 18:36:54 +0000716 }
cristy0910f242010-04-01 18:55:09 +0000717 image_view=DestroyCacheView(image_view);
cristy5f1c1ff2010-12-23 21:38:06 +0000718 if (type == UndefinedType)
cristyda06ed12009-10-14 18:36:54 +0000719 return(MagickFalse);
720 ((Image *) image)->type=type;
721 if ((type == GrayscaleType) && (image->matte != MagickFalse))
722 ((Image *) image)->type=GrayscaleMatteType;
723 return(MagickTrue);
724}
725
726/*
727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
728% %
729% %
730% %
cristy4c08aed2011-07-01 19:47:50 +0000731% I s I m a g e M o n o c h r o m e %
cristyda06ed12009-10-14 18:36:54 +0000732% %
733% %
734% %
735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
736%
cristy4c08aed2011-07-01 19:47:50 +0000737% IsImageMonochrome() returns MagickTrue if all the pixels in the image have
cristyda06ed12009-10-14 18:36:54 +0000738% the same red, green, and blue intensities and the intensity is either
739% 0 or QuantumRange.
740%
cristy4c08aed2011-07-01 19:47:50 +0000741% The format of the IsImageMonochrome method is:
cristyda06ed12009-10-14 18:36:54 +0000742%
cristy4c08aed2011-07-01 19:47:50 +0000743% MagickBooleanType IsImageMonochrome(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000744% ExceptionInfo *exception)
745%
746% A description of each parameter follows:
747%
748% o image: the image.
749%
750% o exception: return any errors or warnings in this structure.
751%
752*/
cristy4c08aed2011-07-01 19:47:50 +0000753MagickExport MagickBooleanType IsImageMonochrome(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000754 ExceptionInfo *exception)
755{
cristy0910f242010-04-01 18:55:09 +0000756 CacheView
757 *image_view;
758
cristyda06ed12009-10-14 18:36:54 +0000759 ImageType
760 type;
761
cristybb503372010-05-27 20:51:26 +0000762 register ssize_t
cristy0910f242010-04-01 18:55:09 +0000763 x;
764
cristy4c08aed2011-07-01 19:47:50 +0000765 register const Quantum
cristyda06ed12009-10-14 18:36:54 +0000766 *p;
767
cristy9d314ff2011-03-09 01:30:28 +0000768 ssize_t
769 y;
770
cristyda06ed12009-10-14 18:36:54 +0000771 assert(image != (Image *) NULL);
772 assert(image->signature == MagickSignature);
773 if (image->debug != MagickFalse)
774 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
775 if (image->type == BilevelType)
776 return(MagickTrue);
cristy501c5592012-04-18 12:45:09 +0000777 if (IssRGBColorspace(image->colorspace) == MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000778 return(MagickFalse);
779 type=BilevelType;
cristydb070952012-04-20 14:33:00 +0000780 image_view=AcquireVirtualCacheView(image,exception);
cristybb503372010-05-27 20:51:26 +0000781 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000782 {
cristy0910f242010-04-01 18:55:09 +0000783 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000784 if (p == (const Quantum *) NULL)
cristy0910f242010-04-01 18:55:09 +0000785 break;
cristybb503372010-05-27 20:51:26 +0000786 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000787 {
cristy4c08aed2011-07-01 19:47:50 +0000788 if (IsPixelMonochrome(image,p) == MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000789 {
cristy5f1c1ff2010-12-23 21:38:06 +0000790 type=UndefinedType;
cristyda06ed12009-10-14 18:36:54 +0000791 break;
cristy0910f242010-04-01 18:55:09 +0000792 }
cristyed231572011-07-14 02:18:59 +0000793 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000794 }
cristy5f1c1ff2010-12-23 21:38:06 +0000795 if (type == UndefinedType)
cristyda06ed12009-10-14 18:36:54 +0000796 break;
cristyda06ed12009-10-14 18:36:54 +0000797 }
cristy0910f242010-04-01 18:55:09 +0000798 image_view=DestroyCacheView(image_view);
cristy5f1c1ff2010-12-23 21:38:06 +0000799 if (type == UndefinedType)
cristyda06ed12009-10-14 18:36:54 +0000800 return(MagickFalse);
801 ((Image *) image)->type=type;
802 return(MagickTrue);
803}
804
805/*
806%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
807% %
808% %
809% %
cristy4c08aed2011-07-01 19:47:50 +0000810% I s I m a g e O p a q u e %
cristyda06ed12009-10-14 18:36:54 +0000811% %
812% %
813% %
814%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
815%
cristy4c08aed2011-07-01 19:47:50 +0000816% IsImageOpaque() returns MagickTrue if none of the pixels in the image have
anthonyfb2cc882012-04-29 11:46:27 +0000817% an alpha value other than OpaqueAlpha (QuantumRange).
818%
819% Will return true immediatally is alpha channel is not available.
cristyda06ed12009-10-14 18:36:54 +0000820%
cristy4c08aed2011-07-01 19:47:50 +0000821% The format of the IsImageOpaque method is:
cristyda06ed12009-10-14 18:36:54 +0000822%
cristy4c08aed2011-07-01 19:47:50 +0000823% MagickBooleanType IsImageOpaque(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000824% ExceptionInfo *exception)
825%
826% A description of each parameter follows:
827%
828% o image: the image.
829%
830% o exception: return any errors or warnings in this structure.
831%
832*/
cristy4c08aed2011-07-01 19:47:50 +0000833MagickExport MagickBooleanType IsImageOpaque(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000834 ExceptionInfo *exception)
835{
cristyc4c8d132010-01-07 01:58:38 +0000836 CacheView
837 *image_view;
838
cristy4c08aed2011-07-01 19:47:50 +0000839 register const Quantum
cristyda06ed12009-10-14 18:36:54 +0000840 *p;
841
cristybb503372010-05-27 20:51:26 +0000842 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000843 x;
844
cristy9d314ff2011-03-09 01:30:28 +0000845 ssize_t
846 y;
847
cristyda06ed12009-10-14 18:36:54 +0000848 /*
849 Determine if image is opaque.
850 */
851 assert(image != (Image *) NULL);
852 assert(image->signature == MagickSignature);
853 if (image->debug != MagickFalse)
854 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
anthonyfb2cc882012-04-29 11:46:27 +0000855
cristyda06ed12009-10-14 18:36:54 +0000856 if (image->matte == MagickFalse)
857 return(MagickTrue);
anthonyfb2cc882012-04-29 11:46:27 +0000858
cristydb070952012-04-20 14:33:00 +0000859 image_view=AcquireVirtualCacheView(image,exception);
cristybb503372010-05-27 20:51:26 +0000860 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000861 {
862 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000863 if (p == (const Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000864 break;
cristybb503372010-05-27 20:51:26 +0000865 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000866 {
cristy4c08aed2011-07-01 19:47:50 +0000867 if (GetPixelAlpha(image,p) != OpaqueAlpha)
cristyda06ed12009-10-14 18:36:54 +0000868 break;
cristyed231572011-07-14 02:18:59 +0000869 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000870 }
cristybb503372010-05-27 20:51:26 +0000871 if (x < (ssize_t) image->columns)
cristyda06ed12009-10-14 18:36:54 +0000872 break;
873 }
874 image_view=DestroyCacheView(image_view);
cristybb503372010-05-27 20:51:26 +0000875 return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
cristyda06ed12009-10-14 18:36:54 +0000876}
877
878/*
879%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
880% %
881% %
882% %
cristyfefab1b2011-07-05 00:33:22 +0000883% S e t I m a g e D e p t h %
cristyda06ed12009-10-14 18:36:54 +0000884% %
885% %
886% %
887%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
888%
cristyfefab1b2011-07-05 00:33:22 +0000889% SetImageDepth() sets the depth of the image.
cristyda06ed12009-10-14 18:36:54 +0000890%
cristyfefab1b2011-07-05 00:33:22 +0000891% The format of the SetImageDepth method is:
cristyda06ed12009-10-14 18:36:54 +0000892%
cristy8a11cb12011-10-19 23:53:34 +0000893% MagickBooleanType SetImageDepth(Image *image,const size_t depth,
894% ExceptionInfo *exception)
cristyda06ed12009-10-14 18:36:54 +0000895%
896% A description of each parameter follows:
897%
898% o image: the image.
899%
900% o channel: the channel.
901%
902% o depth: the image depth.
903%
cristy8a11cb12011-10-19 23:53:34 +0000904% o exception: return any errors or warnings in this structure.
905%
cristyda06ed12009-10-14 18:36:54 +0000906*/
cristyda06ed12009-10-14 18:36:54 +0000907MagickExport MagickBooleanType SetImageDepth(Image *image,
cristy8a11cb12011-10-19 23:53:34 +0000908 const size_t depth,ExceptionInfo *exception)
cristyda06ed12009-10-14 18:36:54 +0000909{
cristyc4c8d132010-01-07 01:58:38 +0000910 CacheView
911 *image_view;
912
cristyda06ed12009-10-14 18:36:54 +0000913 MagickBooleanType
914 status;
915
916 QuantumAny
cristyb6d6f7c2010-06-09 13:17:57 +0000917 range;
cristyda06ed12009-10-14 18:36:54 +0000918
cristy9d314ff2011-03-09 01:30:28 +0000919 ssize_t
920 y;
921
cristyda06ed12009-10-14 18:36:54 +0000922 assert(image != (Image *) NULL);
923 if (image->debug != MagickFalse)
924 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
925 assert(image->signature == MagickSignature);
cristy0aa82c12012-01-08 18:22:09 +0000926 if (depth >= MAGICKCORE_QUANTUM_DEPTH)
cristyda06ed12009-10-14 18:36:54 +0000927 {
cristy0aa82c12012-01-08 18:22:09 +0000928 image->depth=MAGICKCORE_QUANTUM_DEPTH;
cristyda06ed12009-10-14 18:36:54 +0000929 return(MagickTrue);
930 }
cristy5d6f7ed2012-01-08 02:53:08 +0000931 range=GetQuantumRange(depth);
932 if (image->storage_class == PseudoClass)
933 {
cristy5d6f7ed2012-01-08 02:53:08 +0000934 register ssize_t
935 i;
936
cristy5d6f7ed2012-01-08 02:53:08 +0000937#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000938 #pragma omp parallel for schedule(static) shared(status) \
cristy16881e62012-05-06 14:41:29 +0000939 IsConcurrentUno(image->colors,256)
cristy5d6f7ed2012-01-08 02:53:08 +0000940#endif
941 for (i=0; i < (ssize_t) image->colors; i++)
942 {
943 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000944 image->colormap[i].red=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
945 ClampToQuantum(image->colormap[i].red),range),range);
cristy5d6f7ed2012-01-08 02:53:08 +0000946 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
cristy16881e62012-05-06 14:41:29 +0000947 image->colormap[i].green=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
948 ClampToQuantum(image->colormap[i].green),range),range);
cristy5d6f7ed2012-01-08 02:53:08 +0000949 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000950 image->colormap[i].blue=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
951 ClampToQuantum(image->colormap[i].blue),range),range);
cristy5d6f7ed2012-01-08 02:53:08 +0000952 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000953 image->colormap[i].alpha=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
954 ClampToQuantum(image->colormap[i].alpha),range),range);
cristy5d6f7ed2012-01-08 02:53:08 +0000955 }
956 status=SyncImage(image,exception);
957 if (status != MagickFalse)
958 image->depth=depth;
959 return(status);
960 }
cristy0aa82c12012-01-08 18:22:09 +0000961 status=MagickTrue;
cristydb070952012-04-20 14:33:00 +0000962 image_view=AcquireAuthenticCacheView(image,exception);
cristy52936202012-01-12 12:07:45 +0000963#if !defined(MAGICKCORE_HDRI_SUPPORT)
964 if (QuantumRange <= MaxMap)
cristy0aa82c12012-01-08 18:22:09 +0000965 {
cristy52936202012-01-12 12:07:45 +0000966 Quantum
967 *depth_map;
968
cristy0aa82c12012-01-08 18:22:09 +0000969 register ssize_t
cristy52936202012-01-12 12:07:45 +0000970 i;
cristy0aa82c12012-01-08 18:22:09 +0000971
cristy52936202012-01-12 12:07:45 +0000972 /*
973 Scale pixels to desired (optimized with depth map).
974 */
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),
980 range);
981#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000982 #pragma omp parallel for schedule(static,4) shared(status) \
cristy16881e62012-05-06 14:41:29 +0000983 IsConcurrentDos(image->columns,image->rows,64)
cristy52936202012-01-12 12:07:45 +0000984#endif
985 for (y=0; y < (ssize_t) image->rows; y++)
cristy0aa82c12012-01-08 18:22:09 +0000986 {
cristy52936202012-01-12 12:07:45 +0000987 register ssize_t
988 x;
cristy0aa82c12012-01-08 18:22:09 +0000989
cristy52936202012-01-12 12:07:45 +0000990 register Quantum
991 *restrict q;
cristy0aa82c12012-01-08 18:22:09 +0000992
cristy52936202012-01-12 12:07:45 +0000993 if (status == MagickFalse)
cristy0aa82c12012-01-08 18:22:09 +0000994 continue;
cristy52936202012-01-12 12:07:45 +0000995 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
996 exception);
997 if (q == (Quantum *) NULL)
998 {
999 status=MagickFalse;
1000 continue;
1001 }
1002 for (x=0; x < (ssize_t) image->columns; x++)
1003 {
cristyaa874e12012-01-20 21:00:51 +00001004 register ssize_t
1005 i;
1006
cristy10a6c612012-01-29 21:41:05 +00001007 if (GetPixelMask(image,q) != 0)
1008 {
1009 q+=GetPixelChannels(image);
1010 continue;
1011 }
cristy52936202012-01-12 12:07:45 +00001012 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1013 {
1014 PixelChannel
1015 channel;
1016
1017 PixelTrait
1018 traits;
1019
1020 channel=GetPixelChannelMapChannel(image,i);
1021 traits=GetPixelChannelMapTraits(image,channel);
1022 if ((traits == UndefinedPixelTrait) ||
cristy10a6c612012-01-29 21:41:05 +00001023 (channel == IndexPixelChannel) || (channel == MaskPixelChannel))
cristy52936202012-01-12 12:07:45 +00001024 continue;
1025 q[i]=depth_map[ScaleQuantumToMap(q[i])];
1026 }
1027 q+=GetPixelChannels(image);
cristy0aa82c12012-01-08 18:22:09 +00001028 }
cristy52936202012-01-12 12:07:45 +00001029 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1030 {
1031 status=MagickFalse;
1032 continue;
1033 }
1034 }
1035 image_view=DestroyCacheView(image_view);
1036 depth_map=(Quantum *) RelinquishMagickMemory(depth_map);
1037 if (status != MagickFalse)
1038 image->depth=depth;
1039 return(status);
cristy0aa82c12012-01-08 18:22:09 +00001040 }
cristy0aa82c12012-01-08 18:22:09 +00001041#endif
cristyda06ed12009-10-14 18:36:54 +00001042 /*
1043 Scale pixels to desired depth.
1044 */
cristyb5d5f722009-11-04 03:03:49 +00001045#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00001046 #pragma omp parallel for schedule(static,4) shared(status) \
cristy16881e62012-05-06 14:41:29 +00001047 IsConcurrentDos(image->columns,image->rows,64)
cristyda06ed12009-10-14 18:36:54 +00001048#endif
cristybb503372010-05-27 20:51:26 +00001049 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +00001050 {
cristybb503372010-05-27 20:51:26 +00001051 register ssize_t
cristyda06ed12009-10-14 18:36:54 +00001052 x;
1053
cristy4c08aed2011-07-01 19:47:50 +00001054 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001055 *restrict q;
cristyda06ed12009-10-14 18:36:54 +00001056
1057 if (status == MagickFalse)
1058 continue;
cristy8a11cb12011-10-19 23:53:34 +00001059 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00001060 if (q == (Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +00001061 {
1062 status=MagickFalse;
1063 continue;
1064 }
cristybb503372010-05-27 20:51:26 +00001065 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +00001066 {
cristy8a11cb12011-10-19 23:53:34 +00001067 register ssize_t
1068 i;
1069
cristy10a6c612012-01-29 21:41:05 +00001070 if (GetPixelMask(image,q) != 0)
1071 {
1072 q+=GetPixelChannels(image);
1073 continue;
1074 }
cristy8a11cb12011-10-19 23:53:34 +00001075 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1076 {
cristyabace412011-12-11 15:56:53 +00001077 PixelChannel
1078 channel;
1079
cristy8a11cb12011-10-19 23:53:34 +00001080 PixelTrait
1081 traits;
1082
cristyabace412011-12-11 15:56:53 +00001083 channel=GetPixelChannelMapChannel(image,i);
1084 traits=GetPixelChannelMapTraits(image,channel);
cristy10a6c612012-01-29 21:41:05 +00001085 if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
1086 (channel == MaskPixelChannel))
cristy8a11cb12011-10-19 23:53:34 +00001087 continue;
cristy0aa82c12012-01-08 18:22:09 +00001088 q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(q[i],range),range);
cristy8a11cb12011-10-19 23:53:34 +00001089 }
cristyed231572011-07-14 02:18:59 +00001090 q+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +00001091 }
1092 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1093 {
1094 status=MagickFalse;
1095 continue;
1096 }
1097 }
1098 image_view=DestroyCacheView(image_view);
cristy5d6f7ed2012-01-08 02:53:08 +00001099 if (status != MagickFalse)
1100 image->depth=depth;
cristyda06ed12009-10-14 18:36:54 +00001101 return(status);
1102}