| /*****************************************************************************/ |
| // Copyright 2006-2012 Adobe Systems Incorporated |
| // All Rights Reserved. |
| // |
| // NOTICE: Adobe permits you to use, modify, and distribute this file in |
| // accordance with the terms of the Adobe license agreement accompanying it. |
| /*****************************************************************************/ |
| |
| /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_utils.h#3 $ */ |
| /* $DateTime: 2012/06/14 20:24:41 $ */ |
| /* $Change: 835078 $ */ |
| /* $Author: tknoll $ */ |
| |
| /*****************************************************************************/ |
| |
| #ifndef __dng_utils__ |
| #define __dng_utils__ |
| |
| /*****************************************************************************/ |
| |
| #include <cmath> |
| #include <limits> |
| |
| #include "dng_classes.h" |
| #include "dng_flags.h" |
| #include "dng_memory.h" |
| #include "dng_safe_arithmetic.h" |
| #include "dng_types.h" |
| |
| /*****************************************************************************/ |
| |
| // The unsigned integer overflow is intended here since a wrap around is used to |
| // calculate the abs() in the branchless version. |
| #if defined(__clang__) && defined(__has_attribute) |
| #if __has_attribute(no_sanitize) |
| __attribute__((no_sanitize("unsigned-integer-overflow"))) |
| #endif |
| #endif |
| inline uint32 Abs_int32 (int32 x) |
| { |
| |
| #if 0 |
| |
| // Reference version. |
| |
| return (uint32) (x < 0 ? -x : x); |
| |
| #else |
| |
| // Branchless version. |
| |
| uint32 mask = (uint32) (x >> 31); |
| |
| return (uint32) (((uint32) x + mask) ^ mask); |
| |
| #endif |
| |
| } |
| |
| inline int32 Min_int32 (int32 x, int32 y) |
| { |
| |
| return (x <= y ? x : y); |
| |
| } |
| |
| inline int32 Max_int32 (int32 x, int32 y) |
| { |
| |
| return (x >= y ? x : y); |
| |
| } |
| |
| inline int32 Pin_int32 (int32 min, int32 x, int32 max) |
| { |
| |
| return Max_int32 (min, Min_int32 (x, max)); |
| |
| } |
| |
| inline int32 Pin_int32_between (int32 a, int32 x, int32 b) |
| { |
| |
| int32 min, max; |
| if (a < b) { min = a; max = b; } |
| else { min = b; max = a; } |
| |
| return Pin_int32 (min, x, max); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| inline uint16 Min_uint16 (uint16 x, uint16 y) |
| { |
| |
| return (x <= y ? x : y); |
| |
| } |
| |
| inline uint16 Max_uint16 (uint16 x, uint16 y) |
| { |
| |
| return (x >= y ? x : y); |
| |
| } |
| |
| inline int16 Pin_int16 (int32 x) |
| { |
| |
| x = Pin_int32 (-32768, x, 32767); |
| |
| return (int16) x; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| inline uint32 Min_uint32 (uint32 x, uint32 y) |
| { |
| |
| return (x <= y ? x : y); |
| |
| } |
| |
| inline uint32 Min_uint32 (uint32 x, uint32 y, uint32 z) |
| { |
| |
| return Min_uint32 (x, Min_uint32 (y, z)); |
| |
| } |
| |
| inline uint32 Max_uint32 (uint32 x, uint32 y) |
| { |
| |
| return (x >= y ? x : y); |
| |
| } |
| |
| inline uint32 Max_uint32 (uint32 x, uint32 y, uint32 z) |
| { |
| |
| return Max_uint32 (x, Max_uint32 (y, z)); |
| |
| } |
| |
| inline uint32 Pin_uint32 (uint32 min, uint32 x, uint32 max) |
| { |
| |
| return Max_uint32 (min, Min_uint32 (x, max)); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| inline uint16 Pin_uint16 (int32 x) |
| { |
| |
| #if 0 |
| |
| // Reference version. |
| |
| x = Pin_int32 (0, x, 0x0FFFF); |
| |
| #else |
| |
| // Single branch version. |
| |
| if (x & ~65535) |
| { |
| |
| x = ~x >> 31; |
| |
| } |
| |
| #endif |
| |
| return (uint16) x; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| inline uint32 RoundDown2 (uint32 x) |
| { |
| |
| return x & (uint32) ~1; |
| |
| } |
| |
| inline uint32 RoundDown4 (uint32 x) |
| { |
| |
| return x & (uint32) ~3; |
| |
| } |
| |
| inline uint32 RoundDown8 (uint32 x) |
| { |
| |
| return x & (uint32) ~7; |
| |
| } |
| |
| inline uint32 RoundDown16 (uint32 x) |
| { |
| |
| return x & (uint32) ~15; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| inline bool RoundUpForPixelSize (uint32 x, uint32 pixelSize, uint32 *result) |
| { |
| |
| uint32 multiple; |
| switch (pixelSize) |
| { |
| |
| case 1: |
| case 2: |
| case 4: |
| case 8: |
| multiple = 16 / pixelSize; |
| break; |
| |
| default: |
| multiple = 16; |
| break; |
| |
| } |
| |
| return RoundUpUint32ToMultiple(x, multiple, result); |
| |
| } |
| |
| /******************************************************************************/ |
| |
| // Type of padding to be performed by ComputeBufferSize(). |
| enum PaddingType |
| { |
| // Don't perform any padding. |
| padNone, |
| // Pad each scanline to an integer multiple of 16 bytes (in the same way |
| // that RoundUpForPixelSize() does). |
| pad16Bytes |
| }; |
| |
| // Returns the number of bytes required for an image tile with the given pixel |
| // type, tile size, number of image planes, and desired padding. Throws a |
| // dng_exception with dng_error_memory error code if one of the components of |
| // tileSize is negative or if arithmetic overflow occurs during the computation. |
| uint32 ComputeBufferSize(uint32 pixelType, const dng_point &tileSize, |
| uint32 numPlanes, PaddingType paddingType); |
| |
| /******************************************************************************/ |
| |
| inline uint64 Abs_int64 (int64 x) |
| { |
| |
| return (uint64) (x < 0 ? -x : x); |
| |
| } |
| |
| inline int64 Min_int64 (int64 x, int64 y) |
| { |
| |
| return (x <= y ? x : y); |
| |
| } |
| |
| inline int64 Max_int64 (int64 x, int64 y) |
| { |
| |
| return (x >= y ? x : y); |
| |
| } |
| |
| inline int64 Pin_int64 (int64 min, int64 x, int64 max) |
| { |
| |
| return Max_int64 (min, Min_int64 (x, max)); |
| |
| } |
| |
| /******************************************************************************/ |
| |
| inline uint64 Min_uint64 (uint64 x, uint64 y) |
| { |
| |
| return (x <= y ? x : y); |
| |
| } |
| |
| inline uint64 Max_uint64 (uint64 x, uint64 y) |
| { |
| |
| return (x >= y ? x : y); |
| |
| } |
| |
| inline uint64 Pin_uint64 (uint64 min, uint64 x, uint64 max) |
| { |
| |
| return Max_uint64 (min, Min_uint64 (x, max)); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| inline real32 Abs_real32 (real32 x) |
| { |
| |
| return (x < 0.0f ? -x : x); |
| |
| } |
| |
| inline real32 Min_real32 (real32 x, real32 y) |
| { |
| |
| return (x < y ? x : y); |
| |
| } |
| |
| inline real32 Max_real32 (real32 x, real32 y) |
| { |
| |
| return (x > y ? x : y); |
| |
| } |
| |
| inline real32 Pin_real32 (real32 min, real32 x, real32 max) |
| { |
| |
| return Max_real32 (min, Min_real32 (x, max)); |
| |
| } |
| |
| inline real32 Pin_real32 (real32 x) |
| { |
| |
| return Pin_real32 (0.0f, x, 1.0f); |
| |
| } |
| |
| inline real32 Pin_real32_Overrange (real32 min, |
| real32 x, |
| real32 max) |
| { |
| |
| // Normal numbers in (min,max). No change. |
| |
| if (x > min && x < max) |
| { |
| return x; |
| } |
| |
| // Map large numbers (including positive infinity) to max. |
| |
| else if (x > min) |
| { |
| return max; |
| } |
| |
| // Map everything else (including negative infinity and all NaNs) to min. |
| |
| return min; |
| |
| } |
| |
| inline real32 Pin_Overrange (real32 x) |
| { |
| |
| // Normal in-range numbers, except for plus and minus zero. |
| |
| if (x > 0.0f && x <= 1.0f) |
| { |
| return x; |
| } |
| |
| // Large numbers, including positive infinity. |
| |
| else if (x > 0.5f) |
| { |
| return 1.0f; |
| } |
| |
| // Plus and minus zero, negative numbers, negative infinity, and all NaNs. |
| |
| return 0.0f; |
| |
| } |
| |
| inline real32 Lerp_real32 (real32 a, real32 b, real32 t) |
| { |
| |
| return a + t * (b - a); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| inline real64 Abs_real64 (real64 x) |
| { |
| |
| return (x < 0.0 ? -x : x); |
| |
| } |
| |
| inline real64 Min_real64 (real64 x, real64 y) |
| { |
| |
| return (x < y ? x : y); |
| |
| } |
| |
| inline real64 Max_real64 (real64 x, real64 y) |
| { |
| |
| return (x > y ? x : y); |
| |
| } |
| |
| inline real64 Pin_real64 (real64 min, real64 x, real64 max) |
| { |
| |
| return Max_real64 (min, Min_real64 (x, max)); |
| |
| } |
| |
| inline real64 Pin_real64 (real64 x) |
| { |
| |
| return Pin_real64 (0.0, x, 1.0); |
| |
| } |
| |
| inline real64 Pin_real64_Overrange (real64 min, |
| real64 x, |
| real64 max) |
| { |
| |
| // Normal numbers in (min,max). No change. |
| |
| if (x > min && x < max) |
| { |
| return x; |
| } |
| |
| // Map large numbers (including positive infinity) to max. |
| |
| else if (x > min) |
| { |
| return max; |
| } |
| |
| // Map everything else (including negative infinity and all NaNs) to min. |
| |
| return min; |
| |
| } |
| |
| inline real64 Lerp_real64 (real64 a, real64 b, real64 t) |
| { |
| |
| return a + t * (b - a); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| inline int32 Round_int32 (real32 x) |
| { |
| |
| return (int32) (x > 0.0f ? x + 0.5f : x - 0.5f); |
| |
| } |
| |
| inline int32 Round_int32 (real64 x) |
| { |
| |
| const real64 temp = x > 0.0 ? x + 0.5 : x - 0.5; |
| |
| // NaNs will fail this test (because NaNs compare false against |
| // everything) and will therefore also take the else branch. |
| if (temp > real64(std::numeric_limits<int32>::min()) - 1.0 && |
| temp < real64(std::numeric_limits<int32>::max()) + 1.0) |
| { |
| return (int32) temp; |
| } |
| |
| else |
| { |
| ThrowProgramError("Overflow in Round_int32"); |
| // Dummy return. |
| return 0; |
| } |
| |
| } |
| |
| inline uint32 Floor_uint32 (real32 x) |
| { |
| |
| return (uint32) Max_real32 (0.0f, x); |
| |
| } |
| |
| inline uint32 Floor_uint32 (real64 x) |
| { |
| |
| const real64 temp = Max_real64 (0.0, x); |
| |
| // NaNs will fail this test (because NaNs compare false against |
| // everything) and will therefore also take the else branch. |
| if (temp < real64(std::numeric_limits<uint32>::max()) + 1.0) |
| { |
| return (uint32) temp; |
| } |
| |
| else |
| { |
| ThrowProgramError("Overflow in Floor_uint32"); |
| // Dummy return. |
| return 0; |
| } |
| |
| } |
| |
| inline uint32 Round_uint32 (real32 x) |
| { |
| |
| return Floor_uint32 (x + 0.5f); |
| |
| } |
| |
| inline uint32 Round_uint32 (real64 x) |
| { |
| |
| return Floor_uint32 (x + 0.5); |
| |
| } |
| |
| /******************************************************************************/ |
| |
| inline int64 Round_int64 (real64 x) |
| { |
| |
| return (int64) (x >= 0.0 ? x + 0.5 : x - 0.5); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| const int64 kFixed64_One = (((int64) 1) << 32); |
| const int64 kFixed64_Half = (((int64) 1) << 31); |
| |
| /******************************************************************************/ |
| |
| inline int64 Real64ToFixed64 (real64 x) |
| { |
| |
| return Round_int64 (x * (real64) kFixed64_One); |
| |
| } |
| |
| /******************************************************************************/ |
| |
| inline real64 Fixed64ToReal64 (int64 x) |
| { |
| |
| return x * (1.0 / (real64) kFixed64_One); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| inline char ForceUppercase (char c) |
| { |
| |
| if (c >= 'a' && c <= 'z') |
| { |
| |
| c -= 'a' - 'A'; |
| |
| } |
| |
| return c; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| inline uint16 SwapBytes16 (uint16 x) |
| { |
| |
| return (uint16) ((x << 8) | |
| (x >> 8)); |
| |
| } |
| |
| inline uint32 SwapBytes32 (uint32 x) |
| { |
| |
| return (x << 24) + |
| ((x << 8) & 0x00FF0000) + |
| ((x >> 8) & 0x0000FF00) + |
| (x >> 24); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| inline bool IsAligned16 (const void *p) |
| { |
| |
| return (((uintptr) p) & 1) == 0; |
| |
| } |
| |
| inline bool IsAligned32 (const void *p) |
| { |
| |
| return (((uintptr) p) & 3) == 0; |
| |
| } |
| |
| inline bool IsAligned64 (const void *p) |
| { |
| |
| return (((uintptr) p) & 7) == 0; |
| |
| } |
| |
| inline bool IsAligned128 (const void *p) |
| { |
| |
| return (((uintptr) p) & 15) == 0; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| // Converts from RGB values (range 0.0 to 1.0) to HSV values (range 0.0 to |
| // 6.0 for hue, and 0.0 to 1.0 for saturation and value). |
| |
| inline void DNG_RGBtoHSV (real32 r, |
| real32 g, |
| real32 b, |
| real32 &h, |
| real32 &s, |
| real32 &v) |
| { |
| |
| v = Max_real32 (r, Max_real32 (g, b)); |
| |
| real32 gap = v - Min_real32 (r, Min_real32 (g, b)); |
| |
| if (gap > 0.0f) |
| { |
| |
| if (r == v) |
| { |
| |
| h = (g - b) / gap; |
| |
| if (h < 0.0f) |
| { |
| h += 6.0f; |
| } |
| |
| } |
| |
| else if (g == v) |
| { |
| h = 2.0f + (b - r) / gap; |
| } |
| |
| else |
| { |
| h = 4.0f + (r - g) / gap; |
| } |
| |
| s = gap / v; |
| |
| } |
| |
| else |
| { |
| h = 0.0f; |
| s = 0.0f; |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| // Converts from HSV values (range 0.0 to 6.0 for hue, and 0.0 to 1.0 for |
| // saturation and value) to RGB values (range 0.0 to 1.0). |
| |
| inline void DNG_HSVtoRGB (real32 h, |
| real32 s, |
| real32 v, |
| real32 &r, |
| real32 &g, |
| real32 &b) |
| { |
| |
| if (s > 0.0f) |
| { |
| |
| if (!std::isfinite(h)) |
| ThrowProgramError("Unexpected NaN or Inf"); |
| h = std::fmod(h, 6.0f); |
| if (h < 0.0f) |
| h += 6.0f; |
| |
| int32 i = (int32) h; |
| real32 f = h - (real32) i; |
| |
| real32 p = v * (1.0f - s); |
| |
| #define q (v * (1.0f - s * f)) |
| #define t (v * (1.0f - s * (1.0f - f))) |
| |
| switch (i) |
| { |
| case 0: r = v; g = t; b = p; break; |
| case 1: r = q; g = v; b = p; break; |
| case 2: r = p; g = v; b = t; break; |
| case 3: r = p; g = q; b = v; break; |
| case 4: r = t; g = p; b = v; break; |
| case 5: r = v; g = p; b = q; break; |
| } |
| |
| #undef q |
| #undef t |
| |
| } |
| |
| else |
| { |
| r = v; |
| g = v; |
| b = v; |
| } |
| |
| } |
| |
| /******************************************************************************/ |
| |
| // High resolution timer, for code profiling. |
| |
| real64 TickTimeInSeconds (); |
| |
| // Lower resolution timer, but more stable. |
| |
| real64 TickCountInSeconds (); |
| |
| /******************************************************************************/ |
| |
| class dng_timer |
| { |
| |
| public: |
| |
| dng_timer (const char *message); |
| |
| ~dng_timer (); |
| |
| private: |
| |
| // Hidden copy constructor and assignment operator. |
| |
| dng_timer (const dng_timer &timer); |
| |
| dng_timer & operator= (const dng_timer &timer); |
| |
| private: |
| |
| const char *fMessage; |
| |
| real64 fStartTime; |
| |
| }; |
| |
| /*****************************************************************************/ |
| |
| // Returns the maximum squared Euclidean distance from the specified point to the |
| // specified rectangle rect. |
| |
| real64 MaxSquaredDistancePointToRect (const dng_point_real64 &point, |
| const dng_rect_real64 &rect); |
| |
| /*****************************************************************************/ |
| |
| // Returns the maximum Euclidean distance from the specified point to the specified |
| // rectangle rect. |
| |
| real64 MaxDistancePointToRect (const dng_point_real64 &point, |
| const dng_rect_real64 &rect); |
| |
| /*****************************************************************************/ |
| |
| inline uint32 DNG_HalfToFloat (uint16 halfValue) |
| { |
| |
| int32 sign = (halfValue >> 15) & 0x00000001; |
| int32 exponent = (halfValue >> 10) & 0x0000001f; |
| int32 mantissa = halfValue & 0x000003ff; |
| |
| if (exponent == 0) |
| { |
| |
| if (mantissa == 0) |
| { |
| |
| // Plus or minus zero |
| |
| return (uint32) (sign << 31); |
| |
| } |
| |
| else |
| { |
| |
| // Denormalized number -- renormalize it |
| |
| while (!(mantissa & 0x00000400)) |
| { |
| mantissa <<= 1; |
| exponent -= 1; |
| } |
| |
| exponent += 1; |
| mantissa &= ~0x00000400; |
| |
| } |
| |
| } |
| |
| else if (exponent == 31) |
| { |
| |
| if (mantissa == 0) |
| { |
| |
| // Positive or negative infinity, convert to maximum (16 bit) values. |
| |
| return (uint32) ((sign << 31) | ((0x1eL + 127 - 15) << 23) | (0x3ffL << 13)); |
| |
| } |
| |
| else |
| { |
| |
| // Nan -- Just set to zero. |
| |
| return 0; |
| |
| } |
| |
| } |
| |
| // Normalized number |
| |
| exponent += (127 - 15); |
| mantissa <<= 13; |
| |
| // Assemble sign, exponent and mantissa. |
| |
| return (uint32) ((sign << 31) | (exponent << 23) | mantissa); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| inline uint16 DNG_FloatToHalf (uint32 i) |
| { |
| |
| int32 sign = (i >> 16) & 0x00008000; |
| int32 exponent = ((i >> 23) & 0x000000ff) - (127 - 15); |
| int32 mantissa = i & 0x007fffff; |
| |
| if (exponent <= 0) |
| { |
| |
| if (exponent < -10) |
| { |
| |
| // Zero or underflow to zero. |
| |
| return (uint16)sign; |
| |
| } |
| |
| // E is between -10 and 0. We convert f to a denormalized half. |
| |
| mantissa = (mantissa | 0x00800000) >> (1 - exponent); |
| |
| // Round to nearest, round "0.5" up. |
| // |
| // Rounding may cause the significand to overflow and make |
| // our number normalized. Because of the way a half's bits |
| // are laid out, we don't have to treat this case separately; |
| // the code below will handle it correctly. |
| |
| if (mantissa & 0x00001000) |
| mantissa += 0x00002000; |
| |
| // Assemble the half from sign, exponent (zero) and mantissa. |
| |
| return (uint16)(sign | (mantissa >> 13)); |
| |
| } |
| |
| else if (exponent == 0xff - (127 - 15)) |
| { |
| |
| if (mantissa == 0) |
| { |
| |
| // F is an infinity; convert f to a half |
| // infinity with the same sign as f. |
| |
| return (uint16)(sign | 0x7c00); |
| |
| } |
| |
| else |
| { |
| |
| // F is a NAN; produce a half NAN that preserves |
| // the sign bit and the 10 leftmost bits of the |
| // significand of f. |
| |
| return (uint16)(sign | 0x7c00 | (mantissa >> 13)); |
| |
| } |
| |
| } |
| |
| // E is greater than zero. F is a normalized float. |
| // We try to convert f to a normalized half. |
| |
| // Round to nearest, round "0.5" up |
| |
| if (mantissa & 0x00001000) |
| { |
| |
| mantissa += 0x00002000; |
| |
| if (mantissa & 0x00800000) |
| { |
| mantissa = 0; // overflow in significand, |
| exponent += 1; // adjust exponent |
| } |
| |
| } |
| |
| // Handle exponent overflow |
| |
| if (exponent > 30) |
| { |
| return (uint16)(sign | 0x7c00); // infinity with the same sign as f. |
| } |
| |
| // Assemble the half from sign, exponent and mantissa. |
| |
| return (uint16)(sign | (exponent << 10) | (mantissa >> 13)); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| inline uint32 DNG_FP24ToFloat (const uint8 *input) |
| { |
| |
| int32 sign = (input [0] >> 7) & 0x01; |
| int32 exponent = (input [0] ) & 0x7F; |
| int32 mantissa = (((int32) input [1]) << 8) | input[2]; |
| |
| if (exponent == 0) |
| { |
| |
| if (mantissa == 0) |
| { |
| |
| // Plus or minus zero |
| |
| return (uint32) (sign << 31); |
| |
| } |
| |
| else |
| { |
| |
| // Denormalized number -- renormalize it |
| |
| while (!(mantissa & 0x00010000)) |
| { |
| mantissa <<= 1; |
| exponent -= 1; |
| } |
| |
| exponent += 1; |
| mantissa &= ~0x00010000; |
| |
| } |
| |
| } |
| |
| else if (exponent == 127) |
| { |
| |
| if (mantissa == 0) |
| { |
| |
| // Positive or negative infinity, convert to maximum (24 bit) values. |
| |
| return (uint32) ((sign << 31) | ((0x7eL + 128 - 64) << 23) | (0xffffL << 7)); |
| |
| } |
| |
| else |
| { |
| |
| // Nan -- Just set to zero. |
| |
| return 0; |
| |
| } |
| |
| } |
| |
| // Normalized number |
| |
| exponent += (128 - 64); |
| mantissa <<= 7; |
| |
| // Assemble sign, exponent and mantissa. |
| |
| return (uint32) ((sign << 31) | (exponent << 23) | mantissa); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| inline void DNG_FloatToFP24 (uint32 input, uint8 *output) |
| { |
| |
| int32 exponent = (int32) ((input >> 23) & 0xFF) - 128; |
| int32 mantissa = input & 0x007FFFFF; |
| |
| if (exponent == 127) // infinity or NaN |
| { |
| |
| // Will the NaN alais to infinity? |
| |
| if (mantissa != 0x007FFFFF && ((mantissa >> 7) == 0xFFFF)) |
| { |
| |
| mantissa &= 0x003FFFFF; // knock out msb to make it a NaN |
| |
| } |
| |
| } |
| |
| else if (exponent > 63) // overflow, map to infinity |
| { |
| |
| exponent = 63; |
| mantissa = 0x007FFFFF; |
| |
| } |
| |
| else if (exponent <= -64) |
| { |
| |
| if (exponent >= -79) // encode as denorm |
| { |
| mantissa = (mantissa | 0x00800000) >> (-63 - exponent); |
| } |
| |
| else // underflow to zero |
| { |
| mantissa = 0; |
| } |
| |
| exponent = -64; |
| |
| } |
| |
| output [0] = (uint8)(((input >> 24) & 0x80) | (uint32) (exponent + 64)); |
| |
| output [1] = (mantissa >> 15) & 0x00FF; |
| output [2] = (mantissa >> 7) & 0x00FF; |
| |
| } |
| |
| /******************************************************************************/ |
| |
| // The following code was from PSDivide.h in Photoshop. |
| |
| // High order 32-bits of an unsigned 32 by 32 multiply. |
| |
| #ifndef MULUH |
| |
| #if defined(_X86_) && defined(_MSC_VER) |
| |
| inline uint32 Muluh86 (uint32 x, uint32 y) |
| { |
| uint32 result; |
| __asm |
| { |
| MOV EAX, x |
| MUL y |
| MOV result, EDX |
| } |
| return (result); |
| } |
| |
| #define MULUH Muluh86 |
| |
| #else |
| |
| #define MULUH(x,y) ((uint32) (((x) * (uint64) (y)) >> 32)) |
| |
| #endif |
| |
| #endif |
| |
| // High order 32-bits of an signed 32 by 32 multiply. |
| |
| #ifndef MULSH |
| |
| #if defined(_X86_) && defined(_MSC_VER) |
| |
| inline int32 Mulsh86 (int32 x, int32 y) |
| { |
| int32 result; |
| __asm |
| { |
| MOV EAX, x |
| IMUL y |
| MOV result, EDX |
| } |
| return (result); |
| } |
| |
| #define MULSH Mulsh86 |
| |
| #else |
| |
| #define MULSH(x,y) ((int32) (((x) * (int64) (y)) >> 32)) |
| |
| #endif |
| |
| #endif |
| |
| /******************************************************************************/ |
| |
| // Random number generator (identical to Apple's) for portable use. |
| |
| // This implements the "minimal standard random number generator" |
| // as proposed by Park and Miller in CACM October, 1988. |
| // It has a period of 2147483647 (0x7fffffff) |
| |
| // This is the ACM standard 30 bit generator: |
| // x' = (x * 16807) mod 2^31-1 |
| // This function intentionally exploits the defined behavior of unsigned integer |
| // overflow. |
| #if defined(__clang__) && defined(__has_attribute) |
| #if __has_attribute(no_sanitize) |
| __attribute__((no_sanitize("unsigned-integer-overflow"))) |
| #endif |
| #endif |
| inline uint32 DNG_Random (uint32 seed) |
| { |
| |
| // high = seed / 127773 |
| |
| uint32 temp = MULUH (0x069C16BD, seed); |
| uint32 high = (temp + ((seed - temp) >> 1)) >> 16; |
| |
| // low = seed % 127773 |
| |
| uint32 low = seed - high * 127773; |
| |
| // seed = (seed * 16807) % 2147483647 |
| |
| seed = 16807 * low - 2836 * high; |
| |
| if (seed & 0x80000000) |
| seed += 2147483647; |
| |
| return seed; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| class dng_dither |
| { |
| |
| public: |
| |
| static const uint32 kRNGBits = 7; |
| |
| static const uint32 kRNGSize = 1 << kRNGBits; |
| |
| static const uint32 kRNGMask = kRNGSize - 1; |
| |
| static const uint32 kRNGSize2D = kRNGSize * kRNGSize; |
| |
| private: |
| |
| dng_memory_data fNoiseBuffer; |
| |
| private: |
| |
| dng_dither (); |
| |
| // Hidden copy constructor and assignment operator. |
| |
| dng_dither (const dng_dither &); |
| |
| dng_dither & operator= (const dng_dither &); |
| |
| public: |
| |
| static const dng_dither & Get (); |
| |
| public: |
| |
| const uint16 *NoiseBuffer16 () const |
| { |
| return fNoiseBuffer.Buffer_uint16 (); |
| } |
| |
| }; |
| |
| /*****************************************************************************/ |
| |
| void HistogramArea (dng_host &host, |
| const dng_image &image, |
| const dng_rect &area, |
| uint32 *hist, |
| uint32 histLimit, |
| uint32 plane = 0); |
| |
| /*****************************************************************************/ |
| |
| void LimitFloatBitDepth (dng_host &host, |
| const dng_image &srcImage, |
| dng_image &dstImage, |
| uint32 bitDepth, |
| real32 scale = 1.0f); |
| |
| /*****************************************************************************/ |
| |
| #endif |
| |
| /*****************************************************************************/ |