You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1264 lines
22 KiB
1264 lines
22 KiB
/*****************************************************************************/ |
|
// 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 |
|
|
|
/*****************************************************************************/
|
|
|