blob: 4943ace728427366c642c51bdc993122407a658f [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% %
cristyfe676ee2013-11-18 13:03:38 +000020% Copyright 1999-2014 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"
cristye65d6532013-04-25 11:28:16 +000049#include "MagickCore/cache-private.h"
cristy4c08aed2011-07-01 19:47:50 +000050#include "MagickCore/cache-view.h"
cristy6a2180c2013-05-27 10:28:36 +000051#include "MagickCore/channel.h"
cristy4c08aed2011-07-01 19:47:50 +000052#include "MagickCore/client.h"
53#include "MagickCore/color.h"
54#include "MagickCore/color-private.h"
55#include "MagickCore/colormap.h"
56#include "MagickCore/colormap-private.h"
57#include "MagickCore/colorspace.h"
cristycca1bfa2011-09-12 12:39:53 +000058#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000059#include "MagickCore/composite.h"
60#include "MagickCore/composite-private.h"
61#include "MagickCore/constitute.h"
62#include "MagickCore/draw.h"
63#include "MagickCore/draw-private.h"
64#include "MagickCore/effect.h"
65#include "MagickCore/enhance.h"
66#include "MagickCore/exception.h"
67#include "MagickCore/exception-private.h"
68#include "MagickCore/geometry.h"
69#include "MagickCore/histogram.h"
70#include "MagickCore/identify.h"
71#include "MagickCore/image.h"
72#include "MagickCore/image-private.h"
73#include "MagickCore/list.h"
74#include "MagickCore/log.h"
75#include "MagickCore/memory_.h"
76#include "MagickCore/magick.h"
77#include "MagickCore/monitor.h"
78#include "MagickCore/monitor-private.h"
cristy623aaec2012-06-21 00:49:08 +000079#include "MagickCore/option.h"
cristy4c08aed2011-07-01 19:47:50 +000080#include "MagickCore/paint.h"
81#include "MagickCore/pixel.h"
82#include "MagickCore/pixel-accessor.h"
83#include "MagickCore/property.h"
84#include "MagickCore/quantize.h"
85#include "MagickCore/quantum-private.h"
86#include "MagickCore/random_.h"
87#include "MagickCore/resource_.h"
88#include "MagickCore/semaphore.h"
89#include "MagickCore/segment.h"
90#include "MagickCore/splay-tree.h"
91#include "MagickCore/string_.h"
92#include "MagickCore/thread-private.h"
93#include "MagickCore/threshold.h"
94#include "MagickCore/transform.h"
95#include "MagickCore/utility.h"
cristyda06ed12009-10-14 18:36:54 +000096
97/*
98%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
99% %
100% %
101% %
102+ G e t I m a g e B o u n d i n g B o x %
103% %
104% %
105% %
106%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107%
108% GetImageBoundingBox() returns the bounding box of an image canvas.
109%
110% The format of the GetImageBoundingBox method is:
111%
112% RectangleInfo GetImageBoundingBox(const Image *image,
113% ExceptionInfo *exception)
114%
115% A description of each parameter follows:
116%
117% o bounds: Method GetImageBoundingBox returns the bounding box of an
118% image canvas.
119%
120% o image: the image.
121%
122% o exception: return any errors or warnings in this structure.
123%
124*/
125MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
126 ExceptionInfo *exception)
127{
cristyc4c8d132010-01-07 01:58:38 +0000128 CacheView
129 *image_view;
130
cristyda06ed12009-10-14 18:36:54 +0000131 MagickBooleanType
132 status;
133
cristy4c08aed2011-07-01 19:47:50 +0000134 PixelInfo
cristyda06ed12009-10-14 18:36:54 +0000135 target[3],
136 zero;
137
138 RectangleInfo
139 bounds;
140
cristy4c08aed2011-07-01 19:47:50 +0000141 register const Quantum
cristyda06ed12009-10-14 18:36:54 +0000142 *p;
143
cristy9d314ff2011-03-09 01:30:28 +0000144 ssize_t
145 y;
146
cristyda06ed12009-10-14 18:36:54 +0000147 assert(image != (Image *) NULL);
148 assert(image->signature == MagickSignature);
149 if (image->debug != MagickFalse)
150 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
151 bounds.width=0;
152 bounds.height=0;
cristybb503372010-05-27 20:51:26 +0000153 bounds.x=(ssize_t) image->columns;
154 bounds.y=(ssize_t) image->rows;
cristy4c08aed2011-07-01 19:47:50 +0000155 GetPixelInfo(image,&target[0]);
cristy46ff2672012-12-14 15:32:26 +0000156 image_view=AcquireVirtualCacheView(image,exception);
cristyda06ed12009-10-14 18:36:54 +0000157 p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000158 if (p == (const Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000159 {
160 image_view=DestroyCacheView(image_view);
161 return(bounds);
162 }
cristy803640d2011-11-17 02:11:32 +0000163 GetPixelInfoPixel(image,p,&target[0]);
cristy4c08aed2011-07-01 19:47:50 +0000164 GetPixelInfo(image,&target[1]);
cristybb503372010-05-27 20:51:26 +0000165 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,0,1,1,
cristyda06ed12009-10-14 18:36:54 +0000166 exception);
cristy803640d2011-11-17 02:11:32 +0000167 GetPixelInfoPixel(image,p,&target[1]);
cristy4c08aed2011-07-01 19:47:50 +0000168 GetPixelInfo(image,&target[2]);
cristy4cb39ab2010-06-07 13:59:16 +0000169 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-1,1,1,
170 exception);
cristy803640d2011-11-17 02:11:32 +0000171 GetPixelInfoPixel(image,p,&target[2]);
cristyda06ed12009-10-14 18:36:54 +0000172 status=MagickTrue;
cristy4c08aed2011-07-01 19:47:50 +0000173 GetPixelInfo(image,&zero);
cristyb5d5f722009-11-04 03:03:49 +0000174#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000175 #pragma omp parallel for schedule(static,4) shared(status) \
cristy5e6b2592012-12-19 14:08:11 +0000176 magick_threads(image,image,image->rows,1)
cristyda06ed12009-10-14 18:36:54 +0000177#endif
cristybb503372010-05-27 20:51:26 +0000178 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000179 {
cristy4c08aed2011-07-01 19:47:50 +0000180 PixelInfo
cristyda06ed12009-10-14 18:36:54 +0000181 pixel;
182
183 RectangleInfo
184 bounding_box;
185
cristy4c08aed2011-07-01 19:47:50 +0000186 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000187 *restrict p;
cristyda06ed12009-10-14 18:36:54 +0000188
cristybb503372010-05-27 20:51:26 +0000189 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000190 x;
191
192 if (status == MagickFalse)
193 continue;
cristyb5d5f722009-11-04 03:03:49 +0000194#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyda06ed12009-10-14 18:36:54 +0000195# pragma omp critical (MagickCore_GetImageBoundingBox)
196#endif
197 bounding_box=bounds;
198 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000199 if (p == (const Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000200 {
201 status=MagickFalse;
202 continue;
203 }
cristyda06ed12009-10-14 18:36:54 +0000204 pixel=zero;
cristybb503372010-05-27 20:51:26 +0000205 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000206 {
cristy803640d2011-11-17 02:11:32 +0000207 GetPixelInfoPixel(image,p,&pixel);
cristyda06ed12009-10-14 18:36:54 +0000208 if ((x < bounding_box.x) &&
cristy4c08aed2011-07-01 19:47:50 +0000209 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
cristyda06ed12009-10-14 18:36:54 +0000210 bounding_box.x=x;
cristybb503372010-05-27 20:51:26 +0000211 if ((x > (ssize_t) bounding_box.width) &&
cristy4c08aed2011-07-01 19:47:50 +0000212 (IsFuzzyEquivalencePixelInfo(&pixel,&target[1]) == MagickFalse))
cristybb503372010-05-27 20:51:26 +0000213 bounding_box.width=(size_t) x;
cristyda06ed12009-10-14 18:36:54 +0000214 if ((y < bounding_box.y) &&
cristy4c08aed2011-07-01 19:47:50 +0000215 (IsFuzzyEquivalencePixelInfo(&pixel,&target[0]) == MagickFalse))
cristyda06ed12009-10-14 18:36:54 +0000216 bounding_box.y=y;
cristybb503372010-05-27 20:51:26 +0000217 if ((y > (ssize_t) bounding_box.height) &&
cristy4c08aed2011-07-01 19:47:50 +0000218 (IsFuzzyEquivalencePixelInfo(&pixel,&target[2]) == MagickFalse))
cristybb503372010-05-27 20:51:26 +0000219 bounding_box.height=(size_t) y;
cristyed231572011-07-14 02:18:59 +0000220 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000221 }
cristyb5d5f722009-11-04 03:03:49 +0000222#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyda06ed12009-10-14 18:36:54 +0000223# pragma omp critical (MagickCore_GetImageBoundingBox)
224#endif
225 {
226 if (bounding_box.x < bounds.x)
227 bounds.x=bounding_box.x;
228 if (bounding_box.y < bounds.y)
229 bounds.y=bounding_box.y;
230 if (bounding_box.width > bounds.width)
231 bounds.width=bounding_box.width;
232 if (bounding_box.height > bounds.height)
233 bounds.height=bounding_box.height;
234 }
cristy84c09fb2013-06-15 01:36:28 +0000235 }
cristyda06ed12009-10-14 18:36:54 +0000236 image_view=DestroyCacheView(image_view);
237 if ((bounds.width == 0) || (bounds.height == 0))
238 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
cristyefe601c2013-01-05 17:51:12 +0000239 "GeometryDoesNotContainImage","`%s'",image->filename);
cristyda06ed12009-10-14 18:36:54 +0000240 else
241 {
242 bounds.width-=(bounds.x-1);
243 bounds.height-=(bounds.y-1);
244 }
245 return(bounds);
246}
247
248/*
249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250% %
251% %
252% %
cristyfefab1b2011-07-05 00:33:22 +0000253% G e t I m a g e D e p t h %
cristyda06ed12009-10-14 18:36:54 +0000254% %
255% %
256% %
257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
258%
cristyfefab1b2011-07-05 00:33:22 +0000259% GetImageDepth() returns the depth of a particular image channel.
cristyda06ed12009-10-14 18:36:54 +0000260%
cristyfefab1b2011-07-05 00:33:22 +0000261% The format of the GetImageDepth method is:
cristyda06ed12009-10-14 18:36:54 +0000262%
cristybb503372010-05-27 20:51:26 +0000263% size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
cristyda06ed12009-10-14 18:36:54 +0000264%
265% A description of each parameter follows:
266%
267% o image: the image.
268%
cristyda06ed12009-10-14 18:36:54 +0000269% o exception: return any errors or warnings in this structure.
270%
271*/
cristy0aa82c12012-01-08 18:22:09 +0000272MagickExport size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
cristyda06ed12009-10-14 18:36:54 +0000273{
cristyc4c8d132010-01-07 01:58:38 +0000274 CacheView
275 *image_view;
276
cristyda06ed12009-10-14 18:36:54 +0000277 MagickBooleanType
278 status;
279
cristybb503372010-05-27 20:51:26 +0000280 register ssize_t
dirk4cfba412013-10-20 08:34:40 +0000281 i;
cristyda06ed12009-10-14 18:36:54 +0000282
cristybb503372010-05-27 20:51:26 +0000283 size_t
cristyda06ed12009-10-14 18:36:54 +0000284 *current_depth,
285 depth,
286 number_threads;
287
cristy9d314ff2011-03-09 01:30:28 +0000288 ssize_t
289 y;
290
cristyda06ed12009-10-14 18:36:54 +0000291 /*
292 Compute image depth.
293 */
294 assert(image != (Image *) NULL);
295 assert(image->signature == MagickSignature);
296 if (image->debug != MagickFalse)
297 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy9357bdd2012-07-30 12:28:34 +0000298 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
cristybb503372010-05-27 20:51:26 +0000299 current_depth=(size_t *) AcquireQuantumMemory(number_threads,
cristyda06ed12009-10-14 18:36:54 +0000300 sizeof(*current_depth));
cristybb503372010-05-27 20:51:26 +0000301 if (current_depth == (size_t *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000302 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
303 status=MagickTrue;
dirk4cfba412013-10-20 08:34:40 +0000304 for (i=0; i < (ssize_t) number_threads; i++)
305 current_depth[i]=1;
cristy8a46d822012-08-28 23:32:39 +0000306 if ((image->storage_class == PseudoClass) && (image->alpha_trait != BlendPixelTrait))
cristyda06ed12009-10-14 18:36:54 +0000307 {
cristyb5d5f722009-11-04 03:03:49 +0000308#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy9a5a52f2012-10-09 14:40:31 +0000309 #pragma omp parallel for schedule(static,4) shared(status) \
cristyac245f82012-05-05 17:13:57 +0000310 if ((image->colors) > 256) \
311 num_threads(GetMagickResourceLimit(ThreadResource))
cristyda06ed12009-10-14 18:36:54 +0000312#endif
cristybb503372010-05-27 20:51:26 +0000313 for (i=0; i < (ssize_t) image->colors; i++)
cristyda06ed12009-10-14 18:36:54 +0000314 {
cristy5c9e6f22010-09-17 17:31:01 +0000315 const int
316 id = GetOpenMPThreadId();
317
cristyda06ed12009-10-14 18:36:54 +0000318 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
319 {
dirke9f70982013-10-21 17:54:30 +0000320 MagickBooleanType
321 atDepth;
322
cristyda06ed12009-10-14 18:36:54 +0000323 QuantumAny
cristyb6d6f7c2010-06-09 13:17:57 +0000324 range;
cristyda06ed12009-10-14 18:36:54 +0000325
dirke9f70982013-10-21 17:54:30 +0000326 atDepth=MagickTrue;
cristyb6d6f7c2010-06-09 13:17:57 +0000327 range=GetQuantumRange(current_depth[id]);
cristydd0b4f22013-10-22 11:03:47 +0000328 if ((atDepth != MagickFalse) &&
329 (GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
dirke9f70982013-10-21 17:54:30 +0000330 if (IsPixelAtDepth(image->colormap[i].red,range) == MagickFalse)
cristydd0b4f22013-10-22 11:03:47 +0000331 atDepth=MagickFalse;
332 if ((atDepth != MagickFalse) &&
333 (GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
dirke9f70982013-10-21 17:54:30 +0000334 if (IsPixelAtDepth(image->colormap[i].green,range) == MagickFalse)
cristydd0b4f22013-10-22 11:03:47 +0000335 atDepth=MagickFalse;
336 if ((atDepth != MagickFalse) &&
337 (GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
dirke9f70982013-10-21 17:54:30 +0000338 if (IsPixelAtDepth(image->colormap[i].blue,range) == MagickFalse)
cristydd0b4f22013-10-22 11:03:47 +0000339 atDepth=MagickFalse;
340 if ((atDepth != MagickFalse))
dirke9f70982013-10-21 17:54:30 +0000341 break;
cristyda06ed12009-10-14 18:36:54 +0000342 current_depth[id]++;
343 }
cristyda06ed12009-10-14 18:36:54 +0000344 }
345 depth=current_depth[0];
dirk4cfba412013-10-20 08:34:40 +0000346 for (i=1; i < (ssize_t) number_threads; i++)
347 if (depth < current_depth[i])
348 depth=current_depth[i];
cristybb503372010-05-27 20:51:26 +0000349 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
cristyda06ed12009-10-14 18:36:54 +0000350 return(depth);
351 }
cristy46ff2672012-12-14 15:32:26 +0000352 image_view=AcquireVirtualCacheView(image,exception);
cristy52936202012-01-12 12:07:45 +0000353#if !defined(MAGICKCORE_HDRI_SUPPORT)
354 if (QuantumRange <= MaxMap)
cristy13868012012-01-08 21:44:07 +0000355 {
cristy52936202012-01-12 12:07:45 +0000356 size_t
357 *depth_map;
358
359 /*
360 Scale pixels to desired (optimized with depth map).
361 */
362 depth_map=(size_t *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
363 if (depth_map == (size_t *) NULL)
364 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
365 for (i=0; i <= (ssize_t) MaxMap; i++)
cristy13868012012-01-08 21:44:07 +0000366 {
cristy52936202012-01-12 12:07:45 +0000367 unsigned int
368 depth;
cristy13868012012-01-08 21:44:07 +0000369
cristy52936202012-01-12 12:07:45 +0000370 for (depth=1; depth < MAGICKCORE_QUANTUM_DEPTH; depth++)
cristy13868012012-01-08 21:44:07 +0000371 {
cristy52936202012-01-12 12:07:45 +0000372 Quantum
373 pixel;
cristy13868012012-01-08 21:44:07 +0000374
cristy52936202012-01-12 12:07:45 +0000375 QuantumAny
376 range;
cristy13868012012-01-08 21:44:07 +0000377
cristy52936202012-01-12 12:07:45 +0000378 range=GetQuantumRange(depth);
379 pixel=(Quantum) i;
380 if (pixel == ScaleAnyToQuantum(ScaleQuantumToAny(pixel,range),range))
381 break;
cristy13868012012-01-08 21:44:07 +0000382 }
cristy52936202012-01-12 12:07:45 +0000383 depth_map[i]=depth;
cristy13868012012-01-08 21:44:07 +0000384 }
cristy52936202012-01-12 12:07:45 +0000385#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000386 #pragma omp parallel for schedule(static,4) shared(status) \
cristy5e6b2592012-12-19 14:08:11 +0000387 magick_threads(image,image,image->rows,1)
cristy52936202012-01-12 12:07:45 +0000388#endif
389 for (y=0; y < (ssize_t) image->rows; y++)
390 {
391 const int
392 id = GetOpenMPThreadId();
393
394 register const Quantum
395 *restrict p;
396
397 register ssize_t
398 x;
399
400 if (status == MagickFalse)
401 continue;
402 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
403 if (p == (const Quantum *) NULL)
404 continue;
405 for (x=0; x < (ssize_t) image->columns; x++)
406 {
cristy883fde12013-04-08 00:50:13 +0000407 if (GetPixelReadMask(image,p) == 0)
cristy10a6c612012-01-29 21:41:05 +0000408 {
409 p+=GetPixelChannels(image);
410 continue;
411 }
cristy52936202012-01-12 12:07:45 +0000412 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
413 {
cristy5a23c552013-02-13 14:34:28 +0000414 PixelChannel channel=GetPixelChannelChannel(image,i);
415 PixelTrait traits=GetPixelChannelTraits(image,channel);
cristy52936202012-01-12 12:07:45 +0000416 if ((traits == UndefinedPixelTrait) ||
cristy883fde12013-04-08 00:50:13 +0000417 (channel == IndexPixelChannel) ||
cristyc3a58022013-10-09 23:22:42 +0000418 (channel == ReadMaskPixelChannel) ||
419 (channel == MetaPixelChannel))
cristy52936202012-01-12 12:07:45 +0000420 continue;
421 if (depth_map[ScaleQuantumToMap(p[i])] > current_depth[id])
422 current_depth[id]=depth_map[ScaleQuantumToMap(p[i])];
423 }
424 p+=GetPixelChannels(image);
425 }
426 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
427 status=MagickFalse;
428 }
429 image_view=DestroyCacheView(image_view);
430 depth=current_depth[0];
dirk4cfba412013-10-20 08:34:40 +0000431 for (i=1; i < (ssize_t) number_threads; i++)
432 if (depth < current_depth[i])
433 depth=current_depth[i];
cristy52936202012-01-12 12:07:45 +0000434 depth_map=(size_t *) RelinquishMagickMemory(depth_map);
435 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
436 return(depth);
cristy13868012012-01-08 21:44:07 +0000437 }
cristy13868012012-01-08 21:44:07 +0000438#endif
cristy0aa82c12012-01-08 18:22:09 +0000439 /*
440 Compute pixel depth.
441 */
cristyb5d5f722009-11-04 03:03:49 +0000442#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000443 #pragma omp parallel for schedule(static,4) shared(status) \
cristy5e6b2592012-12-19 14:08:11 +0000444 magick_threads(image,image,image->rows,1)
cristyda06ed12009-10-14 18:36:54 +0000445#endif
cristybb503372010-05-27 20:51:26 +0000446 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000447 {
cristy5c9e6f22010-09-17 17:31:01 +0000448 const int
449 id = GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +0000450
cristy4c08aed2011-07-01 19:47:50 +0000451 register const Quantum
cristyc47d1f82009-11-26 01:44:43 +0000452 *restrict p;
cristyda06ed12009-10-14 18:36:54 +0000453
cristybb503372010-05-27 20:51:26 +0000454 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000455 x;
456
457 if (status == MagickFalse)
458 continue;
cristyda06ed12009-10-14 18:36:54 +0000459 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000460 if (p == (const Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000461 continue;
cristybb503372010-05-27 20:51:26 +0000462 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000463 {
cristy883fde12013-04-08 00:50:13 +0000464 if (GetPixelReadMask(image,p) == 0)
cristy10a6c612012-01-29 21:41:05 +0000465 {
466 p+=GetPixelChannels(image);
467 continue;
468 }
cristy8a11cb12011-10-19 23:53:34 +0000469 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
cristyda06ed12009-10-14 18:36:54 +0000470 {
cristyabace412011-12-11 15:56:53 +0000471 PixelChannel
472 channel;
473
cristy8a11cb12011-10-19 23:53:34 +0000474 PixelTrait
475 traits;
cristyda06ed12009-10-14 18:36:54 +0000476
cristycf1296e2012-08-26 23:40:49 +0000477 channel=GetPixelChannelChannel(image,i);
478 traits=GetPixelChannelTraits(image,channel);
cristy10a6c612012-01-29 21:41:05 +0000479 if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
cristy883fde12013-04-08 00:50:13 +0000480 (channel == ReadMaskPixelChannel))
cristy8a11cb12011-10-19 23:53:34 +0000481 continue;
482 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
483 {
cristy8a11cb12011-10-19 23:53:34 +0000484 QuantumAny
485 range;
486
cristy8a11cb12011-10-19 23:53:34 +0000487 range=GetQuantumRange(current_depth[id]);
cristy3b2b1712012-01-08 21:52:15 +0000488 if (p[i] == ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),range))
cristy8a11cb12011-10-19 23:53:34 +0000489 break;
490 current_depth[id]++;
491 }
cristyda06ed12009-10-14 18:36:54 +0000492 }
cristyed231572011-07-14 02:18:59 +0000493 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000494 }
495 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
496 status=MagickFalse;
497 }
498 image_view=DestroyCacheView(image_view);
499 depth=current_depth[0];
dirk4cfba412013-10-20 08:34:40 +0000500 for (i=1; i < (ssize_t) number_threads; i++)
501 if (depth < current_depth[i])
502 depth=current_depth[i];
cristybb503372010-05-27 20:51:26 +0000503 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
cristyda06ed12009-10-14 18:36:54 +0000504 return(depth);
505}
506
507/*
508%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
509% %
510% %
511% %
512% G e t I m a g e Q u a n t u m D e p t h %
513% %
514% %
515% %
516%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
517%
518% GetImageQuantumDepth() returns the depth of the image rounded to a legal
519% quantum depth: 8, 16, or 32.
520%
521% The format of the GetImageQuantumDepth method is:
522%
cristybb503372010-05-27 20:51:26 +0000523% size_t GetImageQuantumDepth(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000524% const MagickBooleanType constrain)
525%
526% A description of each parameter follows:
527%
528% o image: the image.
529%
530% o constrain: A value other than MagickFalse, constrains the depth to
531% a maximum of MAGICKCORE_QUANTUM_DEPTH.
532%
533*/
534
535static inline double MagickMin(const double x,const double y)
536{
537 if (x < y)
538 return(x);
539 return(y);
540}
541
cristybb503372010-05-27 20:51:26 +0000542MagickExport size_t GetImageQuantumDepth(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000543 const MagickBooleanType constrain)
544{
cristybb503372010-05-27 20:51:26 +0000545 size_t
cristyda06ed12009-10-14 18:36:54 +0000546 depth;
547
548 depth=image->depth;
549 if (depth <= 8)
550 depth=8;
551 else
552 if (depth <= 16)
553 depth=16;
554 else
555 if (depth <= 32)
556 depth=32;
557 else
558 if (depth <= 64)
559 depth=64;
560 if (constrain != MagickFalse)
cristy9e940dd2011-12-13 01:22:25 +0000561 depth=(size_t) MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH);
cristyda06ed12009-10-14 18:36:54 +0000562 return(depth);
563}
564
565/*
566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
567% %
568% %
569% %
570% G e t I m a g e T y p e %
571% %
572% %
573% %
574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
575%
576% GetImageType() returns the potential type of image:
577%
578% Bilevel Grayscale GrayscaleMatte
579% Palette PaletteMatte TrueColor
580% TrueColorMatte ColorSeparation ColorSeparationMatte
581%
582% To ensure the image type matches its potential, use SetImageType():
583%
584% (void) SetImageType(image,GetImageType(image));
585%
586% The format of the GetImageType method is:
587%
588% ImageType GetImageType(const Image *image,ExceptionInfo *exception)
589%
590% A description of each parameter follows:
591%
592% o image: the image.
593%
594% o exception: return any errors or warnings in this structure.
595%
596*/
597MagickExport ImageType GetImageType(const Image *image,ExceptionInfo *exception)
598{
599 assert(image != (Image *) NULL);
600 assert(image->signature == MagickSignature);
601 if (image->debug != MagickFalse)
602 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
603 if (image->colorspace == CMYKColorspace)
604 {
cristy8a46d822012-08-28 23:32:39 +0000605 if (image->alpha_trait != BlendPixelTrait)
cristyda06ed12009-10-14 18:36:54 +0000606 return(ColorSeparationType);
607 return(ColorSeparationMatteType);
608 }
cristy4c08aed2011-07-01 19:47:50 +0000609 if (IsImageMonochrome(image,exception) != MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000610 return(BilevelType);
cristy4c08aed2011-07-01 19:47:50 +0000611 if (IsImageGray(image,exception) != MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000612 {
cristy8a46d822012-08-28 23:32:39 +0000613 if (image->alpha_trait == BlendPixelTrait)
cristyda06ed12009-10-14 18:36:54 +0000614 return(GrayscaleMatteType);
615 return(GrayscaleType);
616 }
617 if (IsPaletteImage(image,exception) != MagickFalse)
618 {
cristy8a46d822012-08-28 23:32:39 +0000619 if (image->alpha_trait == BlendPixelTrait)
cristyda06ed12009-10-14 18:36:54 +0000620 return(PaletteMatteType);
621 return(PaletteType);
622 }
cristy8a46d822012-08-28 23:32:39 +0000623 if (image->alpha_trait == BlendPixelTrait)
cristyda06ed12009-10-14 18:36:54 +0000624 return(TrueColorMatteType);
625 return(TrueColorType);
626}
627
628/*
629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
630% %
631% %
632% %
cristy4c08aed2011-07-01 19:47:50 +0000633% I s I m a g e G r a y %
cristyda06ed12009-10-14 18:36:54 +0000634% %
635% %
636% %
637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
638%
cristy4c08aed2011-07-01 19:47:50 +0000639% IsImageGray() returns MagickTrue if all the pixels in the image have the
cristyda06ed12009-10-14 18:36:54 +0000640% same red, green, and blue intensities.
641%
cristy4c08aed2011-07-01 19:47:50 +0000642% The format of the IsImageGray method is:
cristyda06ed12009-10-14 18:36:54 +0000643%
cristy4c08aed2011-07-01 19:47:50 +0000644% MagickBooleanType IsImageGray(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000645% ExceptionInfo *exception)
646%
647% A description of each parameter follows:
648%
649% o image: the image.
650%
651% o exception: return any errors or warnings in this structure.
652%
653*/
cristy4c08aed2011-07-01 19:47:50 +0000654MagickExport MagickBooleanType IsImageGray(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000655 ExceptionInfo *exception)
656{
cristy0910f242010-04-01 18:55:09 +0000657 CacheView
658 *image_view;
659
cristyda06ed12009-10-14 18:36:54 +0000660 ImageType
661 type;
662
cristy4c08aed2011-07-01 19:47:50 +0000663 register const Quantum
cristyda06ed12009-10-14 18:36:54 +0000664 *p;
665
cristybb503372010-05-27 20:51:26 +0000666 register ssize_t
cristy0910f242010-04-01 18:55:09 +0000667 x;
668
cristy95802a72010-09-05 19:07:17 +0000669 ssize_t
670 y;
671
cristyda06ed12009-10-14 18:36:54 +0000672 assert(image != (Image *) NULL);
673 assert(image->signature == MagickSignature);
674 if (image->debug != MagickFalse)
675 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
676 if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
677 (image->type == GrayscaleMatteType))
678 return(MagickTrue);
cristy3bf83e62012-05-22 15:23:25 +0000679 if ((IsGrayColorspace(image->colorspace) == MagickFalse) &&
cristy5836c742013-03-27 21:10:56 +0000680 (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse))
cristyda06ed12009-10-14 18:36:54 +0000681 return(MagickFalse);
682 type=BilevelType;
cristy46ff2672012-12-14 15:32:26 +0000683 image_view=AcquireVirtualCacheView(image,exception);
cristybb503372010-05-27 20:51:26 +0000684 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000685 {
cristy0910f242010-04-01 18:55:09 +0000686 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000687 if (p == (const Quantum *) NULL)
cristy0910f242010-04-01 18:55:09 +0000688 break;
cristybb503372010-05-27 20:51:26 +0000689 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000690 {
cristy4c08aed2011-07-01 19:47:50 +0000691 if (IsPixelGray(image,p) == MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000692 {
cristy5f1c1ff2010-12-23 21:38:06 +0000693 type=UndefinedType;
cristyda06ed12009-10-14 18:36:54 +0000694 break;
cristy0910f242010-04-01 18:55:09 +0000695 }
cristybd5a96c2011-08-21 00:04:26 +0000696 if ((type == BilevelType) &&
697 (IsPixelMonochrome(image,p) == MagickFalse))
cristy0910f242010-04-01 18:55:09 +0000698 type=GrayscaleType;
cristyed231572011-07-14 02:18:59 +0000699 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000700 }
cristy5f1c1ff2010-12-23 21:38:06 +0000701 if (type == UndefinedType)
cristyda06ed12009-10-14 18:36:54 +0000702 break;
cristyda06ed12009-10-14 18:36:54 +0000703 }
cristy0910f242010-04-01 18:55:09 +0000704 image_view=DestroyCacheView(image_view);
cristy5f1c1ff2010-12-23 21:38:06 +0000705 if (type == UndefinedType)
cristyda06ed12009-10-14 18:36:54 +0000706 return(MagickFalse);
cristye65d6532013-04-25 11:28:16 +0000707 ((Image *) image)->colorspace=GRAYColorspace;
cristy9b61be92013-10-12 00:12:52 +0000708 if (SyncImagePixelCache((Image *) image,exception) == MagickFalse)
709 return(MagickFalse);
cristyda06ed12009-10-14 18:36:54 +0000710 ((Image *) image)->type=type;
cristy8a46d822012-08-28 23:32:39 +0000711 if ((type == GrayscaleType) && (image->alpha_trait == BlendPixelTrait))
cristyda06ed12009-10-14 18:36:54 +0000712 ((Image *) image)->type=GrayscaleMatteType;
cristy9b61be92013-10-12 00:12:52 +0000713 return(MagickTrue);
cristyda06ed12009-10-14 18:36:54 +0000714}
715
716/*
717%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
718% %
719% %
720% %
cristy4c08aed2011-07-01 19:47:50 +0000721% I s I m a g e M o n o c h r o m e %
cristyda06ed12009-10-14 18:36:54 +0000722% %
723% %
724% %
725%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
726%
cristy4c08aed2011-07-01 19:47:50 +0000727% IsImageMonochrome() returns MagickTrue if all the pixels in the image have
cristyda06ed12009-10-14 18:36:54 +0000728% the same red, green, and blue intensities and the intensity is either
729% 0 or QuantumRange.
730%
cristy4c08aed2011-07-01 19:47:50 +0000731% The format of the IsImageMonochrome method is:
cristyda06ed12009-10-14 18:36:54 +0000732%
cristy4c08aed2011-07-01 19:47:50 +0000733% MagickBooleanType IsImageMonochrome(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000734% ExceptionInfo *exception)
735%
736% A description of each parameter follows:
737%
738% o image: the image.
739%
740% o exception: return any errors or warnings in this structure.
741%
742*/
cristy4c08aed2011-07-01 19:47:50 +0000743MagickExport MagickBooleanType IsImageMonochrome(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000744 ExceptionInfo *exception)
745{
cristy0910f242010-04-01 18:55:09 +0000746 CacheView
747 *image_view;
748
cristyda06ed12009-10-14 18:36:54 +0000749 ImageType
750 type;
751
cristybb503372010-05-27 20:51:26 +0000752 register ssize_t
cristy0910f242010-04-01 18:55:09 +0000753 x;
754
cristy4c08aed2011-07-01 19:47:50 +0000755 register const Quantum
cristyda06ed12009-10-14 18:36:54 +0000756 *p;
757
cristy9d314ff2011-03-09 01:30:28 +0000758 ssize_t
759 y;
760
cristyda06ed12009-10-14 18:36:54 +0000761 assert(image != (Image *) NULL);
762 assert(image->signature == MagickSignature);
763 if (image->debug != MagickFalse)
764 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
765 if (image->type == BilevelType)
766 return(MagickTrue);
cristy3bf83e62012-05-22 15:23:25 +0000767 if ((IsGrayColorspace(image->colorspace) == MagickFalse) &&
cristy5836c742013-03-27 21:10:56 +0000768 (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse))
cristyda06ed12009-10-14 18:36:54 +0000769 return(MagickFalse);
770 type=BilevelType;
cristy46ff2672012-12-14 15:32:26 +0000771 image_view=AcquireVirtualCacheView(image,exception);
cristybb503372010-05-27 20:51:26 +0000772 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000773 {
cristy0910f242010-04-01 18:55:09 +0000774 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000775 if (p == (const Quantum *) NULL)
cristy0910f242010-04-01 18:55:09 +0000776 break;
cristybb503372010-05-27 20:51:26 +0000777 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000778 {
cristy4c08aed2011-07-01 19:47:50 +0000779 if (IsPixelMonochrome(image,p) == MagickFalse)
cristyda06ed12009-10-14 18:36:54 +0000780 {
cristy5f1c1ff2010-12-23 21:38:06 +0000781 type=UndefinedType;
cristyda06ed12009-10-14 18:36:54 +0000782 break;
cristy0910f242010-04-01 18:55:09 +0000783 }
cristyed231572011-07-14 02:18:59 +0000784 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000785 }
cristy5f1c1ff2010-12-23 21:38:06 +0000786 if (type == UndefinedType)
cristyda06ed12009-10-14 18:36:54 +0000787 break;
cristyda06ed12009-10-14 18:36:54 +0000788 }
cristy0910f242010-04-01 18:55:09 +0000789 image_view=DestroyCacheView(image_view);
cristy5f1c1ff2010-12-23 21:38:06 +0000790 if (type == UndefinedType)
cristyda06ed12009-10-14 18:36:54 +0000791 return(MagickFalse);
cristye65d6532013-04-25 11:28:16 +0000792 ((Image *) image)->colorspace=GRAYColorspace;
cristy9b61be92013-10-12 00:12:52 +0000793 if (SyncImagePixelCache((Image *) image,exception) == MagickFalse)
794 return(MagickFalse);
cristyda06ed12009-10-14 18:36:54 +0000795 ((Image *) image)->type=type;
cristy9b61be92013-10-12 00:12:52 +0000796 return(MagickTrue);
cristyda06ed12009-10-14 18:36:54 +0000797}
798
799/*
800%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
801% %
802% %
803% %
cristy4c08aed2011-07-01 19:47:50 +0000804% I s I m a g e O p a q u e %
cristyda06ed12009-10-14 18:36:54 +0000805% %
806% %
807% %
808%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
809%
cristy4c08aed2011-07-01 19:47:50 +0000810% IsImageOpaque() returns MagickTrue if none of the pixels in the image have
anthonyfb2cc882012-04-29 11:46:27 +0000811% an alpha value other than OpaqueAlpha (QuantumRange).
812%
813% Will return true immediatally is alpha channel is not available.
cristyda06ed12009-10-14 18:36:54 +0000814%
cristy4c08aed2011-07-01 19:47:50 +0000815% The format of the IsImageOpaque method is:
cristyda06ed12009-10-14 18:36:54 +0000816%
cristy4c08aed2011-07-01 19:47:50 +0000817% MagickBooleanType IsImageOpaque(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000818% ExceptionInfo *exception)
819%
820% A description of each parameter follows:
821%
822% o image: the image.
823%
824% o exception: return any errors or warnings in this structure.
825%
826*/
cristy4c08aed2011-07-01 19:47:50 +0000827MagickExport MagickBooleanType IsImageOpaque(const Image *image,
cristyda06ed12009-10-14 18:36:54 +0000828 ExceptionInfo *exception)
829{
cristyc4c8d132010-01-07 01:58:38 +0000830 CacheView
831 *image_view;
832
cristy4c08aed2011-07-01 19:47:50 +0000833 register const Quantum
cristyda06ed12009-10-14 18:36:54 +0000834 *p;
835
cristybb503372010-05-27 20:51:26 +0000836 register ssize_t
cristyda06ed12009-10-14 18:36:54 +0000837 x;
838
cristy9d314ff2011-03-09 01:30:28 +0000839 ssize_t
840 y;
841
cristyda06ed12009-10-14 18:36:54 +0000842 /*
843 Determine if image is opaque.
844 */
845 assert(image != (Image *) NULL);
846 assert(image->signature == MagickSignature);
847 if (image->debug != MagickFalse)
848 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy8a46d822012-08-28 23:32:39 +0000849 if (image->alpha_trait != BlendPixelTrait)
cristyda06ed12009-10-14 18:36:54 +0000850 return(MagickTrue);
cristy46ff2672012-12-14 15:32:26 +0000851 image_view=AcquireVirtualCacheView(image,exception);
cristybb503372010-05-27 20:51:26 +0000852 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +0000853 {
854 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000855 if (p == (const Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +0000856 break;
cristybb503372010-05-27 20:51:26 +0000857 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +0000858 {
cristy4c08aed2011-07-01 19:47:50 +0000859 if (GetPixelAlpha(image,p) != OpaqueAlpha)
cristyda06ed12009-10-14 18:36:54 +0000860 break;
cristyed231572011-07-14 02:18:59 +0000861 p+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +0000862 }
cristybb503372010-05-27 20:51:26 +0000863 if (x < (ssize_t) image->columns)
cristyda06ed12009-10-14 18:36:54 +0000864 break;
865 }
866 image_view=DestroyCacheView(image_view);
cristybb503372010-05-27 20:51:26 +0000867 return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
cristyda06ed12009-10-14 18:36:54 +0000868}
869
870/*
871%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
872% %
873% %
874% %
cristyfefab1b2011-07-05 00:33:22 +0000875% S e t I m a g e D e p t h %
cristyda06ed12009-10-14 18:36:54 +0000876% %
877% %
878% %
879%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
880%
cristyfefab1b2011-07-05 00:33:22 +0000881% SetImageDepth() sets the depth of the image.
cristyda06ed12009-10-14 18:36:54 +0000882%
cristyfefab1b2011-07-05 00:33:22 +0000883% The format of the SetImageDepth method is:
cristyda06ed12009-10-14 18:36:54 +0000884%
cristy8a11cb12011-10-19 23:53:34 +0000885% MagickBooleanType SetImageDepth(Image *image,const size_t depth,
886% ExceptionInfo *exception)
cristyda06ed12009-10-14 18:36:54 +0000887%
888% A description of each parameter follows:
889%
890% o image: the image.
891%
892% o channel: the channel.
893%
894% o depth: the image depth.
895%
cristy8a11cb12011-10-19 23:53:34 +0000896% o exception: return any errors or warnings in this structure.
897%
cristyda06ed12009-10-14 18:36:54 +0000898*/
cristyda06ed12009-10-14 18:36:54 +0000899MagickExport MagickBooleanType SetImageDepth(Image *image,
cristy8a11cb12011-10-19 23:53:34 +0000900 const size_t depth,ExceptionInfo *exception)
cristyda06ed12009-10-14 18:36:54 +0000901{
cristyc4c8d132010-01-07 01:58:38 +0000902 CacheView
903 *image_view;
904
cristyda06ed12009-10-14 18:36:54 +0000905 MagickBooleanType
906 status;
907
908 QuantumAny
cristyb6d6f7c2010-06-09 13:17:57 +0000909 range;
cristyda06ed12009-10-14 18:36:54 +0000910
cristy9d314ff2011-03-09 01:30:28 +0000911 ssize_t
912 y;
913
cristyda06ed12009-10-14 18:36:54 +0000914 assert(image != (Image *) NULL);
915 if (image->debug != MagickFalse)
916 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
917 assert(image->signature == MagickSignature);
cristy0aa82c12012-01-08 18:22:09 +0000918 if (depth >= MAGICKCORE_QUANTUM_DEPTH)
cristyda06ed12009-10-14 18:36:54 +0000919 {
cristy8eacae42012-06-19 16:22:15 +0000920 image->depth=depth;
cristyda06ed12009-10-14 18:36:54 +0000921 return(MagickTrue);
922 }
cristy5d6f7ed2012-01-08 02:53:08 +0000923 range=GetQuantumRange(depth);
924 if (image->storage_class == PseudoClass)
925 {
cristy5d6f7ed2012-01-08 02:53:08 +0000926 register ssize_t
927 i;
928
cristy5d6f7ed2012-01-08 02:53:08 +0000929#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy9a5a52f2012-10-09 14:40:31 +0000930 #pragma omp parallel for schedule(static,4) shared(status) \
cristycb7dfcc2013-01-06 18:34:59 +0000931 magick_threads(image,image,1,1)
cristy5d6f7ed2012-01-08 02:53:08 +0000932#endif
933 for (i=0; i < (ssize_t) image->colors; i++)
934 {
935 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000936 image->colormap[i].red=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
937 ClampToQuantum(image->colormap[i].red),range),range);
cristy5d6f7ed2012-01-08 02:53:08 +0000938 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
cristy16881e62012-05-06 14:41:29 +0000939 image->colormap[i].green=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
940 ClampToQuantum(image->colormap[i].green),range),range);
cristy5d6f7ed2012-01-08 02:53:08 +0000941 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000942 image->colormap[i].blue=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
943 ClampToQuantum(image->colormap[i].blue),range),range);
cristy5d6f7ed2012-01-08 02:53:08 +0000944 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
cristy0aa82c12012-01-08 18:22:09 +0000945 image->colormap[i].alpha=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
946 ClampToQuantum(image->colormap[i].alpha),range),range);
cristy5d6f7ed2012-01-08 02:53:08 +0000947 }
cristy5d6f7ed2012-01-08 02:53:08 +0000948 }
cristy0aa82c12012-01-08 18:22:09 +0000949 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +0000950 image_view=AcquireAuthenticCacheView(image,exception);
cristy52936202012-01-12 12:07:45 +0000951#if !defined(MAGICKCORE_HDRI_SUPPORT)
952 if (QuantumRange <= MaxMap)
cristy0aa82c12012-01-08 18:22:09 +0000953 {
cristy52936202012-01-12 12:07:45 +0000954 Quantum
955 *depth_map;
956
cristy0aa82c12012-01-08 18:22:09 +0000957 register ssize_t
cristy52936202012-01-12 12:07:45 +0000958 i;
cristy0aa82c12012-01-08 18:22:09 +0000959
cristy52936202012-01-12 12:07:45 +0000960 /*
961 Scale pixels to desired (optimized with depth map).
962 */
963 depth_map=(Quantum *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
964 if (depth_map == (Quantum *) NULL)
965 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
966 for (i=0; i <= (ssize_t) MaxMap; i++)
967 depth_map[i]=ScaleAnyToQuantum(ScaleQuantumToAny((Quantum) i,range),
968 range);
969#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +0000970 #pragma omp parallel for schedule(static,4) shared(status) \
cristy5e6b2592012-12-19 14:08:11 +0000971 magick_threads(image,image,image->rows,1)
cristy52936202012-01-12 12:07:45 +0000972#endif
973 for (y=0; y < (ssize_t) image->rows; y++)
cristy0aa82c12012-01-08 18:22:09 +0000974 {
cristy52936202012-01-12 12:07:45 +0000975 register ssize_t
976 x;
cristy0aa82c12012-01-08 18:22:09 +0000977
cristy52936202012-01-12 12:07:45 +0000978 register Quantum
979 *restrict q;
cristy0aa82c12012-01-08 18:22:09 +0000980
cristy52936202012-01-12 12:07:45 +0000981 if (status == MagickFalse)
cristy0aa82c12012-01-08 18:22:09 +0000982 continue;
cristy52936202012-01-12 12:07:45 +0000983 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
984 exception);
985 if (q == (Quantum *) NULL)
986 {
987 status=MagickFalse;
988 continue;
989 }
990 for (x=0; x < (ssize_t) image->columns; x++)
991 {
cristyaa874e12012-01-20 21:00:51 +0000992 register ssize_t
993 i;
994
cristy883fde12013-04-08 00:50:13 +0000995 if (GetPixelReadMask(image,q) == 0)
cristy10a6c612012-01-29 21:41:05 +0000996 {
997 q+=GetPixelChannels(image);
998 continue;
999 }
cristy52936202012-01-12 12:07:45 +00001000 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1001 {
1002 PixelChannel
1003 channel;
1004
1005 PixelTrait
1006 traits;
1007
cristycf1296e2012-08-26 23:40:49 +00001008 channel=GetPixelChannelChannel(image,i);
1009 traits=GetPixelChannelTraits(image,channel);
cristy52936202012-01-12 12:07:45 +00001010 if ((traits == UndefinedPixelTrait) ||
cristy883fde12013-04-08 00:50:13 +00001011 (channel == IndexPixelChannel) || (channel == ReadMaskPixelChannel))
cristy52936202012-01-12 12:07:45 +00001012 continue;
1013 q[i]=depth_map[ScaleQuantumToMap(q[i])];
1014 }
1015 q+=GetPixelChannels(image);
cristy0aa82c12012-01-08 18:22:09 +00001016 }
cristy52936202012-01-12 12:07:45 +00001017 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1018 {
1019 status=MagickFalse;
1020 continue;
1021 }
1022 }
1023 image_view=DestroyCacheView(image_view);
1024 depth_map=(Quantum *) RelinquishMagickMemory(depth_map);
1025 if (status != MagickFalse)
1026 image->depth=depth;
1027 return(status);
cristy0aa82c12012-01-08 18:22:09 +00001028 }
cristy0aa82c12012-01-08 18:22:09 +00001029#endif
cristyda06ed12009-10-14 18:36:54 +00001030 /*
1031 Scale pixels to desired depth.
1032 */
cristyb5d5f722009-11-04 03:03:49 +00001033#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristyac245f82012-05-05 17:13:57 +00001034 #pragma omp parallel for schedule(static,4) shared(status) \
cristy5e6b2592012-12-19 14:08:11 +00001035 magick_threads(image,image,image->rows,1)
cristyda06ed12009-10-14 18:36:54 +00001036#endif
cristybb503372010-05-27 20:51:26 +00001037 for (y=0; y < (ssize_t) image->rows; y++)
cristyda06ed12009-10-14 18:36:54 +00001038 {
cristybb503372010-05-27 20:51:26 +00001039 register ssize_t
cristyda06ed12009-10-14 18:36:54 +00001040 x;
1041
cristy4c08aed2011-07-01 19:47:50 +00001042 register Quantum
cristyc47d1f82009-11-26 01:44:43 +00001043 *restrict q;
cristyda06ed12009-10-14 18:36:54 +00001044
1045 if (status == MagickFalse)
1046 continue;
cristy8a11cb12011-10-19 23:53:34 +00001047 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00001048 if (q == (Quantum *) NULL)
cristyda06ed12009-10-14 18:36:54 +00001049 {
1050 status=MagickFalse;
1051 continue;
1052 }
cristybb503372010-05-27 20:51:26 +00001053 for (x=0; x < (ssize_t) image->columns; x++)
cristyda06ed12009-10-14 18:36:54 +00001054 {
cristy8a11cb12011-10-19 23:53:34 +00001055 register ssize_t
1056 i;
1057
cristy883fde12013-04-08 00:50:13 +00001058 if (GetPixelReadMask(image,q) == 0)
cristy10a6c612012-01-29 21:41:05 +00001059 {
1060 q+=GetPixelChannels(image);
1061 continue;
1062 }
cristy8a11cb12011-10-19 23:53:34 +00001063 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1064 {
cristyabace412011-12-11 15:56:53 +00001065 PixelChannel
1066 channel;
1067
cristy8a11cb12011-10-19 23:53:34 +00001068 PixelTrait
1069 traits;
1070
cristycf1296e2012-08-26 23:40:49 +00001071 channel=GetPixelChannelChannel(image,i);
1072 traits=GetPixelChannelTraits(image,channel);
cristy10a6c612012-01-29 21:41:05 +00001073 if ((traits == UndefinedPixelTrait) || (channel == IndexPixelChannel) ||
cristy883fde12013-04-08 00:50:13 +00001074 (channel == ReadMaskPixelChannel))
cristy8a11cb12011-10-19 23:53:34 +00001075 continue;
cristy0aa82c12012-01-08 18:22:09 +00001076 q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(q[i],range),range);
cristy8a11cb12011-10-19 23:53:34 +00001077 }
cristyed231572011-07-14 02:18:59 +00001078 q+=GetPixelChannels(image);
cristyda06ed12009-10-14 18:36:54 +00001079 }
1080 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1081 {
1082 status=MagickFalse;
1083 continue;
1084 }
1085 }
1086 image_view=DestroyCacheView(image_view);
cristy5d6f7ed2012-01-08 02:53:08 +00001087 if (status != MagickFalse)
1088 image->depth=depth;
cristyda06ed12009-10-14 18:36:54 +00001089 return(status);
1090}
cristy623aaec2012-06-21 00:49:08 +00001091
1092/*
1093%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1094% %
1095% %
1096% %
1097% S e t I m a g e T y p e %
1098% %
1099% %
1100% %
1101%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1102%
1103% SetImageType() sets the type of image. Choose from these types:
1104%
1105% Bilevel Grayscale GrayscaleMatte
1106% Palette PaletteMatte TrueColor
1107% TrueColorMatte ColorSeparation ColorSeparationMatte
1108% OptimizeType
1109%
1110% The format of the SetImageType method is:
1111%
1112% MagickBooleanType SetImageType(Image *image,const ImageType type,
1113% ExceptionInfo *exception)
1114%
1115% A description of each parameter follows:
1116%
1117% o image: the image.
1118%
1119% o type: Image type.
1120%
1121% o exception: return any errors or warnings in this structure.
1122%
1123*/
1124MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type,
1125 ExceptionInfo *exception)
1126{
1127 const char
1128 *artifact;
1129
1130 ImageInfo
1131 *image_info;
1132
1133 MagickBooleanType
1134 status;
1135
1136 QuantizeInfo
1137 *quantize_info;
1138
1139 assert(image != (Image *) NULL);
1140 if (image->debug != MagickFalse)
1141 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1142 assert(image->signature == MagickSignature);
1143 status=MagickTrue;
1144 image_info=AcquireImageInfo();
1145 image_info->dither=image->dither;
1146 artifact=GetImageArtifact(image,"dither");
1147 if (artifact != (const char *) NULL)
1148 (void) SetImageOption(image_info,"dither",artifact);
1149 switch (type)
1150 {
1151 case BilevelType:
1152 {
cristy91a21512013-11-29 16:10:42 +00001153 if (IsImageGray(image,exception) == MagickFalse)
1154 status=TransformImageColorspace(image,GRAYColorspace,exception);
cristy313cb352013-11-29 16:11:13 +00001155 (void) NormalizeImage(image,exception);
cristy623aaec2012-06-21 00:49:08 +00001156 if (IsImageMonochrome(image,exception) == MagickFalse)
1157 {
1158 quantize_info=AcquireQuantizeInfo(image_info);
1159 quantize_info->number_colors=2;
1160 quantize_info->colorspace=GRAYColorspace;
1161 status=QuantizeImage(quantize_info,image,exception);
1162 quantize_info=DestroyQuantizeInfo(quantize_info);
1163 }
cristy8a46d822012-08-28 23:32:39 +00001164 image->alpha_trait=UndefinedPixelTrait;
cristy623aaec2012-06-21 00:49:08 +00001165 break;
1166 }
1167 case GrayscaleType:
1168 {
1169 if (IsImageGray(image,exception) == MagickFalse)
1170 status=TransformImageColorspace(image,GRAYColorspace,exception);
cristy8a46d822012-08-28 23:32:39 +00001171 image->alpha_trait=UndefinedPixelTrait;
cristy623aaec2012-06-21 00:49:08 +00001172 break;
1173 }
1174 case GrayscaleMatteType:
1175 {
1176 if (IsImageGray(image,exception) == MagickFalse)
1177 status=TransformImageColorspace(image,GRAYColorspace,exception);
cristy8a46d822012-08-28 23:32:39 +00001178 if (image->alpha_trait != BlendPixelTrait)
cristy623aaec2012-06-21 00:49:08 +00001179 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1180 break;
1181 }
1182 case PaletteType:
1183 {
cristy3d9f5ba2012-06-26 13:37:31 +00001184 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy623aaec2012-06-21 00:49:08 +00001185 status=TransformImageColorspace(image,sRGBColorspace,exception);
1186 if ((image->storage_class == DirectClass) || (image->colors > 256))
1187 {
1188 quantize_info=AcquireQuantizeInfo(image_info);
1189 quantize_info->number_colors=256;
1190 status=QuantizeImage(quantize_info,image,exception);
1191 quantize_info=DestroyQuantizeInfo(quantize_info);
1192 }
cristy8a46d822012-08-28 23:32:39 +00001193 image->alpha_trait=UndefinedPixelTrait;
cristy623aaec2012-06-21 00:49:08 +00001194 break;
1195 }
1196 case PaletteBilevelMatteType:
1197 {
1198 ChannelType
1199 channel_mask;
1200
cristy3d9f5ba2012-06-26 13:37:31 +00001201 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy623aaec2012-06-21 00:49:08 +00001202 status=TransformImageColorspace(image,sRGBColorspace,exception);
cristy8a46d822012-08-28 23:32:39 +00001203 if (image->alpha_trait != BlendPixelTrait)
cristy623aaec2012-06-21 00:49:08 +00001204 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
cristycf1296e2012-08-26 23:40:49 +00001205 channel_mask=SetImageChannelMask(image,AlphaChannel);
cristy623aaec2012-06-21 00:49:08 +00001206 (void) BilevelImage(image,(double) QuantumRange/2.0,exception);
cristycf1296e2012-08-26 23:40:49 +00001207 (void) SetImageChannelMask(image,channel_mask);
cristy623aaec2012-06-21 00:49:08 +00001208 quantize_info=AcquireQuantizeInfo(image_info);
1209 status=QuantizeImage(quantize_info,image,exception);
1210 quantize_info=DestroyQuantizeInfo(quantize_info);
1211 break;
1212 }
1213 case PaletteMatteType:
1214 {
cristy3d9f5ba2012-06-26 13:37:31 +00001215 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy623aaec2012-06-21 00:49:08 +00001216 status=TransformImageColorspace(image,sRGBColorspace,exception);
cristy8a46d822012-08-28 23:32:39 +00001217 if (image->alpha_trait != BlendPixelTrait)
cristy623aaec2012-06-21 00:49:08 +00001218 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1219 quantize_info=AcquireQuantizeInfo(image_info);
1220 quantize_info->colorspace=TransparentColorspace;
1221 status=QuantizeImage(quantize_info,image,exception);
1222 quantize_info=DestroyQuantizeInfo(quantize_info);
1223 break;
1224 }
1225 case TrueColorType:
1226 {
cristy3d9f5ba2012-06-26 13:37:31 +00001227 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy623aaec2012-06-21 00:49:08 +00001228 status=TransformImageColorspace(image,sRGBColorspace,exception);
1229 if (image->storage_class != DirectClass)
1230 status=SetImageStorageClass(image,DirectClass,exception);
cristy8a46d822012-08-28 23:32:39 +00001231 image->alpha_trait=UndefinedPixelTrait;
cristy623aaec2012-06-21 00:49:08 +00001232 break;
1233 }
1234 case TrueColorMatteType:
1235 {
cristy3d9f5ba2012-06-26 13:37:31 +00001236 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy623aaec2012-06-21 00:49:08 +00001237 status=TransformImageColorspace(image,sRGBColorspace,exception);
1238 if (image->storage_class != DirectClass)
1239 status=SetImageStorageClass(image,DirectClass,exception);
cristy8a46d822012-08-28 23:32:39 +00001240 if (image->alpha_trait != BlendPixelTrait)
cristy623aaec2012-06-21 00:49:08 +00001241 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1242 break;
1243 }
1244 case ColorSeparationType:
1245 {
1246 if (image->colorspace != CMYKColorspace)
1247 {
cristy3d9f5ba2012-06-26 13:37:31 +00001248 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy623aaec2012-06-21 00:49:08 +00001249 status=TransformImageColorspace(image,sRGBColorspace,exception);
1250 status=TransformImageColorspace(image,CMYKColorspace,exception);
1251 }
1252 if (image->storage_class != DirectClass)
1253 status=SetImageStorageClass(image,DirectClass,exception);
cristy8a46d822012-08-28 23:32:39 +00001254 image->alpha_trait=UndefinedPixelTrait;
cristy623aaec2012-06-21 00:49:08 +00001255 break;
1256 }
1257 case ColorSeparationMatteType:
1258 {
1259 if (image->colorspace != CMYKColorspace)
1260 {
cristy3d9f5ba2012-06-26 13:37:31 +00001261 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
cristy623aaec2012-06-21 00:49:08 +00001262 status=TransformImageColorspace(image,sRGBColorspace,exception);
1263 status=TransformImageColorspace(image,CMYKColorspace,exception);
1264 }
1265 if (image->storage_class != DirectClass)
1266 status=SetImageStorageClass(image,DirectClass,exception);
cristy8a46d822012-08-28 23:32:39 +00001267 if (image->alpha_trait != BlendPixelTrait)
cristy623aaec2012-06-21 00:49:08 +00001268 status=SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1269 break;
1270 }
1271 case OptimizeType:
1272 case UndefinedType:
1273 break;
1274 }
cristy623aaec2012-06-21 00:49:08 +00001275 image_info=DestroyImageInfo(image_info);
cristy362333f2013-10-12 00:17:29 +00001276 if (status == MagickFalse)
1277 return(status);
1278 image->type=type;
1279 return(MagickTrue);
cristy623aaec2012-06-21 00:49:08 +00001280}