Skip to content

Instantly share code, notes, and snippets.

@usagi
Last active December 11, 2015 03:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save usagi/4542114 to your computer and use it in GitHub Desktop.
Save usagi/4542114 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <iomanip>
#include <stdexcept>
#include <limits>
#include <vector>
#include <array>
#include <set>
#include <cmath>
#include <algorithm>
#include <string>
#include <cassert>
#include <fstream>
using namespace std;
struct RGB24 { uint8_t r, g, b; };
template<class T>
struct HSL { T h, s, l; };
using HSL192F = HSL<double>;
using HSL96F = HSL<float>;
template<class HSL_TYPE>
bool operator<(const HSL_TYPE& a,const HSL_TYPE& b) {
if ( a.l > b.l || a.s > b.s ) return false;
return a.h < b.h;
}
template<class HSL_TYPE>
bool operator==(const HSL_TYPE& a,const HSL_TYPE& b) {
return a.h == b.h && a.s == b.s && a.l == b.l;
}
template<class INTERNAL_TYPE = double, class RGB_TYPE = RGB24, class HSL_TYPE = HSL192F>
HSL_TYPE hsl_from_rgb(RGB_TYPE&& i){
using internal_type = INTERNAL_TYPE;
using rgb_type = RGB_TYPE;
constexpr internal_type
zero = 0., one = 1., two = 2., four = 4., six = 6.,
binary_1 = one / two,
senary_1 = one / six,
max_factor = numeric_limits<decltype(i.r)>::max(),
unorm_factor = one / max_factor;
const auto
r = internal_type( i.r ) * unorm_factor,
g = internal_type( i.g ) * unorm_factor,
b = internal_type( i.b ) * unorm_factor;
const auto
max_value = max({r, g, b}),
min_value = min({r, g, b});
const auto l = (max_value + min_value) * binary_1;
if (max_value == min_value)
return {
static_cast<decltype(HSL_TYPE::h)>(zero),
static_cast<decltype(HSL_TYPE::s)>(zero),
static_cast<decltype(HSL_TYPE::l)>(l)
};
auto d = max_value - min_value;
const auto s = d / (
(l > binary_1)
? (two - max_value - min_value)
: (max_value + min_value)
);
if (max_value == r)
return {
static_cast<decltype(HSL_TYPE::h)>( ((g - b) / d + (g < b ? six : zero)) * senary_1 ),
static_cast<decltype(HSL_TYPE::s)>(s),
static_cast<decltype(HSL_TYPE::l)>(l)
};
if (max_value == g)
return {
static_cast<decltype(HSL_TYPE::h)>( ((b - r) / d + two) * senary_1 ),
static_cast<decltype(HSL_TYPE::s)>(s),
static_cast<decltype(HSL_TYPE::l)>(l)
};
return {
static_cast<decltype(HSL_TYPE::h)>( ((r - g) / d + four) * senary_1 ),
static_cast<decltype(HSL_TYPE::s)>(s),
static_cast<decltype(HSL_TYPE::l)>(l)
};
}
template<class INTERNAL_TYPE = double, class HSL_TYPE = HSL192F>
vector<HSL_TYPE> generate_hsl_colors_from_rgb24() {
constexpr uint_fast16_t u = numeric_limits<uint8_t>::max() + 1;
constexpr size_t
b8 = 256,
b16 = b8 * b8,
b24 = b16 * b8;
vector<HSL_TYPE> colors(b24);
#pragma omp parallel for
for(uint_fast16_t r = 0; r < u; ++r)
for(uint_fast16_t g = 0; g < u; ++g)
for(uint_fast16_t b = 0; b < u; ++b)
colors[ r + g * b8 + b * b16 ] = hsl_from_rgb<INTERNAL_TYPE, RGB24, HSL_TYPE>({
static_cast<uint8_t>(r),
static_cast<uint8_t>(g),
static_cast<uint8_t>(b)
});
sort(colors.begin(), colors.end());
auto unique_ = unique(colors.begin(), colors.end());
colors.resize(unique_ - colors.begin());
return move(colors);
}
template<class INTERNAL_TYPE, class HSL_TYPE>
void test(const string& filename){
auto cs = generate_hsl_colors_from_rgb24<INTERNAL_TYPE, HSL_TYPE>();
ofstream s(filename);
for(auto c : cs)
s << c.h << "\t" << c.s << "\t" << c.l << "\n";
}
int main() try {
constexpr unsigned binary64_precision = log2(52.);
constexpr unsigned binary32_precision = log2(23.);
setiosflags(ios::scientific);
#define TEST(a,b) test<a, b>("hsl_" #a "_" #b ".tsv");
cout.precision(binary64_precision);
TEST(double, HSL192F)
TEST(float, HSL192F)
cout.precision(binary32_precision);
TEST(double, HSL96F)
TEST(float, HSL96F)
#undef TEST
} catch (exception e) {
cerr << "oops! : " << e.what();
} catch (...) {
cerr << "oops! : unknown exception";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment