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