Warning, file /office/calligra/libs/pigment/lut.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * Copyright (c) 2010 Cyrille Berger <cberger@cberger.net> 0003 * 0004 * Redistribution and use in source and binary forms, with or without 0005 * modification, are permitted provided that the following conditions 0006 * are met: 0007 * 0008 * 1. Redistributions of source code must retain the above copyright 0009 * notice, this list of conditions and the following disclaimer. 0010 * 2. Redistributions in binary form must reproduce the above copyright 0011 * notice, this list of conditions and the following disclaimer in the 0012 * documentation and/or other materials provided with the distribution. 0013 * 3. The name of the author may not be used to endorse or promote products 0014 * derived from this software without specific prior written permission. 0015 * 0016 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 0017 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 0018 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 0019 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 0020 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 0021 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 0022 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 0023 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0024 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 0025 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0026 */ 0027 0028 #ifndef _LUT_H_ 0029 #define _LUT_H_ 0030 0031 template<typename _InputT_> 0032 class LutKey; 0033 0034 template<typename _InputT_> 0035 class FullLutKey; 0036 0037 /** 0038 * Provide an implementation for a look-up table for a function. Do not use directly, instead 0039 * use @ref Lut when you are not interested in having the full look-up table or for floating 0040 * point, or use @ref FullLut for 8bits and 16bits when you want to have a full Lut. 0041 * 0042 * @code 0043 * struct MyFunction { 0044 * inline static int compute(int i) 0045 * { 0046 * return 1-i; 0047 * } 0048 * } 0049 * Lut<MyFunction, int, int> myLut; 0050 * @endcode 0051 */ 0052 template<typename _FunctionT_, typename _OutputT_, typename _InputT_, typename _LutKeyT_ > 0053 class BaseLut { 0054 private: 0055 /** 0056 * Initialization of the table. 0057 */ 0058 inline void init() 0059 { 0060 int size = m_key.size(); 0061 m_table = new _OutputT_[size]; 0062 for(int i = 0; i < size; ++i) 0063 { 0064 m_table[i] = m_function(m_key.keyToInput(i)); 0065 } 0066 } 0067 public: 0068 /** 0069 * Create the lut with the specific key. 0070 */ 0071 inline BaseLut(_LutKeyT_ key, _FunctionT_ function = _FunctionT_()) : m_key(key), m_function(function) 0072 { 0073 init(); 0074 } 0075 inline ~BaseLut() { 0076 // just leak on exit -- we get into trouble for explicitly 0077 // deleting stuff from static objects, like registries 0078 //delete[] m_table; 0079 } 0080 public: 0081 /** 0082 * @return the function value for parameter @p i 0083 */ 0084 inline _OutputT_ operator()(_InputT_ i) const 0085 { 0086 if(m_key.inrange(i)) 0087 { 0088 return m_table[m_key.inputToKey(i)]; 0089 } 0090 return m_function(i); 0091 } 0092 private: 0093 _OutputT_* m_table; 0094 _LutKeyT_ m_key; 0095 _FunctionT_ m_function; 0096 }; 0097 0098 /** 0099 * This Lut is limited to a range of values. 0100 */ 0101 template<typename _FunctionT_, typename _OutputT_, typename _InputT_> 0102 class Lut : public BaseLut<_FunctionT_, _OutputT_, _InputT_, LutKey<_InputT_> > { 0103 public: 0104 /** 0105 * Create the lut between @p _min and @p _max . 0106 */ 0107 inline Lut(_InputT_ _min, _InputT_ _max, _FunctionT_ function = _FunctionT_()) : 0108 BaseLut<_FunctionT_, _OutputT_, _InputT_, LutKey<_InputT_> >( LutKey<_InputT_>(_min, _max), function) 0109 { 0110 } 0111 inline Lut(LutKey<_InputT_> key, _FunctionT_ function = _FunctionT_()) : 0112 BaseLut<_FunctionT_, _OutputT_, _InputT_, LutKey<_InputT_> >( key, function) 0113 { 0114 } 0115 }; 0116 0117 /** 0118 * This Lut has precomputed values for all elements. 0119 */ 0120 template<typename _FunctionT_, typename _OutputT_, typename _InputT_> 0121 class FullLut : public BaseLut<_FunctionT_, _OutputT_, _InputT_, FullLutKey<_InputT_> > { 0122 public: 0123 inline FullLut( _FunctionT_ function = _FunctionT_()) : 0124 BaseLut<_FunctionT_, _OutputT_, _InputT_, FullLutKey<_InputT_> >( FullLutKey<_InputT_>(), function) 0125 { 0126 } 0127 }; 0128 0129 #ifdef _USE_QT_TYPES_ 0130 typedef quint8 lut_uint8; 0131 typedef quint16 lut_uint16; 0132 typedef quint32 lut_uint32; 0133 #else 0134 #include <stdint.h> 0135 typedef uint8_t lut_uint8; 0136 typedef uint16_t lut_uint16; 0137 typedef uint32_t lut_uint32; 0138 #endif 0139 0140 // integer specialization 0141 0142 #define PARTIAL_LUT_INT_SPECIALIZATION(_INT_TYPE_) \ 0143 template<> \ 0144 class LutKey<_INT_TYPE_> { \ 0145 public: \ 0146 LutKey<_INT_TYPE_>(_INT_TYPE_ min, _INT_TYPE_ max) : m_min(min), m_max(max) \ 0147 { \ 0148 } \ 0149 public: \ 0150 inline int inputToKey(_INT_TYPE_ i) const \ 0151 { \ 0152 return i - m_min; \ 0153 } \ 0154 inline _INT_TYPE_ keyToInput(int k) const \ 0155 { \ 0156 return k + m_min; \ 0157 } \ 0158 inline bool inrange(_INT_TYPE_ i) const \ 0159 { \ 0160 return i >= m_min && i <= m_max; \ 0161 } \ 0162 inline _INT_TYPE_ minimum() const \ 0163 { \ 0164 return m_min; \ 0165 } \ 0166 inline _INT_TYPE_ maximum() const \ 0167 { \ 0168 return m_max; \ 0169 } \ 0170 inline int size() const \ 0171 { \ 0172 return m_max - m_min + 1; \ 0173 } \ 0174 private: \ 0175 _INT_TYPE_ m_min, m_max; \ 0176 }; 0177 0178 PARTIAL_LUT_INT_SPECIALIZATION(lut_uint8) 0179 PARTIAL_LUT_INT_SPECIALIZATION(lut_uint16) 0180 PARTIAL_LUT_INT_SPECIALIZATION(lut_uint32) 0181 0182 #define FULL_LUT_INT_SPECIALIZATION(_INT_TYPE_, _MIN_, _MAX_) \ 0183 template<> \ 0184 class FullLutKey<_INT_TYPE_> { \ 0185 public: \ 0186 FullLutKey<_INT_TYPE_>() \ 0187 { \ 0188 } \ 0189 public: \ 0190 inline int inputToKey(_INT_TYPE_ i) const \ 0191 { \ 0192 return i - _MIN_; \ 0193 } \ 0194 inline _INT_TYPE_ keyToInput(int k) const \ 0195 { \ 0196 return k + _MIN_; \ 0197 } \ 0198 inline bool inrange(_INT_TYPE_ ) const \ 0199 { \ 0200 return true; \ 0201 } \ 0202 inline _INT_TYPE_ minimum() const \ 0203 { \ 0204 return _MIN_; \ 0205 } \ 0206 inline _INT_TYPE_ maximum() const \ 0207 { \ 0208 return _MAX_; \ 0209 } \ 0210 inline int size() const \ 0211 { \ 0212 return _MAX_ - _MIN_ + 1; \ 0213 } \ 0214 private: \ 0215 }; 0216 0217 FULL_LUT_INT_SPECIALIZATION(lut_uint8, 0, 255) 0218 FULL_LUT_INT_SPECIALIZATION(lut_uint16, 0, 65535) 0219 0220 // float specialization 0221 0222 /** 0223 * This provide an implementation for a LutKey for floating point input values. 0224 * 0225 * Based on "High-speed Conversion of Floating Point Images to 8-bit" by Bill Spitzaks 0226 * (http://mysite.verizon.net/spitzak/conversion/) 0227 */ 0228 template<> 0229 class LutKey<float> { 0230 public: 0231 union IFNumber { 0232 lut_uint32 i; 0233 float f; 0234 }; 0235 public: 0236 LutKey<float>(float min, float max, float precision) : m_min(min), m_max(max), m_precision(precision) 0237 { 0238 // Those values where computed using the test_linear and setting the shift and then using 0239 // the standard deviation. 0240 if (precision <= 0.000011809f) { 0241 m_min = 1; 0242 m_max = -1; 0243 } 0244 else if (precision <= 0.0000237291f) m_shift = 8; 0245 else if (precision <= 0.0000475024f) m_shift = 9; 0246 else if (precision <= 0.0000948575f) m_shift = 10; 0247 else if (precision <= 0.00019013f) m_shift = 11; 0248 else if (precision <= 0.000379523f) m_shift = 12; 0249 else if (precision <= 0.000758431f) m_shift = 13; 0250 else if (precision <= 0.00151891f) m_shift = 14; 0251 else if (precision <= 0.00303725f) m_shift = 15; 0252 else m_shift = 16; 0253 0254 if ( 0.0 <= m_min && m_min <= precision) 0255 m_min = precision; 0256 if ( -precision <= m_max && m_max <= 0.0) 0257 m_max = -precision; 0258 0259 IFNumber uf; 0260 0261 if(m_min > 0 && m_max > 0) 0262 { 0263 uf.f = m_min; 0264 m_tMin_p = uf.i >> m_shift; 0265 uf.f = m_max; 0266 m_tMax_p = uf.i >> m_shift; 0267 m_tMin_n = m_tMax_p; 0268 m_tMax_n = m_tMax_p; 0269 } else if( m_max < 0) 0270 { 0271 uf.f = m_min; 0272 m_tMax_n = uf.i >> m_shift; 0273 uf.f = m_max; 0274 m_tMin_n = uf.i >> m_shift; 0275 m_tMin_p = m_tMax_n; 0276 m_tMax_p = m_tMax_n; 0277 } else { // m_min <0 && m_max > 0 0278 uf.f = precision; 0279 m_tMin_p = uf.i >> m_shift; 0280 uf.f = m_max; 0281 m_tMax_p = uf.i >> m_shift; 0282 uf.f = -precision; 0283 m_tMin_n = uf.i >> m_shift; 0284 uf.f = m_min; 0285 m_tMax_n = uf.i >> m_shift; 0286 } 0287 m_diff_p = m_tMax_p - m_tMin_p; 0288 } 0289 public: 0290 inline int inputToKey(float i) const 0291 { 0292 IFNumber uf; 0293 uf.f = i; 0294 int k = (uf.i >> m_shift); 0295 if(k <= m_tMax_p) 0296 { 0297 return k - m_tMin_p; 0298 } else { 0299 return k - m_tMin_n + m_diff_p; 0300 } 0301 } 0302 inline float keyToInput(int k) const 0303 { 0304 IFNumber uf; 0305 if( k <= m_diff_p ) { 0306 uf.i = ((k + m_tMin_p) << m_shift); 0307 } else { 0308 uf.i = ((k + m_tMin_n - m_diff_p ) << m_shift); 0309 } 0310 return uf.f; 0311 } 0312 inline bool inrange(float i) const 0313 { 0314 return i >= m_min && i <= m_max && (i < -m_precision || i > m_precision); 0315 } 0316 inline float minimum() const 0317 { 0318 return m_min; 0319 } 0320 inline float maximum() const 0321 { 0322 return m_max; 0323 } 0324 inline int size() const 0325 { 0326 return m_diff_p + m_tMax_n - m_tMin_p + 1; 0327 } 0328 private: 0329 float m_min, m_max, m_precision; 0330 int m_tMin_p, m_tMax_p, m_tMin_n, m_tMax_n, m_diff_p; 0331 int m_shift; 0332 }; 0333 0334 #endif