Skip to content

Instantly share code, notes, and snippets.

@GitMoDu
Created March 19, 2025 14:21
Show Gist options
  • Select an option

  • Save GitMoDu/7587a97b1dd6479da7af89a24e9e46ae to your computer and use it in GitHub Desktop.

Select an option

Save GitMoDu/7587a97b1dd6479da7af89a24e9e46ae to your computer and use it in GitHub Desktop.
Cpp converter of HSV to RGB888 using integer-only math.
/// <summary>
/// Converts HSV to RGB888 using integer-only math.
/// </summary>
/// <param name="hue">Hue angle [0 ; UINT16_MAX], corresponds to [0 ; 360] degrees color wheel.</param>
/// <param name="saturation">Saturation value [0 ; 255].</param>
/// <param name="value">Brightness value [0 ; 255].</param>
/// <returns>uint32 RGB888 color, where the color is represented as 0xRRGGBB.</returns>
static uint32_t HsvToRgb(const uint16_t hue, const uint8_t saturation, const uint8_t value)
{
static constexpr uint8_t Segments = 6;
if (saturation == 0)
{
// Achromatic (gray).
return ((uint32_t)value << 16)
| ((uint16_t)value << 8)
| value;
}
else
{
// Scale hue to fit into the number of segments.
const uint16_t hueScaled = ((uint32_t)hue * Segments) >> 8;
const uint8_t hueSegment = (hueScaled >> 8) % Segments;
const uint8_t f = hueScaled & UINT8_MAX;
// Calculate intermediate values.
const uint8_t p = (((uint16_t)value * (UINT8_MAX - saturation)) / UINT8_MAX);
const uint8_t fs = (((uint16_t)f * saturation) / UINT8_MAX);
const uint8_t q = (((uint16_t)value * (UINT8_MAX - fs)) / UINT8_MAX);
const uint8_t fsR = (((uint16_t)(UINT8_MAX - f) * saturation) / UINT8_MAX);
const uint8_t t = (((uint16_t)value * (UINT8_MAX - fsR)) / UINT8_MAX);
// Determine the RGB values based on the hue segment.
switch (hueSegment % Segments)
{
case 0: // Red is dominant.
return ((uint32_t)value << 16)
| ((uint16_t)t << 8)
| p;
case 1: // Green is dominant.
return ((uint32_t)q << 16)
| ((uint16_t)value << 8)
| p;
case 2: // Green is dominant.
return ((uint32_t)p << 16)
| ((uint16_t)value << 8)
| t;
case 3: // Blue is dominant.
return ((uint32_t)p << 16)
| ((uint16_t)q << 8)
| value;
case 4: // Blue is dominant.
return ((uint32_t)t << 16)
| ((uint16_t)p << 8)
| value;
case (Segments - 1): // Red is dominant.
default:
return ((uint32_t)value << 16)
| ((uint16_t)p << 8)
| q;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment