blob: d6b36bd9129a0f577f1ec847825b807eae457536 [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"
cristy623aaec2012-06-21 00:49:08 +000044#include "MagickCore/artifact.h"
cristy4c08aed2011-07-01 19:47:50 +000045#include "MagickCore/attribute.h"
46#include "MagickCore/blob.h"
47#include "MagickCore/blob-private.h"
48#include "MagickCore/cache.h"
49#include "MagickCore/cache-view.h"
50#include "MagickCore/client.h"
51#include "MagickCore/color.h"
52#include "MagickCore/color-private.h"
53#include "MagickCore/colormap.h"
54#include "MagickCore/colormap-private.h"
55#include "MagickCore/colorspace.h"
cristycca1bfa2011-09-12 12:39:53 +000056#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000057#include "MagickCore/composite.h"
58#include "MagickCore/composite-private.h"
59#include "MagickCore/constitute.h"
60#include "MagickCore/draw.h"
61#include "MagickCore/draw-private.h"
62#include "MagickCore/effect.h"
63#include "MagickCore/enhance.h"
64#include "MagickCore/exception.h"
65#include "MagickCore/exception-private.h"
66#include "MagickCore/geometry.h"
67#include "MagickCore/histogram.h"
68#include "MagickCore/identify.h"
69#include "MagickCore/image.h"
70#include "MagickCore/image-private.h"
71#include "MagickCore/list.h"
72#include "MagickCore/log.h"
73#include "MagickCore/memory_.h"
74#include "MagickCore/magick.h"
75#include "MagickCore/monitor.h"
76#include "MagickCore/monitor-private.h"
cristy623aaec2012-06-21 00:49:08 +000077#include "MagickCore/option.h"
cristy4c08aed2011-07-01 19:47:50 +000078#include "MagickCore/paint.h"
79#include "MagickCore/pixel.h"
80#include "MagickCore/pixel-accessor.h"
81#include "MagickCore/property.h"
82#include "MagickCore/quantize.h"
83#include "MagickCore/quantum-private.h"
84#include "MagickCore/random_.h"
85#include "MagickCore/resource_.h"
86#include "MagickCore/semaphore.h"
87#include "MagickCore/segment.h"
88#include "MagickCore/splay-tree.h"
89#include "MagickCore/string_.h"
90#include "MagickCore/thread-private.h"
91#include "MagickCore/threshold.h"
92#include "MagickCore/transform.h"
93#include "MagickCore/utility.h"
cristyda06ed12009-10-14 18:36:54 +000094
95/*
96%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97% %
98% %
99% %
100+ G e t I m a g e B o u n d i n g B o x %
101% %
102% %
103% %
104%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105%
106% GetImageBoundingBox() returns the bounding box of an image canvas.
107%
108% The format of the GetImageBoundingBox method is:
109%
110% RectangleInfo GetImageBoundingBox(const Image *image,
111% ExceptionInfo *exception)
112%
113% A description of each parameter follows:
114%
115% o bounds: Method GetImageBoundingBox returns the bounding box of an
116% image canvas.
117%
118% o image: the image.
119%
120% o exception: return any errors or warnings in this structure.
121%
122*/
123MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
124 ExceptionInfo *exception)
125{
cristyc4c8d132010-01-07 01:58:38 +0000126 CacheView
127 *image_view;
128
cristyda06ed12009-10-14 18:36:54 +0000129 MagickBooleanType
130 status;
131
cristy4c08aed2011-07-01 19:47:50 +0000132 PixelInfo
cristyda06ed12009-10-14 18:36:54 +0000133 target[3],
134 zero;
135
136 RectangleInfo
137 bounds;
138
cristy4c08aed2011-07-01 19:47:50 +0000139 register const Quantum
cristyda06ed12009-10-14 18:36:54 +0000140 *p;
141
cristy9d314ff2011-03-09 01:30:28 +0000142 ssize_t
143 y;
144
cristyda06ed12009-10-14 18:36:54 +0000145 assert(image != (Image *) NULL);
146 assert(image->signature == MagickSignature);
147 if (image->debug != MagickFalse)
148 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
149 bounds.width=0;
150 bounds.height=0;
cristybb503372010-05-27 20:51:26 +0000151 bounds.x=(ssize_t) image->columns;
152 bounds.y=(ssize_t) image->rows;
cristy4c08aed2011-07-01 19:47:50 +0000153 GetPixelInfo(image,&target[0]);
cristydb070952012-04-20 14:33:00 +0000154 image_view=AcquireVirtualCacheView(image,exception);
cristyda06ed12009-10-14 18:36:54 +0000155 p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000156 if (p == (const Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000157 {
158 image_view=DestroyCacheView(image_view);
159 return(bounds);
160 }
cristy803640d2011-11-17 02:11:32 +0000161 GetPixelInfoPixel(image,p,&target[0]);
cristy4c08aed2011-07-01 19:47:50 +0000162 GetPixelInfo(image,&target[1]);
cristybb503372010-05-27 20:51:26 +0000163 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,0,1,1,
cristyda06ed12009-10-14 18:36:54 +0000164 exception);
cristy803640d2011-11-17 02:11:32 +0000165 GetPixelInfoPixel(image,p,&target[1]);
cristy4c08aed2011-07-01 19:47:50 +0000166 GetPixelInfo(image,&target[2]);
cristy4cb39ab2010-06-07 13:59:16 +0000167 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-1,1,1,
168 exception);
cristy803640d2011-11-17 02:11:32 +0000169 GetPixelInfoPixel(image,p,&target[2]);
cristyda06ed12009-10-14 18:36:54 +0000170 status=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +0000171 GetPixelInfo(image,&zero);
cristyb5d5f722009-11-04 03:03:49 +0000172#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000173 #pragma omp parallel for schedule(static,4) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +0000174 dynamic_number_threads(image,image->columns,image->rows,1)
cristyda06ed12009-10-14 18:36:54 +0000175#endif
cristybb503372010-05-27 20:51:26 +0000176 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000177 {
cristy4c08aed2011-07-01 19:47:50 +0000178 PixelInfo
cristyda06ed12009-10-14 18:36:54 +0000179 pixel;
180
181 RectangleInfo
182 bounding_box;
183
cristy4c08aed2011-07-01 19:47:50 +0000184 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000185 *restrict p;
cristyda06ed12009-10-14 18:36:54 +0000186
cristybb503372010-05-27 20:51:26 +0000187 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000188 x;
189
190 if (status == MagickFalse)
191 continue;
cristyb5d5f722009-11-04 03:03:49 +0000192#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyda06ed12009-10-14 18:36:54 +0000193# pragma omp critical (MagickCore_GetImageBoundingBox)
194#endif
195 bounding_box=bounds;
196 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000197 if (p == (const Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000198 {
199 status=MagickFalse;
200 continue;
201 }
cristyda06ed12009-10-14 18:36:54 +0000202 pixel=zero;
cristybb503372010-05-27 20:51:26 +0000203 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000204 {
cristy803640d2011-11-17 02:11:32 +0000205 GetPixelInfoPixel(image,p,&pixel);
cristyda06ed12009-10-14 18:36:54 +0000206 if ((x < bounding_box.x) &&
cristy4c08aed2011-07-01 19:47:50 +0000207 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
cristyda06ed12009-10-14 18:36:54 +0000208 bounding_box.x=x;
cristybb503372010-05-27 20:51:26 +0000209 if ((x > (ssize_t) bounding_box.width) &&
cristy4c08aed2011-07-01 19:47:50 +0000210 (IsFuzzyEquivalencePixelInfo(&pixel,&target[1]) == MagickFalse))
cristybb503372010-05-27 20:51:26 +0000211 bounding_box.width=(size_t) x;
cristyda06ed12009-10-14 18:36:54 +0000212 if ((y < bounding_box.y) &&
cristy4c08aed2011-07-01 19:47:50 +0000213 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
cristyda06ed12009-10-14 18:36:54 +0000214 bounding_box.y=y;
cristybb503372010-05-27 20:51:26 +0000215 if ((y > (ssize_t) bounding_box.height) &&
cristy4c08aed2011-07-01 19:47:50 +0000216 (IsFuzzyEquivalencePixelInfo(&pixel,&target[2]) == MagickFalse))
cristybb503372010-05-27 20:51:26 +0000217 bounding_box.height=(size_t) y;
cristyed231572011-07-14 02:18:59 +0000218 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000219 }
cristyb5d5f722009-11-04 03:03:49 +0000220#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyda06ed12009-10-14 18:36:54 +0000221# pragma omp critical (MagickCore_GetImageBoundingBox)
222#endif
223 {
224 if (bounding_box.x < bounds.x)
225 bounds.x=bounding_box.x;
226 if (bounding_box.y < bounds.y)
227 bounds.y=bounding_box.y;
228 if (bounding_box.width > bounds.width)
229 bounds.width=bounding_box.width;
230 if (bounding_box.height > bounds.height)
231 bounds.height=bounding_box.height;
232 }
233 }
234 image_view=DestroyCacheView(image_view);
235 if ((bounds.width == 0) || (bounds.height == 0))
236 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
anthonye5b39652012-04-21 05:37:29 +0000237 "GeometryDoesNotContainImage","'%s'",image->filename);
cristyda06ed12009-10-14 18:36:54 +0000238 else
239 {
240 bounds.width-=(bounds.x-1);
241 bounds.height-=(bounds.y-1);
242 }
243 return(bounds);
244}
245
246/*
247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248% %
249% %
250% %
cristyfefab1b2011-07-05 00:33:22 +0000251% G e t I m a g e D e p t h %
cristyda06ed12009-10-14 18:36:54 +0000252% %
253% %
254% %
255%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
256%
cristyfefab1b2011-07-05 00:33:22 +0000257% GetImageDepth() returns the depth of a particular image channel.
cristyda06ed12009-10-14 18:36:54 +0000258%
cristyfefab1b2011-07-05 00:33:22 +0000259% The format of the GetImageDepth method is:
cristyda06ed12009-10-14 18:36:54 +0000260%
cristybb503372010-05-27 20:51:26 +0000261% size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
cristyda06ed12009-10-14 18:36:54 +0000262%
263% A description of each parameter follows:
264%
265% o image: the image.
266%
cristyda06ed12009-10-14 18:36:54 +0000267% o exception: return any errors or warnings in this structure.
268%
269*/
cristy0aa82c12012-01-08 18:22:09 +0000270MagickExport size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
cristyda06ed12009-10-14 18:36:54 +0000271{
cristyc4c8d132010-01-07 01:58:38 +0000272 CacheView
273 *image_view;
274
cristyda06ed12009-10-14 18:36:54 +0000275 MagickBooleanType
276 status;
277
cristybb503372010-05-27 20:51:26 +0000278 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000279 id;
280
cristybb503372010-05-27 20:51:26 +0000281 size_t
cristyda06ed12009-10-14 18:36:54 +0000282 *current_depth,
283 depth,
284 number_threads;
285
cristy9d314ff2011-03-09 01:30:28 +0000286 ssize_t
287 y;
288
cristyda06ed12009-10-14 18:36:54 +0000289 /*
290 Compute image depth.
291 */
292 assert(image != (Image *) NULL);
293 assert(image->signature == MagickSignature);
294 if (image->debug != MagickFalse)
295 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy9357bdd2012-07-30 12:28:34 +0000296 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
cristybb503372010-05-27 20:51:26 +0000297 current_depth=(size_t *) AcquireQuantumMemory(number_threads,
cristyda06ed12009-10-14 18:36:54 +0000298 sizeof(*current_depth));
cristybb503372010-05-27 20:51:26 +0000299 if (current_depth == (size_t *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000300 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
301 status=MagickTrue;
cristybb503372010-05-27 20:51:26 +0000302 for (id=0; id < (ssize_t) number_threads; id++)
cristyda06ed12009-10-14 18:36:54 +0000303 current_depth[id]=1;
cristy8a46d822012-08-28 23:32:39 +0000304 if ((image->storage_class == PseudoClass) && (image->alpha_trait != BlendPixelTrait))
cristyda06ed12009-10-14 18:36:54 +0000305 {
cristybb503372010-05-27 20:51:26 +0000306 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000307 i;
308
cristyb5d5f722009-11-04 03:03:49 +0000309#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy9a5a52f2012-10-09 14:40:31 +0000310 #pragma omp parallel for schedule(static,4) shared(status) \
cristyac245f82012-05-05 17:13:57 +0000311 if ((image->colors) > 256) \
312 num_threads(GetMagickResourceLimit(ThreadResource))
cristyda06ed12009-10-14 18:36:54 +0000313#endif
cristybb503372010-05-27 20:51:26 +0000314 for (i=0; i < (ssize_t) image->colors; i++)
cristyda06ed12009-10-14 18:36:54 +0000315 {
cristy5c9e6f22010-09-17 17:31:01 +0000316 const int
317 id = GetOpenMPThreadId();
318
cristyda06ed12009-10-14 18:36:54 +0000319 if (status == MagickFalse)
320 continue;
cristyda06ed12009-10-14 18:36:54 +0000321 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
322 {
323 MagickStatusType
324 status;
325
326 QuantumAny
cristyb6d6f7c2010-06-09 13:17:57 +0000327 range;
cristyda06ed12009-10-14 18:36:54 +0000328
329 status=0;
cristyb6d6f7c2010-06-09 13:17:57 +0000330 range=GetQuantumRange(current_depth[id]);
cristyed231572011-07-14 02:18:59 +0000331 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000332 status|=ClampToQuantum(image->colormap[i].red) !=
333 ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
334 image->colormap[i].red),range),range);
cristyed231572011-07-14 02:18:59 +0000335 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000336 status|=ClampToQuantum(image->colormap[i].green) !=
337 ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
338 image->colormap[i].green),range),range);
cristyed231572011-07-14 02:18:59 +0000339 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000340 status|=ClampToQuantum(image->colormap[i].blue) !=
341 ScaleAnyToQuantum(ScaleQuantumToAny(ClampToQuantum(
342 image->colormap[i].blue),range),range);
cristyda06ed12009-10-14 18:36:54 +0000343 if (status == 0)
344 break;
345 current_depth[id]++;
346 }
cristyda06ed12009-10-14 18:36:54 +0000347 }
348 depth=current_depth[0];
cristybb503372010-05-27 20:51:26 +0000349 for (id=1; id < (ssize_t) number_threads; id++)
cristyda06ed12009-10-14 18:36:54 +0000350 if (depth < current_depth[id])
351 depth=current_depth[id];
cristybb503372010-05-27 20:51:26 +0000352 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
cristyda06ed12009-10-14 18:36:54 +0000353 return(depth);
354 }
cristydb070952012-04-20 14:33:00 +0000355 image_view=AcquireVirtualCacheView(image,exception);
cristy52936202012-01-12 12:07:45 +0000356#if !defined(MAGICKCORE_HDRI_SUPPORT)
357 if (QuantumRange <= MaxMap)
cristy13868012012-01-08 21:44:07 +0000358 {
cristy13868012012-01-08 21:44:07 +0000359 register ssize_t
cristy52936202012-01-12 12:07:45 +0000360 i;
cristy13868012012-01-08 21:44:07 +0000361
cristy52936202012-01-12 12:07:45 +0000362 size_t
363 *depth_map;
364
365 /*
366 Scale pixels to desired (optimized with depth map).
367 */
368 depth_map=(size_t *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
369 if (depth_map == (size_t *) NULL)
370 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
371 for (i=0; i <= (ssize_t) MaxMap; i++)
cristy13868012012-01-08 21:44:07 +0000372 {
cristy52936202012-01-12 12:07:45 +0000373 unsigned int
374 depth;
cristy13868012012-01-08 21:44:07 +0000375
cristy52936202012-01-12 12:07:45 +0000376 for (depth=1; depth < MAGICKCORE_QUANTUM_DEPTH; depth++)
cristy13868012012-01-08 21:44:07 +0000377 {
cristy52936202012-01-12 12:07:45 +0000378 Quantum
379 pixel;
cristy13868012012-01-08 21:44:07 +0000380
cristy52936202012-01-12 12:07:45 +0000381 QuantumAny
382 range;
cristy13868012012-01-08 21:44:07 +0000383
cristy52936202012-01-12 12:07:45 +0000384 range=GetQuantumRange(depth);
385 pixel=(Quantum) i;
386 if (pixel == ScaleAnyToQuantum(ScaleQuantumToAny(pixel,range),range))
387 break;
cristy13868012012-01-08 21:44:07 +0000388 }
cristy52936202012-01-12 12:07:45 +0000389 depth_map[i]=depth;
cristy13868012012-01-08 21:44:07 +0000390 }
cristy52936202012-01-12 12:07:45 +0000391#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000392 #pragma omp parallel for schedule(static,4) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +0000393 dynamic_number_threads(image,image->columns,image->rows,1)
cristy52936202012-01-12 12:07:45 +0000394#endif
395 for (y=0; y < (ssize_t) image->rows; y++)
396 {
397 const int
398 id = GetOpenMPThreadId();
399
400 register const Quantum
401 *restrict p;
402
403 register ssize_t
404 x;
405
406 if (status == MagickFalse)
407 continue;
408 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
409 if (p == (const Quantum *) NULL)
410 continue;
411 for (x=0; x < (ssize_t) image->columns; x++)
412 {
413 register ssize_t
414 i;
415
cristy10a6c612012-01-29 21:41:05 +0000416 if (GetPixelMask(image,p) != 0)
417 {
418 p+=GetPixelChannels(image);
419 continue;
420 }
cristy52936202012-01-12 12:07:45 +0000421 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
422 {
423 PixelChannel
424 channel;
425
426 PixelTrait
427 traits;
428
cristycf1296e2012-08-26 23:40:49 +0000429 channel=GetPixelChannelChannel(image,i);
430 traits=GetPixelChannelTraits(image,channel);
cristy52936202012-01-12 12:07:45 +0000431 if ((traits == UndefinedPixelTrait) ||
cristy10a6c612012-01-29 21:41:05 +0000432 (channel == IndexPixelChannel) || (channel == MaskPixelChannel))
cristy52936202012-01-12 12:07:45 +0000433 continue;
434 if (depth_map[ScaleQuantumToMap(p[i])] > current_depth[id])
435 current_depth[id]=depth_map[ScaleQuantumToMap(p[i])];
436 }
437 p+=GetPixelChannels(image);
438 }
439 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
440 status=MagickFalse;
441 }
442 image_view=DestroyCacheView(image_view);
443 depth=current_depth[0];
444 for (id=1; id < (ssize_t) number_threads; id++)
445 if (depth < current_depth[id])
446 depth=current_depth[id];
447 depth_map=(size_t *) RelinquishMagickMemory(depth_map);
448 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
449 return(depth);
cristy13868012012-01-08 21:44:07 +0000450 }
cristy13868012012-01-08 21:44:07 +0000451#endif
cristy0aa82c12012-01-08 18:22:09 +0000452 /*
453 Compute pixel depth.
454 */
cristyb5d5f722009-11-04 03:03:49 +0000455#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000456 #pragma omp parallel for schedule(static,4) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +0000457 dynamic_number_threads(image,image->columns,image->rows,1)
cristyda06ed12009-10-14 18:36:54 +0000458#endif
cristybb503372010-05-27 20:51:26 +0000459 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000460 {
cristy5c9e6f22010-09-17 17:31:01 +0000461 const int
462 id = GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +0000463
cristy4c08aed2011-07-01 19:47:50 +0000464 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000465 *restrict p;
cristyda06ed12009-10-14 18:36:54 +0000466
cristybb503372010-05-27 20:51:26 +0000467 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000468 x;
469
470 if (status == MagickFalse)
471 continue;
cristyda06ed12009-10-14 18:36:54 +0000472 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000473 if (p == (const Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000474 continue;
cristybb503372010-05-27 20:51:26 +0000475 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000476 {
cristy8a11cb12011-10-19 23:53:34 +0000477 register ssize_t
478 i;
479
cristy10a6c612012-01-29 21:41:05 +0000480 if (GetPixelMask(image,p) != 0)
481 {
482 p+=GetPixelChannels(image);
483 continue;
484 }
cristy8a11cb12011-10-19 23:53:34 +0000485 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
cristyda06ed12009-10-14 18:36:54 +0000486 {
cristyabace412011-12-11 15:56:53 +0000487 PixelChannel
488 channel;
489
cristy8a11cb12011-10-19 23:53:34 +0000490 PixelTrait
491 traits;
cristyda06ed12009-10-14 18:36:54 +0000492
cristycf1296e2012-08-26 23:40:49 +0000493 channel=GetPixelChannelChannel(image,i);
494 traits=GetPixelChannelTraits(image,channel);
cristy10a6c612012-01-29 21:41:05 +0000495 if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
496 (channel == MaskPixelChannel))
cristy8a11cb12011-10-19 23:53:34 +0000497 continue;
498 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
499 {
cristy8a11cb12011-10-19 23:53:34 +0000500 QuantumAny
501 range;
502
cristy8a11cb12011-10-19 23:53:34 +0000503 range=GetQuantumRange(current_depth[id]);
cristy3b2b1712012-01-08 21:52:15 +0000504 if (p[i] == ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),range))
cristy8a11cb12011-10-19 23:53:34 +0000505 break;
506 current_depth[id]++;
507 }
cristyda06ed12009-10-14 18:36:54 +0000508 }
cristyed231572011-07-14 02:18:59 +0000509 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000510 }
511 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
512 status=MagickFalse;
513 }
514 image_view=DestroyCacheView(image_view);
515 depth=current_depth[0];
cristybb503372010-05-27 20:51:26 +0000516 for (id=1; id < (ssize_t) number_threads; id++)
cristyda06ed12009-10-14 18:36:54 +0000517 if (depth < current_depth[id])
518 depth=current_depth[id];
cristybb503372010-05-27 20:51:26 +0000519 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
cristyda06ed12009-10-14 18:36:54 +0000520 return(depth);
521}
522
523/*
524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525% %
526% %
527% %
528% G e t I m a g e Q u a n t u m D e p t h %
529% %
530% %
531% %
532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
533%
534% GetImageQuantumDepth() returns the depth of the image rounded to a legal
535% quantum depth: 8, 16, or 32.
536%
537% The format of the GetImageQuantumDepth method is:
538%
cristybb503372010-05-27 20:51:26 +0000539% size_t GetImageQuantumDepth(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000540% const MagickBooleanType constrain)
541%
542% A description of each parameter follows:
543%
544% o image: the image.
545%
546% o constrain: A value other than MagickFalse, constrains the depth to
547% a maximum of MAGICKCORE_QUANTUM_DEPTH.
548%
549*/
550
551static inline double MagickMin(const double x,const double y)
552{
553 if (x < y)
554 return(x);
555 return(y);
556}
557
cristybb503372010-05-27 20:51:26 +0000558MagickExport size_t GetImageQuantumDepth(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000559 const MagickBooleanType constrain)
560{
cristybb503372010-05-27 20:51:26 +0000561 size_t
cristyda06ed12009-10-14 18:36:54 +0000562 depth;
563
564 depth=image->depth;
565 if (depth <= 8)
566 depth=8;
567 else
568 if (depth <= 16)
569 depth=16;
570 else
571 if (depth <= 32)
572 depth=32;
573 else
574 if (depth <= 64)
575 depth=64;
576 if (constrain != MagickFalse)
cristy9e940dd2011-12-13 01:22:25 +0000577 depth=(size_t) MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH);
cristyda06ed12009-10-14 18:36:54 +0000578 return(depth);
579}
580
581/*
582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
583% %
584% %
585% %
586% G e t I m a g e T y p e %
587% %
588% %
589% %
590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
591%
592% GetImageType() returns the potential type of image:
593%
594% Bilevel Grayscale GrayscaleMatte
595% Palette PaletteMatte TrueColor
596% TrueColorMatte ColorSeparation ColorSeparationMatte
597%
598% To ensure the image type matches its potential, use SetImageType():
599%
600% (void) SetImageType(image,GetImageType(image));
601%
602% The format of the GetImageType method is:
603%
604% ImageType GetImageType(const Image *image,ExceptionInfo *exception)
605%
606% A description of each parameter follows:
607%
608% o image: the image.
609%
610% o exception: return any errors or warnings in this structure.
611%
612*/
613MagickExport ImageType GetImageType(const Image *image,ExceptionInfo *exception)
614{
615 assert(image != (Image *) NULL);
616 assert(image->signature == MagickSignature);
617 if (image->debug != MagickFalse)
618 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
619 if (image->colorspace == CMYKColorspace)
620 {
cristy8a46d822012-08-28 23:32:39 +0000621 if (image->alpha_trait != BlendPixelTrait)
cristyda06ed12009-10-14 18:36:54 +0000622 return(ColorSeparationType);
623 return(ColorSeparationMatteType);
624 }
cristy4c08aed2011-07-01 19:47:50 +0000625 if (IsImageMonochrome(image,exception) != MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000626 return(BilevelType);
cristy4c08aed2011-07-01 19:47:50 +0000627 if (IsImageGray(image,exception) != MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000628 {
cristy8a46d822012-08-28 23:32:39 +0000629 if (image->alpha_trait == BlendPixelTrait)
cristyda06ed12009-10-14 18:36:54 +0000630 return(GrayscaleMatteType);
631 return(GrayscaleType);
632 }
633 if (IsPaletteImage(image,exception) != MagickFalse)
634 {
cristy8a46d822012-08-28 23:32:39 +0000635 if (image->alpha_trait == BlendPixelTrait)
cristyda06ed12009-10-14 18:36:54 +0000636 return(PaletteMatteType);
637 return(PaletteType);
638 }
cristy8a46d822012-08-28 23:32:39 +0000639 if (image->alpha_trait == BlendPixelTrait)
cristyda06ed12009-10-14 18:36:54 +0000640 return(TrueColorMatteType);
641 return(TrueColorType);
642}
643
644/*
645%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
646% %
647% %
648% %
cristy4c08aed2011-07-01 19:47:50 +0000649% I s I m a g e G r a y %
cristyda06ed12009-10-14 18:36:54 +0000650% %
651% %
652% %
653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
654%
cristy4c08aed2011-07-01 19:47:50 +0000655% IsImageGray() returns MagickTrue if all the pixels in the image have the
cristyda06ed12009-10-14 18:36:54 +0000656% same red, green, and blue intensities.
657%
cristy4c08aed2011-07-01 19:47:50 +0000658% The format of the IsImageGray method is:
cristyda06ed12009-10-14 18:36:54 +0000659%
cristy4c08aed2011-07-01 19:47:50 +0000660% MagickBooleanType IsImageGray(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000661% ExceptionInfo *exception)
662%
663% A description of each parameter follows:
664%
665% o image: the image.
666%
667% o exception: return any errors or warnings in this structure.
668%
669*/
cristy4c08aed2011-07-01 19:47:50 +0000670MagickExport MagickBooleanType IsImageGray(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000671 ExceptionInfo *exception)
672{
cristy0910f242010-04-01 18:55:09 +0000673 CacheView
674 *image_view;
675
cristyda06ed12009-10-14 18:36:54 +0000676 ImageType
677 type;
678
cristy4c08aed2011-07-01 19:47:50 +0000679 register const Quantum
cristyda06ed12009-10-14 18:36:54 +0000680 *p;
681
cristybb503372010-05-27 20:51:26 +0000682 register ssize_t
cristy0910f242010-04-01 18:55:09 +0000683 x;
684
cristy95802a72010-09-05 19:07:17 +0000685 ssize_t
686 y;
687
cristyda06ed12009-10-14 18:36:54 +0000688 assert(image != (Image *) NULL);
689 assert(image->signature == MagickSignature);
690 if (image->debug != MagickFalse)
691 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
692 if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
693 (image->type == GrayscaleMatteType))
694 return(MagickTrue);
cristy3bf83e62012-05-22 15:23:25 +0000695 if ((IsGrayColorspace(image->colorspace) == MagickFalse) &&
cristy32fe3a52012-05-24 13:55:58 +0000696 (IsRGBColorspace(image->colorspace) == MagickFalse))
cristyda06ed12009-10-14 18:36:54 +0000697 return(MagickFalse);
698 type=BilevelType;
cristydb070952012-04-20 14:33:00 +0000699 image_view=AcquireVirtualCacheView(image,exception);
cristybb503372010-05-27 20:51:26 +0000700 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000701 {
cristy0910f242010-04-01 18:55:09 +0000702 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000703 if (p == (const Quantum *) NULL)
cristy0910f242010-04-01 18:55:09 +0000704 break;
cristybb503372010-05-27 20:51:26 +0000705 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000706 {
cristy4c08aed2011-07-01 19:47:50 +0000707 if (IsPixelGray(image,p) == MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000708 {
cristy5f1c1ff2010-12-23 21:38:06 +0000709 type=UndefinedType;
cristyda06ed12009-10-14 18:36:54 +0000710 break;
cristy0910f242010-04-01 18:55:09 +0000711 }
cristybd5a96c2011-08-21 00:04:26 +0000712 if ((type == BilevelType) &&
713 (IsPixelMonochrome(image,p) == MagickFalse))
cristy0910f242010-04-01 18:55:09 +0000714 type=GrayscaleType;
cristyed231572011-07-14 02:18:59 +0000715 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000716 }
cristy5f1c1ff2010-12-23 21:38:06 +0000717 if (type == UndefinedType)
cristyda06ed12009-10-14 18:36:54 +0000718 break;
cristyda06ed12009-10-14 18:36:54 +0000719 }
cristy0910f242010-04-01 18:55:09 +0000720 image_view=DestroyCacheView(image_view);
cristy5f1c1ff2010-12-23 21:38:06 +0000721 if (type == UndefinedType)
cristyda06ed12009-10-14 18:36:54 +0000722 return(MagickFalse);
723 ((Image *) image)->type=type;
cristy8a46d822012-08-28 23:32:39 +0000724 if ((type == GrayscaleType) && (image->alpha_trait == BlendPixelTrait))
cristyda06ed12009-10-14 18:36:54 +0000725 ((Image *) image)->type=GrayscaleMatteType;
726 return(MagickTrue);
727}
728
729/*
730%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
731% %
732% %
733% %
cristy4c08aed2011-07-01 19:47:50 +0000734% I s I m a g e M o n o c h r o m e %
cristyda06ed12009-10-14 18:36:54 +0000735% %
736% %
737% %
738%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
739%
cristy4c08aed2011-07-01 19:47:50 +0000740% IsImageMonochrome() returns MagickTrue if all the pixels in the image have
cristyda06ed12009-10-14 18:36:54 +0000741% the same red, green, and blue intensities and the intensity is either
742% 0 or QuantumRange.
743%
cristy4c08aed2011-07-01 19:47:50 +0000744% The format of the IsImageMonochrome method is:
cristyda06ed12009-10-14 18:36:54 +0000745%
cristy4c08aed2011-07-01 19:47:50 +0000746% MagickBooleanType IsImageMonochrome(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000747% ExceptionInfo *exception)
748%
749% A description of each parameter follows:
750%
751% o image: the image.
752%
753% o exception: return any errors or warnings in this structure.
754%
755*/
cristy4c08aed2011-07-01 19:47:50 +0000756MagickExport MagickBooleanType IsImageMonochrome(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000757 ExceptionInfo *exception)
758{
cristy0910f242010-04-01 18:55:09 +0000759 CacheView
760 *image_view;
761
cristyda06ed12009-10-14 18:36:54 +0000762 ImageType
763 type;
764
cristybb503372010-05-27 20:51:26 +0000765 register ssize_t
cristy0910f242010-04-01 18:55:09 +0000766 x;
767
cristy4c08aed2011-07-01 19:47:50 +0000768 register const Quantum
cristyda06ed12009-10-14 18:36:54 +0000769 *p;
770
cristy9d314ff2011-03-09 01:30:28 +0000771 ssize_t
772 y;
773
cristyda06ed12009-10-14 18:36:54 +0000774 assert(image != (Image *) NULL);
775 assert(image->signature == MagickSignature);
776 if (image->debug != MagickFalse)
777 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
778 if (image->type == BilevelType)
779 return(MagickTrue);
cristy3bf83e62012-05-22 15:23:25 +0000780 if ((IsGrayColorspace(image->colorspace) == MagickFalse) &&
cristy32fe3a52012-05-24 13:55:58 +0000781 (IsRGBColorspace(image->colorspace) == MagickFalse))
cristyda06ed12009-10-14 18:36:54 +0000782 return(MagickFalse);
783 type=BilevelType;
cristydb070952012-04-20 14:33:00 +0000784 image_view=AcquireVirtualCacheView(image,exception);
cristybb503372010-05-27 20:51:26 +0000785 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000786 {
cristy0910f242010-04-01 18:55:09 +0000787 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000788 if (p == (const Quantum *) NULL)
cristy0910f242010-04-01 18:55:09 +0000789 break;
cristybb503372010-05-27 20:51:26 +0000790 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000791 {
cristy4c08aed2011-07-01 19:47:50 +0000792 if (IsPixelMonochrome(image,p) == MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000793 {
cristy5f1c1ff2010-12-23 21:38:06 +0000794 type=UndefinedType;
cristyda06ed12009-10-14 18:36:54 +0000795 break;
cristy0910f242010-04-01 18:55:09 +0000796 }
cristyed231572011-07-14 02:18:59 +0000797 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000798 }
cristy5f1c1ff2010-12-23 21:38:06 +0000799 if (type == UndefinedType)
cristyda06ed12009-10-14 18:36:54 +0000800 break;
cristyda06ed12009-10-14 18:36:54 +0000801 }
cristy0910f242010-04-01 18:55:09 +0000802 image_view=DestroyCacheView(image_view);
cristy5f1c1ff2010-12-23 21:38:06 +0000803 if (type == UndefinedType)
cristyda06ed12009-10-14 18:36:54 +0000804 return(MagickFalse);
805 ((Image *) image)->type=type;
806 return(MagickTrue);
807}
808
809/*
810%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
811% %
812% %
813% %
cristy4c08aed2011-07-01 19:47:50 +0000814% I s I m a g e O p a q u e %
cristyda06ed12009-10-14 18:36:54 +0000815% %
816% %
817% %
818%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
819%
cristy4c08aed2011-07-01 19:47:50 +0000820% IsImageOpaque() returns MagickTrue if none of the pixels in the image have
anthonyfb2cc882012-04-29 11:46:27 +0000821% an alpha value other than OpaqueAlpha (QuantumRange).
822%
823% Will return true immediatally is alpha channel is not available.
cristyda06ed12009-10-14 18:36:54 +0000824%
cristy4c08aed2011-07-01 19:47:50 +0000825% The format of the IsImageOpaque method is:
cristyda06ed12009-10-14 18:36:54 +0000826%
cristy4c08aed2011-07-01 19:47:50 +0000827% MagickBooleanType IsImageOpaque(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000828% ExceptionInfo *exception)
829%
830% A description of each parameter follows:
831%
832% o image: the image.
833%
834% o exception: return any errors or warnings in this structure.
835%
836*/
cristy4c08aed2011-07-01 19:47:50 +0000837MagickExport MagickBooleanType IsImageOpaque(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000838 ExceptionInfo *exception)
839{
cristyc4c8d132010-01-07 01:58:38 +0000840 CacheView
841 *image_view;
842
cristy4c08aed2011-07-01 19:47:50 +0000843 register const Quantum
cristyda06ed12009-10-14 18:36:54 +0000844 *p;
845
cristybb503372010-05-27 20:51:26 +0000846 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000847 x;
848
cristy9d314ff2011-03-09 01:30:28 +0000849 ssize_t
850 y;
851
cristyda06ed12009-10-14 18:36:54 +0000852 /*
853 Determine if image is opaque.
854 */
855 assert(image != (Image *) NULL);
856 assert(image->signature == MagickSignature);
857 if (image->debug != MagickFalse)
858 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy8a46d822012-08-28 23:32:39 +0000859 if (image->alpha_trait != BlendPixelTrait)
cristyda06ed12009-10-14 18:36:54 +0000860 return(MagickTrue);
cristydb070952012-04-20 14:33:00 +0000861 image_view=AcquireVirtualCacheView(image,exception);
cristybb503372010-05-27 20:51:26 +0000862 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000863 {
864 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000865 if (p == (const Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000866 break;
cristybb503372010-05-27 20:51:26 +0000867 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000868 {
cristy4c08aed2011-07-01 19:47:50 +0000869 if (GetPixelAlpha(image,p) != OpaqueAlpha)
cristyda06ed12009-10-14 18:36:54 +0000870 break;
cristyed231572011-07-14 02:18:59 +0000871 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000872 }
cristybb503372010-05-27 20:51:26 +0000873 if (x < (ssize_t) image->columns)
cristyda06ed12009-10-14 18:36:54 +0000874 break;
875 }
876 image_view=DestroyCacheView(image_view);
cristybb503372010-05-27 20:51:26 +0000877 return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
cristyda06ed12009-10-14 18:36:54 +0000878}
879
880/*
881%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
882% %
883% %
884% %
cristyfefab1b2011-07-05 00:33:22 +0000885% S e t I m a g e D e p t h %
cristyda06ed12009-10-14 18:36:54 +0000886% %
887% %
888% %
889%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
890%
cristyfefab1b2011-07-05 00:33:22 +0000891% SetImageDepth() sets the depth of the image.
cristyda06ed12009-10-14 18:36:54 +0000892%
cristyfefab1b2011-07-05 00:33:22 +0000893% The format of the SetImageDepth method is:
cristyda06ed12009-10-14 18:36:54 +0000894%
cristy8a11cb12011-10-19 23:53:34 +0000895% MagickBooleanType SetImageDepth(Image *image,const size_t depth,
896% ExceptionInfo *exception)
cristyda06ed12009-10-14 18:36:54 +0000897%
898% A description of each parameter follows:
899%
900% o image: the image.
901%
902% o channel: the channel.
903%
904% o depth: the image depth.
905%
cristy8a11cb12011-10-19 23:53:34 +0000906% o exception: return any errors or warnings in this structure.
907%
cristyda06ed12009-10-14 18:36:54 +0000908*/
cristyda06ed12009-10-14 18:36:54 +0000909MagickExport MagickBooleanType SetImageDepth(Image *image,
cristy8a11cb12011-10-19 23:53:34 +0000910 const size_t depth,ExceptionInfo *exception)
cristyda06ed12009-10-14 18:36:54 +0000911{
cristyc4c8d132010-01-07 01:58:38 +0000912 CacheView
913 *image_view;
914
cristyda06ed12009-10-14 18:36:54 +0000915 MagickBooleanType
916 status;
917
918 QuantumAny
cristyb6d6f7c2010-06-09 13:17:57 +0000919 range;
cristyda06ed12009-10-14 18:36:54 +0000920
cristy9d314ff2011-03-09 01:30:28 +0000921 ssize_t
922 y;
923
cristyda06ed12009-10-14 18:36:54 +0000924 assert(image != (Image *) NULL);
925 if (image->debug != MagickFalse)
926 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
927 assert(image->signature == MagickSignature);
cristy0aa82c12012-01-08 18:22:09 +0000928 if (depth >= MAGICKCORE_QUANTUM_DEPTH)
cristyda06ed12009-10-14 18:36:54 +0000929 {
cristy8eacae42012-06-19 16:22:15 +0000930 image->depth=depth;
cristyda06ed12009-10-14 18:36:54 +0000931 return(MagickTrue);
932 }
cristy5d6f7ed2012-01-08 02:53:08 +0000933 range=GetQuantumRange(depth);
934 if (image->storage_class == PseudoClass)
935 {
cristy5d6f7ed2012-01-08 02:53:08 +0000936 register ssize_t
937 i;
938
cristy5d6f7ed2012-01-08 02:53:08 +0000939#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy9a5a52f2012-10-09 14:40:31 +0000940 #pragma omp parallel for schedule(static,4) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +0000941 dynamic_number_threads(image,image->columns,1,1)
cristy5d6f7ed2012-01-08 02:53:08 +0000942#endif
943 for (i=0; i < (ssize_t) image->colors; i++)
944 {
945 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000946 image->colormap[i].red=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
947 ClampToQuantum(image->colormap[i].red),range),range);
cristy5d6f7ed2012-01-08 02:53:08 +0000948 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
cristy16881e62012-05-06 14:41:29 +0000949 image->colormap[i].green=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
950 ClampToQuantum(image->colormap[i].green),range),range);
cristy5d6f7ed2012-01-08 02:53:08 +0000951 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000952 image->colormap[i].blue=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
953 ClampToQuantum(image->colormap[i].blue),range),range);
cristy5d6f7ed2012-01-08 02:53:08 +0000954 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000955 image->colormap[i].alpha=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
956 ClampToQuantum(image->colormap[i].alpha),range),range);
cristy5d6f7ed2012-01-08 02:53:08 +0000957 }
cristy5d6f7ed2012-01-08 02:53:08 +0000958 }
cristy0aa82c12012-01-08 18:22:09 +0000959 status=MagickTrue;
cristydb070952012-04-20 14:33:00 +0000960 image_view=AcquireAuthenticCacheView(image,exception);
cristy52936202012-01-12 12:07:45 +0000961#if !defined(MAGICKCORE_HDRI_SUPPORT)
962 if (QuantumRange <= MaxMap)
cristy0aa82c12012-01-08 18:22:09 +0000963 {
cristy52936202012-01-12 12:07:45 +0000964 Quantum
965 *depth_map;
966
cristy0aa82c12012-01-08 18:22:09 +0000967 register ssize_t
cristy52936202012-01-12 12:07:45 +0000968 i;
cristy0aa82c12012-01-08 18:22:09 +0000969
cristy52936202012-01-12 12:07:45 +0000970 /*
971 Scale pixels to desired (optimized with depth map).
972 */
973 depth_map=(Quantum *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
974 if (depth_map == (Quantum *) NULL)
975 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
976 for (i=0; i <= (ssize_t) MaxMap; i++)
977 depth_map[i]=ScaleAnyToQuantum(ScaleQuantumToAny((Quantum) i,range),
978 range);
979#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000980 #pragma omp parallel for schedule(static,4) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +0000981 dynamic_number_threads(image,image->columns,image->rows,1)
cristy52936202012-01-12 12:07:45 +0000982#endif
983 for (y=0; y < (ssize_t) image->rows; y++)
cristy0aa82c12012-01-08 18:22:09 +0000984 {
cristy52936202012-01-12 12:07:45 +0000985 register ssize_t
986 x;
cristy0aa82c12012-01-08 18:22:09 +0000987
cristy52936202012-01-12 12:07:45 +0000988 register Quantum
989 *restrict q;
cristy0aa82c12012-01-08 18:22:09 +0000990
cristy52936202012-01-12 12:07:45 +0000991 if (status == MagickFalse)
cristy0aa82c12012-01-08 18:22:09 +0000992 continue;
cristy52936202012-01-12 12:07:45 +0000993 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
994 exception);
995 if (q == (Quantum *) NULL)
996 {
997 status=MagickFalse;
998 continue;
999 }
1000 for (x=0; x < (ssize_t) image->columns; x++)
1001 {
cristyaa874e12012-01-20 21:00:51 +00001002 register ssize_t
1003 i;
1004
cristy10a6c612012-01-29 21:41:05 +00001005 if (GetPixelMask(image,q) != 0)
1006 {
1007 q+=GetPixelChannels(image);
1008 continue;
1009 }
cristy52936202012-01-12 12:07:45 +00001010 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1011 {
1012 PixelChannel
1013 channel;
1014
1015 PixelTrait
1016 traits;
1017
cristycf1296e2012-08-26 23:40:49 +00001018 channel=GetPixelChannelChannel(image,i);
1019 traits=GetPixelChannelTraits(image,channel);
cristy52936202012-01-12 12:07:45 +00001020 if ((traits == UndefinedPixelTrait) ||
cristy10a6c612012-01-29 21:41:05 +00001021 (channel == IndexPixelChannel) || (channel == MaskPixelChannel))
cristy52936202012-01-12 12:07:45 +00001022 continue;
1023 q[i]=depth_map[ScaleQuantumToMap(q[i])];
1024 }
1025 q+=GetPixelChannels(image);
cristy0aa82c12012-01-08 18:22:09 +00001026 }
cristy52936202012-01-12 12:07:45 +00001027 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1028 {
1029 status=MagickFalse;
1030 continue;
1031 }
1032 }
1033 image_view=DestroyCacheView(image_view);
1034 depth_map=(Quantum *) RelinquishMagickMemory(depth_map);
1035 if (status != MagickFalse)
1036 image->depth=depth;
1037 return(status);
cristy0aa82c12012-01-08 18:22:09 +00001038 }
cristy0aa82c12012-01-08 18:22:09 +00001039#endif
cristyda06ed12009-10-14 18:36:54 +00001040 /*
1041 Scale pixels to desired depth.
1042 */
cristyb5d5f722009-11-04 03:03:49 +00001043#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00001044 #pragma omp parallel for schedule(static,4) shared(status) \
cristy4ee2b0c2012-05-15 00:30:35 +00001045 dynamic_number_threads(image,image->columns,image->rows,1)
cristyda06ed12009-10-14 18:36:54 +00001046#endif
cristybb503372010-05-27 20:51:26 +00001047 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +00001048 {
cristybb503372010-05-27 20:51:26 +00001049 register ssize_t
cristyda06ed12009-10-14 18:36:54 +00001050 x;
1051
cristy4c08aed2011-07-01 19:47:50 +00001052 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001053 *restrict q;
cristyda06ed12009-10-14 18:36:54 +00001054
1055 if (status == MagickFalse)
1056 continue;
cristy8a11cb12011-10-19 23:53:34 +00001057 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00001058 if (q == (Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +00001059 {
1060 status=MagickFalse;
1061 continue;
1062 }
cristybb503372010-05-27 20:51:26 +00001063 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +00001064 {
cristy8a11cb12011-10-19 23:53:34 +00001065 register ssize_t
1066 i;
1067
cristy10a6c612012-01-29 21:41:05 +00001068 if (GetPixelMask(image,q) != 0)
1069 {
1070 q+=GetPixelChannels(image);
1071 continue;
1072 }
cristy8a11cb12011-10-19 23:53:34 +00001073 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1074 {
cristyabace412011-12-11 15:56:53 +00001075 PixelChannel
1076 channel;
1077
cristy8a11cb12011-10-19 23:53:34 +00001078 PixelTrait
1079 traits;
1080
cristycf1296e2012-08-26 23:40:49 +00001081 channel=GetPixelChannelChannel(image,i);
1082 traits=GetPixelChannelTraits(image,channel);
cristy10a6c612012-01-29 21:41:05 +00001083 if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
1084 (channel == MaskPixelChannel))
cristy8a11cb12011-10-19 23:53:34 +00001085 continue;
cristy0aa82c12012-01-08 18:22:09 +00001086 q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(q[i],range),range);
cristy8a11cb12011-10-19 23:53:34 +00001087 }
cristyed231572011-07-14 02:18:59 +00001088 q+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +00001089 }
1090 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1091 {
1092 status=MagickFalse;
1093 continue;
1094 }
1095 }
1096 image_view=DestroyCacheView(image_view);
cristy5d6f7ed2012-01-08 02:53:08 +00001097 if (status != MagickFalse)
1098 image->depth=depth;
cristyda06ed12009-10-14 18:36:54 +00001099 return(status);
1100}
cristy623aaec2012-06-21 00:49:08 +00001101
1102/*
1103%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1104% %
1105% %
1106% %
1107% S e t I m a g e T y p e %
1108% %
1109% %
1110% %
1111%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1112%
1113% SetImageType() sets the type of image. Choose from these types:
1114%
1115% Bilevel Grayscale GrayscaleMatte
1116% Palette PaletteMatte TrueColor
1117% TrueColorMatte ColorSeparation ColorSeparationMatte
1118% OptimizeType
1119%
1120% The format of the SetImageType method is:
1121%
1122% MagickBooleanType SetImageType(Image *image,const ImageType type,
1123% ExceptionInfo *exception)
1124%
1125% A description of each parameter follows:
1126%
1127% o image: the image.
1128%
1129% o type: Image type.
1130%
1131% o exception: return any errors or warnings in this structure.
1132%
1133*/
1134MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type,
1135 ExceptionInfo *exception)
1136{
1137 const char
1138 *artifact;
1139
1140 ImageInfo
1141 *image_info;
1142
1143 MagickBooleanType
1144 status;
1145
1146 QuantizeInfo
1147 *quantize_info;
1148
1149 assert(image != (Image *) NULL);
1150 if (image->debug != MagickFalse)
1151 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1152 assert(image->signature == MagickSignature);
1153 status=MagickTrue;
1154 image_info=AcquireImageInfo();
1155 image_info->dither=image->dither;
1156 artifact=GetImageArtifact(image,"dither");
1157 if (artifact != (const char *) NULL)
1158 (void) SetImageOption(image_info,"dither",artifact);
1159 switch (type)
1160 {
1161 case BilevelType:
1162 {
1163 if (IsImageMonochrome(image,exception) == MagickFalse)
1164 {
1165 quantize_info=AcquireQuantizeInfo(image_info);
1166 quantize_info->number_colors=2;
1167 quantize_info->colorspace=GRAYColorspace;
1168 status=QuantizeImage(quantize_info,image,exception);
1169 quantize_info=DestroyQuantizeInfo(quantize_info);
1170 }
cristy8a46d822012-08-28 23:32:39 +00001171 image->alpha_trait=UndefinedPixelTrait;
cristy623aaec2012-06-21 00:49:08 +00001172 break;
1173 }
1174 case GrayscaleType:
1175 {
1176 if (IsImageGray(image,exception) == MagickFalse)
1177 status=TransformImageColorspace(image,GRAYColorspace,exception);
cristy8a46d822012-08-28 23:32:39 +00001178 image->alpha_trait=UndefinedPixelTrait;
cristy623aaec2012-06-21 00:49:08 +00001179 break;
1180 }
1181 case GrayscaleMatteType:
1182 {
1183 if (IsImageGray(image,exception) == MagickFalse)
1184 status=TransformImageColorspace(image,GRAYColorspace,exception);
cristy8a46d822012-08-28 23:32:39 +00001185 if (image->alpha_trait != BlendPixelTrait)
cristy623aaec2012-06-21 00:49:08 +00001186 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1187 break;
1188 }
1189 case PaletteType:
1190 {
cristy3d9f5ba2012-06-26 13:37:31 +00001191 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy623aaec2012-06-21 00:49:08 +00001192 status=TransformImageColorspace(image,sRGBColorspace,exception);
1193 if ((image->storage_class == DirectClass) || (image->colors > 256))
1194 {
1195 quantize_info=AcquireQuantizeInfo(image_info);
1196 quantize_info->number_colors=256;
1197 status=QuantizeImage(quantize_info,image,exception);
1198 quantize_info=DestroyQuantizeInfo(quantize_info);
1199 }
cristy8a46d822012-08-28 23:32:39 +00001200 image->alpha_trait=UndefinedPixelTrait;
cristy623aaec2012-06-21 00:49:08 +00001201 break;
1202 }
1203 case PaletteBilevelMatteType:
1204 {
1205 ChannelType
1206 channel_mask;
1207
cristy3d9f5ba2012-06-26 13:37:31 +00001208 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy623aaec2012-06-21 00:49:08 +00001209 status=TransformImageColorspace(image,sRGBColorspace,exception);
cristy8a46d822012-08-28 23:32:39 +00001210 if (image->alpha_trait != BlendPixelTrait)
cristy623aaec2012-06-21 00:49:08 +00001211 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristycf1296e2012-08-26 23:40:49 +00001212 channel_mask=SetImageChannelMask(image,AlphaChannel);
cristy623aaec2012-06-21 00:49:08 +00001213 (void) BilevelImage(image,(double) QuantumRange/2.0,exception);
cristycf1296e2012-08-26 23:40:49 +00001214 (void) SetImageChannelMask(image,channel_mask);
cristy623aaec2012-06-21 00:49:08 +00001215 quantize_info=AcquireQuantizeInfo(image_info);
1216 status=QuantizeImage(quantize_info,image,exception);
1217 quantize_info=DestroyQuantizeInfo(quantize_info);
1218 break;
1219 }
1220 case PaletteMatteType:
1221 {
cristy3d9f5ba2012-06-26 13:37:31 +00001222 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy623aaec2012-06-21 00:49:08 +00001223 status=TransformImageColorspace(image,sRGBColorspace,exception);
cristy8a46d822012-08-28 23:32:39 +00001224 if (image->alpha_trait != BlendPixelTrait)
cristy623aaec2012-06-21 00:49:08 +00001225 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1226 quantize_info=AcquireQuantizeInfo(image_info);
1227 quantize_info->colorspace=TransparentColorspace;
1228 status=QuantizeImage(quantize_info,image,exception);
1229 quantize_info=DestroyQuantizeInfo(quantize_info);
1230 break;
1231 }
1232 case TrueColorType:
1233 {
cristy3d9f5ba2012-06-26 13:37:31 +00001234 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy623aaec2012-06-21 00:49:08 +00001235 status=TransformImageColorspace(image,sRGBColorspace,exception);
1236 if (image->storage_class != DirectClass)
1237 status=SetImageStorageClass(image,DirectClass,exception);
cristy8a46d822012-08-28 23:32:39 +00001238 image->alpha_trait=UndefinedPixelTrait;
cristy623aaec2012-06-21 00:49:08 +00001239 break;
1240 }
1241 case TrueColorMatteType:
1242 {
cristy3d9f5ba2012-06-26 13:37:31 +00001243 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy623aaec2012-06-21 00:49:08 +00001244 status=TransformImageColorspace(image,sRGBColorspace,exception);
1245 if (image->storage_class != DirectClass)
1246 status=SetImageStorageClass(image,DirectClass,exception);
cristy8a46d822012-08-28 23:32:39 +00001247 if (image->alpha_trait != BlendPixelTrait)
cristy623aaec2012-06-21 00:49:08 +00001248 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1249 break;
1250 }
1251 case ColorSeparationType:
1252 {
1253 if (image->colorspace != CMYKColorspace)
1254 {
cristy3d9f5ba2012-06-26 13:37:31 +00001255 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy623aaec2012-06-21 00:49:08 +00001256 status=TransformImageColorspace(image,sRGBColorspace,exception);
1257 status=TransformImageColorspace(image,CMYKColorspace,exception);
1258 }
1259 if (image->storage_class != DirectClass)
1260 status=SetImageStorageClass(image,DirectClass,exception);
cristy8a46d822012-08-28 23:32:39 +00001261 image->alpha_trait=UndefinedPixelTrait;
cristy623aaec2012-06-21 00:49:08 +00001262 break;
1263 }
1264 case ColorSeparationMatteType:
1265 {
1266 if (image->colorspace != CMYKColorspace)
1267 {
cristy3d9f5ba2012-06-26 13:37:31 +00001268 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy623aaec2012-06-21 00:49:08 +00001269 status=TransformImageColorspace(image,sRGBColorspace,exception);
1270 status=TransformImageColorspace(image,CMYKColorspace,exception);
1271 }
1272 if (image->storage_class != DirectClass)
1273 status=SetImageStorageClass(image,DirectClass,exception);
cristy8a46d822012-08-28 23:32:39 +00001274 if (image->alpha_trait != BlendPixelTrait)
cristy623aaec2012-06-21 00:49:08 +00001275 status=SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1276 break;
1277 }
1278 case OptimizeType:
1279 case UndefinedType:
1280 break;
1281 }
1282 image->type=type;
1283 image_info=DestroyImageInfo(image_info);
1284 return(status);
1285}