TDE graphics utilities
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.

kpcolor.cpp 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /*
  2. Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions
  6. are met:
  7. 1. Redistributions of source code must retain the above copyright
  8. notice, this list of conditions and the following disclaimer.
  9. 2. Redistributions in binary form must reproduce the above copyright
  10. notice, this list of conditions and the following disclaimer in the
  11. documentation and/or other materials provided with the distribution.
  12. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  13. IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  14. OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  15. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  16. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  17. NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  18. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  19. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  21. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. #define DEBUG_KP_COLOR 0
  24. #include <kpcolor.h>
  25. #include <tqdatastream.h>
  26. #include <kdebug.h>
  27. // public static
  28. const int kpColor::Exact = 0;
  29. // public static
  30. const kpColor kpColor::invalid; // TODO: what's wrong with explicitly specifying () constructor?
  31. const kpColor kpColor::transparent (0, 0, 0, true/*isTransparent*/);
  32. kpColor::kpColor ()
  33. : m_rgbaIsValid (false),
  34. m_colorCacheIsValid (false)
  35. {
  36. }
  37. kpColor::kpColor (int red, int green, int blue, bool isTransparent)
  38. : m_colorCacheIsValid (false)
  39. {
  40. if (red < 0 || red > 255 ||
  41. green < 0 || green > 255 ||
  42. blue < 0 || blue > 255)
  43. {
  44. kdError () << "kpColor::<ctor>(r=" << red
  45. << ",g=" << green
  46. << ",b=" << blue
  47. << ",t=" << isTransparent
  48. << ") passed out of range values" << endl;
  49. m_rgbaIsValid = false;
  50. return;
  51. }
  52. m_rgba = tqRgba (red, green, blue, isTransparent ? 0 : 255/*opaque*/);
  53. m_rgbaIsValid = true;
  54. }
  55. kpColor::kpColor (const TQRgb &rgba)
  56. : m_colorCacheIsValid (false)
  57. {
  58. if (tqAlpha (rgba) > 0 && tqAlpha (rgba) < 255)
  59. {
  60. kdError () << "kpColor::<ctor>(TQRgb) passed translucent alpha "
  61. << tqAlpha (rgba)
  62. << " - trying to recover"
  63. << endl;
  64. // Forget the alpha channel - make it opaque
  65. m_rgba = tqRgb (tqRed (m_rgba), tqGreen (m_rgba), tqBlue (m_rgba));
  66. m_rgbaIsValid = true;
  67. }
  68. else
  69. {
  70. m_rgba = rgba;
  71. m_rgbaIsValid = true;
  72. }
  73. }
  74. kpColor::kpColor (const kpColor &rhs)
  75. : m_rgbaIsValid (rhs.m_rgbaIsValid),
  76. m_rgba (rhs.m_rgba),
  77. m_colorCacheIsValid (rhs.m_colorCacheIsValid),
  78. m_colorCache (rhs.m_colorCache)
  79. {
  80. }
  81. // friend
  82. TQDataStream &operator<< (TQDataStream &stream, const kpColor &color)
  83. {
  84. stream << int (color.m_rgbaIsValid) << int (color.m_rgba);
  85. return stream;
  86. }
  87. // friend
  88. TQDataStream &operator>> (TQDataStream &stream, kpColor &color)
  89. {
  90. int a, b;
  91. stream >> a >> b;
  92. color.m_rgbaIsValid = a;
  93. color.m_rgba = b;
  94. color.m_colorCacheIsValid = false;
  95. return stream;
  96. }
  97. kpColor &kpColor::operator= (const kpColor &rhs)
  98. {
  99. // (as soon as you add a ptr, you won't be complaining to me that this
  100. // method was unnecessary :))
  101. if (this == &rhs)
  102. return *this;
  103. m_rgbaIsValid = rhs.m_rgbaIsValid;
  104. m_rgba = rhs.m_rgba;
  105. m_colorCacheIsValid = rhs.m_colorCacheIsValid;
  106. m_colorCache = rhs.m_colorCache;
  107. return *this;
  108. }
  109. bool kpColor::operator== (const kpColor &rhs) const
  110. {
  111. return isSimilarTo (rhs, kpColor::Exact);
  112. }
  113. bool kpColor::operator!= (const kpColor &rhs) const
  114. {
  115. return !(*this == rhs);
  116. }
  117. template <class dtype>
  118. inline dtype square (dtype val)
  119. {
  120. return val * val;
  121. }
  122. // public static
  123. int kpColor::processSimilarity (double colorSimilarity)
  124. {
  125. // sqrt (dr ^ 2 + dg ^ 2 + db ^ 2) <= colorSimilarity * sqrt (255 ^ 2 * 3)
  126. // dr ^ 2 + dg ^ 2 + db ^ 2 <= (colorSimilarity ^ 2) * (255 ^ 2 * 3)
  127. return int (square (colorSimilarity) * (square (255) * 3));
  128. }
  129. bool kpColor::isSimilarTo (const kpColor &rhs, int processedSimilarity) const
  130. {
  131. // Are we the same?
  132. if (this == &rhs)
  133. return true;
  134. // Do we dither in terms of validity?
  135. if (isValid () != rhs.isValid ())
  136. return false;
  137. // Are both of us invalid?
  138. if (!isValid ())
  139. return true;
  140. // --- both are now valid ---
  141. if (isTransparent () != rhs.isTransparent ())
  142. return false;
  143. // Are both of us transparent?
  144. if (isTransparent ())
  145. return true;
  146. // --- both are now valid and opaque ---
  147. if (m_rgba == rhs.m_rgba)
  148. return true;
  149. if (processedSimilarity == kpColor::Exact)
  150. return false;
  151. else
  152. {
  153. return (square (tqRed (m_rgba) - tqRed (rhs.m_rgba)) +
  154. square (tqGreen (m_rgba) - tqGreen (rhs.m_rgba)) +
  155. square (tqBlue (m_rgba) - tqBlue (rhs.m_rgba))
  156. <= processedSimilarity);
  157. }
  158. }
  159. kpColor::~kpColor ()
  160. {
  161. }
  162. // public
  163. bool kpColor::isValid () const
  164. {
  165. return m_rgbaIsValid;
  166. }
  167. // public
  168. int kpColor::red () const
  169. {
  170. if (!m_rgbaIsValid)
  171. {
  172. kdError () << "kpColor::red() called with invalid kpColor" << endl;
  173. return 0;
  174. }
  175. if (isTransparent ())
  176. {
  177. kdError () << "kpColor::red() called with transparent kpColor" << endl;
  178. return 0;
  179. }
  180. return tqRed (m_rgba);
  181. }
  182. // public
  183. int kpColor::green () const
  184. {
  185. if (!m_rgbaIsValid)
  186. {
  187. kdError () << "kpColor::green() called with invalid kpColor" << endl;
  188. return 0;
  189. }
  190. if (isTransparent ())
  191. {
  192. kdError () << "kpColor::green() called with transparent kpColor" << endl;
  193. return 0;
  194. }
  195. return tqGreen (m_rgba);
  196. }
  197. // public
  198. int kpColor::blue () const
  199. {
  200. if (!m_rgbaIsValid)
  201. {
  202. kdError () << "kpColor::blue() called with invalid kpColor" << endl;
  203. return 0;
  204. }
  205. if (isTransparent ())
  206. {
  207. kdError () << "kpColor::blue() called with transparent kpColor" << endl;
  208. return 0;
  209. }
  210. return tqBlue (m_rgba);
  211. }
  212. // public
  213. int kpColor::alpha () const
  214. {
  215. if (!m_rgbaIsValid)
  216. {
  217. kdError () << "kpColor::alpha() called with invalid kpColor" << endl;
  218. return 0;
  219. }
  220. const int alpha = tqAlpha (m_rgba);
  221. if (alpha > 0 && alpha < 255)
  222. {
  223. kdError () << "kpColor::alpha() called with translucent kpColor alpha=" << alpha << endl;
  224. // no translucency
  225. return alpha ? 255 : 0;
  226. }
  227. else
  228. {
  229. return alpha;
  230. }
  231. }
  232. // public
  233. bool kpColor::isTransparent () const
  234. {
  235. return (alpha () == 0);
  236. }
  237. // public
  238. bool kpColor::isOpaque () const
  239. {
  240. return (alpha () == 255);
  241. }
  242. // public
  243. TQRgb kpColor::toTQRgb () const
  244. {
  245. if (!m_rgbaIsValid)
  246. {
  247. kdError () << "kpColor::toTQRgb() called with invalid kpColor" << endl;
  248. return 0;
  249. }
  250. return m_rgba;
  251. }
  252. // public
  253. const TQColor &kpColor::toTQColor () const
  254. {
  255. if (!m_rgbaIsValid)
  256. {
  257. kdError () << "kpColor::toTQColor() called with invalid kpColor" << endl;
  258. return TQt::black;
  259. }
  260. if (m_colorCacheIsValid)
  261. return m_colorCache;
  262. if (tqAlpha (m_rgba) < 255)
  263. {
  264. kdError () << "kpColor::toTQColor() called with not fully opaque kpColor alpha="
  265. << tqAlpha (m_rgba)
  266. << endl;
  267. return TQt::black;
  268. }
  269. m_colorCache = TQColor (m_rgba);
  270. if (!m_colorCache.isValid ())
  271. {
  272. kdError () << "kpColor::toTQColor () internal error - could not return valid TQColor"
  273. << endl;
  274. return TQt::black;
  275. }
  276. m_colorCacheIsValid = true;
  277. return m_colorCache;
  278. }
  279. // public
  280. TQColor kpColor::maskColor () const
  281. {
  282. return isTransparent () ? TQt::color0 : TQt::color1;
  283. }