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