]> granicus.if.org Git - imagemagick/commitdiff
(no commit message)
authorcristy <urban-warrior@git.imagemagick.org>
Wed, 1 Aug 2012 12:54:37 +0000 (12:54 +0000)
committercristy <urban-warrior@git.imagemagick.org>
Wed, 1 Aug 2012 12:54:37 +0000 (12:54 +0000)
MagickCore/colorspace.c
MagickCore/colorspace.h
MagickCore/option.c

index f905f28d46a3d6253e59b0b57ccb81df5479ba24..1693eb20ee3f866576d534810726f939f95720fe 100644 (file)
@@ -168,6 +168,24 @@ static inline void ConvertXYZToLab(const double X,const double Y,const double Z,
   *b=(200.0*(y-z))/255.0+0.5;
 }
 
+
+static inline void ConvertXYZToLuv(const double X,const double Y,const double Z,
+  double *L,double *u,double *v)
+{
+  assert(L != (double *) NULL);
+  assert(u != (double *) NULL);
+  assert(v != (double *) NULL);
+  if ((Y/D50Y) > CIEEpsilon)
+    *L=(double) (116.0*pow(Y/D50Y,1/3.0)-16.0);
+  else
+    *L=CIEK*(Y/D50Y);
+  *u=13.0**L*((4.0*X/(X+15.0*Y+3.0*Z))-(4.0*D50X/(D50X+15.0*D50Y+3.0*D50Z)));
+  *v=13.0**L*((9.0*Y/(X+15.0*Y+3.0*Z))-(9.0*D50Y/(D50X+15.0*D50Y+3.0*D50Z)));
+  *L/=100.0;
+  *u=(*u+134.0)/354.0;
+  *v=(*v+140.0)/256.0;
+}
+
 static MagickBooleanType sRGBTransformImage(Image *image,
   const ColorspaceType colorspace,ExceptionInfo *exception)
 {
@@ -777,6 +795,75 @@ static MagickBooleanType sRGBTransformImage(Image *image,
         return(MagickFalse);
       return(status);
     }
+    case LuvColorspace:
+    {
+      /*
+        Transform image from sRGB to Luv.
+      */
+      if (image->storage_class == PseudoClass)
+        {
+          if (SyncImage(image,exception) == MagickFalse)
+            return(MagickFalse);
+          if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
+            return(MagickFalse);
+        }
+      image_view=AcquireAuthenticCacheView(image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+      #pragma omp parallel for schedule(static,4) shared(status) \
+        dynamic_number_threads(image,image->columns,image->rows,1)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          double
+            blue,
+            green,
+            L,
+            red,
+            u,
+            v,
+            X,
+            Y,
+            Z;
+
+          red=QuantumRange*DecompandsRGB(QuantumScale*GetPixelRed(image,q));
+          green=QuantumRange*DecompandsRGB(QuantumScale*GetPixelGreen(image,q));
+          blue=QuantumRange*DecompandsRGB(QuantumScale*GetPixelBlue(image,q));
+          ConvertRGBToXYZ(red,green,blue,&X,&Y,&Z);
+          ConvertXYZToLuv(X,Y,Z,&L,&u,&v);
+          SetPixelRed(image,ClampToQuantum(QuantumRange*L),q);
+          SetPixelGreen(image,ClampToQuantum(QuantumRange*u),q);
+          SetPixelBlue(image,ClampToQuantum(QuantumRange*v),q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      if (SetImageColorspace(image,colorspace,exception) == MagickFalse)
+        return(MagickFalse);
+      return(status);
+    }
     case Rec709LumaColorspace:
     {
       /*
@@ -1549,6 +1636,24 @@ static inline void ConvertLabToXYZ(const double L,const double a,const double b,
   *Z=D50Z*z;
 }
 
+static inline void ConvertLuvToXYZ(const double L,const double u,const double v,
+  double *X,double *Y,double *Z)
+{
+  assert(X != (double *) NULL);
+  assert(Y != (double *) NULL);
+  assert(Z != (double *) NULL);
+  if ((100.0*L) > (CIEK*CIEEpsilon))
+    *Y=(double) pow(((100.0*L)+16.0)/116.0,3.0);
+  else
+    *Y=(100.0*L)/CIEK;
+  *X=((*Y*((39.0*(100.0*L)/((256.0*v-140.0)+13.0*(100.0*L)*(9.0*D50Y/
+     (D50X+15.0*D50Y+3.0*D50Z))))-5.0))+5.0*(*Y))/((((52.0*(100.0*L)/
+     ((354.0*u-134.0)+13.0*(100.0*L)*(4.0*D50X/(D50X+15.0*D50Y+3.0*D50Z))))-
+     1.0)/3.0)-(-1.0/3.0));
+  *Z=(*X*(((52.0*(100.0*L)/((354.0*u-134.0)+13.0*(100.0*L)*(4.0*D50X/
+     (D50X+15.0*D50Y+3.0*D50Z))))-1.0)/3.0))-5.0*(*Y);
+}
+
 static inline ssize_t RoundToYCC(const MagickRealType value)
 {
   if (value <= 0.0)
@@ -2438,6 +2543,78 @@ static MagickBooleanType TransformsRGBImage(Image *image,
         return(MagickFalse);
       return(status);
     }
+    case LuvColorspace:
+    {
+      /*
+        Transform image from Luv to sRGB.
+      */
+      if (image->storage_class == PseudoClass)
+        {
+          if (SyncImage(image,exception) == MagickFalse)
+            return(MagickFalse);
+          if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
+            return(MagickFalse);
+        }
+      image_view=AcquireAuthenticCacheView(image,exception);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+      #pragma omp parallel for schedule(static,4) shared(status) \
+        dynamic_number_threads(image,image->columns,image->rows,1)
+#endif
+      for (y=0; y < (ssize_t) image->rows; y++)
+      {
+        MagickBooleanType
+          sync;
+
+        register ssize_t
+          x;
+
+        register Quantum
+          *restrict q;
+
+        if (status == MagickFalse)
+          continue;
+        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
+          exception);
+        if (q == (Quantum *) NULL)
+          {
+            status=MagickFalse;
+            continue;
+          }
+        for (x=0; x < (ssize_t) image->columns; x++)
+        {
+          double
+            blue,
+            green,
+            L,
+            red,
+            u,
+            v,
+            X,
+            Y,
+            Z;
+
+          L=QuantumScale*GetPixelRed(image,q);
+          u=QuantumScale*GetPixelGreen(image,q);
+          v=QuantumScale*GetPixelBlue(image,q);
+          ConvertLuvToXYZ(L,u,v,&X,&Y,&Z);
+          ConvertXYZToRGB(X,Y,Z,&red,&green,&blue);
+          red=QuantumRange*CompandsRGB(QuantumScale*red);
+          green=QuantumRange*CompandsRGB(QuantumScale*green);
+          blue=QuantumRange*CompandsRGB(QuantumScale*blue);
+          SetPixelRed(image,ClampToQuantum(red),q);
+          SetPixelGreen(image,ClampToQuantum(green),q);
+          SetPixelBlue(image,ClampToQuantum(blue),q);
+          q+=GetPixelChannels(image);
+        }
+        sync=SyncCacheViewAuthenticPixels(image_view,exception);
+        if (sync == MagickFalse)
+          status=MagickFalse;
+      }
+      image_view=DestroyCacheView(image_view);
+      if (SetImageColorspace(image,sRGBColorspace,exception) == MagickFalse)
+        return(MagickFalse);
+      return(status);
+    }
     case RGBColorspace:
     {
       /*
index 07d169a4a59cbcc4b1bf73c1c435fec1527ca9aa..3bade3b922f076f11a8e200a7ca7eb83fd75a47e 100644 (file)
@@ -33,6 +33,7 @@ typedef enum
   HWBColorspace,
   LabColorspace,
   LogColorspace,
+  LuvColorspace,
   OHTAColorspace,
   Rec601LumaColorspace,
   Rec601YCbCrColorspace,
index f5a7f86469b93012ad34db6838939b6b7c5ac46d..a34446ba88360b246b7ab9941e471564949d8095 100644 (file)
@@ -870,6 +870,7 @@ static const OptionInfo
     { "HWB", HWBColorspace, UndefinedOptionFlag, MagickFalse },
     { "Lab", LabColorspace, UndefinedOptionFlag, MagickFalse },
     { "Log", LogColorspace, UndefinedOptionFlag, MagickFalse },
+    { "Luv", LuvColorspace, UndefinedOptionFlag, MagickFalse },
     { "OHTA", OHTAColorspace, UndefinedOptionFlag, MagickFalse },
     { "Rec601Luma", Rec601LumaColorspace, UndefinedOptionFlag, MagickFalse },
     { "Rec601YCbCr", Rec601YCbCrColorspace, UndefinedOptionFlag, MagickFalse },