MagickCore 6.9.12-98
Convert, Edit, Or Compose Bitmap Images
Loading...
Searching...
No Matches
colorspace.c
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC OOO L OOO RRRR SSSSS PPPP AAA CCCC EEEEE %
7% C O O L O O R R SS P P A A C E %
8% C O O L O O RRRR SSS PPPP AAAAA C EEE %
9% C O O L O O R R SS P A A C E %
10% CCCC OOO LLLLL OOO R R SSSSS P A A CCCC EEEEE %
11% %
12% %
13% MagickCore Image Colorspace Methods %
14% %
15% Software Design %
16% Cristy %
17% July 1992 %
18% %
19% %
20% Copyright 1999 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% https://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 Include declarations.
41*/
42#include "magick/studio.h"
43#include "magick/attribute.h"
44#include "magick/cache.h"
45#include "magick/cache-private.h"
46#include "magick/cache-view.h"
47#include "magick/color.h"
48#include "magick/color-private.h"
49#include "magick/colorspace.h"
50#include "magick/colorspace-private.h"
51#include "magick/exception.h"
52#include "magick/exception-private.h"
53#include "magick/enhance.h"
54#include "magick/image.h"
55#include "magick/image-private.h"
56#include "magick/gem.h"
57#include "magick/gem-private.h"
58#include "magick/memory_.h"
59#include "magick/monitor.h"
60#include "magick/monitor-private.h"
61#include "magick/pixel-private.h"
62#include "magick/property.h"
63#include "magick/quantize.h"
64#include "magick/quantum.h"
65#include "magick/resource_.h"
66#include "magick/string_.h"
67#include "magick/string-private.h"
68#include "magick/utility.h"
69
70/*
71 Typedef declarations.
72*/
73typedef struct _TransformPacket
74{
75 MagickRealType
76 x,
77 y,
78 z;
80
81/*
82%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
83% %
84% %
85% %
86% G e t I m a g e C o l o r s p a c e T y p e %
87% %
88% %
89% %
90%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91%
92% GetImageColorspaceType() returns the potential colorspace of image:
93% sRGBColorspaceType, RGBColorspaceType, GRAYColorspaceType, etc.
94%
95% To ensure the image type matches its potential, use SetImageColorspaceType():
96%
97% (void) SetImageColorspaceType(image,GetImageColorspaceType(image),
98% exception);
99%
100% The format of the GetImageColorspaceType method is:
101%
102% ColorspaceType GetImageColorspaceType(const Image *image,
103% ExceptionInfo *exception)
104%
105% A description of each parameter follows:
106%
107% o image: the image.
108%
109% o exception: return any errors or warnings in this structure.
110%
111*/
112MagickExport ColorspaceType GetImageColorspaceType(const Image *image,
113 ExceptionInfo *exception)
114{
115 ColorspaceType
116 colorspace;
117
118 ImageType
119 type;
120
121 assert(image != (Image *) NULL);
122 assert(image->signature == MagickCoreSignature);
123 if (IsEventLogging() != MagickFalse)
124 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
125 colorspace=image->colorspace;
126 type=IdentifyImageType(image,exception);
127 if ((type == BilevelType) || (type == GrayscaleType) ||
128 (type == GrayscaleMatteType))
129 colorspace=GRAYColorspace;
130 return(colorspace);
131}
132
133/*
134%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
135% %
136% %
137% %
138+ R G B T r a n s f o r m I m a g e %
139% %
140% %
141% %
142%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143%
144% RGBTransformImage() converts the reference image from sRGB to an alternate
145% colorspace. The transformation matrices are not the standard ones: the
146% weights are rescaled to normalized the range of the transformed values to
147% be [0..QuantumRange].
148%
149% The format of the RGBTransformImage method is:
150%
151% MagickBooleanType RGBTransformImage(Image *image,
152% const ColorspaceType colorspace)
153%
154% A description of each parameter follows:
155%
156% o image: the image.
157%
158% o colorspace: the colorspace to transform the image to.
159%
160*/
161
162static inline void ConvertRGBToCMY(const Quantum red,const Quantum green,
163 const Quantum blue,double *cyan,double *magenta,double *yellow)
164{
165 *cyan=QuantumScale*((double) QuantumRange-(double) red);
166 *magenta=QuantumScale*((double) QuantumRange-(double) green);
167 *yellow=QuantumScale*((double) QuantumRange-(double) blue);
168}
169
170static void ConvertRGBToLab(const Quantum red,const Quantum green,
171 const Quantum blue,double *L,double *a,double *b)
172{
173 double
174 X,
175 Y,
176 Z;
177
178 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
179 ConvertXYZToLab(X,Y,Z,L,a,b);
180}
181
182static inline void ConvertXYZToLMS(const double x,const double y,
183 const double z,double *L,double *M,double *S)
184{
185 *L=0.7328*x+0.4296*y-0.1624*z;
186 *M=(-0.7036*x+1.6975*y+0.0061*z);
187 *S=0.0030*x+0.0136*y+0.9834*z;
188}
189
190static void ConvertRGBToLMS(const Quantum red,const Quantum green,
191 const Quantum blue,double *L,double *M,double *S)
192{
193 double
194 X,
195 Y,
196 Z;
197
198 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
199 ConvertXYZToLMS(X,Y,Z,L,M,S);
200}
201
202static void ConvertRGBToLuv(const Quantum red,const Quantum green,
203 const Quantum blue,double *L,double *u,double *v)
204{
205 double
206 X,
207 Y,
208 Z;
209
210 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
211 ConvertXYZToLuv(X,Y,Z,L,u,v);
212}
213
214static void ConvertRGBToxyY(const Quantum red,const Quantum green,
215 const Quantum blue,double *low_x,double *low_y,double *cap_Y)
216{
217 double
218 gamma,
219 X,
220 Y,
221 Z;
222
223 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
224 gamma=PerceptibleReciprocal(X+Y+Z);
225 *low_x=gamma*X;
226 *low_y=gamma*Y;
227 *cap_Y=Y;
228}
229
230static void ConvertRGBToYPbPr(const Quantum red,const Quantum green,
231 const Quantum blue,double *Y,double *Pb,double *Pr)
232{
233 *Y=QuantumScale*(0.298839*(double) red+0.586811*(double) green+0.114350*
234 (double) blue);
235 *Pb=QuantumScale*((-0.1687367)*(double) red-0.331264*(double) green+0.5*
236 (double) blue)+0.5;
237 *Pr=QuantumScale*(0.5*(double) red-0.418688*(double) green-0.081312*
238 (double) blue)+0.5;
239}
240
241static void ConvertRGBToYCbCr(const Quantum red,const Quantum green,
242 const Quantum blue,double *Y,double *Cb,double *Cr)
243{
244 ConvertRGBToYPbPr(red,green,blue,Y,Cb,Cr);
245}
246
247static void ConvertRGBToYUV(const Quantum red,const Quantum green,
248 const Quantum blue,double *Y,double *U,double *V)
249{
250 *Y=QuantumScale*(0.298839*(double) red+0.586811*(double) green+0.114350*
251 (double) blue);
252 *U=QuantumScale*((-0.147)*(double) red-0.289*(double) green+0.436*
253 (double) blue)+0.5;
254 *V=QuantumScale*(0.615*(double) red-0.515*(double) green-0.100*
255 (double) blue)+0.5;
256}
257
258static void ConvertRGBToYDbDr(const Quantum red,const Quantum green,
259 const Quantum blue,double *Y,double *Db,double *Dr)
260{
261 *Y=QuantumScale*(0.298839*(double) red+0.586811*(double) green+0.114350*
262 (double) blue);
263 *Db=QuantumScale*(-0.450*(double) red-0.883*(double) green+1.333*
264 (double) blue)+0.5;
265 *Dr=QuantumScale*(-1.333*(double) red+1.116*(double) green+0.217*
266 (double) blue)+0.5;
267}
268
269static void ConvertRGBToYIQ(const Quantum red,const Quantum green,
270 const Quantum blue,double *Y,double *I,double *Q)
271{
272 *Y=QuantumScale*(0.298839*(double) red+0.586811*(double) green+0.114350*
273 (double) blue);
274 *I=QuantumScale*(0.595716*(double) red-0.274453*(double) green-0.321263*
275 (double) blue)+0.5;
276 *Q=QuantumScale*(0.211456*(double) red-0.522591*(double) green+0.311135*
277 (double) blue)+0.5;
278}
279
280MagickExport MagickBooleanType RGBTransformImage(Image *image,
281 const ColorspaceType colorspace)
282{
283#define RGBTransformImageTag "RGBTransform/Image"
284
286 *image_view;
287
289 *exception;
290
291 MagickBooleanType
292 status;
293
294 MagickOffsetType
295 progress;
296
298 primary_info;
299
300 ssize_t
301 i;
302
303 ssize_t
304 y;
305
307 *x_map,
308 *y_map,
309 *z_map;
310
311 assert(image != (Image *) NULL);
312 assert(image->signature == MagickCoreSignature);
313 assert(colorspace != sRGBColorspace);
314 assert(colorspace != TransparentColorspace);
315 assert(colorspace != UndefinedColorspace);
316 if (IsEventLogging() != MagickFalse)
317 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
318 status=MagickTrue;
319 progress=0;
320 exception=(&image->exception);
321 switch (colorspace)
322 {
323 case CMYKColorspace:
324 {
326 zero;
327
328 /*
329 Convert RGB to CMYK colorspace.
330 */
331 if (image->storage_class == PseudoClass)
332 {
333 if (SyncImage(image) == MagickFalse)
334 return(MagickFalse);
335 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
336 return(MagickFalse);
337 }
338 if (SetImageColorspace(image,colorspace) == MagickFalse)
339 return(MagickFalse);
340 GetMagickPixelPacket(image,&zero);
341 image_view=AcquireAuthenticCacheView(image,exception);
342#if defined(MAGICKCORE_OPENMP_SUPPORT)
343 #pragma omp parallel for schedule(static) shared(status) \
344 magick_number_threads(image,image,image->rows,1)
345#endif
346 for (y=0; y < (ssize_t) image->rows; y++)
347 {
348 MagickBooleanType
349 sync;
350
352 pixel;
353
354 IndexPacket
355 *magick_restrict indexes;
356
357 ssize_t
358 x;
359
361 *magick_restrict q;
362
363 if (status == MagickFalse)
364 continue;
365 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
366 exception);
367 if (q == (PixelPacket *) NULL)
368 {
369 status=MagickFalse;
370 continue;
371 }
372 indexes=GetCacheViewAuthenticIndexQueue(image_view);
373 pixel=zero;
374 for (x=0; x < (ssize_t) image->columns; x++)
375 {
376 SetMagickPixelPacket(image,q,indexes+x,&pixel);
377 pixel.red=(MagickRealType) pixel.red;
378 pixel.green=(MagickRealType) pixel.green;
379 pixel.blue=(MagickRealType) pixel.blue;
380 ConvertRGBToCMYK(&pixel);
381 SetPixelPacket(image,&pixel,q,indexes+x);
382 q++;
383 }
384 sync=SyncCacheViewAuthenticPixels(image_view,exception);
385 if (sync == MagickFalse)
386 status=MagickFalse;
387 }
388 image_view=DestroyCacheView(image_view);
389 image->type=image->matte == MagickFalse ? ColorSeparationType :
390 ColorSeparationMatteType;
391 if (SetImageColorspace(image,colorspace) == MagickFalse)
392 return(MagickFalse);
393 return(status);
394 }
395 case LinearGRAYColorspace:
396 {
397 /*
398 Transform image from sRGB to GRAY.
399 */
400 if (image->storage_class == PseudoClass)
401 {
402 if (SyncImage(image) == MagickFalse)
403 return(MagickFalse);
404 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
405 return(MagickFalse);
406 }
407 image_view=AcquireAuthenticCacheView(image,exception);
408#if defined(MAGICKCORE_OPENMP_SUPPORT)
409 #pragma omp parallel for schedule(static) shared(status) \
410 magick_number_threads(image,image,image->rows,1)
411#endif
412 for (y=0; y < (ssize_t) image->rows; y++)
413 {
414 MagickBooleanType
415 sync;
416
417 ssize_t
418 x;
419
421 *magick_restrict q;
422
423 if (status == MagickFalse)
424 continue;
425 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
426 exception);
427 if (q == (PixelPacket *) NULL)
428 {
429 status=MagickFalse;
430 continue;
431 }
432 for (x=0; x < (ssize_t) image->columns; x++)
433 {
434 MagickRealType
435 gray;
436
437 gray=0.212656*DecodePixelGamma(GetPixelRed(q))+0.715158*
438 DecodePixelGamma(GetPixelGreen(q))+0.072186*
439 DecodePixelGamma(GetPixelBlue(q));
440 SetPixelGray(q,ClampToQuantum(gray));
441 q++;
442 }
443 sync=SyncCacheViewAuthenticPixels(image_view,exception);
444 if (sync == MagickFalse)
445 status=MagickFalse;
446 }
447 image_view=DestroyCacheView(image_view);
448 if (SetImageColorspace(image,colorspace) == MagickFalse)
449 return(MagickFalse);
450 image->type=GrayscaleType;
451 return(status);
452 }
453 case GRAYColorspace:
454 {
455 /*
456 Transform image from sRGB to GRAY.
457 */
458 if (image->storage_class == PseudoClass)
459 {
460 if (SyncImage(image) == MagickFalse)
461 return(MagickFalse);
462 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
463 return(MagickFalse);
464 }
465 image_view=AcquireAuthenticCacheView(image,exception);
466#if defined(MAGICKCORE_OPENMP_SUPPORT)
467 #pragma omp parallel for schedule(static) shared(status) \
468 magick_number_threads(image,image,image->rows,1)
469#endif
470 for (y=0; y < (ssize_t) image->rows; y++)
471 {
472 MagickBooleanType
473 sync;
474
475 ssize_t
476 x;
477
479 *magick_restrict q;
480
481 if (status == MagickFalse)
482 continue;
483 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
484 exception);
485 if (q == (PixelPacket *) NULL)
486 {
487 status=MagickFalse;
488 continue;
489 }
490 for (x=0; x < (ssize_t) image->columns; x++)
491 {
492 MagickRealType
493 gray;
494
495 gray=0.212656*(double) GetPixelRed(q)+0.715158*(double)
496 GetPixelGreen(q)+0.072186*(double) GetPixelBlue(q);
497 SetPixelGray(q,ClampToQuantum(gray));
498 q++;
499 }
500 sync=SyncCacheViewAuthenticPixels(image_view,exception);
501 if (sync == MagickFalse)
502 status=MagickFalse;
503 }
504 image_view=DestroyCacheView(image_view);
505 if (SetImageColorspace(image,colorspace) == MagickFalse)
506 return(MagickFalse);
507 image->type=GrayscaleType;
508 return(status);
509 }
510 case CMYColorspace:
511 case HCLColorspace:
512 case HCLpColorspace:
513 case HSBColorspace:
514 case HSIColorspace:
515 case HSLColorspace:
516 case HSVColorspace:
517 case HWBColorspace:
518 case LabColorspace:
519 case LCHColorspace:
520 case LCHabColorspace:
521 case LCHuvColorspace:
522 case LMSColorspace:
523 case LuvColorspace:
524 case xyYColorspace:
525 case XYZColorspace:
526 case YCbCrColorspace:
527 case YDbDrColorspace:
528 case YIQColorspace:
529 case YPbPrColorspace:
530 case YUVColorspace:
531 {
532 /*
533 Transform image from sRGB to HSI.
534 */
535 if (image->storage_class == PseudoClass)
536 {
537 if (SyncImage(image) == MagickFalse)
538 return(MagickFalse);
539 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
540 return(MagickFalse);
541 }
542 image_view=AcquireAuthenticCacheView(image,exception);
543#if defined(MAGICKCORE_OPENMP_SUPPORT)
544 #pragma omp parallel for schedule(static) shared(status) \
545 magick_number_threads(image,image,image->rows,1)
546#endif
547 for (y=0; y < (ssize_t) image->rows; y++)
548 {
549 MagickBooleanType
550 sync;
551
552 ssize_t
553 x;
554
556 *magick_restrict q;
557
558 if (status == MagickFalse)
559 continue;
560 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
561 exception);
562 if (q == (PixelPacket *) NULL)
563 {
564 status=MagickFalse;
565 continue;
566 }
567 for (x=0; x < (ssize_t) image->columns; x++)
568 {
569 double
570 X,
571 Y,
572 Z;
573
574 Quantum
575 blue,
576 green,
577 red;
578
579 red=ClampToQuantum((MagickRealType) GetPixelRed(q));
580 green=ClampToQuantum((MagickRealType) GetPixelGreen(q));
581 blue=ClampToQuantum((MagickRealType) GetPixelBlue(q));
582 switch (colorspace)
583 {
584 case CMYColorspace:
585 {
586 ConvertRGBToCMY(red,green,blue,&X,&Y,&Z);
587 break;
588 }
589 case HCLColorspace:
590 {
591 ConvertRGBToHCL(red,green,blue,&X,&Y,&Z);
592 break;
593 }
594 case HCLpColorspace:
595 {
596 ConvertRGBToHCLp(red,green,blue,&X,&Y,&Z);
597 break;
598 }
599 case HSBColorspace:
600 {
601 ConvertRGBToHSB(red,green,blue,&X,&Y,&Z);
602 break;
603 }
604 case HSIColorspace:
605 {
606 ConvertRGBToHSI(red,green,blue,&X,&Y,&Z);
607 break;
608 }
609 case HSLColorspace:
610 {
611 ConvertRGBToHSL(red,green,blue,&X,&Y,&Z);
612 break;
613 }
614 case HSVColorspace:
615 {
616 ConvertRGBToHSV(red,green,blue,&X,&Y,&Z);
617 break;
618 }
619 case HWBColorspace:
620 {
621 ConvertRGBToHWB(red,green,blue,&X,&Y,&Z);
622 break;
623 }
624 case LabColorspace:
625 {
626 ConvertRGBToLab(red,green,blue,&X,&Y,&Z);
627 break;
628 }
629 case LCHColorspace:
630 case LCHabColorspace:
631 {
632 ConvertRGBToLCHab(red,green,blue,&X,&Y,&Z);
633 break;
634 }
635 case LCHuvColorspace:
636 {
637 ConvertRGBToLCHuv(red,green,blue,&X,&Y,&Z);
638 break;
639 }
640 case LMSColorspace:
641 {
642 ConvertRGBToLMS(red,green,blue,&X,&Y,&Z);
643 break;
644 }
645 case LuvColorspace:
646 {
647 ConvertRGBToLuv(red,green,blue,&X,&Y,&Z);
648 break;
649 }
650 case xyYColorspace:
651 {
652 ConvertRGBToxyY(red,green,blue,&X,&Y,&Z);
653 break;
654 }
655 case XYZColorspace:
656 {
657 ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
658 break;
659 }
660 case YCbCrColorspace:
661 {
662 ConvertRGBToYCbCr(red,green,blue,&X,&Y,&Z);
663 break;
664 }
665 case YDbDrColorspace:
666 {
667 ConvertRGBToYDbDr(red,green,blue,&X,&Y,&Z);
668 break;
669 }
670 case YIQColorspace:
671 {
672 ConvertRGBToYIQ(red,green,blue,&X,&Y,&Z);
673 break;
674 }
675 case YPbPrColorspace:
676 {
677 ConvertRGBToYPbPr(red,green,blue,&X,&Y,&Z);
678 break;
679 }
680 case YUVColorspace:
681 {
682 ConvertRGBToYUV(red,green,blue,&X,&Y,&Z);
683 break;
684 }
685 default:
686 {
687 X=QuantumScale*(double) red;
688 Y=QuantumScale*(double) green;
689 Z=QuantumScale*(double) blue;
690 break;
691 }
692 }
693 SetPixelRed(q,ClampToQuantum((MagickRealType) QuantumRange*X));
694 SetPixelGreen(q,ClampToQuantum((MagickRealType) QuantumRange*Y));
695 SetPixelBlue(q,ClampToQuantum((MagickRealType) QuantumRange*Z));
696 q++;
697 }
698 sync=SyncCacheViewAuthenticPixels(image_view,exception);
699 if (sync == MagickFalse)
700 status=MagickFalse;
701 }
702 image_view=DestroyCacheView(image_view);
703 if (SetImageColorspace(image,colorspace) == MagickFalse)
704 return(MagickFalse);
705 return(status);
706 }
707 case LogColorspace:
708 {
709#define DisplayGamma (1.0/1.7)
710#define FilmGamma 0.6
711#define ReferenceBlack 95.0
712#define ReferenceWhite 685.0
713
714 const char
715 *value;
716
717 double
718 black,
719 density,
720 film_gamma,
721 gamma,
722 reference_black,
723 reference_white;
724
725 Quantum
726 *logmap;
727
728 /*
729 Transform RGB to Log colorspace.
730 */
731 density=DisplayGamma;
732 gamma=DisplayGamma;
733 value=GetImageProperty(image,"gamma");
734 if (value != (const char *) NULL)
735 gamma=PerceptibleReciprocal(StringToDouble(value,(char **) NULL));
736 film_gamma=FilmGamma;
737 value=GetImageProperty(image,"film-gamma");
738 if (value != (const char *) NULL)
739 film_gamma=StringToDouble(value,(char **) NULL);
740 reference_black=ReferenceBlack;
741 value=GetImageProperty(image,"reference-black");
742 if (value != (const char *) NULL)
743 reference_black=StringToDouble(value,(char **) NULL);
744 reference_white=ReferenceWhite;
745 value=GetImageProperty(image,"reference-white");
746 if (value != (const char *) NULL)
747 reference_white=StringToDouble(value,(char **) NULL);
748 logmap=(Quantum *) AcquireQuantumMemory((size_t) MaxMap+1UL,
749 sizeof(*logmap));
750 if (logmap == (Quantum *) NULL)
751 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
752 image->filename);
753 black=pow(10.0,(reference_black-reference_white)*(gamma/density)*0.002*
754 PerceptibleReciprocal(film_gamma));
755#if defined(MAGICKCORE_OPENMP_SUPPORT)
756 #pragma omp parallel for schedule(static)
757#endif
758 for (i=0; i <= (ssize_t) MaxMap; i++)
759 logmap[i]=ScaleMapToQuantum((MagickRealType) (MaxMap*(reference_white+
760 log10(black+(1.0*i/MaxMap)*(1.0-black))/((gamma/density)*0.002*
761 PerceptibleReciprocal(film_gamma)))/1024.0));
762 image_view=AcquireAuthenticCacheView(image,exception);
763#if defined(MAGICKCORE_OPENMP_SUPPORT)
764 #pragma omp parallel for schedule(static) shared(status) \
765 magick_number_threads(image,image,image->rows,1)
766#endif
767 for (y=0; y < (ssize_t) image->rows; y++)
768 {
769 MagickBooleanType
770 sync;
771
772 ssize_t
773 x;
774
776 *magick_restrict q;
777
778 if (status == MagickFalse)
779 continue;
780 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
781 exception);
782 if (q == (PixelPacket *) NULL)
783 {
784 status=MagickFalse;
785 continue;
786 }
787 for (x=(ssize_t) image->columns; x != 0; x--)
788 {
789 Quantum
790 blue,
791 green,
792 red;
793
794 red=ClampToQuantum(DecodePixelGamma((MagickRealType)
795 GetPixelRed(q)));
796 green=ClampToQuantum(DecodePixelGamma((MagickRealType)
797 GetPixelGreen(q)));
798 blue=ClampToQuantum(DecodePixelGamma((MagickRealType)
799 GetPixelBlue(q)));
800 SetPixelRed(q,logmap[ScaleQuantumToMap(red)]);
801 SetPixelGreen(q,logmap[ScaleQuantumToMap(green)]);
802 SetPixelBlue(q,logmap[ScaleQuantumToMap(blue)]);
803 q++;
804 }
805 sync=SyncCacheViewAuthenticPixels(image_view,exception);
806 if (sync == MagickFalse)
807 status=MagickFalse;
808 }
809 image_view=DestroyCacheView(image_view);
810 logmap=(Quantum *) RelinquishMagickMemory(logmap);
811 if (SetImageColorspace(image,colorspace) == MagickFalse)
812 return(MagickFalse);
813 return(status);
814 }
815 case RGBColorspace:
816 case scRGBColorspace:
817 {
818 /*
819 Transform image from sRGB to linear RGB.
820 */
821 if (image->storage_class == PseudoClass)
822 {
823 if (SyncImage(image) == MagickFalse)
824 return(MagickFalse);
825 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
826 return(MagickFalse);
827 }
828 image_view=AcquireAuthenticCacheView(image,exception);
829#if defined(MAGICKCORE_OPENMP_SUPPORT)
830 #pragma omp parallel for schedule(static) shared(status) \
831 magick_number_threads(image,image,image->rows,1)
832#endif
833 for (y=0; y < (ssize_t) image->rows; y++)
834 {
835 MagickBooleanType
836 sync;
837
838 ssize_t
839 x;
840
842 *magick_restrict q;
843
844 if (status == MagickFalse)
845 continue;
846 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
847 exception);
848 if (q == (PixelPacket *) NULL)
849 {
850 status=MagickFalse;
851 continue;
852 }
853 for (x=0; x < (ssize_t) image->columns; x++)
854 {
855 Quantum
856 blue,
857 green,
858 red;
859
860 red=ClampToQuantum(DecodePixelGamma((MagickRealType)
861 GetPixelRed(q)));
862 green=ClampToQuantum(DecodePixelGamma((MagickRealType)
863 GetPixelGreen(q)));
864 blue=ClampToQuantum(DecodePixelGamma((MagickRealType)
865 GetPixelBlue(q)));
866 SetPixelRed(q,red);
867 SetPixelGreen(q,green);
868 SetPixelBlue(q,blue);
869 q++;
870 }
871 sync=SyncCacheViewAuthenticPixels(image_view,exception);
872 if (sync == MagickFalse)
873 status=MagickFalse;
874 }
875 image_view=DestroyCacheView(image_view);
876 if (SetImageColorspace(image,colorspace) == MagickFalse)
877 return(MagickFalse);
878 return(status);
879 }
880 default:
881 break;
882 }
883 /*
884 Allocate the tables.
885 */
886 x_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
887 sizeof(*x_map));
888 y_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
889 sizeof(*y_map));
890 z_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
891 sizeof(*z_map));
892 if ((x_map == (TransformPacket *) NULL) ||
893 (y_map == (TransformPacket *) NULL) ||
894 (z_map == (TransformPacket *) NULL))
895 {
896 if (x_map != (TransformPacket *) NULL)
897 x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
898 if (y_map != (TransformPacket *) NULL)
899 y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
900 if (z_map != (TransformPacket *) NULL)
901 z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
902 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
903 image->filename);
904 }
905 (void) memset(&primary_info,0,sizeof(primary_info));
906 switch (colorspace)
907 {
908 case OHTAColorspace:
909 {
910 /*
911 Initialize OHTA tables:
912
913 I1 = 0.33333*R+0.33334*G+0.33333*B
914 I2 = 0.50000*R+0.00000*G-0.50000*B
915 I3 =-0.25000*R+0.50000*G-0.25000*B
916
917 I and Q, normally -0.5 through 0.5, are normalized to the range 0
918 through QuantumRange.
919 */
920 primary_info.y=(double) (MaxMap+1.0)/2.0;
921 primary_info.z=(double) (MaxMap+1.0)/2.0;
922#if defined(MAGICKCORE_OPENMP_SUPPORT)
923 #pragma omp parallel for schedule(static)
924#endif
925 for (i=0; i <= (ssize_t) MaxMap; i++)
926 {
927 x_map[i].x=(MagickRealType) (0.33333*(double) i);
928 x_map[i].y=(MagickRealType) (0.50000*(double) i);
929 x_map[i].z=(MagickRealType) (-0.25000*(double) i);
930 y_map[i].x=(MagickRealType) (0.33334*(double) i);
931 y_map[i].y=(MagickRealType) (0.00000*(double) i);
932 y_map[i].z=(MagickRealType) (0.50000*(double) i);
933 z_map[i].x=(MagickRealType) (0.33333*(double) i);
934 z_map[i].y=(MagickRealType) (-0.50000*(double) i);
935 z_map[i].z=(MagickRealType) (-0.25000*(double) i);
936 }
937 break;
938 }
939 case Rec601LumaColorspace:
940 {
941 /*
942 Initialize Rec601 luma tables:
943
944 G = 0.298839*R+0.586811*G+0.114350*B
945 */
946#if defined(MAGICKCORE_OPENMP_SUPPORT)
947 #pragma omp parallel for schedule(static)
948#endif
949 for (i=0; i <= (ssize_t) MaxMap; i++)
950 {
951 x_map[i].x=(MagickRealType) (0.298839*(double) i);
952 x_map[i].y=(MagickRealType) (0.298839*(double) i);
953 x_map[i].z=(MagickRealType) (0.298839*(double) i);
954 y_map[i].x=(MagickRealType) (0.586811*(double) i);
955 y_map[i].y=(MagickRealType) (0.586811*(double) i);
956 y_map[i].z=(MagickRealType) (0.586811*(double) i);
957 z_map[i].x=(MagickRealType) (0.114350*(double) i);
958 z_map[i].y=(MagickRealType) (0.114350*(double) i);
959 z_map[i].z=(MagickRealType) (0.114350*(double) i);
960 }
961 break;
962 }
963 case Rec601YCbCrColorspace:
964 {
965 /*
966 Initialize YCbCr tables (ITU-R BT.601):
967
968 Y = 0.2988390*R+0.5868110*G+0.1143500*B
969 Cb= -0.1687367*R-0.3312640*G+0.5000000*B
970 Cr= 0.5000000*R-0.4186880*G-0.0813120*B
971
972 Cb and Cr, normally -0.5 through 0.5, are normalized to the range 0
973 through QuantumRange.
974 */
975 primary_info.y=(double) (MaxMap+1.0)/2.0;
976 primary_info.z=(double) (MaxMap+1.0)/2.0;
977#if defined(MAGICKCORE_OPENMP_SUPPORT)
978 #pragma omp parallel for schedule(static)
979#endif
980 for (i=0; i <= (ssize_t) MaxMap; i++)
981 {
982 x_map[i].x=(MagickRealType) (0.298839*(double) i);
983 x_map[i].y=(MagickRealType) (-0.1687367*(double) i);
984 x_map[i].z=(MagickRealType) (0.500000*(double) i);
985 y_map[i].x=(MagickRealType) (0.586811*(double) i);
986 y_map[i].y=(MagickRealType) (-0.331264*(double) i);
987 y_map[i].z=(MagickRealType) (-0.418688*(double) i);
988 z_map[i].x=(MagickRealType) (0.114350*(double) i);
989 z_map[i].y=(MagickRealType) (0.500000*(double) i);
990 z_map[i].z=(MagickRealType) (-0.081312*(double) i);
991 }
992 break;
993 }
994 case Rec709LumaColorspace:
995 {
996 /*
997 Initialize Rec709 luma tables:
998
999 G = 0.212656*R+0.715158*G+0.072186*B
1000 */
1001#if defined(MAGICKCORE_OPENMP_SUPPORT)
1002 #pragma omp parallel for schedule(static)
1003#endif
1004 for (i=0; i <= (ssize_t) MaxMap; i++)
1005 {
1006 x_map[i].x=(MagickRealType) (0.212656*(double) i);
1007 x_map[i].y=(MagickRealType) (0.212656*(double) i);
1008 x_map[i].z=(MagickRealType) (0.212656*(double) i);
1009 y_map[i].x=(MagickRealType) (0.715158*(double) i);
1010 y_map[i].y=(MagickRealType) (0.715158*(double) i);
1011 y_map[i].z=(MagickRealType) (0.715158*(double) i);
1012 z_map[i].x=(MagickRealType) (0.072186*(double) i);
1013 z_map[i].y=(MagickRealType) (0.072186*(double) i);
1014 z_map[i].z=(MagickRealType) (0.072186*(double) i);
1015 }
1016 break;
1017 }
1018 case Rec709YCbCrColorspace:
1019 {
1020 /*
1021 Initialize YCbCr tables (ITU-R BT.709):
1022
1023 Y = 0.212656*R+0.715158*G+0.072186*B
1024 Cb= -0.114572*R-0.385428*G+0.500000*B
1025 Cr= 0.500000*R-0.454153*G-0.045847*B
1026
1027 Cb and Cr, normally -0.5 through 0.5, are normalized to the range 0
1028 through QuantumRange.
1029 */
1030 primary_info.y=(double) (MaxMap+1.0)/2.0;
1031 primary_info.z=(double) (MaxMap+1.0)/2.0;
1032#if defined(MAGICKCORE_OPENMP_SUPPORT)
1033 #pragma omp parallel for schedule(static)
1034#endif
1035 for (i=0; i <= (ssize_t) MaxMap; i++)
1036 {
1037 x_map[i].x=(MagickRealType) (0.212656*(double) i);
1038 x_map[i].y=(MagickRealType) (-0.114572*(double) i);
1039 x_map[i].z=(MagickRealType) (0.500000*(double) i);
1040 y_map[i].x=(MagickRealType) (0.715158*(double) i);
1041 y_map[i].y=(MagickRealType) (-0.385428*(double) i);
1042 y_map[i].z=(MagickRealType) (-0.454153*(double) i);
1043 z_map[i].x=(MagickRealType) (0.072186*(double) i);
1044 z_map[i].y=(MagickRealType) (0.500000*(double) i);
1045 z_map[i].z=(MagickRealType) (-0.045847*(double) i);
1046 }
1047 break;
1048 }
1049 case YCCColorspace:
1050 {
1051 /*
1052 Initialize YCC tables:
1053
1054 Y = 0.298839*R+0.586811*G+0.114350*B
1055 C1= -0.298839*R-0.586811*G+0.88600*B
1056 C2= 0.70100*R-0.586811*G-0.114350*B
1057
1058 YCC is scaled by 1.3584. C1 zero is 156 and C2 is at 137.
1059 */
1060 primary_info.y=(double) ScaleQuantumToMap(ScaleCharToQuantum(156));
1061 primary_info.z=(double) ScaleQuantumToMap(ScaleCharToQuantum(137));
1062 for (i=0; i <= (ssize_t) (0.018*MaxMap); i++)
1063 {
1064 x_map[i].x=0.005382*i;
1065 x_map[i].y=(-0.003296)*i;
1066 x_map[i].z=0.009410*i;
1067 y_map[i].x=0.010566*i;
1068 y_map[i].y=(-0.006471)*i;
1069 y_map[i].z=(-0.007880)*i;
1070 z_map[i].x=0.002052*i;
1071 z_map[i].y=0.009768*i;
1072 z_map[i].z=(-0.001530)*i;
1073 }
1074 for ( ; i <= (ssize_t) MaxMap; i++)
1075 {
1076 x_map[i].x=0.298839*(1.099*i-0.099);
1077 x_map[i].y=(-0.298839)*(1.099*i-0.099);
1078 x_map[i].z=0.70100*(1.099*i-0.099);
1079 y_map[i].x=0.586811*(1.099*i-0.099);
1080 y_map[i].y=(-0.586811)*(1.099*i-0.099);
1081 y_map[i].z=(-0.586811)*(1.099*i-0.099);
1082 z_map[i].x=0.114350*(1.099*i-0.099);
1083 z_map[i].y=0.88600*(1.099*i-0.099);
1084 z_map[i].z=(-0.114350)*(1.099*i-0.099);
1085 }
1086 break;
1087 }
1088 default:
1089 {
1090 /*
1091 Linear conversion tables.
1092 */
1093#if defined(MAGICKCORE_OPENMP_SUPPORT)
1094 #pragma omp parallel for schedule(static)
1095#endif
1096 for (i=0; i <= (ssize_t) MaxMap; i++)
1097 {
1098 x_map[i].x=(MagickRealType) (1.0*(double) i);
1099 y_map[i].x=(MagickRealType) 0.0;
1100 z_map[i].x=(MagickRealType) 0.0;
1101 x_map[i].y=(MagickRealType) 0.0;
1102 y_map[i].y=(MagickRealType) (1.0*(double) i);
1103 z_map[i].y=(MagickRealType) 0.0;
1104 x_map[i].z=(MagickRealType) 0.0;
1105 y_map[i].z=(MagickRealType) 0.0;
1106 z_map[i].z=(MagickRealType) (1.0*(double) i);
1107 }
1108 break;
1109 }
1110 }
1111 /*
1112 Convert from sRGB.
1113 */
1114 switch (image->storage_class)
1115 {
1116 case DirectClass:
1117 default:
1118 {
1119 /*
1120 Convert DirectClass image.
1121 */
1122 image_view=AcquireAuthenticCacheView(image,exception);
1123#if defined(MAGICKCORE_OPENMP_SUPPORT)
1124 #pragma omp parallel for schedule(static) shared(status) \
1125 magick_number_threads(image,image,image->rows,1)
1126#endif
1127 for (y=0; y < (ssize_t) image->rows; y++)
1128 {
1129 MagickBooleanType
1130 sync;
1131
1133 pixel;
1134
1135 ssize_t
1136 x;
1137
1139 *magick_restrict q;
1140
1141 size_t
1142 blue,
1143 green,
1144 red;
1145
1146 if (status == MagickFalse)
1147 continue;
1148 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1149 exception);
1150 if (q == (PixelPacket *) NULL)
1151 {
1152 status=MagickFalse;
1153 continue;
1154 }
1155 for (x=0; x < (ssize_t) image->columns; x++)
1156 {
1157 red=ScaleQuantumToMap(ClampToQuantum((MagickRealType)
1158 GetPixelRed(q)));
1159 green=ScaleQuantumToMap(ClampToQuantum((MagickRealType)
1160 GetPixelGreen(q)));
1161 blue=ScaleQuantumToMap(ClampToQuantum((MagickRealType)
1162 GetPixelBlue(q)));
1163 pixel.red=(x_map[red].x+y_map[green].x+z_map[blue].x)+
1164 (MagickRealType) primary_info.x;
1165 pixel.green=(x_map[red].y+y_map[green].y+z_map[blue].y)+
1166 (MagickRealType) primary_info.y;
1167 pixel.blue=(x_map[red].z+y_map[green].z+z_map[blue].z)+
1168 (MagickRealType) primary_info.z;
1169 SetPixelRed(q,ScaleMapToQuantum(pixel.red));
1170 SetPixelGreen(q,ScaleMapToQuantum(pixel.green));
1171 SetPixelBlue(q,ScaleMapToQuantum(pixel.blue));
1172 q++;
1173 }
1174 sync=SyncCacheViewAuthenticPixels(image_view,exception);
1175 if (sync == MagickFalse)
1176 status=MagickFalse;
1177 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1178 {
1179 MagickBooleanType
1180 proceed;
1181
1182#if defined(MAGICKCORE_OPENMP_SUPPORT)
1183 #pragma omp atomic
1184#endif
1185 progress++;
1186 proceed=SetImageProgress(image,RGBTransformImageTag,progress,
1187 image->rows);
1188 if (proceed == MagickFalse)
1189 status=MagickFalse;
1190 }
1191 }
1192 image_view=DestroyCacheView(image_view);
1193 break;
1194 }
1195 case PseudoClass:
1196 {
1197 size_t
1198 blue,
1199 green,
1200 red;
1201
1202 /*
1203 Convert PseudoClass image.
1204 */
1205 for (i=0; i < (ssize_t) image->colors; i++)
1206 {
1208 pixel;
1209
1210 red=ScaleQuantumToMap(ClampToQuantum((MagickRealType)
1211 image->colormap[i].red));
1212 green=ScaleQuantumToMap(ClampToQuantum((MagickRealType)
1213 image->colormap[i].green));
1214 blue=ScaleQuantumToMap(ClampToQuantum((MagickRealType)
1215 image->colormap[i].blue));
1216 pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x+primary_info.x;
1217 pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y+primary_info.y;
1218 pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z+primary_info.z;
1219 image->colormap[i].red=ScaleMapToQuantum(pixel.red);
1220 image->colormap[i].green=ScaleMapToQuantum(pixel.green);
1221 image->colormap[i].blue=ScaleMapToQuantum(pixel.blue);
1222 }
1223 (void) SyncImage(image);
1224 break;
1225 }
1226 }
1227 /*
1228 Relinquish resources.
1229 */
1230 z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
1231 y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
1232 x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
1233 if (SetImageColorspace(image,colorspace) == MagickFalse)
1234 return(MagickFalse);
1235 return(status);
1236}
1237
1238/*
1239%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1240% %
1241% %
1242% %
1243% S e t I m a g e C o l o r s p a c e %
1244% %
1245% %
1246% %
1247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1248%
1249% SetImageColorspace() sets the colorspace member of the Image structure.
1250%
1251% The format of the SetImageColorspace method is:
1252%
1253% MagickBooleanType SetImageColorspace(Image *image,
1254% const ColorspaceType colorspace)
1255%
1256% A description of each parameter follows:
1257%
1258% o image: the image.
1259%
1260% o colorspace: the colorspace.
1261%
1262*/
1263MagickExport MagickBooleanType SetImageColorspace(Image *image,
1264 const ColorspaceType colorspace)
1265{
1266 ImageType
1267 type;
1268
1269 MagickBooleanType
1270 status;
1271
1272 assert(image != (Image *) NULL);
1273 assert(image->signature == MagickCoreSignature);
1274 if (IsEventLogging() != MagickFalse)
1275 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1276 if (image->colorspace == colorspace)
1277 return(MagickTrue);
1278 image->colorspace=colorspace;
1279 image->rendering_intent=UndefinedIntent;
1280 image->gamma=1.000/2.200;
1281 (void) memset(&image->chromaticity,0,sizeof(image->chromaticity));
1282 type=image->type;
1283 if (IsGrayColorspace(colorspace) != MagickFalse)
1284 {
1285 if (colorspace == LinearGRAYColorspace)
1286 image->gamma=1.0;
1287 type=GrayscaleType;
1288 }
1289 else
1290 if ((IsRGBColorspace(colorspace) != MagickFalse) ||
1291 (colorspace == XYZColorspace) || (colorspace == xyYColorspace))
1292 image->gamma=1.0;
1293 else
1294 {
1295 image->rendering_intent=PerceptualIntent;
1296 image->chromaticity.red_primary.x=0.6400;
1297 image->chromaticity.red_primary.y=0.3300;
1298 image->chromaticity.red_primary.z=0.0300;
1299 image->chromaticity.green_primary.x=0.3000;
1300 image->chromaticity.green_primary.y=0.6000;
1301 image->chromaticity.green_primary.z=0.1000;
1302 image->chromaticity.blue_primary.x=0.1500;
1303 image->chromaticity.blue_primary.y=0.0600;
1304 image->chromaticity.blue_primary.z=0.7900;
1305 image->chromaticity.white_point.x=0.3127;
1306 image->chromaticity.white_point.y=0.3290;
1307 image->chromaticity.white_point.z=0.3583;
1308 }
1309 status=SyncImagePixelCache(image,&image->exception);
1310 image->type=type;
1311 return(status);
1312}
1313
1314/*
1315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1316% %
1317% %
1318% %
1319% S e t I m a g e G r a y %
1320% %
1321% %
1322% %
1323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1324%
1325% SetImageGray() returns MagickTrue if all the pixels in the image have the
1326% same red, green, and blue intensities and changes the type of the image to
1327% bi-level or grayscale.
1328%
1329% The format of the SetImageGray method is:
1330%
1331% MagickBooleanType SetImageGray(const Image *image,
1332% ExceptionInfo *exception)
1333%
1334% A description of each parameter follows:
1335%
1336% o image: the image.
1337%
1338% o exception: return any errors or warnings in this structure.
1339%
1340*/
1341MagickExport MagickBooleanType SetImageGray(Image *image,
1342 ExceptionInfo *exception)
1343{
1344 const char
1345 *value;
1346
1347 CacheView
1348 *image_view;
1349
1350 ImageType
1351 type;
1352
1353 const PixelPacket
1354 *p;
1355
1356 ssize_t
1357 x;
1358
1359 ssize_t
1360 y;
1361
1362 assert(image != (Image *) NULL);
1363 assert(image->signature == MagickCoreSignature);
1364 if (IsEventLogging() != MagickFalse)
1365 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1366 if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
1367 (image->type == GrayscaleMatteType))
1368 return(MagickTrue);
1369 if ((IsGrayColorspace(image->colorspace) == MagickFalse) &&
1370 (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse))
1371 return(MagickFalse);
1372 value=GetImageProperty(image,"colorspace:auto-grayscale");
1373 if (IsStringNotFalse(value) == MagickFalse)
1374 return(MagickFalse);
1375 type=BilevelType;
1376 image_view=AcquireVirtualCacheView(image,exception);
1377 for (y=0; y < (ssize_t) image->rows; y++)
1378 {
1379 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1380 if (p == (const PixelPacket *) NULL)
1381 break;
1382 for (x=0; x < (ssize_t) image->columns; x++)
1383 {
1384 if (IsGrayPixel(p) == MagickFalse)
1385 {
1386 type=UndefinedType;
1387 break;
1388 }
1389 if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
1390 type=GrayscaleType;
1391 p++;
1392 }
1393 if (type == UndefinedType)
1394 break;
1395 }
1396 image_view=DestroyCacheView(image_view);
1397 if (type == UndefinedType)
1398 return(MagickFalse);
1399 image->colorspace=GRAYColorspace;
1400 if (SyncImagePixelCache((Image *) image,exception) == MagickFalse)
1401 return(MagickFalse);
1402 image->type=type;
1403 if ((type == GrayscaleType) && (image->matte != MagickFalse))
1404 image->type=GrayscaleMatteType;
1405 return(MagickTrue);
1406}
1407
1408/*
1409%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1410% %
1411% %
1412% %
1413% S e t I m a g e M o n o c h r o m e %
1414% %
1415% %
1416% %
1417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1418%
1419% SetImageMonochrome() returns MagickTrue if all the pixels in the image have
1420% the same red, green, and blue intensities and the intensity is either
1421% 0 or QuantumRange and changes the type of the image to bi-level.
1422%
1423% The format of the SetImageMonochrome method is:
1424%
1425% MagickBooleanType SetImageMonochrome(const Image *image,
1426% ExceptionInfo *exception)
1427%
1428% A description of each parameter follows:
1429%
1430% o image: the image.
1431%
1432% o exception: return any errors or warnings in this structure.
1433%
1434*/
1435MagickExport MagickBooleanType SetImageMonochrome(Image *image,
1436 ExceptionInfo *exception)
1437{
1438 const char
1439 *value;
1440
1441 CacheView
1442 *image_view;
1443
1444 ImageType
1445 type;
1446
1447 ssize_t
1448 x;
1449
1450 const PixelPacket
1451 *p;
1452
1453 ssize_t
1454 y;
1455
1456 assert(image != (Image *) NULL);
1457 assert(image->signature == MagickCoreSignature);
1458 if (IsEventLogging() != MagickFalse)
1459 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1460 if (IsMonochromeImage(image,&image->exception) != MagickFalse)
1461 return(MagickTrue);
1462 if ((IsGrayColorspace(image->colorspace) == MagickFalse) &&
1463 (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse))
1464 return(MagickFalse);
1465 value=GetImageProperty(image,"colorspace:auto-grayscale");
1466 if (IsStringNotFalse(value) == MagickFalse)
1467 return(MagickFalse);
1468 type=BilevelType;
1469 image_view=AcquireVirtualCacheView(image,exception);
1470 for (y=0; y < (ssize_t) image->rows; y++)
1471 {
1472 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1473 if (p == (const PixelPacket *) NULL)
1474 break;
1475 for (x=0; x < (ssize_t) image->columns; x++)
1476 {
1477 if (IsMonochromePixel(p) == MagickFalse)
1478 {
1479 type=UndefinedType;
1480 break;
1481 }
1482 p++;
1483 }
1484 if (type == UndefinedType)
1485 break;
1486 }
1487 image_view=DestroyCacheView(image_view);
1488 if (type == UndefinedType)
1489 return(MagickFalse);
1490 image->colorspace=GRAYColorspace;
1491 if (SyncImagePixelCache((Image *) image,exception) == MagickFalse)
1492 return(MagickFalse);
1493 image->type=type;
1494 return(MagickTrue);
1495}
1496
1497/*
1498%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1499% %
1500% %
1501% %
1502% T r a n s f o r m I m a g e C o l o r s p a c e %
1503% %
1504% %
1505% %
1506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1507%
1508% TransformImageColorspace() transforms an image colorspace.
1509%
1510% The format of the TransformImageColorspace method is:
1511%
1512% MagickBooleanType TransformImageColorspace(Image *image,
1513% const ColorspaceType colorspace)
1514%
1515% A description of each parameter follows:
1516%
1517% o image: the image.
1518%
1519% o colorspace: the colorspace.
1520%
1521*/
1522MagickExport MagickBooleanType TransformImageColorspace(Image *image,
1523 const ColorspaceType colorspace)
1524{
1525 MagickBooleanType
1526 status;
1527
1528 assert(image != (Image *) NULL);
1529 assert(image->signature == MagickCoreSignature);
1530 if (IsEventLogging() != MagickFalse)
1531 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1532 if (image->colorspace == colorspace)
1533 return(MagickTrue);
1534 (void) DeleteImageProfile(image,"icc");
1535 (void) DeleteImageProfile(image,"icm");
1536 if (colorspace == UndefinedColorspace)
1537 return(SetImageColorspace(image,colorspace));
1538 /*
1539 Convert the reference image from an alternate colorspace to sRGB.
1540 */
1541 if (IssRGBColorspace(colorspace) != MagickFalse)
1542 return(TransformRGBImage(image,image->colorspace));
1543 status=MagickTrue;
1544 if (IssRGBColorspace(image->colorspace) == MagickFalse)
1545 status=TransformRGBImage(image,image->colorspace);
1546 if (status == MagickFalse)
1547 return(status);
1548 /*
1549 Convert the reference image from sRGB to an alternate colorspace.
1550 */
1551 if (RGBTransformImage(image,colorspace) == MagickFalse)
1552 status=MagickFalse;
1553 return(status);
1554}
1555
1556/*
1557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1558% %
1559% %
1560% %
1561+ T r a n s f o r m R G B I m a g e %
1562% %
1563% %
1564% %
1565%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1566%
1567% TransformRGBImage() converts the reference image from an alternate
1568% colorspace to sRGB. The transformation matrices are not the standard ones:
1569% the weights are rescaled to normalize the range of the transformed values to
1570% be [0..QuantumRange].
1571%
1572% The format of the TransformRGBImage method is:
1573%
1574% MagickBooleanType TransformRGBImage(Image *image,
1575% const ColorspaceType colorspace)
1576%
1577% A description of each parameter follows:
1578%
1579% o image: the image.
1580%
1581% o colorspace: the colorspace to transform the image to.
1582%
1583*/
1584
1585static inline void ConvertCMYToRGB(const double cyan,const double magenta,
1586 const double yellow,Quantum *red,Quantum *green,Quantum *blue)
1587{
1588 *red=ClampToQuantum((MagickRealType) QuantumRange*(1.0-cyan));
1589 *green=ClampToQuantum((MagickRealType) QuantumRange*(1.0-magenta));
1590 *blue=ClampToQuantum((MagickRealType) QuantumRange*(1.0-yellow));
1591}
1592
1593static inline void ConvertLMSToXYZ(const double L,const double M,const double S,
1594 double *X,double *Y,double *Z)
1595{
1596 *X=1.096123820835514*L-0.278869000218287*M+0.182745179382773*S;
1597 *Y=0.454369041975359*L+0.473533154307412*M+0.072097803717229*S;
1598 *Z=(-0.009627608738429)*L-0.005698031216113*M+1.015325639954543*S;
1599}
1600
1601static inline void ConvertLMSToRGB(const double L,const double M,
1602 const double S,Quantum *red,Quantum *green,Quantum *blue)
1603{
1604 double
1605 X,
1606 Y,
1607 Z;
1608
1609 ConvertLMSToXYZ(L,M,S,&X,&Y,&Z);
1610 ConvertXYZToRGB(X,Y,Z,red,green,blue);
1611}
1612
1613static inline void ConvertLuvToRGB(const double L,const double u,
1614 const double v,Quantum *red,Quantum *green,Quantum *blue)
1615{
1616 double
1617 X,
1618 Y,
1619 Z;
1620
1621 ConvertLuvToXYZ(100.0*L,354.0*u-134.0,262.0*v-140.0,&X,&Y,&Z);
1622 ConvertXYZToRGB(X,Y,Z,red,green,blue);
1623}
1624
1625static inline ssize_t RoundToYCC(const MagickRealType value)
1626{
1627 if (value <= 0.0)
1628 return(0);
1629 if (value >= 1388.0)
1630 return(1388);
1631 return((ssize_t) (value+0.5));
1632}
1633
1634static inline void ConvertLabToRGB(const double L,const double a,
1635 const double b,Quantum *red,Quantum *green,Quantum *blue)
1636{
1637 double
1638 X,
1639 Y,
1640 Z;
1641
1642 ConvertLabToXYZ(100.0*L,255.0*(a-0.5),255.0*(b-0.5),&X,&Y,&Z);
1643 ConvertXYZToRGB(X,Y,Z,red,green,blue);
1644}
1645
1646static inline void ConvertxyYToRGB(const double low_x,const double low_y,
1647 const double cap_Y,Quantum *red,Quantum *green,Quantum *blue)
1648{
1649 double
1650 gamma,
1651 X,
1652 Y,
1653 Z;
1654
1655 gamma=PerceptibleReciprocal(low_y);
1656 X=gamma*cap_Y*low_x;
1657 Y=cap_Y;
1658 Z=gamma*cap_Y*(1.0-low_x-low_y);
1659 ConvertXYZToRGB(X,Y,Z,red,green,blue);
1660}
1661
1662static void ConvertYPbPrToRGB(const double Y,const double Pb,const double Pr,
1663 Quantum *red,Quantum *green,Quantum *blue)
1664{
1665 *red=ClampToQuantum((MagickRealType) QuantumRange*(0.99999999999914679361*Y-
1666 1.2188941887145875e-06*(Pb-0.5)+1.4019995886561440468*(Pr-0.5)));
1667 *green=ClampToQuantum((MagickRealType) QuantumRange*(0.99999975910502514331*Y-
1668 0.34413567816504303521*(Pb-0.5)-0.71413649331646789076*(Pr-0.5)));
1669 *blue=ClampToQuantum((MagickRealType) QuantumRange*(1.00000124040004623180*Y+
1670 1.77200006607230409200*(Pb-0.5)+2.1453384174593273e-06*(Pr-0.5)));
1671}
1672
1673static void ConvertYCbCrToRGB(const double Y,const double Cb,
1674 const double Cr,Quantum *red,Quantum *green,Quantum *blue)
1675{
1676 ConvertYPbPrToRGB(Y,Cb,Cr,red,green,blue);
1677}
1678
1679static void ConvertYDbDrToRGB(const double Y,const double Db,const double Dr,
1680 Quantum *red,Quantum *green,Quantum *blue)
1681{
1682 *red=ClampToQuantum((MagickRealType) QuantumRange*(Y+9.2303716147657e-05*
1683 (Db-0.5)-0.52591263066186533*(Dr-0.5)));
1684 *green=ClampToQuantum((MagickRealType) QuantumRange*(Y-0.12913289889050927*
1685 (Db-0.5)+0.26789932820759876*(Dr-0.5)));
1686 *blue=ClampToQuantum((MagickRealType) QuantumRange*(Y+0.66467905997895482*
1687 (Db-0.5)-7.9202543533108e-05*(Dr-0.5)));
1688}
1689
1690static void ConvertYIQToRGB(const double Y,const double I,const double Q,
1691 Quantum *red,Quantum *green,Quantum *blue)
1692{
1693 *red=ClampToQuantum((MagickRealType) QuantumRange*(Y+0.9562957197589482261*
1694 (I-0.5)+0.6210244164652610754*(Q-0.5)));
1695 *green=ClampToQuantum((MagickRealType) QuantumRange*(Y-0.2721220993185104464*
1696 (I-0.5)-0.6473805968256950427*(Q-0.5)));
1697 *blue=ClampToQuantum((MagickRealType) QuantumRange*(Y-1.1069890167364901945*
1698 (I-0.5)+1.7046149983646481374*(Q-0.5)));
1699}
1700
1701static void ConvertYUVToRGB(const double Y,const double U,const double V,
1702 Quantum *red,Quantum *green,Quantum *blue)
1703{
1704 *red=ClampToQuantum((MagickRealType) QuantumRange*(Y-3.945707070708279e-05*
1705 (U-0.5)+1.1398279671717170825*(V-0.5)));
1706 *green=ClampToQuantum((MagickRealType) QuantumRange*(Y-0.3946101641414141437*
1707 (U-0.5)-0.5805003156565656797*(V-0.5)));
1708 *blue=ClampToQuantum((MagickRealType) QuantumRange*(Y+2.0319996843434342537*
1709 (U-0.5)-4.813762626262513e-04*(V-0.5)));
1710}
1711
1712MagickExport MagickBooleanType TransformRGBImage(Image *image,
1713 const ColorspaceType colorspace)
1714{
1715#define TransformRGBImageTag "Transform/Image"
1716
1717 static const float
1718 YCCMap[1389] =
1719 {
1720 0.000000, 0.000720f, 0.001441f, 0.002161f, 0.002882f, 0.003602f,
1721 0.004323f, 0.005043f, 0.005764f, 0.006484f, 0.007205f, 0.007925f,
1722 0.008646f, 0.009366f, 0.010086f, 0.010807f, 0.011527f, 0.012248f,
1723 0.012968f, 0.013689f, 0.014409f, 0.015130f, 0.015850f, 0.016571f,
1724 0.017291f, 0.018012f, 0.018732f, 0.019452f, 0.020173f, 0.020893f,
1725 0.021614f, 0.022334f, 0.023055f, 0.023775f, 0.024496f, 0.025216f,
1726 0.025937f, 0.026657f, 0.027378f, 0.028098f, 0.028818f, 0.029539f,
1727 0.030259f, 0.030980f, 0.031700f, 0.032421f, 0.033141f, 0.033862f,
1728 0.034582f, 0.035303f, 0.036023f, 0.036744f, 0.037464f, 0.038184f,
1729 0.038905f, 0.039625f, 0.040346f, 0.041066f, 0.041787f, 0.042507f,
1730 0.043228f, 0.043948f, 0.044669f, 0.045389f, 0.046110f, 0.046830f,
1731 0.047550f, 0.048271f, 0.048991f, 0.049712f, 0.050432f, 0.051153f,
1732 0.051873f, 0.052594f, 0.053314f, 0.054035f, 0.054755f, 0.055476f,
1733 0.056196f, 0.056916f, 0.057637f, 0.058357f, 0.059078f, 0.059798f,
1734 0.060519f, 0.061239f, 0.061960f, 0.062680f, 0.063401f, 0.064121f,
1735 0.064842f, 0.065562f, 0.066282f, 0.067003f, 0.067723f, 0.068444f,
1736 0.069164f, 0.069885f, 0.070605f, 0.071326f, 0.072046f, 0.072767f,
1737 0.073487f, 0.074207f, 0.074928f, 0.075648f, 0.076369f, 0.077089f,
1738 0.077810f, 0.078530f, 0.079251f, 0.079971f, 0.080692f, 0.081412f,
1739 0.082133f, 0.082853f, 0.083573f, 0.084294f, 0.085014f, 0.085735f,
1740 0.086455f, 0.087176f, 0.087896f, 0.088617f, 0.089337f, 0.090058f,
1741 0.090778f, 0.091499f, 0.092219f, 0.092939f, 0.093660f, 0.094380f,
1742 0.095101f, 0.095821f, 0.096542f, 0.097262f, 0.097983f, 0.098703f,
1743 0.099424f, 0.100144f, 0.100865f, 0.101585f, 0.102305f, 0.103026f,
1744 0.103746f, 0.104467f, 0.105187f, 0.105908f, 0.106628f, 0.107349f,
1745 0.108069f, 0.108790f, 0.109510f, 0.110231f, 0.110951f, 0.111671f,
1746 0.112392f, 0.113112f, 0.113833f, 0.114553f, 0.115274f, 0.115994f,
1747 0.116715f, 0.117435f, 0.118156f, 0.118876f, 0.119597f, 0.120317f,
1748 0.121037f, 0.121758f, 0.122478f, 0.123199f, 0.123919f, 0.124640f,
1749 0.125360f, 0.126081f, 0.126801f, 0.127522f, 0.128242f, 0.128963f,
1750 0.129683f, 0.130403f, 0.131124f, 0.131844f, 0.132565f, 0.133285f,
1751 0.134006f, 0.134726f, 0.135447f, 0.136167f, 0.136888f, 0.137608f,
1752 0.138329f, 0.139049f, 0.139769f, 0.140490f, 0.141210f, 0.141931f,
1753 0.142651f, 0.143372f, 0.144092f, 0.144813f, 0.145533f, 0.146254f,
1754 0.146974f, 0.147695f, 0.148415f, 0.149135f, 0.149856f, 0.150576f,
1755 0.151297f, 0.152017f, 0.152738f, 0.153458f, 0.154179f, 0.154899f,
1756 0.155620f, 0.156340f, 0.157061f, 0.157781f, 0.158501f, 0.159222f,
1757 0.159942f, 0.160663f, 0.161383f, 0.162104f, 0.162824f, 0.163545f,
1758 0.164265f, 0.164986f, 0.165706f, 0.166427f, 0.167147f, 0.167867f,
1759 0.168588f, 0.169308f, 0.170029f, 0.170749f, 0.171470f, 0.172190f,
1760 0.172911f, 0.173631f, 0.174352f, 0.175072f, 0.175793f, 0.176513f,
1761 0.177233f, 0.177954f, 0.178674f, 0.179395f, 0.180115f, 0.180836f,
1762 0.181556f, 0.182277f, 0.182997f, 0.183718f, 0.184438f, 0.185159f,
1763 0.185879f, 0.186599f, 0.187320f, 0.188040f, 0.188761f, 0.189481f,
1764 0.190202f, 0.190922f, 0.191643f, 0.192363f, 0.193084f, 0.193804f,
1765 0.194524f, 0.195245f, 0.195965f, 0.196686f, 0.197406f, 0.198127f,
1766 0.198847f, 0.199568f, 0.200288f, 0.201009f, 0.201729f, 0.202450f,
1767 0.203170f, 0.203890f, 0.204611f, 0.205331f, 0.206052f, 0.206772f,
1768 0.207493f, 0.208213f, 0.208934f, 0.209654f, 0.210375f, 0.211095f,
1769 0.211816f, 0.212536f, 0.213256f, 0.213977f, 0.214697f, 0.215418f,
1770 0.216138f, 0.216859f, 0.217579f, 0.218300f, 0.219020f, 0.219741f,
1771 0.220461f, 0.221182f, 0.221902f, 0.222622f, 0.223343f, 0.224063f,
1772 0.224784f, 0.225504f, 0.226225f, 0.226945f, 0.227666f, 0.228386f,
1773 0.229107f, 0.229827f, 0.230548f, 0.231268f, 0.231988f, 0.232709f,
1774 0.233429f, 0.234150f, 0.234870f, 0.235591f, 0.236311f, 0.237032f,
1775 0.237752f, 0.238473f, 0.239193f, 0.239914f, 0.240634f, 0.241354f,
1776 0.242075f, 0.242795f, 0.243516f, 0.244236f, 0.244957f, 0.245677f,
1777 0.246398f, 0.247118f, 0.247839f, 0.248559f, 0.249280f, 0.250000f,
1778 0.250720f, 0.251441f, 0.252161f, 0.252882f, 0.253602f, 0.254323f,
1779 0.255043f, 0.255764f, 0.256484f, 0.257205f, 0.257925f, 0.258646f,
1780 0.259366f, 0.260086f, 0.260807f, 0.261527f, 0.262248f, 0.262968f,
1781 0.263689f, 0.264409f, 0.265130f, 0.265850f, 0.266571f, 0.267291f,
1782 0.268012f, 0.268732f, 0.269452f, 0.270173f, 0.270893f, 0.271614f,
1783 0.272334f, 0.273055f, 0.273775f, 0.274496f, 0.275216f, 0.275937f,
1784 0.276657f, 0.277378f, 0.278098f, 0.278818f, 0.279539f, 0.280259f,
1785 0.280980f, 0.281700f, 0.282421f, 0.283141f, 0.283862f, 0.284582f,
1786 0.285303f, 0.286023f, 0.286744f, 0.287464f, 0.288184f, 0.288905f,
1787 0.289625f, 0.290346f, 0.291066f, 0.291787f, 0.292507f, 0.293228f,
1788 0.293948f, 0.294669f, 0.295389f, 0.296109f, 0.296830f, 0.297550f,
1789 0.298271f, 0.298991f, 0.299712f, 0.300432f, 0.301153f, 0.301873f,
1790 0.302594f, 0.303314f, 0.304035f, 0.304755f, 0.305476f, 0.306196f,
1791 0.306916f, 0.307637f, 0.308357f, 0.309078f, 0.309798f, 0.310519f,
1792 0.311239f, 0.311960f, 0.312680f, 0.313401f, 0.314121f, 0.314842f,
1793 0.315562f, 0.316282f, 0.317003f, 0.317723f, 0.318444f, 0.319164f,
1794 0.319885f, 0.320605f, 0.321326f, 0.322046f, 0.322767f, 0.323487f,
1795 0.324207f, 0.324928f, 0.325648f, 0.326369f, 0.327089f, 0.327810f,
1796 0.328530f, 0.329251f, 0.329971f, 0.330692f, 0.331412f, 0.332133f,
1797 0.332853f, 0.333573f, 0.334294f, 0.335014f, 0.335735f, 0.336455f,
1798 0.337176f, 0.337896f, 0.338617f, 0.339337f, 0.340058f, 0.340778f,
1799 0.341499f, 0.342219f, 0.342939f, 0.343660f, 0.344380f, 0.345101f,
1800 0.345821f, 0.346542f, 0.347262f, 0.347983f, 0.348703f, 0.349424f,
1801 0.350144f, 0.350865f, 0.351585f, 0.352305f, 0.353026f, 0.353746f,
1802 0.354467f, 0.355187f, 0.355908f, 0.356628f, 0.357349f, 0.358069f,
1803 0.358790f, 0.359510f, 0.360231f, 0.360951f, 0.361671f, 0.362392f,
1804 0.363112f, 0.363833f, 0.364553f, 0.365274f, 0.365994f, 0.366715f,
1805 0.367435f, 0.368156f, 0.368876f, 0.369597f, 0.370317f, 0.371037f,
1806 0.371758f, 0.372478f, 0.373199f, 0.373919f, 0.374640f, 0.375360f,
1807 0.376081f, 0.376801f, 0.377522f, 0.378242f, 0.378963f, 0.379683f,
1808 0.380403f, 0.381124f, 0.381844f, 0.382565f, 0.383285f, 0.384006f,
1809 0.384726f, 0.385447f, 0.386167f, 0.386888f, 0.387608f, 0.388329f,
1810 0.389049f, 0.389769f, 0.390490f, 0.391210f, 0.391931f, 0.392651f,
1811 0.393372f, 0.394092f, 0.394813f, 0.395533f, 0.396254f, 0.396974f,
1812 0.397695f, 0.398415f, 0.399135f, 0.399856f, 0.400576f, 0.401297f,
1813 0.402017f, 0.402738f, 0.403458f, 0.404179f, 0.404899f, 0.405620f,
1814 0.406340f, 0.407061f, 0.407781f, 0.408501f, 0.409222f, 0.409942f,
1815 0.410663f, 0.411383f, 0.412104f, 0.412824f, 0.413545f, 0.414265f,
1816 0.414986f, 0.415706f, 0.416427f, 0.417147f, 0.417867f, 0.418588f,
1817 0.419308f, 0.420029f, 0.420749f, 0.421470f, 0.422190f, 0.422911f,
1818 0.423631f, 0.424352f, 0.425072f, 0.425793f, 0.426513f, 0.427233f,
1819 0.427954f, 0.428674f, 0.429395f, 0.430115f, 0.430836f, 0.431556f,
1820 0.432277f, 0.432997f, 0.433718f, 0.434438f, 0.435158f, 0.435879f,
1821 0.436599f, 0.437320f, 0.438040f, 0.438761f, 0.439481f, 0.440202f,
1822 0.440922f, 0.441643f, 0.442363f, 0.443084f, 0.443804f, 0.444524f,
1823 0.445245f, 0.445965f, 0.446686f, 0.447406f, 0.448127f, 0.448847f,
1824 0.449568f, 0.450288f, 0.451009f, 0.451729f, 0.452450f, 0.453170f,
1825 0.453891f, 0.454611f, 0.455331f, 0.456052f, 0.456772f, 0.457493f,
1826 0.458213f, 0.458934f, 0.459654f, 0.460375f, 0.461095f, 0.461816f,
1827 0.462536f, 0.463256f, 0.463977f, 0.464697f, 0.465418f, 0.466138f,
1828 0.466859f, 0.467579f, 0.468300f, 0.469020f, 0.469741f, 0.470461f,
1829 0.471182f, 0.471902f, 0.472622f, 0.473343f, 0.474063f, 0.474784f,
1830 0.475504f, 0.476225f, 0.476945f, 0.477666f, 0.478386f, 0.479107f,
1831 0.479827f, 0.480548f, 0.481268f, 0.481988f, 0.482709f, 0.483429f,
1832 0.484150f, 0.484870f, 0.485591f, 0.486311f, 0.487032f, 0.487752f,
1833 0.488473f, 0.489193f, 0.489914f, 0.490634f, 0.491354f, 0.492075f,
1834 0.492795f, 0.493516f, 0.494236f, 0.494957f, 0.495677f, 0.496398f,
1835 0.497118f, 0.497839f, 0.498559f, 0.499280f, 0.500000f, 0.500720f,
1836 0.501441f, 0.502161f, 0.502882f, 0.503602f, 0.504323f, 0.505043f,
1837 0.505764f, 0.506484f, 0.507205f, 0.507925f, 0.508646f, 0.509366f,
1838 0.510086f, 0.510807f, 0.511527f, 0.512248f, 0.512968f, 0.513689f,
1839 0.514409f, 0.515130f, 0.515850f, 0.516571f, 0.517291f, 0.518012f,
1840 0.518732f, 0.519452f, 0.520173f, 0.520893f, 0.521614f, 0.522334f,
1841 0.523055f, 0.523775f, 0.524496f, 0.525216f, 0.525937f, 0.526657f,
1842 0.527378f, 0.528098f, 0.528818f, 0.529539f, 0.530259f, 0.530980f,
1843 0.531700f, 0.532421f, 0.533141f, 0.533862f, 0.534582f, 0.535303f,
1844 0.536023f, 0.536744f, 0.537464f, 0.538184f, 0.538905f, 0.539625f,
1845 0.540346f, 0.541066f, 0.541787f, 0.542507f, 0.543228f, 0.543948f,
1846 0.544669f, 0.545389f, 0.546109f, 0.546830f, 0.547550f, 0.548271f,
1847 0.548991f, 0.549712f, 0.550432f, 0.551153f, 0.551873f, 0.552594f,
1848 0.553314f, 0.554035f, 0.554755f, 0.555476f, 0.556196f, 0.556916f,
1849 0.557637f, 0.558357f, 0.559078f, 0.559798f, 0.560519f, 0.561239f,
1850 0.561960f, 0.562680f, 0.563401f, 0.564121f, 0.564842f, 0.565562f,
1851 0.566282f, 0.567003f, 0.567723f, 0.568444f, 0.569164f, 0.569885f,
1852 0.570605f, 0.571326f, 0.572046f, 0.572767f, 0.573487f, 0.574207f,
1853 0.574928f, 0.575648f, 0.576369f, 0.577089f, 0.577810f, 0.578530f,
1854 0.579251f, 0.579971f, 0.580692f, 0.581412f, 0.582133f, 0.582853f,
1855 0.583573f, 0.584294f, 0.585014f, 0.585735f, 0.586455f, 0.587176f,
1856 0.587896f, 0.588617f, 0.589337f, 0.590058f, 0.590778f, 0.591499f,
1857 0.592219f, 0.592939f, 0.593660f, 0.594380f, 0.595101f, 0.595821f,
1858 0.596542f, 0.597262f, 0.597983f, 0.598703f, 0.599424f, 0.600144f,
1859 0.600865f, 0.601585f, 0.602305f, 0.603026f, 0.603746f, 0.604467f,
1860 0.605187f, 0.605908f, 0.606628f, 0.607349f, 0.608069f, 0.608790f,
1861 0.609510f, 0.610231f, 0.610951f, 0.611671f, 0.612392f, 0.613112f,
1862 0.613833f, 0.614553f, 0.615274f, 0.615994f, 0.616715f, 0.617435f,
1863 0.618156f, 0.618876f, 0.619597f, 0.620317f, 0.621037f, 0.621758f,
1864 0.622478f, 0.623199f, 0.623919f, 0.624640f, 0.625360f, 0.626081f,
1865 0.626801f, 0.627522f, 0.628242f, 0.628963f, 0.629683f, 0.630403f,
1866 0.631124f, 0.631844f, 0.632565f, 0.633285f, 0.634006f, 0.634726f,
1867 0.635447f, 0.636167f, 0.636888f, 0.637608f, 0.638329f, 0.639049f,
1868 0.639769f, 0.640490f, 0.641210f, 0.641931f, 0.642651f, 0.643372f,
1869 0.644092f, 0.644813f, 0.645533f, 0.646254f, 0.646974f, 0.647695f,
1870 0.648415f, 0.649135f, 0.649856f, 0.650576f, 0.651297f, 0.652017f,
1871 0.652738f, 0.653458f, 0.654179f, 0.654899f, 0.655620f, 0.656340f,
1872 0.657061f, 0.657781f, 0.658501f, 0.659222f, 0.659942f, 0.660663f,
1873 0.661383f, 0.662104f, 0.662824f, 0.663545f, 0.664265f, 0.664986f,
1874 0.665706f, 0.666427f, 0.667147f, 0.667867f, 0.668588f, 0.669308f,
1875 0.670029f, 0.670749f, 0.671470f, 0.672190f, 0.672911f, 0.673631f,
1876 0.674352f, 0.675072f, 0.675793f, 0.676513f, 0.677233f, 0.677954f,
1877 0.678674f, 0.679395f, 0.680115f, 0.680836f, 0.681556f, 0.682277f,
1878 0.682997f, 0.683718f, 0.684438f, 0.685158f, 0.685879f, 0.686599f,
1879 0.687320f, 0.688040f, 0.688761f, 0.689481f, 0.690202f, 0.690922f,
1880 0.691643f, 0.692363f, 0.693084f, 0.693804f, 0.694524f, 0.695245f,
1881 0.695965f, 0.696686f, 0.697406f, 0.698127f, 0.698847f, 0.699568f,
1882 0.700288f, 0.701009f, 0.701729f, 0.702450f, 0.703170f, 0.703891f,
1883 0.704611f, 0.705331f, 0.706052f, 0.706772f, 0.707493f, 0.708213f,
1884 0.708934f, 0.709654f, 0.710375f, 0.711095f, 0.711816f, 0.712536f,
1885 0.713256f, 0.713977f, 0.714697f, 0.715418f, 0.716138f, 0.716859f,
1886 0.717579f, 0.718300f, 0.719020f, 0.719741f, 0.720461f, 0.721182f,
1887 0.721902f, 0.722622f, 0.723343f, 0.724063f, 0.724784f, 0.725504f,
1888 0.726225f, 0.726945f, 0.727666f, 0.728386f, 0.729107f, 0.729827f,
1889 0.730548f, 0.731268f, 0.731988f, 0.732709f, 0.733429f, 0.734150f,
1890 0.734870f, 0.735591f, 0.736311f, 0.737032f, 0.737752f, 0.738473f,
1891 0.739193f, 0.739914f, 0.740634f, 0.741354f, 0.742075f, 0.742795f,
1892 0.743516f, 0.744236f, 0.744957f, 0.745677f, 0.746398f, 0.747118f,
1893 0.747839f, 0.748559f, 0.749280f, 0.750000f, 0.750720f, 0.751441f,
1894 0.752161f, 0.752882f, 0.753602f, 0.754323f, 0.755043f, 0.755764f,
1895 0.756484f, 0.757205f, 0.757925f, 0.758646f, 0.759366f, 0.760086f,
1896 0.760807f, 0.761527f, 0.762248f, 0.762968f, 0.763689f, 0.764409f,
1897 0.765130f, 0.765850f, 0.766571f, 0.767291f, 0.768012f, 0.768732f,
1898 0.769452f, 0.770173f, 0.770893f, 0.771614f, 0.772334f, 0.773055f,
1899 0.773775f, 0.774496f, 0.775216f, 0.775937f, 0.776657f, 0.777378f,
1900 0.778098f, 0.778818f, 0.779539f, 0.780259f, 0.780980f, 0.781700f,
1901 0.782421f, 0.783141f, 0.783862f, 0.784582f, 0.785303f, 0.786023f,
1902 0.786744f, 0.787464f, 0.788184f, 0.788905f, 0.789625f, 0.790346f,
1903 0.791066f, 0.791787f, 0.792507f, 0.793228f, 0.793948f, 0.794669f,
1904 0.795389f, 0.796109f, 0.796830f, 0.797550f, 0.798271f, 0.798991f,
1905 0.799712f, 0.800432f, 0.801153f, 0.801873f, 0.802594f, 0.803314f,
1906 0.804035f, 0.804755f, 0.805476f, 0.806196f, 0.806916f, 0.807637f,
1907 0.808357f, 0.809078f, 0.809798f, 0.810519f, 0.811239f, 0.811960f,
1908 0.812680f, 0.813401f, 0.814121f, 0.814842f, 0.815562f, 0.816282f,
1909 0.817003f, 0.817723f, 0.818444f, 0.819164f, 0.819885f, 0.820605f,
1910 0.821326f, 0.822046f, 0.822767f, 0.823487f, 0.824207f, 0.824928f,
1911 0.825648f, 0.826369f, 0.827089f, 0.827810f, 0.828530f, 0.829251f,
1912 0.829971f, 0.830692f, 0.831412f, 0.832133f, 0.832853f, 0.833573f,
1913 0.834294f, 0.835014f, 0.835735f, 0.836455f, 0.837176f, 0.837896f,
1914 0.838617f, 0.839337f, 0.840058f, 0.840778f, 0.841499f, 0.842219f,
1915 0.842939f, 0.843660f, 0.844380f, 0.845101f, 0.845821f, 0.846542f,
1916 0.847262f, 0.847983f, 0.848703f, 0.849424f, 0.850144f, 0.850865f,
1917 0.851585f, 0.852305f, 0.853026f, 0.853746f, 0.854467f, 0.855187f,
1918 0.855908f, 0.856628f, 0.857349f, 0.858069f, 0.858790f, 0.859510f,
1919 0.860231f, 0.860951f, 0.861671f, 0.862392f, 0.863112f, 0.863833f,
1920 0.864553f, 0.865274f, 0.865994f, 0.866715f, 0.867435f, 0.868156f,
1921 0.868876f, 0.869597f, 0.870317f, 0.871037f, 0.871758f, 0.872478f,
1922 0.873199f, 0.873919f, 0.874640f, 0.875360f, 0.876081f, 0.876801f,
1923 0.877522f, 0.878242f, 0.878963f, 0.879683f, 0.880403f, 0.881124f,
1924 0.881844f, 0.882565f, 0.883285f, 0.884006f, 0.884726f, 0.885447f,
1925 0.886167f, 0.886888f, 0.887608f, 0.888329f, 0.889049f, 0.889769f,
1926 0.890490f, 0.891210f, 0.891931f, 0.892651f, 0.893372f, 0.894092f,
1927 0.894813f, 0.895533f, 0.896254f, 0.896974f, 0.897695f, 0.898415f,
1928 0.899135f, 0.899856f, 0.900576f, 0.901297f, 0.902017f, 0.902738f,
1929 0.903458f, 0.904179f, 0.904899f, 0.905620f, 0.906340f, 0.907061f,
1930 0.907781f, 0.908501f, 0.909222f, 0.909942f, 0.910663f, 0.911383f,
1931 0.912104f, 0.912824f, 0.913545f, 0.914265f, 0.914986f, 0.915706f,
1932 0.916427f, 0.917147f, 0.917867f, 0.918588f, 0.919308f, 0.920029f,
1933 0.920749f, 0.921470f, 0.922190f, 0.922911f, 0.923631f, 0.924352f,
1934 0.925072f, 0.925793f, 0.926513f, 0.927233f, 0.927954f, 0.928674f,
1935 0.929395f, 0.930115f, 0.930836f, 0.931556f, 0.932277f, 0.932997f,
1936 0.933718f, 0.934438f, 0.935158f, 0.935879f, 0.936599f, 0.937320f,
1937 0.938040f, 0.938761f, 0.939481f, 0.940202f, 0.940922f, 0.941643f,
1938 0.942363f, 0.943084f, 0.943804f, 0.944524f, 0.945245f, 0.945965f,
1939 0.946686f, 0.947406f, 0.948127f, 0.948847f, 0.949568f, 0.950288f,
1940 0.951009f, 0.951729f, 0.952450f, 0.953170f, 0.953891f, 0.954611f,
1941 0.955331f, 0.956052f, 0.956772f, 0.957493f, 0.958213f, 0.958934f,
1942 0.959654f, 0.960375f, 0.961095f, 0.961816f, 0.962536f, 0.963256f,
1943 0.963977f, 0.964697f, 0.965418f, 0.966138f, 0.966859f, 0.967579f,
1944 0.968300f, 0.969020f, 0.969741f, 0.970461f, 0.971182f, 0.971902f,
1945 0.972622f, 0.973343f, 0.974063f, 0.974784f, 0.975504f, 0.976225f,
1946 0.976945f, 0.977666f, 0.978386f, 0.979107f, 0.979827f, 0.980548f,
1947 0.981268f, 0.981988f, 0.982709f, 0.983429f, 0.984150f, 0.984870f,
1948 0.985591f, 0.986311f, 0.987032f, 0.987752f, 0.988473f, 0.989193f,
1949 0.989914f, 0.990634f, 0.991354f, 0.992075f, 0.992795f, 0.993516f,
1950 0.994236f, 0.994957f, 0.995677f, 0.996398f, 0.997118f, 0.997839f,
1951 0.998559f, 0.999280f, 1.000000
1952 };
1953
1954 CacheView
1955 *image_view;
1956
1958 *exception;
1959
1960 MagickBooleanType
1961 status;
1962
1963 MagickOffsetType
1964 progress;
1965
1966 ssize_t
1967 i;
1968
1969 ssize_t
1970 y;
1971
1973 *y_map,
1974 *x_map,
1975 *z_map;
1976
1977 assert(image != (Image *) NULL);
1978 assert(image->signature == MagickCoreSignature);
1979 if (IsEventLogging() != MagickFalse)
1980 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1981 status=MagickTrue;
1982 progress=0;
1983 exception=(&image->exception);
1984 switch (colorspace)
1985 {
1986 case CMYKColorspace:
1987 {
1989 zero;
1990
1991 /*
1992 Transform image from CMYK to sRGB.
1993 */
1994 if (image->storage_class == PseudoClass)
1995 {
1996 if (SyncImage(image) == MagickFalse)
1997 return(MagickFalse);
1998 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1999 return(MagickFalse);
2000 }
2001 GetMagickPixelPacket(image,&zero);
2002 image_view=AcquireAuthenticCacheView(image,exception);
2003#if defined(MAGICKCORE_OPENMP_SUPPORT)
2004 #pragma omp parallel for schedule(static) shared(status) \
2005 magick_number_threads(image,image,image->rows,1)
2006#endif
2007 for (y=0; y < (ssize_t) image->rows; y++)
2008 {
2009 MagickBooleanType
2010 sync;
2011
2013 pixel;
2014
2015 IndexPacket
2016 *magick_restrict indexes;
2017
2018 ssize_t
2019 x;
2020
2022 *magick_restrict q;
2023
2024 if (status == MagickFalse)
2025 continue;
2026 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2027 exception);
2028 if (q == (PixelPacket *) NULL)
2029 {
2030 status=MagickFalse;
2031 continue;
2032 }
2033 indexes=GetCacheViewAuthenticIndexQueue(image_view);
2034 pixel=zero;
2035 for (x=0; x < (ssize_t) image->columns; x++)
2036 {
2037 SetMagickPixelPacket(image,q,indexes+x,&pixel);
2038 ConvertCMYKToRGB(&pixel);
2039 SetPixelPacket(image,&pixel,q,indexes+x);
2040 q++;
2041 }
2042 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2043 if (sync == MagickFalse)
2044 status=MagickFalse;
2045 }
2046 image_view=DestroyCacheView(image_view);
2047 if (SetImageColorspace(image,sRGBColorspace) == MagickFalse)
2048 return(MagickFalse);
2049 return(status);
2050 }
2051 case LinearGRAYColorspace:
2052 case Rec601LumaColorspace:
2053 {
2054 /*
2055 Transform linear RGB to sRGB colorspace.
2056 */
2057 if (image->storage_class == PseudoClass)
2058 {
2059 if (SyncImage(image) == MagickFalse)
2060 return(MagickFalse);
2061 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2062 return(MagickFalse);
2063 }
2064 if (SetImageColorspace(image,sRGBColorspace) == MagickFalse)
2065 return(MagickFalse);
2066 image_view=AcquireAuthenticCacheView(image,exception);
2067#if defined(MAGICKCORE_OPENMP_SUPPORT)
2068 #pragma omp parallel for schedule(static) shared(status) \
2069 magick_number_threads(image,image,image->rows,1)
2070#endif
2071 for (y=0; y < (ssize_t) image->rows; y++)
2072 {
2073 MagickBooleanType
2074 sync;
2075
2076 ssize_t
2077 x;
2078
2080 *magick_restrict q;
2081
2082 if (status == MagickFalse)
2083 continue;
2084 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2085 exception);
2086 if (q == (PixelPacket *) NULL)
2087 {
2088 status=MagickFalse;
2089 continue;
2090 }
2091 for (x=(ssize_t) image->columns; x != 0; x--)
2092 {
2093 MagickRealType
2094 gray;
2095
2096 gray=0.212656*EncodePixelGamma(GetPixelRed(q))+0.715158*
2097 EncodePixelGamma(GetPixelGreen(q))+0.072186*
2098 EncodePixelGamma(GetPixelBlue(q));
2099 SetPixelRed(q,ClampToQuantum(gray));
2100 SetPixelGreen(q,ClampToQuantum(gray));
2101 SetPixelBlue(q,ClampToQuantum(gray));
2102 q++;
2103 }
2104 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2105 if (sync == MagickFalse)
2106 status=MagickFalse;
2107 }
2108 image_view=DestroyCacheView(image_view);
2109 if (SetImageColorspace(image,sRGBColorspace) == MagickFalse)
2110 return(MagickFalse);
2111 return(status);
2112 }
2113 case GRAYColorspace:
2114 case Rec709LumaColorspace:
2115 {
2116 /*
2117 Transform linear RGB to sRGB colorspace.
2118 */
2119 if (image->storage_class == PseudoClass)
2120 {
2121 if (SyncImage(image) == MagickFalse)
2122 return(MagickFalse);
2123 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2124 return(MagickFalse);
2125 }
2126 if (SetImageColorspace(image,sRGBColorspace) == MagickFalse)
2127 return(MagickFalse);
2128 image_view=AcquireAuthenticCacheView(image,exception);
2129#if defined(MAGICKCORE_OPENMP_SUPPORT)
2130 #pragma omp parallel for schedule(static) shared(status) \
2131 magick_number_threads(image,image,image->rows,1)
2132#endif
2133 for (y=0; y < (ssize_t) image->rows; y++)
2134 {
2135 MagickBooleanType
2136 sync;
2137
2138 ssize_t
2139 x;
2140
2142 *magick_restrict q;
2143
2144 if (status == MagickFalse)
2145 continue;
2146 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2147 exception);
2148 if (q == (PixelPacket *) NULL)
2149 {
2150 status=MagickFalse;
2151 continue;
2152 }
2153 for (x=(ssize_t) image->columns; x != 0; x--)
2154 {
2155 MagickRealType
2156 gray;
2157
2158 gray=(MagickRealType) (0.212656*(double) GetPixelRed(q)+0.715158*
2159 (double) GetPixelGreen(q)+0.072186*(double) GetPixelBlue(q));
2160 SetPixelRed(q,ClampToQuantum(gray));
2161 SetPixelGreen(q,ClampToQuantum(gray));
2162 SetPixelBlue(q,ClampToQuantum(gray));
2163 q++;
2164 }
2165 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2166 if (sync == MagickFalse)
2167 status=MagickFalse;
2168 }
2169 image_view=DestroyCacheView(image_view);
2170 if (SetImageColorspace(image,sRGBColorspace) == MagickFalse)
2171 return(MagickFalse);
2172 return(status);
2173 }
2174 case CMYColorspace:
2175 case HCLColorspace:
2176 case HCLpColorspace:
2177 case HSBColorspace:
2178 case HSIColorspace:
2179 case HSLColorspace:
2180 case HSVColorspace:
2181 case HWBColorspace:
2182 case LabColorspace:
2183 case LCHColorspace:
2184 case LCHabColorspace:
2185 case LCHuvColorspace:
2186 case LMSColorspace:
2187 case LuvColorspace:
2188 case xyYColorspace:
2189 case XYZColorspace:
2190 case YCbCrColorspace:
2191 case YDbDrColorspace:
2192 case YIQColorspace:
2193 case YPbPrColorspace:
2194 case YUVColorspace:
2195 {
2196 /*
2197 Transform image from source colorspace to sRGB.
2198 */
2199 if (image->storage_class == PseudoClass)
2200 {
2201 if (SyncImage(image) == MagickFalse)
2202 return(MagickFalse);
2203 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2204 return(MagickFalse);
2205 }
2206 image_view=AcquireAuthenticCacheView(image,exception);
2207#if defined(MAGICKCORE_OPENMP_SUPPORT)
2208 #pragma omp parallel for schedule(static) shared(status) \
2209 magick_number_threads(image,image,image->rows,1)
2210#endif
2211 for (y=0; y < (ssize_t) image->rows; y++)
2212 {
2213 MagickBooleanType
2214 sync;
2215
2216 ssize_t
2217 x;
2218
2220 *magick_restrict q;
2221
2222 if (status == MagickFalse)
2223 continue;
2224 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2225 exception);
2226 if (q == (PixelPacket *) NULL)
2227 {
2228 status=MagickFalse;
2229 continue;
2230 }
2231 for (x=0; x < (ssize_t) image->columns; x++)
2232 {
2233 double
2234 X,
2235 Y,
2236 Z;
2237
2238 Quantum
2239 blue,
2240 green,
2241 red;
2242
2243 X=QuantumScale*(double) GetPixelRed(q);
2244 Y=QuantumScale*(double) GetPixelGreen(q);
2245 Z=QuantumScale*(double) GetPixelBlue(q);
2246 switch (colorspace)
2247 {
2248 case CMYColorspace:
2249 {
2250 ConvertCMYToRGB(X,Y,Z,&red,&green,&blue);
2251 break;
2252 }
2253 case HCLColorspace:
2254 {
2255 ConvertHCLToRGB(X,Y,Z,&red,&green,&blue);
2256 break;
2257 }
2258 case HCLpColorspace:
2259 {
2260 ConvertHCLpToRGB(X,Y,Z,&red,&green,&blue);
2261 break;
2262 }
2263 case HSBColorspace:
2264 {
2265 ConvertHSBToRGB(X,Y,Z,&red,&green,&blue);
2266 break;
2267 }
2268 case HSIColorspace:
2269 {
2270 ConvertHSIToRGB(X,Y,Z,&red,&green,&blue);
2271 break;
2272 }
2273 case HSLColorspace:
2274 {
2275 ConvertHSLToRGB(X,Y,Z,&red,&green,&blue);
2276 break;
2277 }
2278 case HSVColorspace:
2279 {
2280 ConvertHSVToRGB(X,Y,Z,&red,&green,&blue);
2281 break;
2282 }
2283 case HWBColorspace:
2284 {
2285 ConvertHWBToRGB(X,Y,Z,&red,&green,&blue);
2286 break;
2287 }
2288 case LabColorspace:
2289 {
2290 ConvertLabToRGB(X,Y,Z,&red,&green,&blue);
2291 break;
2292 }
2293 case LCHColorspace:
2294 case LCHabColorspace:
2295 {
2296 ConvertLCHabToRGB(X,Y,Z,&red,&green,&blue);
2297 break;
2298 }
2299 case LCHuvColorspace:
2300 {
2301 ConvertLCHuvToRGB(X,Y,Z,&red,&green,&blue);
2302 break;
2303 }
2304 case LMSColorspace:
2305 {
2306 ConvertLMSToRGB(X,Y,Z,&red,&green,&blue);
2307 break;
2308 }
2309 case LuvColorspace:
2310 {
2311 ConvertLuvToRGB(X,Y,Z,&red,&green,&blue);
2312 break;
2313 }
2314 case xyYColorspace:
2315 {
2316 ConvertxyYToRGB(X,Y,Z,&red,&green,&blue);
2317 break;
2318 }
2319 case XYZColorspace:
2320 {
2321 ConvertXYZToRGB(X,Y,Z,&red,&green,&blue);
2322 break;
2323 }
2324 case YCbCrColorspace:
2325 {
2326 ConvertYCbCrToRGB(X,Y,Z,&red,&green,&blue);
2327 break;
2328 }
2329 case YDbDrColorspace:
2330 {
2331 ConvertYDbDrToRGB(X,Y,Z,&red,&green,&blue);
2332 break;
2333 }
2334 case YIQColorspace:
2335 {
2336 ConvertYIQToRGB(X,Y,Z,&red,&green,&blue);
2337 break;
2338 }
2339 case YPbPrColorspace:
2340 {
2341 ConvertYPbPrToRGB(X,Y,Z,&red,&green,&blue);
2342 break;
2343 }
2344 case YUVColorspace:
2345 {
2346 ConvertYUVToRGB(X,Y,Z,&red,&green,&blue);
2347 break;
2348 }
2349 default:
2350 {
2351 red=ClampToQuantum((MagickRealType) QuantumRange*X);
2352 green=ClampToQuantum((MagickRealType) QuantumRange*Y);
2353 blue=ClampToQuantum((MagickRealType) QuantumRange*Z);
2354 break;
2355 }
2356 }
2357 SetPixelRed(q,ClampToQuantum((MagickRealType) red));
2358 SetPixelGreen(q,ClampToQuantum((MagickRealType) green));
2359 SetPixelBlue(q,ClampToQuantum((MagickRealType) blue));
2360 q++;
2361 }
2362 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2363 if (sync == MagickFalse)
2364 status=MagickFalse;
2365 }
2366 image_view=DestroyCacheView(image_view);
2367 if (SetImageColorspace(image,sRGBColorspace) == MagickFalse)
2368 return(MagickFalse);
2369 return(status);
2370 }
2371 case LogColorspace:
2372 {
2373 const char
2374 *value;
2375
2376 double
2377 black,
2378 density,
2379 film_gamma,
2380 gamma,
2381 reference_black,
2382 reference_white;
2383
2384 Quantum
2385 *logmap;
2386
2387 /*
2388 Transform Log to sRGB colorspace.
2389 */
2390 density=DisplayGamma;
2391 gamma=DisplayGamma;
2392 value=GetImageProperty(image,"gamma");
2393 if (value != (const char *) NULL)
2394 gamma=PerceptibleReciprocal(StringToDouble(value,(char **) NULL));
2395 film_gamma=FilmGamma;
2396 value=GetImageProperty(image,"film-gamma");
2397 if (value != (const char *) NULL)
2398 film_gamma=StringToDouble(value,(char **) NULL);
2399 reference_black=ReferenceBlack;
2400 value=GetImageProperty(image,"reference-black");
2401 if (value != (const char *) NULL)
2402 reference_black=StringToDouble(value,(char **) NULL);
2403 reference_white=ReferenceWhite;
2404 value=GetImageProperty(image,"reference-white");
2405 if (value != (const char *) NULL)
2406 reference_white=StringToDouble(value,(char **) NULL);
2407 logmap=(Quantum *) AcquireQuantumMemory((size_t) MaxMap+1UL,
2408 sizeof(*logmap));
2409 if (logmap == (Quantum *) NULL)
2410 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2411 image->filename);
2412 black=pow(10.0,(reference_black-reference_white)*(gamma/density)*0.002*
2413 PerceptibleReciprocal(film_gamma));
2414 for (i=0; i <= (ssize_t) (reference_black*MaxMap/1024.0); i++)
2415 logmap[i]=(Quantum) 0;
2416 for ( ; i < (ssize_t) (reference_white*MaxMap/1024.0); i++)
2417 logmap[i]=ClampToQuantum((MagickRealType) QuantumRange/(1.0-black)*
2418 (pow(10.0,(1024.0*i/MaxMap-reference_white)*(gamma/density)*0.002*
2419 PerceptibleReciprocal(film_gamma))-black));
2420 for ( ; i <= (ssize_t) MaxMap; i++)
2421 logmap[i]=QuantumRange;
2422 if (image->storage_class == PseudoClass)
2423 {
2424 if (SyncImage(image) == MagickFalse)
2425 return(MagickFalse);
2426 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2427 return(MagickFalse);
2428 }
2429 image_view=AcquireAuthenticCacheView(image,exception);
2430#if defined(MAGICKCORE_OPENMP_SUPPORT)
2431 #pragma omp parallel for schedule(static) shared(status) \
2432 magick_number_threads(image,image,image->rows,1)
2433#endif
2434 for (y=0; y < (ssize_t) image->rows; y++)
2435 {
2436 MagickBooleanType
2437 sync;
2438
2439 ssize_t
2440 x;
2441
2443 *magick_restrict q;
2444
2445 if (status == MagickFalse)
2446 continue;
2447 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2448 exception);
2449 if (q == (PixelPacket *) NULL)
2450 {
2451 status=MagickFalse;
2452 continue;
2453 }
2454 for (x=(ssize_t) image->columns; x != 0; x--)
2455 {
2456 Quantum
2457 blue,
2458 green,
2459 red;
2460
2461 red=ClampToQuantum(EncodePixelGamma((MagickRealType)
2462 logmap[ScaleQuantumToMap(GetPixelRed(q))]));
2463 green=ClampToQuantum(EncodePixelGamma((MagickRealType)
2464 logmap[ScaleQuantumToMap(GetPixelGreen(q))]));
2465 blue=ClampToQuantum(EncodePixelGamma((MagickRealType)
2466 logmap[ScaleQuantumToMap(GetPixelBlue(q))]));
2467 SetPixelRed(q,red);
2468 SetPixelGreen(q,green);
2469 SetPixelBlue(q,blue);
2470 q++;
2471 }
2472 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2473 if (sync == MagickFalse)
2474 status=MagickFalse;
2475 }
2476 image_view=DestroyCacheView(image_view);
2477 logmap=(Quantum *) RelinquishMagickMemory(logmap);
2478 if (SetImageColorspace(image,sRGBColorspace) == MagickFalse)
2479 return(MagickFalse);
2480 return(status);
2481 }
2482 case RGBColorspace:
2483 case scRGBColorspace:
2484 {
2485 /*
2486 Transform linear RGB to sRGB colorspace.
2487 */
2488 if (image->storage_class == PseudoClass)
2489 {
2490 if (SyncImage(image) == MagickFalse)
2491 return(MagickFalse);
2492 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
2493 return(MagickFalse);
2494 }
2495 image_view=AcquireAuthenticCacheView(image,exception);
2496#if defined(MAGICKCORE_OPENMP_SUPPORT)
2497 #pragma omp parallel for schedule(static) shared(status) \
2498 magick_number_threads(image,image,image->rows,1)
2499#endif
2500 for (y=0; y < (ssize_t) image->rows; y++)
2501 {
2502 MagickBooleanType
2503 sync;
2504
2505 ssize_t
2506 x;
2507
2509 *magick_restrict q;
2510
2511 if (status == MagickFalse)
2512 continue;
2513 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2514 exception);
2515 if (q == (PixelPacket *) NULL)
2516 {
2517 status=MagickFalse;
2518 continue;
2519 }
2520 for (x=(ssize_t) image->columns; x != 0; x--)
2521 {
2522 Quantum
2523 blue,
2524 green,
2525 red;
2526
2527 red=ClampToQuantum(EncodePixelGamma((MagickRealType) GetPixelRed(q)));
2528 green=ClampToQuantum(EncodePixelGamma((MagickRealType)
2529 GetPixelGreen(q)));
2530 blue=ClampToQuantum(EncodePixelGamma((MagickRealType)
2531 GetPixelBlue(q)));
2532 SetPixelRed(q,red);
2533 SetPixelGreen(q,green);
2534 SetPixelBlue(q,blue);
2535 q++;
2536 }
2537 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2538 if (sync == MagickFalse)
2539 status=MagickFalse;
2540 }
2541 image_view=DestroyCacheView(image_view);
2542 if (SetImageColorspace(image,sRGBColorspace) == MagickFalse)
2543 return(MagickFalse);
2544 return(status);
2545 }
2546 default:
2547 break;
2548 }
2549 /*
2550 Allocate the tables.
2551 */
2552 x_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
2553 sizeof(*x_map));
2554 y_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
2555 sizeof(*y_map));
2556 z_map=(TransformPacket *) AcquireQuantumMemory((size_t) MaxMap+1UL,
2557 sizeof(*z_map));
2558 if ((x_map == (TransformPacket *) NULL) ||
2559 (y_map == (TransformPacket *) NULL) ||
2560 (z_map == (TransformPacket *) NULL))
2561 {
2562 if (z_map != (TransformPacket *) NULL)
2563 z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
2564 if (y_map != (TransformPacket *) NULL)
2565 y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
2566 if (x_map != (TransformPacket *) NULL)
2567 x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
2568 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2569 image->filename);
2570 }
2571 switch (colorspace)
2572 {
2573 case OHTAColorspace:
2574 {
2575 /*
2576 Initialize OHTA tables:
2577
2578 R = I1+1.00000*I2-0.66668*I3
2579 G = I1+0.00000*I2+1.33333*I3
2580 B = I1-1.00000*I2-0.66668*I3
2581
2582 I and Q, normally -0.5 through 0.5, must be normalized to the range 0
2583 through QuantumRange.
2584 */
2585#if defined(MAGICKCORE_OPENMP_SUPPORT)
2586 #pragma omp parallel for schedule(static)
2587#endif
2588 for (i=0; i <= (ssize_t) MaxMap; i++)
2589 {
2590 x_map[i].x=(1.0*(double) i);
2591 y_map[i].x=(0.5*1.00000*(2.0*(double) i-MaxMap));
2592 z_map[i].x=(-0.5*0.66668*(2.0*(double) i-MaxMap));
2593 x_map[i].y=(1.0*(double) i);
2594 y_map[i].y=(0.5*0.00000*(2.0*(double) i-MaxMap));
2595 z_map[i].y=(0.5*1.33333*(2.0*(double) i-MaxMap));
2596 x_map[i].z=(1.0*(double) i);
2597 y_map[i].z=(-0.5*1.00000*(2.0*(double) i-MaxMap));
2598 z_map[i].z=(-0.5*0.66668*(2.0*(double) i-MaxMap));
2599 }
2600 break;
2601 }
2602 case Rec601YCbCrColorspace:
2603 {
2604 /*
2605 Initialize YCbCr tables:
2606
2607 R = Y +1.402000*Cr
2608 G = Y-0.344136*Cb-0.714136*Cr
2609 B = Y+1.772000*Cb
2610
2611 Cb and Cr, normally -0.5 through 0.5, must be normalized to the range 0
2612 through QuantumRange.
2613 */
2614#if defined(MAGICKCORE_OPENMP_SUPPORT)
2615 #pragma omp parallel for schedule(static)
2616#endif
2617 for (i=0; i <= (ssize_t) MaxMap; i++)
2618 {
2619 x_map[i].x=0.99999999999914679361*(double) i;
2620 y_map[i].x=0.5*(-1.2188941887145875e-06)*(2.00*(double) i-MaxMap);
2621 z_map[i].x=0.5*1.4019995886561440468*(2.00*(double) i-MaxMap);
2622 x_map[i].y=0.99999975910502514331*(double) i;
2623 y_map[i].y=0.5*(-0.34413567816504303521)*(2.00*(double) i-MaxMap);
2624 z_map[i].y=0.5*(-0.71413649331646789076)*(2.00*(double) i-MaxMap);
2625 x_map[i].z=1.00000124040004623180*(double) i;
2626 y_map[i].z=0.5*1.77200006607230409200*(2.00*(double) i-MaxMap);
2627 z_map[i].z=0.5*2.1453384174593273e-06*(2.00*(double) i-MaxMap);
2628 }
2629 break;
2630 }
2631 case Rec709YCbCrColorspace:
2632 {
2633 /*
2634 Initialize YCbCr tables:
2635
2636 R = Y +1.574800*Cr
2637 G = Y-0.187324*Cb-0.468124*Cr
2638 B = Y+1.855600*Cb
2639
2640 Cb and Cr, normally -0.5 through 0.5, must be normalized to the range 0
2641 through QuantumRange.
2642 */
2643#if defined(MAGICKCORE_OPENMP_SUPPORT)
2644 #pragma omp parallel for schedule(static)
2645#endif
2646 for (i=0; i <= (ssize_t) MaxMap; i++)
2647 {
2648 x_map[i].x=(MagickRealType) (1.0*(double) i);
2649 y_map[i].x=(MagickRealType) (0.5*0.000000*(2.0*(double) i-MaxMap));
2650 z_map[i].x=(MagickRealType) (0.5*1.574800*(2.0*(double) i-MaxMap));
2651 x_map[i].y=(MagickRealType) (1.0*(double) i);
2652 y_map[i].y=(MagickRealType) (0.5*(-0.187324)*(2.0*(double) i-MaxMap));
2653 z_map[i].y=(MagickRealType) (0.5*(-0.468124)*(2.0*(double) i-MaxMap));
2654 x_map[i].z=(MagickRealType) (1.0*(double) i);
2655 y_map[i].z=(MagickRealType) (0.5*1.855600*(2.0*(double) i-MaxMap));
2656 z_map[i].z=(MagickRealType) (0.5*0.000000*(2.0*(double) i-MaxMap));
2657 }
2658 break;
2659 }
2660 case YCCColorspace:
2661 {
2662 /*
2663 Initialize YCC tables:
2664
2665 R = Y +1.340762*C2
2666 G = Y-0.317038*C1-0.682243*C2
2667 B = Y+1.632639*C1
2668
2669 YCC is scaled by 1.3584. C1 zero is 156 and C2 is at 137.
2670 */
2671#if defined(MAGICKCORE_OPENMP_SUPPORT)
2672 #pragma omp parallel for schedule(static)
2673#endif
2674 for (i=0; i <= (ssize_t) MaxMap; i++)
2675 {
2676 x_map[i].x=(MagickRealType) (1.3584000*(double) i);
2677 y_map[i].x=(MagickRealType) (0.0000000);
2678 z_map[i].x=(MagickRealType) (1.8215000*((double) i-(MagickRealType)
2679 ScaleQuantumToMap(ScaleCharToQuantum(137))));
2680 x_map[i].y=(MagickRealType) (1.3584000*(double) i);
2681 y_map[i].y=(MagickRealType) ((-0.4302726)*((double) i-(MagickRealType)
2682 ScaleQuantumToMap(ScaleCharToQuantum(156))));
2683 z_map[i].y=(MagickRealType) ((-0.9271435)*((double) i-(MagickRealType)
2684 ScaleQuantumToMap(ScaleCharToQuantum(137))));
2685 x_map[i].z=(MagickRealType) (1.3584000*(double) i);
2686 y_map[i].z=(MagickRealType) (2.2179000*((double) i-(MagickRealType)
2687 ScaleQuantumToMap(ScaleCharToQuantum(156))));
2688 z_map[i].z=(MagickRealType) (0.0000000);
2689 }
2690 break;
2691 }
2692 default:
2693 {
2694 /*
2695 Linear conversion tables.
2696 */
2697#if defined(MAGICKCORE_OPENMP_SUPPORT)
2698 #pragma omp parallel for schedule(static)
2699#endif
2700 for (i=0; i <= (ssize_t) MaxMap; i++)
2701 {
2702 x_map[i].x=(MagickRealType) (1.0*(double) i);
2703 y_map[i].x=(MagickRealType) 0.0;
2704 z_map[i].x=(MagickRealType) 0.0;
2705 x_map[i].y=(MagickRealType) 0.0;
2706 y_map[i].y=(MagickRealType) (1.0*(double) i);
2707 z_map[i].y=(MagickRealType) 0.0;
2708 x_map[i].z=(MagickRealType) 0.0;
2709 y_map[i].z=(MagickRealType) 0.0;
2710 z_map[i].z=(MagickRealType) (1.0*(double) i);
2711 }
2712 break;
2713 }
2714 }
2715 /*
2716 Convert to sRGB.
2717 */
2718 switch (image->storage_class)
2719 {
2720 case DirectClass:
2721 default:
2722 {
2723 /*
2724 Convert DirectClass image.
2725 */
2726 image_view=AcquireAuthenticCacheView(image,exception);
2727#if defined(MAGICKCORE_OPENMP_SUPPORT)
2728 #pragma omp parallel for schedule(static) shared(status) \
2729 magick_number_threads(image,image,image->rows,1)
2730#endif
2731 for (y=0; y < (ssize_t) image->rows; y++)
2732 {
2733 MagickBooleanType
2734 sync;
2735
2737 pixel;
2738
2739 ssize_t
2740 x;
2741
2743 *magick_restrict q;
2744
2745 if (status == MagickFalse)
2746 continue;
2747 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
2748 exception);
2749 if (q == (PixelPacket *) NULL)
2750 {
2751 status=MagickFalse;
2752 continue;
2753 }
2754 for (x=0; x < (ssize_t) image->columns; x++)
2755 {
2756 size_t
2757 blue,
2758 green,
2759 red;
2760
2761 red=ScaleQuantumToMap(GetPixelRed(q));
2762 green=ScaleQuantumToMap(GetPixelGreen(q));
2763 blue=ScaleQuantumToMap(GetPixelBlue(q));
2764 pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x;
2765 pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y;
2766 pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z;
2767 if (colorspace == YCCColorspace)
2768 {
2769 pixel.red=QuantumRange*YCCMap[RoundToYCC(1024.0*pixel.red/
2770 (double) MaxMap)];
2771 pixel.green=QuantumRange*YCCMap[RoundToYCC(1024.0*pixel.green/
2772 (double) MaxMap)];
2773 pixel.blue=QuantumRange*YCCMap[RoundToYCC(1024.0*pixel.blue/
2774 (double) MaxMap)];
2775 }
2776 else
2777 {
2778 pixel.red=(MagickRealType) ScaleMapToQuantum(pixel.red);
2779 pixel.green=(MagickRealType) ScaleMapToQuantum(pixel.green);
2780 pixel.blue=(MagickRealType) ScaleMapToQuantum(pixel.blue);
2781 }
2782 SetPixelRed(q,ClampToQuantum(pixel.red));
2783 SetPixelGreen(q,ClampToQuantum(pixel.green));
2784 SetPixelBlue(q,ClampToQuantum(pixel.blue));
2785 q++;
2786 }
2787 sync=SyncCacheViewAuthenticPixels(image_view,exception);
2788 if (sync == MagickFalse)
2789 status=MagickFalse;
2790 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2791 {
2792 MagickBooleanType
2793 proceed;
2794
2795#if defined(MAGICKCORE_OPENMP_SUPPORT)
2796 #pragma omp atomic
2797#endif
2798 progress++;
2799 proceed=SetImageProgress(image,TransformRGBImageTag,progress,
2800 image->rows);
2801 if (proceed == MagickFalse)
2802 status=MagickFalse;
2803 }
2804 }
2805 image_view=DestroyCacheView(image_view);
2806 break;
2807 }
2808 case PseudoClass:
2809 {
2810 /*
2811 Convert PseudoClass image.
2812 */
2813#if defined(MAGICKCORE_OPENMP_SUPPORT)
2814 #pragma omp parallel for schedule(static) shared(status) \
2815 magick_number_threads(image,image,image->colors,1)
2816#endif
2817 for (i=0; i < (ssize_t) image->colors; i++)
2818 {
2820 pixel;
2821
2822 size_t
2823 blue,
2824 green,
2825 red;
2826
2827 red=ScaleQuantumToMap(image->colormap[i].red);
2828 green=ScaleQuantumToMap(image->colormap[i].green);
2829 blue=ScaleQuantumToMap(image->colormap[i].blue);
2830 pixel.red=x_map[red].x+y_map[green].x+z_map[blue].x;
2831 pixel.green=x_map[red].y+y_map[green].y+z_map[blue].y;
2832 pixel.blue=x_map[red].z+y_map[green].z+z_map[blue].z;
2833 if (colorspace == YCCColorspace)
2834 {
2835 pixel.red=QuantumRange*YCCMap[RoundToYCC(1024.0*pixel.red/
2836 (double) MaxMap)];
2837 pixel.green=QuantumRange*YCCMap[RoundToYCC(1024.0*pixel.green/
2838 (double) MaxMap)];
2839 pixel.blue=QuantumRange*YCCMap[RoundToYCC(1024.0*pixel.blue/
2840 (double) MaxMap)];
2841 }
2842 else
2843 {
2844 pixel.red=(MagickRealType) ScaleMapToQuantum(pixel.red);
2845 pixel.green=(MagickRealType) ScaleMapToQuantum(pixel.green);
2846 pixel.blue=(MagickRealType) ScaleMapToQuantum(pixel.blue);
2847 }
2848 image->colormap[i].red=ClampToQuantum(pixel.red);
2849 image->colormap[i].green=ClampToQuantum(pixel.green);
2850 image->colormap[i].blue=ClampToQuantum(pixel.blue);
2851 }
2852 (void) SyncImage(image);
2853 break;
2854 }
2855 }
2856 /*
2857 Relinquish resources.
2858 */
2859 z_map=(TransformPacket *) RelinquishMagickMemory(z_map);
2860 y_map=(TransformPacket *) RelinquishMagickMemory(y_map);
2861 x_map=(TransformPacket *) RelinquishMagickMemory(x_map);
2862 if (SetImageColorspace(image,sRGBColorspace) == MagickFalse)
2863 return(MagickFalse);
2864 return(MagickTrue);
2865}