blob: 43f9a291bab22ffcc949408710313ab13b6f6632 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% SSSSS TTTTT AAA TTTTT IIIII SSSSS TTTTT IIIII CCCC %
7% SS T A A T I SS T I C %
8% SSS T AAAAA T I SSS T I C %
9% SS T A A T I SS T I C %
10% SSSSS T A A T IIIII SSSSS T IIIII CCCC %
11% %
12% %
13% MagickCore Image Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1992 %
18% %
19% %
20% Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization %
21% 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*/
43#include "magick/studio.h"
44#include "magick/property.h"
45#include "magick/animate.h"
46#include "magick/blob.h"
47#include "magick/blob-private.h"
48#include "magick/cache.h"
49#include "magick/cache-private.h"
50#include "magick/cache-view.h"
51#include "magick/client.h"
52#include "magick/color.h"
53#include "magick/color-private.h"
54#include "magick/colorspace.h"
55#include "magick/colorspace-private.h"
56#include "magick/composite.h"
57#include "magick/composite-private.h"
58#include "magick/compress.h"
59#include "magick/constitute.h"
60#include "magick/deprecate.h"
61#include "magick/display.h"
62#include "magick/draw.h"
63#include "magick/enhance.h"
64#include "magick/exception.h"
65#include "magick/exception-private.h"
66#include "magick/gem.h"
67#include "magick/geometry.h"
68#include "magick/list.h"
69#include "magick/image-private.h"
70#include "magick/magic.h"
71#include "magick/magick.h"
72#include "magick/memory_.h"
73#include "magick/module.h"
74#include "magick/monitor.h"
75#include "magick/option.h"
76#include "magick/paint.h"
77#include "magick/pixel-private.h"
78#include "magick/profile.h"
79#include "magick/quantize.h"
80#include "magick/random_.h"
81#include "magick/segment.h"
82#include "magick/semaphore.h"
83#include "magick/signature-private.h"
84#include "magick/statistic.h"
85#include "magick/string_.h"
86#include "magick/thread-private.h"
87#include "magick/timer.h"
88#include "magick/utility.h"
89#include "magick/version.h"
90
91/*
92%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93% %
94% %
95% %
96+ G e t I m a g e B o u n d i n g B o x %
97% %
98% %
99% %
100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101%
102% GetImageBoundingBox() returns the bounding box of an image canvas.
103%
104% The format of the GetImageBoundingBox method is:
105%
106% RectangleInfo GetImageBoundingBox(const Image *image,
107% ExceptionInfo *exception)
108%
109% A description of each parameter follows:
110%
111% o bounds: Method GetImageBoundingBox returns the bounding box of an
112% image canvas.
113%
114% o image: the image.
115%
116% o exception: return any errors or warnings in this structure.
117%
118*/
119MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
120 ExceptionInfo *exception)
121{
122 long
123 y;
124
125 MagickBooleanType
126 status;
127
128 MagickPixelPacket
129 target[3],
130 zero;
131
132 RectangleInfo
133 bounds;
134
135 register const PixelPacket
136 *p;
137
138 CacheView
139 *image_view;
140
141 assert(image != (Image *) NULL);
142 assert(image->signature == MagickSignature);
143 if (image->debug != MagickFalse)
144 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
145 bounds.width=0;
146 bounds.height=0;
147 bounds.x=(long) image->columns;
148 bounds.y=(long) image->rows;
149 GetMagickPixelPacket(image,&target[0]);
150 image_view=AcquireCacheView(image);
151 p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
152 if (p == (const PixelPacket *) NULL)
153 {
154 image_view=DestroyCacheView(image_view);
155 return(bounds);
156 }
157 SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
158 &target[0]);
159 GetMagickPixelPacket(image,&target[1]);
160 p=GetCacheViewVirtualPixels(image_view,(long) image->columns-1,0,1,1,
161 exception);
162 SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
163 &target[1]);
164 GetMagickPixelPacket(image,&target[2]);
165 p=GetCacheViewVirtualPixels(image_view,0,(long) image->rows-1,1,1,exception);
166 SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
167 &target[2]);
168 status=MagickTrue;
169 GetMagickPixelPacket(image,&zero);
170#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy07490992009-09-11 19:51:45 +0000171 #pragma omp parallel for schedule(static,1) shared(status)
cristy3ed852e2009-09-05 21:47:34 +0000172#endif
173 for (y=0; y < (long) image->rows; y++)
174 {
175 MagickPixelPacket
176 pixel;
177
178 RectangleInfo
179 bounding_box;
180
181 register const IndexPacket
182 *__restrict indexes;
183
184 register const PixelPacket
185 *__restrict p;
186
187 register long
188 x;
189
190 if (status == MagickFalse)
191 continue;
192#if defined(HAVE_OPENMP)
193# pragma omp critical (MagickCore_GetImageBoundingBox)
194#endif
195 bounding_box=bounds;
196 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
197 if (p == (const PixelPacket *) NULL)
198 {
199 status=MagickFalse;
200 continue;
201 }
202 indexes=GetCacheViewVirtualIndexQueue(image_view);
203 pixel=zero;
204 for (x=0; x < (long) image->columns; x++)
205 {
206 SetMagickPixelPacket(image,p,indexes+x,&pixel);
207 if ((x < bounding_box.x) &&
208 (IsMagickColorSimilar(&pixel,&target[0]) == MagickFalse))
209 bounding_box.x=x;
210 if ((x > (long) bounding_box.width) &&
211 (IsMagickColorSimilar(&pixel,&target[1]) == MagickFalse))
212 bounding_box.width=(unsigned long) x;
213 if ((y < bounding_box.y) &&
214 (IsMagickColorSimilar(&pixel,&target[0]) == MagickFalse))
215 bounding_box.y=y;
216 if ((y > (long) bounding_box.height) &&
217 (IsMagickColorSimilar(&pixel,&target[2]) == MagickFalse))
218 bounding_box.height=(unsigned long) y;
219 p++;
220 }
221#if defined(HAVE_OPENMP)
222# pragma omp critical (MagickCore_GetImageBoundingBox)
223#endif
224 {
225 if (bounding_box.x < bounds.x)
226 bounds.x=bounding_box.x;
227 if (bounding_box.y < bounds.y)
228 bounds.y=bounding_box.y;
229 if (bounding_box.width > bounds.width)
230 bounds.width=bounding_box.width;
231 if (bounding_box.height > bounds.height)
232 bounds.height=bounding_box.height;
233 }
234 }
235 image_view=DestroyCacheView(image_view);
236 if ((bounds.width == 0) || (bounds.height == 0))
237 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
238 "GeometryDoesNotContainImage","`%s'",image->filename);
239 else
240 {
241 bounds.width-=(bounds.x-1);
242 bounds.height-=(bounds.y-1);
243 }
244 return(bounds);
245}
246
247/*
248%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
249% %
250% %
251% %
252% G e t I m a g e C h a n n e l D e p t h %
253% %
254% %
255% %
256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
257%
258% GetImageChannelDepth() returns the depth of a particular image channel.
259%
260% The format of the GetImageChannelDepth method is:
261%
262% unsigned long GetImageDepth(const Image *image,ExceptionInfo *exception)
263% unsigned long GetImageChannelDepth(const Image *image,
264% const ChannelType channel,ExceptionInfo *exception)
265%
266% A description of each parameter follows:
267%
268% o image: the image.
269%
270% o channel: the channel.
271%
272% o exception: return any errors or warnings in this structure.
273%
274*/
275
276MagickExport unsigned long GetImageDepth(const Image *image,
277 ExceptionInfo *exception)
278{
279 return(GetImageChannelDepth(image,AllChannels,exception));
280}
281
282MagickExport unsigned long GetImageChannelDepth(const Image *image,
283 const ChannelType channel,ExceptionInfo *exception)
284{
285 long
286 y;
287
288 MagickBooleanType
289 status;
290
291 register long
292 id;
293
294 unsigned long
295 *current_depth,
296 depth,
297 number_threads;
298
299 CacheView
300 *image_view;
301
302 /*
303 Compute image depth.
304 */
305 assert(image != (Image *) NULL);
306 assert(image->signature == MagickSignature);
307 if (image->debug != MagickFalse)
308 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
309 number_threads=GetOpenMPMaximumThreads();
310 current_depth=(unsigned long *) AcquireQuantumMemory(number_threads,
311 sizeof(*current_depth));
312 if (current_depth == (unsigned long *) NULL)
313 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
314 status=MagickTrue;
315 for (id=0; id < (long) number_threads; id++)
316 current_depth[id]=1;
317 if ((image->storage_class == PseudoClass) && (image->matte == MagickFalse))
318 {
319 register const PixelPacket
320 *__restrict p;
321
322 register long
323 i;
324
325 p=image->colormap;
326#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy07490992009-09-11 19:51:45 +0000327 #pragma omp parallel for schedule(static,1) shared(status)
cristy3ed852e2009-09-05 21:47:34 +0000328#endif
329 for (i=0; i < (long) image->colors; i++)
330 {
331 if (status == MagickFalse)
332 continue;
333 id=GetOpenMPThreadId();
334 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
335 {
336 MagickStatusType
337 status;
338
339 QuantumAny
340 range;
341
342 status=0;
343 range=GetQuantumRange(current_depth[id]);
344 if ((channel & RedChannel) != 0)
345 status|=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,
346 range),range);
347 if ((channel & GreenChannel) != 0)
348 status|=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
349 range),range);
350 if ((channel & BlueChannel) != 0)
351 status|=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
352 range),range);
353 if (status == 0)
354 break;
355 current_depth[id]++;
356 }
357 p++;
358 }
359 depth=current_depth[0];
360 for (id=1; id < (long) number_threads; id++)
361 if (depth < current_depth[id])
362 depth=current_depth[id];
363 current_depth=(unsigned long *) RelinquishMagickMemory(current_depth);
364 return(depth);
365 }
366 image_view=AcquireCacheView(image);
367#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy07490992009-09-11 19:51:45 +0000368 #pragma omp parallel for schedule(static,1) shared(status)
cristy3ed852e2009-09-05 21:47:34 +0000369#endif
370 for (y=0; y < (long) image->rows; y++)
371 {
372 register const IndexPacket
373 *__restrict indexes;
374
375 register const PixelPacket
376 *__restrict p;
377
378 register long
379 id,
380 x;
381
382 if (status == MagickFalse)
383 continue;
384 id=GetOpenMPThreadId();
385 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
386 if (p == (const PixelPacket *) NULL)
387 continue;
388 indexes=GetCacheViewVirtualIndexQueue(image_view);
389 for (x=0; x < (long) image->columns; x++)
390 {
391 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
392 {
393 MagickStatusType
394 status;
395
396 QuantumAny
397 range;
398
399 status=0;
400 range=GetQuantumRange(current_depth[id]);
401 if ((channel & RedChannel) != 0)
402 status|=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,range),
403 range);
404 if ((channel & GreenChannel) != 0)
405 status|=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
406 range),range);
407 if ((channel & BlueChannel) != 0)
408 status|=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,range),
409 range);
410 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
411 status|=p->opacity != ScaleAnyToQuantum(ScaleQuantumToAny(p->opacity,
412 range),range);
413 if (((channel & IndexChannel) != 0) &&
414 (image->colorspace == CMYKColorspace))
415 status|=indexes[x] != ScaleAnyToQuantum(ScaleQuantumToAny(indexes[x],
416 range),range);
417 if (status == 0)
418 break;
419 current_depth[id]++;
420 }
421 p++;
422 }
423 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
424 status=MagickFalse;
425 }
426 image_view=DestroyCacheView(image_view);
427 depth=current_depth[0];
428 for (id=1; id < (long) number_threads; id++)
429 if (depth < current_depth[id])
430 depth=current_depth[id];
431 current_depth=(unsigned long *) RelinquishMagickMemory(current_depth);
432 return(depth);
433}
434
435/*
436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
437% %
438% %
439% %
440+ G e t I m a g e C h a n n e l E x t r e m a %
441% %
442% %
443% %
444%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
445%
446% GetImageChannelExtrema() returns the extrema of one or more image channels.
447%
448% The format of the GetImageChannelExtrema method is:
449%
450% MagickBooleanType GetImageChannelExtrema(const Image *image,
451% const ChannelType channel,unsigned long *minima,unsigned long *maxima,
452% ExceptionInfo *exception)
453%
454% A description of each parameter follows:
455%
456% o image: the image.
457%
458% o channel: the channel.
459%
460% o minima: the minimum value in the channel.
461%
462% o maxima: the maximum value in the channel.
463%
464% o exception: return any errors or warnings in this structure.
465%
466*/
467
468MagickExport MagickBooleanType GetImageExtrema(const Image *image,
469 unsigned long *minima,unsigned long *maxima,ExceptionInfo *exception)
470{
471 return(GetImageChannelExtrema(image,AllChannels,minima,maxima,exception));
472}
473
474MagickExport MagickBooleanType GetImageChannelExtrema(const Image *image,
475 const ChannelType channel,unsigned long *minima,unsigned long *maxima,
476 ExceptionInfo *exception)
477{
478 double
479 max,
480 min;
481
482 MagickBooleanType
483 status;
484
485 assert(image != (Image *) NULL);
486 assert(image->signature == MagickSignature);
487 if (image->debug != MagickFalse)
488 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
489 status=GetImageChannelRange(image,channel,&min,&max,exception);
490 *minima=(unsigned long) (min+0.5);
491 *maxima=(unsigned long) (max+0.5);
492 return(status);
493}
494
495/*
496%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
497% %
498% %
499% %
500% G e t I m a g e C h a n n e l M e a n %
501% %
502% %
503% %
504%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
505%
506% GetImageChannelMean() returns the mean and standard deviation of one or more
507% image channels.
508%
509% The format of the GetImageChannelMean method is:
510%
511% MagickBooleanType GetImageChannelMean(const Image *image,
512% const ChannelType channel,double *mean,double *standard_deviation,
513% ExceptionInfo *exception)
514%
515% A description of each parameter follows:
516%
517% o image: the image.
518%
519% o channel: the channel.
520%
521% o mean: the average value in the channel.
522%
523% o standard_deviation: the standard deviation of the channel.
524%
525% o exception: return any errors or warnings in this structure.
526%
527*/
528
529MagickExport MagickBooleanType GetImageMean(const Image *image,double *mean,
530 double *standard_deviation,ExceptionInfo *exception)
531{
532 MagickBooleanType
533 status;
534
535 status=GetImageChannelMean(image,AllChannels,mean,standard_deviation,
536 exception);
537 return(status);
538}
539
540MagickExport MagickBooleanType GetImageChannelMean(const Image *image,
541 const ChannelType channel,double *mean,double *standard_deviation,
542 ExceptionInfo *exception)
543{
544 double
545 area;
546
547 long
548 y;
549
550 assert(image != (Image *) NULL);
551 assert(image->signature == MagickSignature);
552 if (image->debug != MagickFalse)
553 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
554 *mean=0.0;
555 *standard_deviation=0.0;
556 area=0.0;
557 for (y=0; y < (long) image->rows; y++)
558 {
559 register const IndexPacket
560 *__restrict indexes;
561
562 register const PixelPacket
563 *__restrict p;
564
565 register long
566 x;
567
568 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
569 if (p == (const PixelPacket *) NULL)
570 break;
571 indexes=GetVirtualIndexQueue(image);
572 for (x=0; x < (long) image->columns; x++)
573 {
574 if ((channel & RedChannel) != 0)
575 {
576 *mean+=p->red;
577 *standard_deviation+=(double) p->red*p->red;
578 area++;
579 }
580 if ((channel & GreenChannel) != 0)
581 {
582 *mean+=p->green;
583 *standard_deviation+=(double) p->green*p->green;
584 area++;
585 }
586 if ((channel & BlueChannel) != 0)
587 {
588 *mean+=p->blue;
589 *standard_deviation+=(double) p->blue*p->blue;
590 area++;
591 }
592 if ((channel & OpacityChannel) != 0)
593 {
594 *mean+=p->opacity;
595 *standard_deviation+=(double) p->opacity*p->opacity;
596 area++;
597 }
598 if (((channel & IndexChannel) != 0) &&
599 (image->colorspace == CMYKColorspace))
600 {
601 *mean+=indexes[x];
602 *standard_deviation+=(double) indexes[x]*indexes[x];
603 area++;
604 }
605 p++;
606 }
607 }
608 if (y < (long) image->rows)
609 return(MagickFalse);
610 if (area != 0)
611 {
612 *mean/=area;
613 *standard_deviation/=area;
614 }
615 *standard_deviation=sqrt(*standard_deviation-(*mean*(*mean)));
616 return(y == (long) image->rows ? MagickTrue : MagickFalse);
617}
618
619/*
620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
621% %
622% %
623% %
624% G e t I m a g e C h a n n e l K u r t o s i s %
625% %
626% %
627% %
628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629%
630% GetImageChannelKurtosis() returns the kurtosis and skewness of one or more
631% image channels.
632%
633% The format of the GetImageChannelKurtosis method is:
634%
635% MagickBooleanType GetImageChannelKurtosis(const Image *image,
636% const ChannelType channel,double *kurtosis,double *skewness,
637% ExceptionInfo *exception)
638%
639% A description of each parameter follows:
640%
641% o image: the image.
642%
643% o channel: the channel.
644%
645% o kurtosis: the kurtosis of the channel.
646%
647% o skewness: the skewness of the channel.
648%
649% o exception: return any errors or warnings in this structure.
650%
651*/
652
653MagickExport MagickBooleanType GetImageKurtosis(const Image *image,
654 double *kurtosis,double *skewness,ExceptionInfo *exception)
655{
656 MagickBooleanType
657 status;
658
659 status=GetImageChannelKurtosis(image,AllChannels,kurtosis,skewness,
660 exception);
661 return(status);
662}
663
664MagickExport MagickBooleanType GetImageChannelKurtosis(const Image *image,
665 const ChannelType channel,double *kurtosis,double *skewness,
666 ExceptionInfo *exception)
667{
668 double
669 area,
670 mean,
671 standard_deviation,
672 sum_squares,
673 sum_cubes,
674 sum_fourth_power;
675
676 long
677 y;
678
679 assert(image != (Image *) NULL);
680 assert(image->signature == MagickSignature);
681 if (image->debug != MagickFalse)
682 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
683 *kurtosis=0.0;
684 *skewness=0.0;
685 area=0.0;
686 mean=0.0;
687 standard_deviation=0.0;
688 sum_squares=0.0;
689 sum_cubes=0.0;
690 sum_fourth_power=0.0;
691 for (y=0; y < (long) image->rows; y++)
692 {
693 register const IndexPacket
694 *__restrict indexes;
695
696 register const PixelPacket
697 *__restrict p;
698
699 register long
700 x;
701
702 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
703 if (p == (const PixelPacket *) NULL)
704 break;
705 indexes=GetVirtualIndexQueue(image);
706 for (x=0; x < (long) image->columns; x++)
707 {
708 if ((channel & RedChannel) != 0)
709 {
710 mean+=p->red;
711 sum_squares+=(double) p->red*p->red;
712 sum_cubes+=(double) p->red*p->red*p->red;
713 sum_fourth_power+=(double) p->red*p->red*p->red*p->red;
714 area++;
715 }
716 if ((channel & GreenChannel) != 0)
717 {
718 mean+=p->green;
719 sum_squares+=(double) p->green*p->green;
720 sum_cubes+=(double) p->green*p->green*p->green;
721 sum_fourth_power+=(double) p->green*p->green*p->green*p->green;
722 area++;
723 }
724 if ((channel & BlueChannel) != 0)
725 {
726 mean+=p->blue;
727 sum_squares+=(double) p->blue*p->blue;
728 sum_cubes+=(double) p->blue*p->blue*p->blue;
729 sum_fourth_power+=(double) p->blue*p->blue*p->blue*p->blue;
730 area++;
731 }
732 if ((channel & OpacityChannel) != 0)
733 {
734 mean+=p->opacity;
735 sum_squares+=(double) p->opacity*p->opacity;
736 sum_cubes+=(double) p->opacity*p->opacity*p->opacity;
737 sum_fourth_power+=(double) p->opacity*p->opacity*p->opacity*
738 p->opacity;
739 area++;
740 }
741 if (((channel & IndexChannel) != 0) &&
742 (image->colorspace == CMYKColorspace))
743 {
744 mean+=indexes[x];
745 sum_squares+=(double) indexes[x]*indexes[x];
746 sum_cubes+=(double) indexes[x]*indexes[x]*indexes[x];
747 sum_fourth_power+=(double) indexes[x]*indexes[x]*indexes[x]*
748 indexes[x];
749 area++;
750 }
751 p++;
752 }
753 }
754 if (y < (long) image->rows)
755 return(MagickFalse);
756 if (area != 0.0)
757 {
758 mean/=area;
759 sum_squares/=area;
760 sum_cubes/=area;
761 sum_fourth_power/=area;
762 }
763 standard_deviation=sqrt(sum_squares-(mean*mean));
764 if (standard_deviation != 0.0)
765 {
766 *kurtosis=sum_fourth_power-4.0*mean*sum_cubes+6.0*mean*mean*sum_squares-
767 3.0*mean*mean*mean*mean;
768 *kurtosis/=standard_deviation*standard_deviation*standard_deviation*
769 standard_deviation;
770 *kurtosis-=3.0;
771 *skewness=sum_cubes-3.0*mean*sum_squares+2.0*mean*mean*mean;
772 *skewness/=standard_deviation*standard_deviation*standard_deviation;
773 }
774 return(y == (long) image->rows ? MagickTrue : MagickFalse);
775}
776
777/*
778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
779% %
780% %
781% %
782% G e t I m a g e C h a n n e l R a n g e %
783% %
784% %
785% %
786%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
787%
788% GetImageChannelRange() returns the range of one or more image channels.
789%
790% The format of the GetImageChannelRange method is:
791%
792% MagickBooleanType GetImageChannelRange(const Image *image,
793% const ChannelType channel,double *minima,double *maxima,
794% ExceptionInfo *exception)
795%
796% A description of each parameter follows:
797%
798% o image: the image.
799%
800% o channel: the channel.
801%
802% o minima: the minimum value in the channel.
803%
804% o maxima: the maximum value in the channel.
805%
806% o exception: return any errors or warnings in this structure.
807%
808*/
809
810MagickExport MagickBooleanType GetImageRange(const Image *image,
811 double *minima,double *maxima,ExceptionInfo *exception)
812{
813 return(GetImageChannelRange(image,AllChannels,minima,maxima,exception));
814}
815
816MagickExport MagickBooleanType GetImageChannelRange(const Image *image,
817 const ChannelType channel,double *minima,double *maxima,
818 ExceptionInfo *exception)
819{
820 long
821 y;
822
823 MagickPixelPacket
824 pixel;
825
826 assert(image != (Image *) NULL);
827 assert(image->signature == MagickSignature);
828 if (image->debug != MagickFalse)
829 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
830 *maxima=(-1.0E-37);
831 *minima=1.0E+37;
832 GetMagickPixelPacket(image,&pixel);
833 for (y=0; y < (long) image->rows; y++)
834 {
835 register const IndexPacket
836 *__restrict indexes;
837
838 register const PixelPacket
839 *__restrict p;
840
841 register long
842 x;
843
844 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
845 if (p == (const PixelPacket *) NULL)
846 break;
847 indexes=GetVirtualIndexQueue(image);
848 for (x=0; x < (long) image->columns; x++)
849 {
850 SetMagickPixelPacket(image,p,indexes+x,&pixel);
851 if ((channel & RedChannel) != 0)
852 {
853 if (pixel.red < *minima)
854 *minima=(double) pixel.red;
855 if (pixel.red > *maxima)
856 *maxima=(double) pixel.red;
857 }
858 if ((channel & GreenChannel) != 0)
859 {
860 if (pixel.green < *minima)
861 *minima=(double) pixel.green;
862 if (pixel.green > *maxima)
863 *maxima=(double) pixel.green;
864 }
865 if ((channel & BlueChannel) != 0)
866 {
867 if (pixel.blue < *minima)
868 *minima=(double) pixel.blue;
869 if (pixel.blue > *maxima)
870 *maxima=(double) pixel.blue;
871 }
872 if ((channel & OpacityChannel) != 0)
873 {
874 if (pixel.opacity < *minima)
875 *minima=(double) pixel.opacity;
876 if (pixel.opacity > *maxima)
877 *maxima=(double) pixel.opacity;
878 }
879 if (((channel & IndexChannel) != 0) &&
880 (image->colorspace == CMYKColorspace))
881 {
882 if ((double) indexes[x] < *minima)
883 *minima=(double) indexes[x];
884 if ((double) indexes[x] > *maxima)
885 *maxima=(double) indexes[x];
886 }
887 p++;
888 }
889 }
890 return(y == (long) image->rows ? MagickTrue : MagickFalse);
891}
892
893/*
894%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
895% %
896% %
897% %
898% G e t I m a g e C h a n n e l S t a t i s t i c s %
899% %
900% %
901% %
902%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
903%
904% GetImageChannelStatistics() returns statistics for each channel in the
905% image. The statistics include the channel depth, its minima, maxima, mean,
906% standard deviation, kurtosis and skewness. You can access the red channel
907% mean, for example, like this:
908%
909% channel_statistics=GetImageChannelStatistics(image,excepton);
910% red_mean=channel_statistics[RedChannel].mean;
911%
912% Use MagickRelinquishMemory() to free the statistics buffer.
913%
914% The format of the GetImageChannelStatistics method is:
915%
916% ChannelStatistics *GetImageChannelStatistics(const Image *image,
917% ExceptionInfo *exception)
918%
919% A description of each parameter follows:
920%
921% o image: the image.
922%
923% o exception: return any errors or warnings in this structure.
924%
925*/
926
927static inline double MagickMax(const double x,const double y)
928{
929 if (x > y)
930 return(x);
931 return(y);
932}
933
934static inline double MagickMin(const double x,const double y)
935{
936 if (x < y)
937 return(x);
938 return(y);
939}
940
941MagickExport ChannelStatistics *GetImageChannelStatistics(const Image *image,
942 ExceptionInfo *exception)
943{
944 ChannelStatistics
945 *channel_statistics;
946
947 double
948 area,
949 sum_squares,
950 sum_cubes;
951
952 long
953 y;
954
955 MagickStatusType
956 status;
957
958 QuantumAny
959 range;
960
961 register long
962 i;
963
964 size_t
965 length;
966
967 unsigned long
968 channels,
969 depth;
970
971 assert(image != (Image *) NULL);
972 assert(image->signature == MagickSignature);
973 if (image->debug != MagickFalse)
974 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
975 length=AllChannels+1UL;
976 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(length,
977 sizeof(*channel_statistics));
978 if (channel_statistics == (ChannelStatistics *) NULL)
979 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
980 (void) ResetMagickMemory(channel_statistics,0,length*
981 sizeof(*channel_statistics));
982 for (i=0; i <= AllChannels; i++)
983 {
984 channel_statistics[i].depth=1;
985 channel_statistics[i].maxima=(-1.0E-37);
986 channel_statistics[i].minima=1.0E+37;
987 channel_statistics[i].mean=0.0;
988 channel_statistics[i].standard_deviation=0.0;
989 channel_statistics[i].kurtosis=0.0;
990 channel_statistics[i].skewness=0.0;
991 }
992 for (y=0; y < (long) image->rows; y++)
993 {
994 register const IndexPacket
995 *__restrict indexes;
996
997 register const PixelPacket
998 *__restrict p;
999
1000 register long
1001 x;
1002
1003 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1004 if (p == (const PixelPacket *) NULL)
1005 break;
1006 indexes=GetVirtualIndexQueue(image);
1007 for (x=0; x < (long) image->columns; )
1008 {
1009 if (channel_statistics[RedChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1010 {
1011 depth=channel_statistics[RedChannel].depth;
1012 range=GetQuantumRange(depth);
1013 status=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,range),
1014 range) ? MagickTrue : MagickFalse;
1015 if (status != MagickFalse)
1016 {
1017 channel_statistics[RedChannel].depth++;
1018 continue;
1019 }
1020 }
1021 if (channel_statistics[GreenChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1022 {
1023 depth=channel_statistics[GreenChannel].depth;
1024 range=GetQuantumRange(depth);
1025 status=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
1026 range),range) ? MagickTrue : MagickFalse;
1027 if (status != MagickFalse)
1028 {
1029 channel_statistics[GreenChannel].depth++;
1030 continue;
1031 }
1032 }
1033 if (channel_statistics[BlueChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1034 {
1035 depth=channel_statistics[BlueChannel].depth;
1036 range=GetQuantumRange(depth);
1037 status=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
1038 range),range) ? MagickTrue : MagickFalse;
1039 if (status != MagickFalse)
1040 {
1041 channel_statistics[BlueChannel].depth++;
1042 continue;
1043 }
1044 }
1045 if (image->matte != MagickFalse)
1046 {
1047 if (channel_statistics[OpacityChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1048 {
1049 depth=channel_statistics[OpacityChannel].depth;
1050 range=GetQuantumRange(depth);
1051 status=p->opacity != ScaleAnyToQuantum(ScaleQuantumToAny(
1052 p->opacity,range),range) ? MagickTrue : MagickFalse;
1053 if (status != MagickFalse)
1054 {
1055 channel_statistics[OpacityChannel].depth++;
1056 continue;
1057 }
1058 }
1059 }
1060 if (image->colorspace == CMYKColorspace)
1061 {
1062 if (channel_statistics[BlackChannel].depth != MAGICKCORE_QUANTUM_DEPTH)
1063 {
1064 depth=channel_statistics[BlackChannel].depth;
1065 range=GetQuantumRange(depth);
1066 status=indexes[x] != ScaleAnyToQuantum(ScaleQuantumToAny(
1067 indexes[x],range),range) ? MagickTrue : MagickFalse;
1068 if (status != MagickFalse)
1069 {
1070 channel_statistics[BlackChannel].depth++;
1071 continue;
1072 }
1073 }
1074 }
1075 if ((double) p->red < channel_statistics[RedChannel].minima)
1076 channel_statistics[RedChannel].minima=(double) p->red;
1077 if ((double) p->red > channel_statistics[RedChannel].maxima)
1078 channel_statistics[RedChannel].maxima=(double) p->red;
1079 channel_statistics[RedChannel].mean+=p->red;
1080 channel_statistics[RedChannel].standard_deviation+=(double) p->red*p->red;
1081 channel_statistics[RedChannel].kurtosis+=(double) p->red*p->red*
1082 p->red*p->red;
1083 channel_statistics[RedChannel].skewness+=(double) p->red*p->red*p->red;
1084 if ((double) p->green < channel_statistics[GreenChannel].minima)
1085 channel_statistics[GreenChannel].minima=(double) p->green;
1086 if ((double) p->green > channel_statistics[GreenChannel].maxima)
1087 channel_statistics[GreenChannel].maxima=(double) p->green;
1088 channel_statistics[GreenChannel].mean+=p->green;
1089 channel_statistics[GreenChannel].standard_deviation+=(double) p->green*
1090 p->green;
1091 channel_statistics[GreenChannel].kurtosis+=(double) p->green*p->green*
1092 p->green*p->green;
1093 channel_statistics[GreenChannel].skewness+=(double) p->green*p->green*
1094 p->green;
1095 if ((double) p->blue < channel_statistics[BlueChannel].minima)
1096 channel_statistics[BlueChannel].minima=(double) p->blue;
1097 if ((double) p->blue > channel_statistics[BlueChannel].maxima)
1098 channel_statistics[BlueChannel].maxima=(double) p->blue;
1099 channel_statistics[BlueChannel].mean+=p->blue;
1100 channel_statistics[BlueChannel].standard_deviation+=(double) p->blue*
1101 p->blue;
1102 channel_statistics[BlueChannel].kurtosis+=(double) p->blue*p->blue*
1103 p->blue*p->blue;
1104 channel_statistics[BlueChannel].skewness+=(double) p->blue*p->blue*
1105 p->blue;
1106 if (image->matte != MagickFalse)
1107 {
1108 if ((double) p->opacity < channel_statistics[OpacityChannel].minima)
1109 channel_statistics[OpacityChannel].minima=(double) p->opacity;
1110 if ((double) p->opacity > channel_statistics[OpacityChannel].maxima)
1111 channel_statistics[OpacityChannel].maxima=(double) p->opacity;
1112 channel_statistics[OpacityChannel].mean+=p->opacity;
1113 channel_statistics[OpacityChannel].standard_deviation+=(double)
1114 p->opacity*p->opacity;
1115 channel_statistics[OpacityChannel].kurtosis+=(double) p->opacity*
1116 p->opacity*p->opacity*p->opacity;
1117 channel_statistics[OpacityChannel].skewness+=(double) p->opacity*
1118 p->opacity*p->opacity;
1119 }
1120 if (image->colorspace == CMYKColorspace)
1121 {
1122 if ((double) indexes[x] < channel_statistics[BlackChannel].minima)
1123 channel_statistics[BlackChannel].minima=(double) indexes[x];
1124 if ((double) indexes[x] > channel_statistics[BlackChannel].maxima)
1125 channel_statistics[BlackChannel].maxima=(double) indexes[x];
1126 channel_statistics[BlackChannel].mean+=indexes[x];
1127 channel_statistics[BlackChannel].standard_deviation+=(double)
1128 indexes[x]*indexes[x];
1129 channel_statistics[BlackChannel].kurtosis+=(double) indexes[x]*
1130 indexes[x]*indexes[x]*indexes[x];
1131 channel_statistics[BlackChannel].skewness+=(double) indexes[x]*
1132 indexes[x]*indexes[x];
1133 }
1134 x++;
1135 p++;
1136 }
1137 }
1138 area=(double) image->columns*image->rows;
1139 for (i=0; i < AllChannels; i++)
1140 {
1141 channel_statistics[i].mean/=area;
1142 channel_statistics[i].standard_deviation/=area;
1143 channel_statistics[i].kurtosis/=area;
1144 channel_statistics[i].skewness/=area;
1145 }
1146 for (i=0; i < AllChannels; i++)
1147 {
1148 channel_statistics[AllChannels].depth=(unsigned long) MagickMax((double)
1149 channel_statistics[AllChannels].depth,(double)
1150 channel_statistics[i].depth);
1151 channel_statistics[AllChannels].minima=MagickMin(
1152 channel_statistics[AllChannels].minima,channel_statistics[i].minima);
1153 channel_statistics[AllChannels].maxima=MagickMax(
1154 channel_statistics[AllChannels].maxima,channel_statistics[i].maxima);
1155 channel_statistics[AllChannels].mean+=channel_statistics[i].mean;
1156 channel_statistics[AllChannels].standard_deviation+=
1157 channel_statistics[i].standard_deviation;
1158 channel_statistics[AllChannels].kurtosis+=channel_statistics[i].kurtosis;
1159 channel_statistics[AllChannels].skewness+=channel_statistics[i].skewness;
1160 }
1161 channels=4;
1162 if (image->colorspace == CMYKColorspace)
1163 channels++;
1164 channel_statistics[AllChannels].mean/=channels;
1165 channel_statistics[AllChannels].standard_deviation/=channels;
1166 channel_statistics[AllChannels].kurtosis/=channels;
1167 channel_statistics[AllChannels].skewness/=channels;
1168 for (i=0; i <= AllChannels; i++)
1169 {
1170 sum_squares=0.0;
1171 sum_squares=channel_statistics[i].standard_deviation;
1172 sum_cubes=0.0;
1173 sum_cubes=channel_statistics[i].skewness;
1174 channel_statistics[i].standard_deviation=sqrt(
1175 channel_statistics[i].standard_deviation-
1176 (channel_statistics[i].mean*channel_statistics[i].mean));
1177 if (channel_statistics[i].standard_deviation == 0.0)
1178 {
1179 channel_statistics[i].kurtosis=0.0;
1180 channel_statistics[i].skewness=0.0;
1181 }
1182 else
1183 {
1184 channel_statistics[i].skewness=(channel_statistics[i].skewness-
1185 3.0*channel_statistics[i].mean*sum_squares+
1186 2.0*channel_statistics[i].mean*channel_statistics[i].mean*
1187 channel_statistics[i].mean)/
1188 (channel_statistics[i].standard_deviation*
1189 channel_statistics[i].standard_deviation*
1190 channel_statistics[i].standard_deviation);
1191 channel_statistics[i].kurtosis=(channel_statistics[i].kurtosis-
1192 4.0*channel_statistics[i].mean*sum_cubes+
1193 6.0*channel_statistics[i].mean*channel_statistics[i].mean*sum_squares-
1194 3.0*channel_statistics[i].mean*channel_statistics[i].mean*
1195 1.0*channel_statistics[i].mean*channel_statistics[i].mean)/
1196 (channel_statistics[i].standard_deviation*
1197 channel_statistics[i].standard_deviation*
1198 channel_statistics[i].standard_deviation*
1199 channel_statistics[i].standard_deviation)-3.0;
1200 }
1201 }
1202 return(channel_statistics);
1203}
1204
1205/*
1206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1207% %
1208% %
1209% %
1210% G e t I m a g e Q u a n t u m D e p t h %
1211% %
1212% %
1213% %
1214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1215%
1216% GetImageQuantumDepth() returns the depth of the image rounded to a legal
1217% quantum depth: 8, 16, or 32.
1218%
1219% The format of the GetImageQuantumDepth method is:
1220%
1221% unsigned long GetImageQuantumDepth(const Image *image,
1222% const MagickBooleanType constrain)
1223%
1224% A description of each parameter follows:
1225%
1226% o image: the image.
1227%
1228% o constrain: A value other than MagickFalse, constrains the depth to
1229% a maximum of MAGICKCORE_QUANTUM_DEPTH.
1230%
1231*/
1232MagickExport unsigned long GetImageQuantumDepth(const Image *image,
1233 const MagickBooleanType constrain)
1234{
1235 unsigned long
1236 depth;
1237
1238 depth=image->depth;
1239 if (depth <= 8)
1240 depth=8;
1241 else
1242 if (depth <= 16)
1243 depth=16;
1244 else
1245 if (depth <= 32)
1246 depth=32;
1247 else
1248 if (depth <= 64)
1249 depth=64;
1250 if (constrain != MagickFalse)
1251 depth=(unsigned long) MagickMin((double) depth,(double)
1252 MAGICKCORE_QUANTUM_DEPTH);
1253 return(depth);
1254}
1255
1256/*
1257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1258% %
1259% %
1260% %
1261% S e t I m a g e C h a n n e l D e p t h %
1262% %
1263% %
1264% %
1265%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1266%
1267% SetImageChannelDepth() sets the depth of the image.
1268%
1269% The format of the SetImageChannelDepth method is:
1270%
1271% MagickBooleanType SetImageDepth(Image *image,const unsigned long depth)
1272% MagickBooleanType SetImageChannelDepth(Image *image,
1273% const ChannelType channel,const unsigned long depth)
1274%
1275% A description of each parameter follows:
1276%
1277% o image: the image.
1278%
1279% o channel: the channel.
1280%
1281% o depth: the image depth.
1282%
1283*/
1284
1285MagickExport MagickBooleanType SetImageDepth(Image *image,
1286 const unsigned long depth)
1287{
1288 return(SetImageChannelDepth(image,AllChannels,depth));
1289}
1290
1291MagickExport MagickBooleanType SetImageChannelDepth(Image *image,
1292 const ChannelType channel,const unsigned long depth)
1293{
1294 ExceptionInfo
1295 *exception;
1296
1297 long
1298 y;
1299
1300 MagickBooleanType
1301 status;
1302
1303 QuantumAny
1304 range;
1305
1306 CacheView
1307 *image_view;
1308
1309 assert(image != (Image *) NULL);
1310 if (image->debug != MagickFalse)
1311 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1312 assert(image->signature == MagickSignature);
1313 if (GetImageDepth(image,&image->exception) <= (unsigned long)
1314 MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH))
1315 {
1316 image->depth=depth;
1317 return(MagickTrue);
1318 }
1319 /*
1320 Scale pixels to desired depth.
1321 */
1322 status=MagickTrue;
1323 range=GetQuantumRange(depth);
1324 exception=(&image->exception);
1325 image_view=AcquireCacheView(image);
1326#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy07490992009-09-11 19:51:45 +00001327 #pragma omp parallel for schedule(static,1) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00001328#endif
1329 for (y=0; y < (long) image->rows; y++)
1330 {
1331 register IndexPacket
1332 *__restrict indexes;
1333
1334 register long
1335 x;
1336
1337 register PixelPacket
1338 *__restrict q;
1339
1340 if (status == MagickFalse)
1341 continue;
1342 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1343 exception);
1344 if (q == (PixelPacket *) NULL)
1345 {
1346 status=MagickFalse;
1347 continue;
1348 }
1349 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1350 for (x=0; x < (long) image->columns; x++)
1351 {
1352 if ((channel & RedChannel) != 0)
1353 q->red=ScaleAnyToQuantum(ScaleQuantumToAny(q->red,range),range);
1354 if ((channel & GreenChannel) != 0)
1355 q->green=ScaleAnyToQuantum(ScaleQuantumToAny(q->green,range),range);
1356 if ((channel & BlueChannel) != 0)
1357 q->blue=ScaleAnyToQuantum(ScaleQuantumToAny(q->blue,range),range);
1358 if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
1359 q->opacity=ScaleAnyToQuantum(ScaleQuantumToAny(q->opacity,range),range);
1360 if (((channel & IndexChannel) != 0) &&
1361 (image->colorspace == CMYKColorspace))
1362 indexes[x]=ScaleAnyToQuantum(ScaleQuantumToAny(indexes[x],range),range);
1363 q++;
1364 }
1365 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1366 {
1367 status=MagickFalse;
1368 continue;
1369 }
1370 }
1371 image_view=DestroyCacheView(image_view);
1372 if (image->storage_class == PseudoClass)
1373 {
1374 QuantumAny
1375 range;
1376
1377 register long
1378 i;
1379
1380 register PixelPacket
1381 *__restrict p;
1382
1383 p=image->colormap;
1384 range=GetQuantumRange(depth);
1385#if defined(MAGICKCORE_OPENMP_SUPPORT)
cristy07490992009-09-11 19:51:45 +00001386 #pragma omp parallel for schedule(static,1) shared(status)
cristy3ed852e2009-09-05 21:47:34 +00001387#endif
1388 for (i=0; i < (long) image->colors; i++)
1389 {
1390 if ((channel & RedChannel) != 0)
1391 p->red=ScaleAnyToQuantum(ScaleQuantumToAny(p->red,range),range);
1392 if ((channel & GreenChannel) != 0)
1393 p->green=ScaleAnyToQuantum(ScaleQuantumToAny(p->green,range),range);
1394 if ((channel & BlueChannel) != 0)
1395 p->blue=ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,range),range);
1396 if ((channel & OpacityChannel) != 0)
1397 p->opacity=ScaleAnyToQuantum(ScaleQuantumToAny(p->opacity,range),
1398 range);
1399 p++;
1400 }
1401 }
1402 image->depth=depth;
1403 return(status);
1404}