Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
Native side of color interpolation
Browse files Browse the repository at this point in the history
This is just a start so I can get an idea from the C++ illuminati
about whether it's the right direction. Approach here is

* Since colors are arrays in JS and objects in C++, instead of a
  rgbToLab() method, there's a to_lab() method on the color object
  • Loading branch information
tmcw committed Sep 23, 2016
1 parent c4420d0 commit 78ea832
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 0 deletions.
1 change: 1 addition & 0 deletions cmake/test-files.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ set(MBGL_TEST_FILES

# util
test/util/async_task.cpp
test/util/color.cpp
test/util/geo.cpp
test/util/http_timeout.cpp
test/util/image.cpp
Expand Down
3 changes: 3 additions & 0 deletions include/mbgl/util/color.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <mbgl/util/optional.hpp>
#include <mbgl/util/color_lab.hpp>

#include <string>

Expand All @@ -14,6 +15,8 @@ class Color {
float b = 0.0f;
float a = 0.0f;

optional<ColorLAB> to_lab();

static constexpr Color black() { return { 0.0f, 0.0f, 0.0f, 1.0f }; };
static constexpr Color white() { return { 1.0f, 1.0f, 1.0f, 1.0f }; };

Expand Down
25 changes: 25 additions & 0 deletions include/mbgl/util/color_lab.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <mbgl/util/optional.hpp>
#include <string>

namespace mbgl {

// Stores a LAB color, with all four channels ranging from 0..1
class ColorLAB {
public:
float l = 0.0f;
float a = 0.0f;
float b = 0.0f;
float A = 0.0f;
};

constexpr bool operator==(const ColorLAB& colorA, const ColorLAB& colorB) {
return colorA.l == colorB.l && colorA.a == colorB.a && colorA.b == colorB.b && colorA.A == colorB.A;
}

constexpr bool operator!=(const ColorLAB& colorA, const ColorLAB& colorB) {
return !(colorA == colorB);
}

} // namespace mbgl
46 changes: 46 additions & 0 deletions src/mbgl/util/color.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,36 @@
#include <cmath>
#include <mbgl/util/color.hpp>
#include <mbgl/util/color_lab.hpp>

#include <csscolorparser/csscolorparser.hpp>

const float Kn = 18;
const float Xn = 0.950470; // D65 standard referent
const float Yn = 1;
const float Zn = 1.088830;
const float t0 = 4 / 29;
const float t1 = 6 / 29;
const float t2 = 3 * t1 * t1;
const float t3 = t1 * t1 * t1;
// const float deg2rad = M_PI / 180;
// const float rad2deg = 180 / M_PI;

float xyz2lab(float t) {
return t > t3 ? std::pow(t, 1 / 3) : t / t2 + t0;
}

float lab2xyz(float t) {
return t > t1 ? t * t * t : t2 * (t - t0);
}

float xyz2rgb(float x) {
return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * std::pow(x, 1 / 2.4) - 0.055);
}

float rgb2xyz(float x) {
return (x /= 255) <= 0.04045 ? x / 12.92 : std::pow((x + 0.055) / 1.055, 2.4);
}

namespace mbgl {

optional<Color> Color::parse(const std::string& s) {
Expand All @@ -17,4 +46,21 @@ optional<Color> Color::parse(const std::string& s) {
}};
}

optional<ColorLAB> Color::to_lab() {

const float rawB = rgb2xyz(r);
const float rawA = rgb2xyz(g);
const float rawL = rgb2xyz(b);
const float x = xyz2lab((0.4124564 * rawB + 0.3575761 * rawA + 0.1804375 * rawL) / Xn);
const float y = xyz2lab((0.2126729 * rawB + 0.7151522 * rawA + 0.0721750 * rawL) / Yn);
const float z = xyz2lab((0.0193339 * rawB + 0.1191920 * rawA + 0.9503041 * rawL) / Zn);

return ColorLAB{
116 * y - 16,
500 * (x - y),
200 * (y - z),
a
};
}

} // namespace mbgl
31 changes: 31 additions & 0 deletions test/util/color.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <mbgl/test/util.hpp>

#include <mbgl/util/constants.hpp>
#include <mbgl/util/color.hpp>
#include <mbgl/util/color_lab.hpp>

using namespace mbgl;

TEST(Color, CanParse) {
optional<Color> result = Color::parse("#00ff00");
ASSERT_DOUBLE_EQ( result->r, 0);
ASSERT_DOUBLE_EQ( result->g, 1);
ASSERT_DOUBLE_EQ( result->b, 0);
}

TEST(Color, InvalidColor) {
optional<Color> result = Color::parse(" not a color value");

ASSERT_DOUBLE_EQ( result->r, 0);
ASSERT_DOUBLE_EQ( result->g, 0);
ASSERT_DOUBLE_EQ( result->b, 0);
}

TEST(Color, ColorLAB) {
optional<Color> result = Color::parse("#00ff00");
optional<ColorLAB> labColor = result->to_lab();

ASSERT_DOUBLE_EQ( labColor->l, 100);
ASSERT_DOUBLE_EQ( labColor->a, 0);
ASSERT_DOUBLE_EQ( labColor->b, 0);
}

0 comments on commit 78ea832

Please sign in to comment.