Audio plugin host https://kx.studio/carla
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.

juce_Colour.cpp 15KB

7 years ago
7 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. namespace ColourHelpers
  22. {
  23. static uint8 floatToUInt8 (const float n) noexcept
  24. {
  25. return n <= 0.0f ? 0 : (n >= 1.0f ? 255 : static_cast<uint8> (n * 255.996f));
  26. }
  27. //==============================================================================
  28. struct HSB
  29. {
  30. HSB (Colour col) noexcept
  31. {
  32. const int r = col.getRed();
  33. const int g = col.getGreen();
  34. const int b = col.getBlue();
  35. const int hi = jmax (r, g, b);
  36. const int lo = jmin (r, g, b);
  37. if (hi != 0)
  38. {
  39. saturation = (hi - lo) / (float) hi;
  40. if (saturation > 0)
  41. {
  42. const float invDiff = 1.0f / (hi - lo);
  43. const float red = (hi - r) * invDiff;
  44. const float green = (hi - g) * invDiff;
  45. const float blue = (hi - b) * invDiff;
  46. if (r == hi)
  47. hue = blue - green;
  48. else if (g == hi)
  49. hue = 2.0f + red - blue;
  50. else
  51. hue = 4.0f + green - red;
  52. hue *= 1.0f / 6.0f;
  53. if (hue < 0)
  54. ++hue;
  55. }
  56. else
  57. {
  58. hue = 0;
  59. }
  60. }
  61. else
  62. {
  63. saturation = hue = 0;
  64. }
  65. brightness = hi / 255.0f;
  66. }
  67. Colour toColour (Colour original) const noexcept
  68. {
  69. return Colour (hue, saturation, brightness, original.getAlpha());
  70. }
  71. static PixelARGB toRGB (float h, float s, float v, const uint8 alpha) noexcept
  72. {
  73. v = jlimit (0.0f, 255.0f, v * 255.0f);
  74. const uint8 intV = (uint8) roundToInt (v);
  75. if (s <= 0)
  76. return PixelARGB (alpha, intV, intV, intV);
  77. s = jmin (1.0f, s);
  78. h = (h - std::floor (h)) * 6.0f + 0.00001f; // need a small adjustment to compensate for rounding errors
  79. const float f = h - std::floor (h);
  80. const uint8 x = (uint8) roundToInt (v * (1.0f - s));
  81. if (h < 1.0f) return PixelARGB (alpha, intV, (uint8) roundToInt (v * (1.0f - (s * (1.0f - f)))), x);
  82. if (h < 2.0f) return PixelARGB (alpha, (uint8) roundToInt (v * (1.0f - s * f)), intV, x);
  83. if (h < 3.0f) return PixelARGB (alpha, x, intV, (uint8) roundToInt (v * (1.0f - (s * (1.0f - f)))));
  84. if (h < 4.0f) return PixelARGB (alpha, x, (uint8) roundToInt (v * (1.0f - s * f)), intV);
  85. if (h < 5.0f) return PixelARGB (alpha, (uint8) roundToInt (v * (1.0f - (s * (1.0f - f)))), x, intV);
  86. return PixelARGB (alpha, intV, x, (uint8) roundToInt (v * (1.0f - s * f)));
  87. }
  88. float hue, saturation, brightness;
  89. };
  90. //==============================================================================
  91. struct YIQ
  92. {
  93. YIQ (Colour c) noexcept
  94. {
  95. const float r = c.getFloatRed();
  96. const float g = c.getFloatGreen();
  97. const float b = c.getFloatBlue();
  98. y = 0.2999f * r + 0.5870f * g + 0.1140f * b;
  99. i = 0.5957f * r - 0.2744f * g - 0.3212f * b;
  100. q = 0.2114f * r - 0.5225f * g - 0.3113f * b;
  101. alpha = c.getFloatAlpha();
  102. }
  103. Colour toColour() const noexcept
  104. {
  105. return Colour::fromFloatRGBA (y + 0.9563f * i + 0.6210f * q,
  106. y - 0.2721f * i - 0.6474f * q,
  107. y - 1.1070f * i + 1.7046f * q,
  108. alpha);
  109. }
  110. float y, i, q, alpha;
  111. };
  112. }
  113. //==============================================================================
  114. Colour::Colour() noexcept
  115. : argb (0, 0, 0, 0)
  116. {
  117. }
  118. Colour::Colour (const Colour& other) noexcept
  119. : argb (other.argb)
  120. {
  121. }
  122. Colour& Colour::operator= (const Colour& other) noexcept
  123. {
  124. argb = other.argb;
  125. return *this;
  126. }
  127. bool Colour::operator== (const Colour& other) const noexcept { return argb.getNativeARGB() == other.argb.getNativeARGB(); }
  128. bool Colour::operator!= (const Colour& other) const noexcept { return argb.getNativeARGB() != other.argb.getNativeARGB(); }
  129. //==============================================================================
  130. Colour::Colour (const uint32 col) noexcept
  131. : argb ((col >> 24) & 0xff, (col >> 16) & 0xff, (col >> 8) & 0xff, col & 0xff)
  132. {
  133. }
  134. Colour::Colour (const uint8 red, const uint8 green, const uint8 blue) noexcept
  135. {
  136. argb.setARGB (0xff, red, green, blue);
  137. }
  138. Colour Colour::fromRGB (const uint8 red, const uint8 green, const uint8 blue) noexcept
  139. {
  140. return Colour (red, green, blue);
  141. }
  142. Colour::Colour (const uint8 red, const uint8 green, const uint8 blue, const uint8 alpha) noexcept
  143. {
  144. argb.setARGB (alpha, red, green, blue);
  145. }
  146. Colour Colour::fromRGBA (const uint8 red, const uint8 green, const uint8 blue, const uint8 alpha) noexcept
  147. {
  148. return Colour (red, green, blue, alpha);
  149. }
  150. Colour::Colour (const uint8 red, const uint8 green, const uint8 blue, const float alpha) noexcept
  151. {
  152. argb.setARGB (ColourHelpers::floatToUInt8 (alpha), red, green, blue);
  153. }
  154. Colour Colour::fromFloatRGBA (const float red, const float green, const float blue, const float alpha) noexcept
  155. {
  156. return Colour (ColourHelpers::floatToUInt8 (red),
  157. ColourHelpers::floatToUInt8 (green),
  158. ColourHelpers::floatToUInt8 (blue), alpha);
  159. }
  160. Colour::Colour (const float hue, const float saturation, const float brightness, const float alpha) noexcept
  161. : argb (ColourHelpers::HSB::toRGB (hue, saturation, brightness, ColourHelpers::floatToUInt8 (alpha)))
  162. {
  163. }
  164. Colour Colour::fromHSV (const float hue, const float saturation, const float brightness, const float alpha) noexcept
  165. {
  166. return Colour (hue, saturation, brightness, alpha);
  167. }
  168. Colour::Colour (const float hue, const float saturation, const float brightness, const uint8 alpha) noexcept
  169. : argb (ColourHelpers::HSB::toRGB (hue, saturation, brightness, alpha))
  170. {
  171. }
  172. Colour::Colour (PixelARGB argb_) noexcept
  173. : argb (argb_)
  174. {
  175. }
  176. Colour::Colour (PixelRGB rgb) noexcept
  177. : argb (Colour (rgb.getInARGBMaskOrder()).argb)
  178. {
  179. }
  180. Colour::Colour (PixelAlpha alpha) noexcept
  181. : argb (Colour (alpha.getInARGBMaskOrder()).argb)
  182. {
  183. }
  184. Colour::~Colour() noexcept
  185. {
  186. }
  187. //==============================================================================
  188. const PixelARGB Colour::getPixelARGB() const noexcept
  189. {
  190. PixelARGB p (argb);
  191. p.premultiply();
  192. return p;
  193. }
  194. uint32 Colour::getARGB() const noexcept
  195. {
  196. return argb.getInARGBMaskOrder();
  197. }
  198. //==============================================================================
  199. bool Colour::isTransparent() const noexcept
  200. {
  201. return getAlpha() == 0;
  202. }
  203. bool Colour::isOpaque() const noexcept
  204. {
  205. return getAlpha() == 0xff;
  206. }
  207. Colour Colour::withAlpha (const uint8 newAlpha) const noexcept
  208. {
  209. PixelARGB newCol (argb);
  210. newCol.setAlpha (newAlpha);
  211. return Colour (newCol);
  212. }
  213. Colour Colour::withAlpha (const float newAlpha) const noexcept
  214. {
  215. jassert (newAlpha >= 0 && newAlpha <= 1.0f);
  216. PixelARGB newCol (argb);
  217. newCol.setAlpha (ColourHelpers::floatToUInt8 (newAlpha));
  218. return Colour (newCol);
  219. }
  220. Colour Colour::withMultipliedAlpha (const float alphaMultiplier) const noexcept
  221. {
  222. jassert (alphaMultiplier >= 0);
  223. PixelARGB newCol (argb);
  224. newCol.setAlpha ((uint8) jmin (0xff, roundToInt (alphaMultiplier * newCol.getAlpha())));
  225. return Colour (newCol);
  226. }
  227. //==============================================================================
  228. Colour Colour::overlaidWith (Colour src) const noexcept
  229. {
  230. const int destAlpha = getAlpha();
  231. if (destAlpha <= 0)
  232. return src;
  233. const int invA = 0xff - (int) src.getAlpha();
  234. const int resA = 0xff - (((0xff - destAlpha) * invA) >> 8);
  235. if (resA <= 0)
  236. return *this;
  237. const int da = (invA * destAlpha) / resA;
  238. return Colour ((uint8) (src.getRed() + ((((int) getRed() - src.getRed()) * da) >> 8)),
  239. (uint8) (src.getGreen() + ((((int) getGreen() - src.getGreen()) * da) >> 8)),
  240. (uint8) (src.getBlue() + ((((int) getBlue() - src.getBlue()) * da) >> 8)),
  241. (uint8) resA);
  242. }
  243. Colour Colour::interpolatedWith (Colour other, float proportionOfOther) const noexcept
  244. {
  245. if (proportionOfOther <= 0)
  246. return *this;
  247. if (proportionOfOther >= 1.0f)
  248. return other;
  249. PixelARGB c1 (getPixelARGB());
  250. const PixelARGB c2 (other.getPixelARGB());
  251. c1.tween (c2, (uint32) roundToInt (proportionOfOther * 255.0f));
  252. c1.unpremultiply();
  253. return Colour (c1);
  254. }
  255. //==============================================================================
  256. float Colour::getFloatRed() const noexcept { return getRed() / 255.0f; }
  257. float Colour::getFloatGreen() const noexcept { return getGreen() / 255.0f; }
  258. float Colour::getFloatBlue() const noexcept { return getBlue() / 255.0f; }
  259. float Colour::getFloatAlpha() const noexcept { return getAlpha() / 255.0f; }
  260. //==============================================================================
  261. void Colour::getHSB (float& h, float& s, float& v) const noexcept
  262. {
  263. const ColourHelpers::HSB hsb (*this);
  264. h = hsb.hue;
  265. s = hsb.saturation;
  266. v = hsb.brightness;
  267. }
  268. float Colour::getHue() const noexcept { return ColourHelpers::HSB (*this).hue; }
  269. float Colour::getSaturation() const noexcept { return ColourHelpers::HSB (*this).saturation; }
  270. float Colour::getBrightness() const noexcept { return ColourHelpers::HSB (*this).brightness; }
  271. Colour Colour::withHue (float h) const noexcept { ColourHelpers::HSB hsb (*this); hsb.hue = h; return hsb.toColour (*this); }
  272. Colour Colour::withSaturation (float s) const noexcept { ColourHelpers::HSB hsb (*this); hsb.saturation = s; return hsb.toColour (*this); }
  273. Colour Colour::withBrightness (float v) const noexcept { ColourHelpers::HSB hsb (*this); hsb.brightness = v; return hsb.toColour (*this); }
  274. float Colour::getPerceivedBrightness() const noexcept
  275. {
  276. return std::sqrt (0.241f * square (getFloatRed())
  277. + 0.691f * square (getFloatGreen())
  278. + 0.068f * square (getFloatBlue()));
  279. }
  280. //==============================================================================
  281. Colour Colour::withRotatedHue (const float amountToRotate) const noexcept
  282. {
  283. ColourHelpers::HSB hsb (*this);
  284. hsb.hue += amountToRotate;
  285. return hsb.toColour (*this);
  286. }
  287. Colour Colour::withMultipliedSaturation (const float amount) const noexcept
  288. {
  289. ColourHelpers::HSB hsb (*this);
  290. hsb.saturation = jmin (1.0f, hsb.saturation * amount);
  291. return hsb.toColour (*this);
  292. }
  293. Colour Colour::withMultipliedBrightness (const float amount) const noexcept
  294. {
  295. ColourHelpers::HSB hsb (*this);
  296. hsb.brightness = jmin (1.0f, hsb.brightness * amount);
  297. return hsb.toColour (*this);
  298. }
  299. //==============================================================================
  300. Colour Colour::brighter (float amount) const noexcept
  301. {
  302. amount = 1.0f / (1.0f + amount);
  303. return Colour ((uint8) (255 - (amount * (255 - getRed()))),
  304. (uint8) (255 - (amount * (255 - getGreen()))),
  305. (uint8) (255 - (amount * (255 - getBlue()))),
  306. getAlpha());
  307. }
  308. Colour Colour::darker (float amount) const noexcept
  309. {
  310. amount = 1.0f / (1.0f + amount);
  311. return Colour ((uint8) (amount * getRed()),
  312. (uint8) (amount * getGreen()),
  313. (uint8) (amount * getBlue()),
  314. getAlpha());
  315. }
  316. //==============================================================================
  317. Colour Colour::greyLevel (const float brightness) noexcept
  318. {
  319. const uint8 level = ColourHelpers::floatToUInt8 (brightness);
  320. return Colour (level, level, level);
  321. }
  322. //==============================================================================
  323. Colour Colour::contrasting (const float amount) const noexcept
  324. {
  325. return overlaidWith ((getPerceivedBrightness() >= 0.5f
  326. ? Colours::black
  327. : Colours::white).withAlpha (amount));
  328. }
  329. Colour Colour::contrasting (Colour target, float minContrast) const noexcept
  330. {
  331. const ColourHelpers::YIQ bg (*this);
  332. ColourHelpers::YIQ fg (target);
  333. if (std::abs (bg.y - fg.y) >= minContrast)
  334. return target;
  335. const float y1 = jmax (0.0f, bg.y - minContrast);
  336. const float y2 = jmin (1.0f, bg.y + minContrast);
  337. fg.y = (std::abs (y1 - bg.y) > std::abs (y2 - bg.y)) ? y1 : y2;
  338. return fg.toColour();
  339. }
  340. Colour Colour::contrasting (Colour colour1,
  341. Colour colour2) noexcept
  342. {
  343. const float b1 = colour1.getPerceivedBrightness();
  344. const float b2 = colour2.getPerceivedBrightness();
  345. float best = 0.0f;
  346. float bestDist = 0.0f;
  347. for (float i = 0.0f; i < 1.0f; i += 0.02f)
  348. {
  349. const float d1 = std::abs (i - b1);
  350. const float d2 = std::abs (i - b2);
  351. const float dist = jmin (d1, d2, 1.0f - d1, 1.0f - d2);
  352. if (dist > bestDist)
  353. {
  354. best = i;
  355. bestDist = dist;
  356. }
  357. }
  358. return colour1.overlaidWith (colour2.withMultipliedAlpha (0.5f))
  359. .withBrightness (best);
  360. }
  361. //==============================================================================
  362. String Colour::toString() const
  363. {
  364. return String::toHexString ((int) argb.getInARGBMaskOrder());
  365. }
  366. Colour Colour::fromString (StringRef encodedColourString)
  367. {
  368. return Colour ((uint32) CharacterFunctions::HexParser<int>::parse (encodedColourString.text));
  369. }
  370. String Colour::toDisplayString (const bool includeAlphaValue) const
  371. {
  372. return String::toHexString ((int) (argb.getInARGBMaskOrder() & (includeAlphaValue ? 0xffffffff : 0xffffff)))
  373. .paddedLeft ('0', includeAlphaValue ? 8 : 6)
  374. .toUpperCase();
  375. }
  376. } // namespace juce