agg_gamma_lut.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. //----------------------------------------------------------------------------
  2. // Anti-Grain Geometry - Version 2.4
  3. // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
  4. //
  5. // Permission to copy, use, modify, sell and distribute this software
  6. // is granted provided this copyright notice appears in all copies.
  7. // This software is provided "as is" without express or implied
  8. // warranty, and with no claim as to its suitability for any purpose.
  9. //
  10. //----------------------------------------------------------------------------
  11. // Contact: mcseem@antigrain.com
  12. // mcseemagg@yahoo.com
  13. // http://www.antigrain.com
  14. //----------------------------------------------------------------------------
  15. #ifndef AGG_GAMMA_LUT_INCLUDED
  16. #define AGG_GAMMA_LUT_INCLUDED
  17. #include <math.h>
  18. #include "agg_basics.h"
  19. #include "agg_gamma_functions.h"
  20. namespace agg
  21. {
  22. template<class LoResT=int8u,
  23. class HiResT=int8u,
  24. unsigned GammaShift=8,
  25. unsigned HiResShift=8> class gamma_lut
  26. {
  27. public:
  28. typedef gamma_lut<LoResT, HiResT, GammaShift, HiResShift> self_type;
  29. enum gamma_scale_e
  30. {
  31. gamma_shift = GammaShift,
  32. gamma_size = 1 << gamma_shift,
  33. gamma_mask = gamma_size - 1
  34. };
  35. enum hi_res_scale_e
  36. {
  37. hi_res_shift = HiResShift,
  38. hi_res_size = 1 << hi_res_shift,
  39. hi_res_mask = hi_res_size - 1
  40. };
  41. ~gamma_lut()
  42. {
  43. pod_allocator<LoResT>::deallocate(m_inv_gamma, hi_res_size);
  44. pod_allocator<HiResT>::deallocate(m_dir_gamma, gamma_size);
  45. }
  46. gamma_lut() :
  47. m_gamma(1.0),
  48. m_dir_gamma(pod_allocator<HiResT>::allocate(gamma_size)),
  49. m_inv_gamma(pod_allocator<LoResT>::allocate(hi_res_size))
  50. {
  51. unsigned i;
  52. for(i = 0; i < gamma_size; i++)
  53. {
  54. m_dir_gamma[i] = HiResT(i << (hi_res_shift - gamma_shift));
  55. }
  56. for(i = 0; i < hi_res_size; i++)
  57. {
  58. m_inv_gamma[i] = LoResT(i >> (hi_res_shift - gamma_shift));
  59. }
  60. }
  61. gamma_lut(double g) :
  62. m_gamma(1.0),
  63. m_dir_gamma(pod_allocator<HiResT>::allocate(gamma_size)),
  64. m_inv_gamma(pod_allocator<LoResT>::allocate(hi_res_size))
  65. {
  66. gamma(g);
  67. }
  68. void gamma(double g)
  69. {
  70. m_gamma = g;
  71. unsigned i;
  72. for(i = 0; i < gamma_size; i++)
  73. {
  74. m_dir_gamma[i] = (HiResT)
  75. uround(pow(i / double(gamma_mask), m_gamma) * double(hi_res_mask));
  76. }
  77. double inv_g = 1.0 / g;
  78. for(i = 0; i < hi_res_size; i++)
  79. {
  80. m_inv_gamma[i] = (LoResT)
  81. uround(pow(i / double(hi_res_mask), inv_g) * double(gamma_mask));
  82. }
  83. }
  84. double gamma() const
  85. {
  86. return m_gamma;
  87. }
  88. HiResT dir(LoResT v) const
  89. {
  90. return m_dir_gamma[unsigned(v)];
  91. }
  92. LoResT inv(HiResT v) const
  93. {
  94. return m_inv_gamma[unsigned(v)];
  95. }
  96. private:
  97. gamma_lut(const self_type&);
  98. const self_type& operator = (const self_type&);
  99. double m_gamma;
  100. HiResT* m_dir_gamma;
  101. LoResT* m_inv_gamma;
  102. };
  103. //
  104. // sRGB support classes
  105. //
  106. // Optimized sRGB lookup table. The direct conversion (sRGB to linear)
  107. // is a straightforward lookup. The inverse conversion (linear to sRGB)
  108. // is implemented using binary search.
  109. template<class LinearType>
  110. class sRGB_lut_base
  111. {
  112. public:
  113. LinearType dir(int8u v) const
  114. {
  115. return m_dir_table[v];
  116. }
  117. int8u inv(LinearType v) const
  118. {
  119. // Unrolled binary search.
  120. int8u x = 0;
  121. if (v > m_inv_table[128]) x = 128;
  122. if (v > m_inv_table[x + 64]) x += 64;
  123. if (v > m_inv_table[x + 32]) x += 32;
  124. if (v > m_inv_table[x + 16]) x += 16;
  125. if (v > m_inv_table[x + 8]) x += 8;
  126. if (v > m_inv_table[x + 4]) x += 4;
  127. if (v > m_inv_table[x + 2]) x += 2;
  128. if (v > m_inv_table[x + 1]) x += 1;
  129. return x;
  130. }
  131. protected:
  132. LinearType m_dir_table[256];
  133. LinearType m_inv_table[256];
  134. // Only derived classes may instantiate.
  135. sRGB_lut_base()
  136. {
  137. }
  138. };
  139. // sRGB_lut - implements sRGB conversion for the various types.
  140. // Base template is undefined, specializations are provided below.
  141. template<class LinearType>
  142. class sRGB_lut;
  143. template<>
  144. class sRGB_lut<float> : public sRGB_lut_base<float>
  145. {
  146. public:
  147. sRGB_lut()
  148. {
  149. // Generate lookup tables.
  150. m_dir_table[0] = 0;
  151. m_inv_table[0] = 0;
  152. for (unsigned i = 1; i <= 255; ++i)
  153. {
  154. // Floating-point RGB is in range [0,1].
  155. m_dir_table[i] = float(sRGB_to_linear(i / 255.0));
  156. m_inv_table[i] = float(sRGB_to_linear((i - 0.5) / 255.0));
  157. }
  158. }
  159. };
  160. template<>
  161. class sRGB_lut<int16u> : public sRGB_lut_base<int16u>
  162. {
  163. public:
  164. sRGB_lut()
  165. {
  166. // Generate lookup tables.
  167. m_dir_table[0] = 0;
  168. m_inv_table[0] = 0;
  169. for (unsigned i = 1; i <= 255; ++i)
  170. {
  171. // 16-bit RGB is in range [0,65535].
  172. m_dir_table[i] = uround(65535.0 * sRGB_to_linear(i / 255.0));
  173. m_inv_table[i] = uround(65535.0 * sRGB_to_linear((i - 0.5) / 255.0));
  174. }
  175. }
  176. };
  177. template<>
  178. class sRGB_lut<int8u> : public sRGB_lut_base<int8u>
  179. {
  180. public:
  181. sRGB_lut()
  182. {
  183. // Generate lookup tables.
  184. m_dir_table[0] = 0;
  185. m_inv_table[0] = 0;
  186. for (unsigned i = 1; i <= 255; ++i)
  187. {
  188. // 8-bit RGB is handled with simple bidirectional lookup tables.
  189. m_dir_table[i] = uround(255.0 * sRGB_to_linear(i / 255.0));
  190. m_inv_table[i] = uround(255.0 * linear_to_sRGB(i / 255.0));
  191. }
  192. }
  193. int8u inv(int8u v) const
  194. {
  195. // In this case, the inverse transform is a simple lookup.
  196. return m_inv_table[v];
  197. }
  198. };
  199. // Common base class for sRGB_conv objects. Defines an internal
  200. // sRGB_lut object so that users don't have to.
  201. template<class T>
  202. class sRGB_conv_base
  203. {
  204. public:
  205. static T rgb_from_sRGB(int8u x)
  206. {
  207. return lut.dir(x);
  208. }
  209. static int8u rgb_to_sRGB(T x)
  210. {
  211. return lut.inv(x);
  212. }
  213. private:
  214. static sRGB_lut<T> lut;
  215. };
  216. // Definition of sRGB_conv_base::lut. Due to the fact that this a template,
  217. // we don't need to place the definition in a cpp file. Hurrah.
  218. template<class T>
  219. sRGB_lut<T> sRGB_conv_base<T>::lut;
  220. // Wrapper for sRGB-linear conversion.
  221. // Base template is undefined, specializations are provided below.
  222. template<class T>
  223. class sRGB_conv;
  224. template<>
  225. class sRGB_conv<float> : public sRGB_conv_base<float>
  226. {
  227. public:
  228. static float alpha_from_sRGB(int8u x)
  229. {
  230. return float(x / 255.0);
  231. }
  232. static int8u alpha_to_sRGB(float x)
  233. {
  234. if (x <= 0) return 0;
  235. else if (x >= 1) return 255;
  236. else return int8u(0.5 + x * 255);
  237. }
  238. };
  239. template<>
  240. class sRGB_conv<int16u> : public sRGB_conv_base<int16u>
  241. {
  242. public:
  243. static int16u alpha_from_sRGB(int8u x)
  244. {
  245. return (x << 8) | x;
  246. }
  247. static int8u alpha_to_sRGB(int16u x)
  248. {
  249. return x >> 8;
  250. }
  251. };
  252. template<>
  253. class sRGB_conv<int8u> : public sRGB_conv_base<int8u>
  254. {
  255. public:
  256. static int8u alpha_from_sRGB(int8u x)
  257. {
  258. return x;
  259. }
  260. static int8u alpha_to_sRGB(int8u x)
  261. {
  262. return x;
  263. }
  264. };
  265. }
  266. #endif