base: register single precision conversions for types
authorØyvind Kolås <pippin@gimp.org>
Mon, 27 Aug 2018 19:44:32 +0000 (21:44 +0200)
committerØyvind Kolås <pippin@gimp.org>
Mon, 27 Aug 2018 22:37:04 +0000 (00:37 +0200)
We're already registering double versions, having single precision and
in practice possibly sufficient precision for commonly used conversions.

babl/base/babl-base.c
babl/base/type-half.c
babl/base/type-u15.c
babl/base/type-u16.c
babl/base/type-u32.c
babl/base/type-u8.c
extensions/CIE.c

index a25a14449cdd64bfcffbb6b32796a14eb78cd445..7931cfca94d422c7057fc4c03ab7e8d79b676cdd 100644 (file)
@@ -50,9 +50,9 @@ babl_base_destroy (void)
 static void
 types (void)
 {
+  babl_base_type_float ();
   babl_base_type_u15 ();
   babl_base_type_half ();
-  babl_base_type_float ();
   babl_base_type_u8 ();
   babl_base_type_u16 ();
   babl_base_type_u32 ();
index 93d5e5bdaeb67ef9ae76c4452a105d6e48a1c585..f31cfa0fb7cf7c7d85356fcf1055ec2d4fcc99e3 100644 (file)
@@ -183,6 +183,201 @@ static void halfp2doubles(void *target, void *source, long numel)
     }
 }
 
+
+#define  INT16_TYPE          short
+#define UINT16_TYPE unsigned short
+#define  INT32_TYPE          long
+#define UINT32_TYPE unsigned long
+
+// Prototypes -----------------------------------------------------------------
+
+static int singles2halfp(void *target, void *source, int numel);
+static int halfp2singles(void *target, void *source, int numel);
+
+//-----------------------------------------------------------------------------
+//
+// Routine:  singles2halfp
+//
+// Input:  source = Address of 32-bit floating point data to convert
+//         numel  = Number of values at that address to convert
+//
+// Output: target = Address of 16-bit data to hold output (numel values)
+//         return value = 0 if native floating point format is IEEE
+//                      = 1 if native floating point format is not IEEE
+//
+// Programmer:  James Tursa
+//
+//-----------------------------------------------------------------------------
+
+static int singles2halfp(void *target, void *source, int numel)
+{
+    UINT16_TYPE *hp = (UINT16_TYPE *) target; // Type pun output as an unsigned 16-bit int
+    UINT32_TYPE *xp = (UINT32_TYPE *) source; // Type pun input as an unsigned 32-bit int
+    UINT16_TYPE    hs, he, hm;
+    UINT32_TYPE x, xs, xe, xm;
+    int hes;
+    static int next;  // Little Endian adjustment
+    static int checkieee = 1;  // Flag to check for IEEE754, Endian, and word size
+    double one = 1.0; // Used for checking IEEE754 floating point format
+    UINT32_TYPE *ip; // Used for checking IEEE754 floating point format
+    
+    if( checkieee ) { // 1st call, so check for IEEE754, Endian, and word size
+        ip = (UINT32_TYPE *) &one;
+        if( *ip ) { // If Big Endian, then no adjustment
+            next = 0;
+        } else { // If Little Endian, then adjustment will be necessary
+            next = 1;
+            ip++;
+        }
+        if( *ip != 0x3FF00000u ) { // Check for exact IEEE 754 bit pattern of 1.0
+            return 1;  // Floating point bit pattern is not IEEE 754
+            if (next)
+              return 1; // not used, but silences gcc
+        }
+        if( sizeof(INT16_TYPE) != 2 || sizeof(INT32_TYPE) != 4 ) {
+            return 1;  // short is not 16-bits, or long is not 32-bits.
+        }
+        checkieee = 0; // Everything checks out OK
+    }
+    
+    if( source == NULL || target == NULL ) { // Nothing to convert (e.g., imag part of pure real)
+        return 0;
+    }
+    
+    while( numel-- ) {
+        x = *xp++;
+        if( (x & 0x7FFFFFFFu) == 0 ) {  // Signed zero
+            *hp++ = (UINT16_TYPE) (x >> 16);  // Return the signed zero
+        } else { // Not zero
+            xs = x & 0x80000000u;  // Pick off sign bit
+            xe = x & 0x7F800000u;  // Pick off exponent bits
+            xm = x & 0x007FFFFFu;  // Pick off mantissa bits
+            if( xe == 0 ) {  // Denormal will underflow, return a signed zero
+                *hp++ = (UINT16_TYPE) (xs >> 16);
+            } else if( xe == 0x7F800000u ) {  // Inf or NaN (all the exponent bits are set)
+                if( xm == 0 ) { // If mantissa is zero ...
+                    *hp++ = (UINT16_TYPE) ((xs >> 16) | 0x7C00u); // Signed Inf
+                } else {
+                    *hp++ = (UINT16_TYPE) 0xFE00u; // NaN, only 1st mantissa bit set
+                }
+            } else { // Normalized number
+                hs = (UINT16_TYPE) (xs >> 16); // Sign bit
+                hes = ((int)(xe >> 23)) - 127 + 15; // Exponent unbias the single, then bias the halfp
+                if( hes >= 0x1F ) {  // Overflow
+                    *hp++ = (UINT16_TYPE) ((xs >> 16) | 0x7C00u); // Signed Inf
+                } else if( hes <= 0 ) {  // Underflow
+                    if( (14 - hes) > 24 ) {  // Mantissa shifted all the way off & no rounding possibility
+                        hm = (UINT16_TYPE) 0u;  // Set mantissa to zero
+                    } else {
+                        xm |= 0x00800000u;  // Add the hidden leading bit
+                        hm = (UINT16_TYPE) (xm >> (14 - hes)); // Mantissa
+                        if( (xm >> (13 - hes)) & 0x00000001u ) // Check for rounding
+                            hm += (UINT16_TYPE) 1u; // Round, might overflow into exp bit, but this is OK
+                    }
+                    *hp++ = (hs | hm); // Combine sign bit and mantissa bits, biased exponent is zero
+                } else {
+                    he = (UINT16_TYPE) (hes << 10); // Exponent
+                    hm = (UINT16_TYPE) (xm >> 13); // Mantissa
+                    if( xm & 0x00001000u ) // Check for rounding
+                        *hp++ = (hs | he | hm) + (UINT16_TYPE) 1u; // Round, might overflow to inf, this is OK
+                    else
+                        *hp++ = (hs | he | hm);  // No rounding
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Routine:  halfp2singles
+//
+// Input:  source = address of 16-bit data to convert
+//         numel  = Number of values at that address to convert
+//
+// Output: target = Address of 32-bit floating point data to hold output (numel values)
+//         return value = 0 if native floating point format is IEEE
+//                      = 1 if native floating point format is not IEEE
+//
+// Programmer:  James Tursa
+//
+//-----------------------------------------------------------------------------
+
+static int halfp2singles(void *target, void *source, int numel)
+{
+    UINT16_TYPE *hp = (UINT16_TYPE *) source; // Type pun input as an unsigned 16-bit int
+    UINT32_TYPE *xp = (UINT32_TYPE *) target; // Type pun output as an unsigned 32-bit int
+    UINT16_TYPE h, hs, he, hm;
+    UINT32_TYPE xs, xe, xm;
+    INT32_TYPE xes;
+    int e;
+    static int next;  // Little Endian adjustment
+    static int checkieee = 1;  // Flag to check for IEEE754, Endian, and word size
+    double one = 1.0; // Used for checking IEEE754 floating point format
+    UINT32_TYPE *ip; // Used for checking IEEE754 floating point format
+    
+    if( checkieee ) { // 1st call, so check for IEEE754, Endian, and word size
+        ip = (UINT32_TYPE *) &one;
+        if( *ip ) { // If Big Endian, then no adjustment
+            next = 0;
+        } else { // If Little Endian, then adjustment will be necessary
+            next = 1;
+            ip++;
+        }
+        if( *ip != 0x3FF00000u ) { // Check for exact IEEE 754 bit pattern of 1.0
+            return 1;  // Floating point bit pattern is not IEEE 754
+            if (next)
+              return 1; // not used but silences gcc
+        }
+        if( sizeof(INT16_TYPE) != 2 || sizeof(INT32_TYPE) != 4 ) {
+            return 1;  // short is not 16-bits, or long is not 32-bits.
+        }
+        checkieee = 0; // Everything checks out OK
+    }
+    
+    if( source == NULL || target == NULL ) // Nothing to convert (e.g., imag part of pure real)
+        return 0;
+    
+    while( numel-- ) {
+        h = *hp++;
+        if( (h & 0x7FFFu) == 0 ) {  // Signed zero
+            *xp++ = ((UINT32_TYPE) h) << 16;  // Return the signed zero
+        } else { // Not zero
+            hs = h & 0x8000u;  // Pick off sign bit
+            he = h & 0x7C00u;  // Pick off exponent bits
+            hm = h & 0x03FFu;  // Pick off mantissa bits
+            if( he == 0 ) {  // Denormal will convert to normalized
+                e = -1; // The following loop figures out how much extra to adjust the exponent
+                do {
+                    e++;
+                    hm <<= 1;
+                } while( (hm & 0x0400u) == 0 ); // Shift until leading bit overflows into exponent bit
+                xs = ((UINT32_TYPE) hs) << 16; // Sign bit
+                xes = ((INT32_TYPE) (he >> 10)) - 15 + 127 - e; // Exponent unbias the halfp, then bias the single
+                xe = (UINT32_TYPE) (xes << 23); // Exponent
+                xm = ((UINT32_TYPE) (hm & 0x03FFu)) << 13; // Mantissa
+                *xp++ = (xs | xe | xm); // Combine sign bit, exponent bits, and mantissa bits
+            } else if( he == 0x7C00u ) {  // Inf or NaN (all the exponent bits are set)
+                if( hm == 0 ) { // If mantissa is zero ...
+                    *xp++ = (((UINT32_TYPE) hs) << 16) | ((UINT32_TYPE) 0x7F800000u); // Signed Inf
+                } else {
+                    *xp++ = (UINT32_TYPE) 0xFFC00000u; // NaN, only 1st mantissa bit set
+                }
+            } else { // Normalized number
+                xs = ((UINT32_TYPE) hs) << 16; // Sign bit
+                xes = ((INT32_TYPE) (he >> 10)) - 15 + 127; // Exponent unbias the halfp, then bias the single
+                xe = (UINT32_TYPE) (xes << 23); // Exponent
+                xm = ((UINT32_TYPE) hm) << 13; // Mantissa
+                *xp++ = (xs | xe | xm); // Combine sign bit, exponent bits, and mantissa bits
+            }
+        }
+    }
+    return 0;
+}
+
+
 static void
 convert_double_half (BablConversion *conversion,
                      char *src,
@@ -215,6 +410,42 @@ convert_half_double (BablConversion *conversion,
     }
 }
 
+
+static void
+convert_float_half (BablConversion *conversion,
+                    char *src,
+                    char *dst,
+                    int   src_pitch,
+                    int   dst_pitch,
+                    long  n)
+{
+  while (n--)
+    {
+      singles2halfp (dst, src, 1);
+      dst             += dst_pitch;
+      src             += src_pitch;
+    }
+}
+
+static void
+convert_half_float (BablConversion *conversion,
+                    char *src,
+                    char *dst,
+                    int   src_pitch,
+                    int   dst_pitch,
+                    long  n)
+{
+  while (n--)
+    {
+      halfp2singles (dst, src, 1);
+      dst              += dst_pitch;
+      src              += src_pitch;
+    }
+}
+
+
+
+
 void
 babl_base_type_half (void)
 {
@@ -237,4 +468,18 @@ babl_base_type_half (void)
     "plane", convert_double_half,
     NULL
   );
+
+  babl_conversion_new (
+    babl_type_from_id (BABL_HALF),
+    babl_type_from_id (BABL_FLOAT),
+    "plane", convert_half_float,
+    NULL
+  );
+
+  babl_conversion_new (
+    babl_type_from_id (BABL_FLOAT),
+    babl_type_from_id (BABL_HALF),
+    "plane", convert_float_half,
+    NULL
+  );
 }
index 1f1efe00ccb81b4b6ca6a80797b8c6bea470fd11..c3216f8a44bd6696b3ac18c360802090e7366067 100644 (file)
@@ -111,6 +111,92 @@ convert_u15_double_scaled (BablConversion *conversion,
 
 MAKE_CONVERSIONS (u15, 0.0, 1.0, 0, (1<<15))
 
+
+static inline void
+convert_float_u15_scaled (BablConversion *conversion,
+                          float           min_val,
+                          float           max_val,
+                          uint16_t        min,
+                          uint16_t        max,
+                          char           *src,
+                          char           *dst,
+                          int             src_pitch,
+                          int             dst_pitch,
+                          long            n)
+{
+  while (n--)
+    {
+      float   dval = *(float *) src;
+      uint16_t u15val;
+
+      if (dval < min_val)
+        u15val = min;
+      else if (dval > max_val)
+        u15val = max;
+      else
+        u15val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min);
+
+      *(uint16_t *) dst = u15val;
+      dst              += dst_pitch;
+      src              += src_pitch;
+    }
+}
+
+static inline void
+convert_u15_float_scaled (BablConversion *conversion,
+                          float           min_val,
+                          float           max_val,
+                          uint16_t        min,
+                          uint16_t        max,
+                          char           *src,
+                          char           *dst,
+                          int             src_pitch,
+                          int             dst_pitch,
+                          long            n)
+{
+  while (n--)
+    {
+      int    u15val = *(uint16_t *) src;
+      float dval;
+
+      if (u15val < min)
+        dval = min_val;
+      else if (u15val > max)
+        dval = max_val;
+      else
+        dval = (u15val - min) / (float) (max - min) * (max_val - min_val) + min_val;
+
+      (*(float *) dst) = dval;
+      dst              += dst_pitch;
+      src              += src_pitch;
+    }
+}
+
+#define MAKE_CONVERSIONS_float(name, min_val, max_val, min, max)      \
+  static void \
+  convert_ ## name ## _float (BablConversion *conversion, \
+                              void *src, \
+                              void *dst, \
+                              int src_pitch, \
+                              int dst_pitch, \
+                              long n)                               \
+  { \
+    convert_u15_float_scaled (conversion, min_val, max_val, min, max, \
+                               src, dst, src_pitch, dst_pitch, n); \
+  }                                                               \
+  static void \
+  convert_float_ ## name (BablConversion *conversion, void *src, \
+                          void *dst, \
+                          int src_pitch, \
+                          int dst_pitch, \
+                          long n)                                 \
+  { \
+    convert_float_u15_scaled (conversion, min_val, max_val, min, max, \
+                              src, dst, src_pitch, dst_pitch, n); \
+  }
+
+MAKE_CONVERSIONS_float (u15, 0.0, 1.0, 0, (1<<15))
+
 void
 babl_base_type_u15 (void)
 {
@@ -133,5 +219,20 @@ babl_base_type_u15 (void)
     "plane", convert_double_u15,
     NULL
   );
+
+  babl_conversion_new (
+    babl_type ("u15"),
+    babl_type_from_id (BABL_FLOAT),
+    "plane", convert_u15_float,
+    NULL
+  );
+
+  babl_conversion_new (
+    babl_type_from_id (BABL_FLOAT),
+    babl_type ("u15"),
+    "plane", convert_float_u15,
+    NULL
+  );
+
   babl_hmpf_on_name_lookups++;
 }
index 104bdf4ac55ec5e39e98e5cdd3571fdc7aefab09..68a99bcc5d6d01bd0ea6f1319d0f76a66e8e1019 100644 (file)
@@ -110,6 +110,91 @@ convert_u16_double_scaled (BablConversion *conversion,
 
 MAKE_CONVERSIONS (u16, 0.0, 1.0, 0, UINT16_MAX)
 
+static inline void
+convert_float_u16_scaled (BablConversion *conversion,
+                          float    min_val,
+                          float    max_val,
+                          uint16_t min,
+                          uint16_t max,
+                          char    *src,
+                          char    *dst,
+                          int      src_pitch,
+                          int      dst_pitch,
+                          long     n)
+{
+  while (n--)
+    {
+      float   dval = *(float *) src;
+      uint16_t u16val;
+
+      if (dval < min_val)
+        u16val = min;
+      else if (dval > max_val)
+        u16val = max;
+      else
+        u16val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min);
+
+      *(uint16_t *) dst = u16val;
+      dst              += dst_pitch;
+      src              += src_pitch;
+    }
+}
+
+static inline void
+convert_u16_float_scaled (BablConversion *conversion,
+                          float   min_val,
+                          float   max_val,
+                          uint16_t min,
+                          uint16_t max,
+                          char    *src,
+                          char    *dst,
+                          int      src_pitch,
+                          int      dst_pitch,
+                          long     n)
+{
+  while (n--)
+    {
+      int    u16val = *(uint16_t *) src;
+      float dval;
+
+      if (u16val < min)
+        dval = min_val;
+      else if (u16val > max)
+        dval = max_val;
+      else
+        dval = (u16val - min) / (float) (max - min) * (max_val - min_val) + min_val;
+
+      (*(float *) dst) = dval;
+      dst             += dst_pitch;
+      src             += src_pitch;
+    }
+}
+
+#define MAKE_CONVERSIONS_float(name, min_val, max_val, min, max)      \
+  static void \
+  convert_ ## name ## _float (BablConversion *c, void *src, \
+                               void *dst, \
+                               int src_pitch, \
+                               int dst_pitch, \
+                               long n)                               \
+  { \
+    convert_u16_float_scaled (c, min_val, max_val, min, max, \
+                               src, dst, src_pitch, dst_pitch, n); \
+  }                                                               \
+  static void \
+  convert_float_ ## name (BablConversion *c, void *src, \
+                           void *dst, \
+                           int src_pitch, \
+                           int dst_pitch, \
+                           long n)                                 \
+  { \
+    convert_float_u16_scaled (c, min_val, max_val, min, max, \
+                               src, dst, src_pitch, dst_pitch, n); \
+  }
+
+MAKE_CONVERSIONS_float (u16, 0.0, 1.0, 0, UINT16_MAX)
+
+
 void
 babl_base_type_u16 (void)
 {
@@ -132,4 +217,18 @@ babl_base_type_u16 (void)
     "plane", convert_double_u16,
     NULL
   );
+
+  babl_conversion_new (
+    babl_type_from_id (BABL_U16),
+    babl_type_from_id (BABL_FLOAT),
+    "plane", convert_u16_float,
+    NULL
+  );
+
+  babl_conversion_new (
+    babl_type_from_id (BABL_FLOAT),
+    babl_type_from_id (BABL_U16),
+    "plane", convert_float_u16,
+    NULL
+  );
 }
index 3757925ffd63eee54d9ca792bdd27ee5ac60f6b8..1af223353e83af568ec1113ebbaa378391d2608d 100644 (file)
@@ -109,6 +109,92 @@ convert_u32_double_scaled (BablConversion *c,
 
 MAKE_CONVERSIONS (u32, 0.0, 1.0, 0, UINT32_MAX)
 
+
+static inline void
+convert_float_u32_scaled (BablConversion *c,
+                          float   min_val,
+                          float   max_val,
+                          uint32_t min,
+                          uint32_t max,
+                          char    *src,
+                          char    *dst,
+                          int      src_pitch,
+                          int      dst_pitch,
+                          long     n)
+{
+  while (n--)
+    {
+      float   dval = *(float *) src;
+      uint32_t u32val;
+
+      if (dval < min_val)
+        u32val = min;
+      else if (dval > max_val)
+        u32val = max;
+      else
+        u32val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min);
+
+      *(uint32_t *) dst = u32val;
+      dst              += dst_pitch;
+      src              += src_pitch;
+    }
+}
+
+static inline void
+convert_u32_float_scaled (BablConversion *c,
+                          float   min_val,
+                          float   max_val,
+                          uint32_t min,
+                          uint32_t max,
+                          char    *src,
+                          char    *dst,
+                          int      src_pitch,
+                          int      dst_pitch,
+                          long     n)
+{
+  while (n--)
+    {
+      int    u32val = *(uint32_t *) src;
+      float dval;
+
+      if (u32val < min)
+        dval = min_val;
+      else if (u32val > max)
+        dval = max_val;
+      else
+        dval = (u32val - min) / (float) (max - min) * (max_val - min_val) + min_val;
+
+      (*(float *) dst) = dval;
+      dst             += dst_pitch;
+      src             += src_pitch;
+    }
+}
+
+#define MAKE_CONVERSIONS_float(name, min_val, max_val, min, max)      \
+  static void \
+  convert_ ## name ## _float (BablConversion *c, void *src, \
+                              void *dst, \
+                              int src_pitch, \
+                              int dst_pitch, \
+                              long n)                               \
+  { \
+    convert_u32_float_scaled (c, min_val, max_val, min, max, \
+                               src, dst, src_pitch, dst_pitch, n); \
+  }                                                               \
+  static void \
+  convert_float_ ## name (BablConversion *c, void *src, \
+                          void *dst, \
+                          int src_pitch, \
+                          int dst_pitch, \
+                          long n)                                 \
+  { \
+    convert_float_u32_scaled (c, min_val, max_val, min, max, \
+                              src, dst, src_pitch, dst_pitch, n); \
+  }
+
+MAKE_CONVERSIONS_float(u32, 0.0, 1.0, 0, UINT32_MAX)
+
+
 void
 babl_base_type_u32 (void)
 {
@@ -131,4 +217,18 @@ babl_base_type_u32 (void)
     "plane", convert_double_u32,
     NULL
   );
+
+  babl_conversion_new (
+    babl_type_from_id (BABL_U32),
+    babl_type_from_id (BABL_FLOAT),
+    "plane", convert_u32_float,
+    NULL
+  );
+
+  babl_conversion_new (
+    babl_type_from_id (BABL_FLOAT),
+    babl_type_from_id (BABL_U32),
+    "plane", convert_float_u32,
+    NULL
+  );
 }
index 3d792297641e614fef8e7605aa09141cb7ba499e..1cf0629bc7cd521cd497d95892f4cd745a7e0213 100644 (file)
@@ -112,6 +112,95 @@ MAKE_CONVERSIONS (u8, 0.0, 1.0, 0x00, UINT8_MAX)
 MAKE_CONVERSIONS (u8_luma, 0.0, 1.0, 16, 235)
 MAKE_CONVERSIONS (u8_chroma, -0.5, 0.5, 16, 240)
 
+
+static inline void
+convert_float_u8_scaled (BablConversion *c,
+                         float        min_val,
+                         float        max_val,
+                         unsigned char min,
+                         unsigned char max,
+                         char         *src,
+                         char         *dst,
+                         int           src_pitch,
+                         int           dst_pitch,
+                         long          n)
+{
+  while (n--)
+    {
+      float        dval = *(float *) src;
+      unsigned char u8val;
+
+      if (dval < min_val)
+        u8val = min;
+      else if (dval > max_val)
+        u8val = max;
+      else
+        u8val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min);
+
+      *(unsigned char *) dst = u8val;
+      src                   += src_pitch;
+      dst                   += dst_pitch;
+    }
+}
+
+static inline void
+convert_u8_float_scaled (BablConversion *c,
+                          float        min_val,
+                          float        max_val,
+                          unsigned char min,
+                          unsigned char max,
+                          char         *src,
+                          char         *dst,
+                          int           src_pitch,
+                          int           dst_pitch,
+                          long          n)
+{
+  while (n--)
+    {
+      int    u8val = *(unsigned char *) src;
+      float dval;
+
+      if (u8val < min)
+        dval = min_val;
+      else if (u8val > max)
+        dval = max_val;
+      else
+        dval = (u8val - min) / (float) (max - min) * (max_val - min_val) + min_val;
+
+      (*(float *) dst) = dval;
+
+      dst += dst_pitch;
+      src += src_pitch;
+    }
+}
+
+#define MAKE_CONVERSIONS_float(name, min_val, max_val, min, max)      \
+  static void \
+  convert_ ## name ## _float (BablConversion *c, void *src, \
+                               void *dst, \
+                               int src_pitch, \
+                               int dst_pitch, \
+                               long n)                               \
+  { \
+    convert_u8_float_scaled (c, min_val, max_val, min, max, \
+                              src, dst, src_pitch, dst_pitch, n); \
+  }                                                               \
+  static void \
+  convert_float_ ## name (BablConversion *c, void *src, \
+                           void *dst, \
+                           int src_pitch, \
+                           int dst_pitch, \
+                           long n)                                 \
+  { \
+    convert_float_u8_scaled (c, min_val, max_val, min, max, \
+                              src, dst, src_pitch, dst_pitch, n); \
+  }
+
+MAKE_CONVERSIONS_float (u8, 0.0, 1.0, 0x00, UINT8_MAX)
+MAKE_CONVERSIONS_float (u8_luma, 0.0, 1.0, 16, 235)
+MAKE_CONVERSIONS_float (u8_chroma, -0.5, 0.5, 16, 240)
+
+
 void
 babl_base_type_u8 (void)
 {
@@ -176,4 +265,43 @@ babl_base_type_u8 (void)
     "plane", convert_double_u8_chroma,
     NULL
   );
+
+
+
+  babl_conversion_new (
+    babl_type_from_id (BABL_U8),
+    babl_type_from_id (BABL_FLOAT),
+    "plane", convert_u8_float,
+    NULL
+  );
+  babl_conversion_new (
+    babl_type_from_id (BABL_FLOAT),
+    babl_type_from_id (BABL_U8),
+    "plane", convert_float_u8,
+    NULL
+  );
+  babl_conversion_new (
+    babl_type_from_id (BABL_U8_LUMA),
+    babl_type_from_id (BABL_FLOAT),
+    "plane", convert_u8_luma_float,
+    NULL
+  );
+  babl_conversion_new (
+    babl_type_from_id (BABL_FLOAT),
+    babl_type_from_id (BABL_U8_LUMA),
+    "plane", convert_float_u8_luma,
+    NULL
+  );
+  babl_conversion_new (
+    babl_type_from_id (BABL_U8_CHROMA),
+    babl_type_from_id (BABL_FLOAT),
+    "plane", convert_u8_chroma_float,
+    NULL
+  );
+  babl_conversion_new (
+    babl_type_from_id (BABL_FLOAT),
+    babl_type_from_id (BABL_U8_CHROMA),
+    "plane", convert_float_u8_chroma,
+    NULL
+  );
 }
index b96e124e9de684b863ae18d2449ba4ff614a6e9f..4c11c3b85c86d0c12e65e767ba5daf53a17e5bcc 100644 (file)
@@ -1779,6 +1779,96 @@ MAKE_CONVERSIONS (u8_ab, -128.0, 127.0, 0x00, 0xff)
 
 #undef MAKE_CONVERSIONS
 
+static inline void
+convert_float_u8_scaled (const Babl *conversion,
+                          float          min_val,
+                          float          max_val,
+                          unsigned char min,
+                          unsigned char max,
+                          char         *src,
+                          char         *dst,
+                          int           src_pitch,
+                          int           dst_pitch,
+                          long          n)
+{
+  while (n--)
+    {
+      float        dval = *(float *) src;
+      unsigned char u8val;
+
+      if (dval < min_val)
+        u8val = min;
+      else if (dval > max_val)
+        u8val = max;
+      else
+        u8val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min);
+
+      *(unsigned char *) dst = u8val;
+      src                   += src_pitch;
+      dst                   += dst_pitch;
+    }
+}
+
+static inline void
+convert_u8_float_scaled (const Babl *conversion,
+                          float        min_val,
+                          float        max_val,
+                          unsigned char min,
+                          unsigned char max,
+                          char         *src,
+                          char         *dst,
+                          int           src_pitch,
+                          int           dst_pitch,
+                          long          n)
+{
+  while (n--)
+    {
+      int    u8val = *(unsigned char *) src;
+      float dval;
+
+      if (u8val < min)
+        dval = min_val;
+      else if (u8val > max)
+        dval = max_val;
+      else
+        dval = (u8val - min) / (float) (max - min) * (max_val - min_val) + min_val;
+
+      (*(float *) dst) = dval;
+
+      dst += dst_pitch;
+      src += src_pitch;
+    }
+}
+
+#define MAKE_CONVERSIONS(name, min_val, max_val, min, max) \
+  static void \
+  convert_ ## name ## _float (const Babl *c, char *src, \
+                               char *dst, \
+                               int src_pitch, \
+                               int dst_pitch, \
+                               long n)        \
+  { \
+    convert_u8_float_scaled (c, min_val, max_val, min, max, \
+                              src, dst, src_pitch, dst_pitch, n); \
+  }                                                               \
+  static void \
+  convert_float_ ## name (const Babl *c, char *src, \
+                           char *dst, \
+                           int src_pitch, \
+                           int dst_pitch, \
+                           long n)        \
+  { \
+    convert_float_u8_scaled (c, min_val, max_val, min, max, \
+                              src, dst, src_pitch, dst_pitch, n); \
+  }
+
+/* source ICC.1:2004-10 */
+
+MAKE_CONVERSIONS (u8_l, 0.0, 100.0, 0x00, 0xff)
+MAKE_CONVERSIONS (u8_ab, -128.0, 127.0, 0x00, 0xff)
+
+#undef MAKE_CONVERSIONS
+
 static void
 types_u8 (void)
 {
@@ -1827,6 +1917,32 @@ types_u8 (void)
     "plane", convert_double_u8_ab,
     NULL
   );
+
+  babl_conversion_new (
+    babl_type ("CIE u8 L"),
+    babl_type ("float"),
+    "plane", convert_u8_l_float,
+    NULL
+  );
+  babl_conversion_new (
+    babl_type ("float"),
+    babl_type ("CIE u8 L"),
+    "plane", convert_float_u8_l,
+    NULL
+  );
+
+  babl_conversion_new (
+    babl_type ("CIE u8 ab"),
+    babl_type ("float"),
+    "plane", convert_u8_ab_float,
+    NULL
+  );
+  babl_conversion_new (
+    babl_type ("float"),
+    babl_type ("CIE u8 ab"),
+    "plane", convert_float_u8_ab,
+    NULL
+  );
 }
 
 static inline void
@@ -1916,6 +2032,94 @@ MAKE_CONVERSIONS (u16_ab, -128.0, 127.0, 0x00, 0xffff)
 
 #undef MAKE_CONVERSIONS
 
+
+static inline void
+convert_float_u16_scaled (const Babl *conversion,
+                           float         min_val,
+                           float         max_val,
+                           unsigned short min,
+                           unsigned short max,
+                           char          *src,
+                           char          *dst,
+                           int            src_pitch,
+                           int            dst_pitch,
+                           long           n)
+{
+  while (n--)
+    {
+      float         dval = *(float *) src;
+      unsigned short u16val;
+
+      if (dval < min_val)
+        u16val = min;
+      else if (dval > max_val)
+        u16val = max;
+      else
+        u16val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min);
+
+      *(unsigned short *) dst = u16val;
+      dst                    += dst_pitch;
+      src                    += src_pitch;
+    }
+}
+
+static inline void
+convert_u16_float_scaled (const Babl *conversion,
+                           float         min_val,
+                           float         max_val,
+                           unsigned short min,
+                           unsigned short max,
+                           char          *src,
+                           char          *dst,
+                           int            src_pitch,
+                           int            dst_pitch,
+                           long           n)
+{
+  while (n--)
+    {
+      int    u16val = *(unsigned short *) src;
+      float dval;
+
+      if (u16val < min)
+        dval = min_val;
+      else if (u16val > max)
+        dval = max_val;
+      else
+        dval = (u16val - min) / (float) (max - min) * (max_val - min_val) + min_val;
+
+      (*(float *) dst) = dval;
+      dst              += dst_pitch;
+      src              += src_pitch;
+    }
+}
+
+#define MAKE_CONVERSIONS(name, min_val, max_val, min, max)      \
+  static void \
+  convert_ ## name ## _float (const Babl *c, char *src, \
+                               char *dst, \
+                               int src_pitch, \
+                               int dst_pitch, \
+                               long n)        \
+  { \
+    convert_u16_float_scaled (c, min_val, max_val, min, max, \
+                               src, dst, src_pitch, dst_pitch, n); \
+  }                                                               \
+  static void \
+  convert_float_ ## name (const Babl *c, char *src, \
+                           char *dst, \
+                           int src_pitch, \
+                           int dst_pitch, \
+                           long n)        \
+  { \
+    convert_float_u16_scaled (c, min_val, max_val, min, max, \
+                               src, dst, src_pitch, dst_pitch, n); \
+  }
+
+MAKE_CONVERSIONS (u16_l, 0.0, 100.0, 0x00, 0xffff)
+MAKE_CONVERSIONS (u16_ab, -128.0, 127.0, 0x00, 0xffff)
+
+#undef MAKE_CONVERSIONS
+
 static void
 types_u16 (void)
 {
@@ -1965,6 +2169,32 @@ types_u16 (void)
     "plane", convert_double_u16_ab,
     NULL
   );
+
+  babl_conversion_new (
+    babl_type ("CIE u16 L"),
+    babl_type ("float"),
+    "plane", convert_u16_l_float,
+    NULL
+  );
+  babl_conversion_new (
+    babl_type ("float"),
+    babl_type ("CIE u16 L"),
+    "plane", convert_float_u16_l,
+    NULL
+  );
+
+  babl_conversion_new (
+    babl_type ("CIE u16 ab"),
+    babl_type ("float"),
+    "plane", convert_u16_ab_float,
+    NULL
+  );
+  babl_conversion_new (
+    babl_type ("float"),
+    babl_type ("CIE u16 ab"),
+    "plane", convert_float_u16_ab,
+    NULL
+  );
 }
 
 static void