OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp} Namespace Reference

Classes

struct  LabColor
struct  StandardRecipeEntry

Functions

static double srgb_to_linear (double v)
static double xyz_to_lab_component (double v)
static LabColor rgb_to_lab (const ColorDecomposeRgb &rgb)
static std::string lab_to_srgb_hex (const LabColor &lab)
static double delta_e76 (const LabColor &a, const LabColor &b)
static bool material_matches (const std::string &a, const std::string &b)
static std::vector< std::vector< int > > ratio_grid (size_t n)
static ColorDecomposeRecipeMode parse_mode (const std::string &s)
static std::vector< StandardRecipeEntry > load_standard_entries ()
static const std::vector< StandardRecipeEntry > & standard_entries ()
static void evaluate_candidate (const ColorDecomposeRgb &target, const std::vector< std::string > &hexes, const std::vector< int > &ratios, const std::vector< unsigned int > &indices, ColorDecomposeRecipeMode mode, double &best_score, ColorDecomposeRecipeResult &best)

Class Documentation

◆ Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::LabColor

struct Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::LabColor
Class Members
double a {0.0}
double b {0.0}
double l {0.0}

◆ Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::StandardRecipeEntry

struct Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::StandardRecipeEntry
Collaboration diagram for Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::StandardRecipeEntry:
Class Members
vector< string > component_hexes
vector< string > component_keys
string material
string measured_hex
LabColor measured_lab
ColorDecomposeRecipeMode mode {ColorDecomposeRecipeMode::CMYW}
vector< int > ratios
string source

Function Documentation

◆ delta_e76()

double Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::delta_e76 ( const LabColor & a,
const LabColor & b )
static
103{
104 return std::sqrt(std::pow(a.l - b.l, 2.0) + std::pow(a.a - b.a, 2.0) + std::pow(a.b - b.b, 2.0));
105}
double a
Definition ColorDecomposeRecipe.cpp:21
double l
Definition ColorDecomposeRecipe.cpp:20
double b
Definition ColorDecomposeRecipe.cpp:22

References Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::LabColor::a, Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::LabColor::b, delta_e76(), and Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::LabColor::l.

Referenced by delta_e76(), and evaluate_candidate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ evaluate_candidate()

void Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::evaluate_candidate ( const ColorDecomposeRgb & target,
const std::vector< std::string > & hexes,
const std::vector< int > & ratios,
const std::vector< unsigned int > & indices,
ColorDecomposeRecipeMode mode,
double & best_score,
ColorDecomposeRecipeResult & best )
static
206{
207 const std::string mixed = blend_color_multi(hexes, ratios);
208 ColorDecomposeRgb mixed_rgb;
209 if (!color_decompose_hex_to_rgb(mixed, mixed_rgb))
210 return;
211
212 const double score = delta_e76(rgb_to_lab(target), rgb_to_lab(mixed_rgb));
213 if (score >= best_score)
214 return;
215
216 best_score = score;
217 best.valid = true;
218 best.mode = mode;
219 best.matched_color_hex = mixed;
220 best.components.clear();
221 for (size_t i = 0; i < hexes.size(); ++i) {
223 comp.color_hex = hexes[i];
224 comp.ratio = ratios[i];
225 comp.filament_index = i < indices.size() ? indices[i] : 0;
226 best.components.push_back(comp);
227 }
228}
static LabColor rgb_to_lab(const ColorDecomposeRgb &rgb)
Definition ColorDecomposeRecipe.cpp:49
static double delta_e76(const LabColor &a, const LabColor &b)
Definition ColorDecomposeRecipe.cpp:102
unsigned int filament_index
Definition ColorDecomposeRecipe.hpp:33
std::vector< ColorDecomposeRecipeComponent > components
Definition ColorDecomposeRecipe.hpp:40
bool color_decompose_hex_to_rgb(const std::string &hex, ColorDecomposeRgb &out)
Definition ColorDecomposeRecipe.cpp:239
std::string matched_color_hex
Definition ColorDecomposeRecipe.hpp:39
ColorDecomposeRecipeMode mode
Definition ColorDecomposeRecipe.hpp:38
int ratio
Definition ColorDecomposeRecipe.hpp:32
std::string blend_color_multi(const std::vector< std::string > &hex_colors, const std::vector< int > &weights)
Definition FilamentMixer.cpp:124
std::string color_hex
Definition ColorDecomposeRecipe.hpp:30
bool valid
Definition ColorDecomposeRecipe.hpp:37
Definition ColorDecomposeRecipe.hpp:29
Definition ColorDecomposeRecipe.hpp:15

References Slic3r::blend_color_multi(), Slic3r::color_decompose_hex_to_rgb(), Slic3r::ColorDecomposeRecipeComponent::color_hex, Slic3r::ColorDecomposeRecipeResult::components, delta_e76(), evaluate_candidate(), Slic3r::ColorDecomposeRecipeComponent::filament_index, Slic3r::ColorDecomposeRecipeResult::matched_color_hex, Slic3r::ColorDecomposeRecipeResult::mode, Slic3r::ColorDecomposeRecipeComponent::ratio, rgb_to_lab(), and Slic3r::ColorDecomposeRecipeResult::valid.

Referenced by evaluate_candidate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ lab_to_srgb_hex()

std::string Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::lab_to_srgb_hex ( const LabColor & lab)
static
67{
68 constexpr double Xn = 0.95047, Yn = 1.0, Zn = 1.08883;
69
70 auto f_inv = [](double t) -> double {
71 constexpr double eps = 216.0 / 24389.0;
72 constexpr double kappa = 24389.0 / 27.0;
73 const double t3 = t * t * t;
74 return t3 > eps ? t3 : (t * 116.0 - 16.0) / kappa;
75 };
76
77 const double fy = (lab.l + 16.0) / 116.0;
78 const double fx = lab.a / 500.0 + fy;
79 const double fz = fy - lab.b / 200.0;
80
81 const double X = Xn * f_inv(fx);
82 const double Y = Yn * f_inv(fy);
83 const double Z = Zn * f_inv(fz);
84
85 double r = 3.2406 * X - 1.5372 * Y - 0.4986 * Z;
86 double g = -0.9689 * X + 1.8758 * Y + 0.0415 * Z;
87 double b = 0.0557 * X - 0.2040 * Y + 1.0570 * Z;
88
89 auto gamma = [](double c) -> double {
90 c = std::max(0.0, std::min(1.0, c));
91 return c <= 0.0031308 ? 12.92 * c : 1.055 * std::pow(c, 1.0 / 2.4) - 0.055;
92 };
93 auto u8 = [&](double c) -> int {
94 return std::max(0, std::min(255, static_cast<int>(std::lround(gamma(c) * 255.0))));
95 };
96
97 char buf[8];
98 std::snprintf(buf, sizeof(buf), "#%02X%02X%02X", u8(r), u8(g), u8(b));
99 return std::string(buf);
100}
static const float Zn
Definition ColorSpaceConvert.cpp:18
static const float Yn
Definition ColorSpaceConvert.cpp:17
static const float Xn
Definition ColorSpaceConvert.cpp:16
@ Y
Definition libslic3r.h:142
@ Z
Definition libslic3r.h:143
@ X
Definition libslic3r.h:141

References Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::LabColor::a, Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::LabColor::b, Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::LabColor::l, lab_to_srgb_hex(), Slic3r::X, Xn, Slic3r::Y, Yn, Slic3r::Z, and Zn.

Referenced by lab_to_srgb_hex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ load_standard_entries()

std::vector< StandardRecipeEntry > Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::load_standard_entries ( )
static
139{
140 std::vector<StandardRecipeEntry> entries;
141 const std::string path = resources_dir() + "/filament_mixing/standard_color_recipes.json";
142 std::ifstream ifs(path);
143 if (!ifs)
144 return entries;
145
146 nlohmann::json root = nlohmann::json::parse(ifs, nullptr, false);
147 if (root.is_discarded() || !root.contains("entries") || !root["entries"].is_array())
148 return entries;
149
150 for (const auto& item : root["entries"]) {
151 if (!item.is_object())
152 continue;
154 entry.mode = parse_mode(item.value("mode", "CMYW"));
155 entry.material = item.value("material", "");
156 entry.source = item.value("source", "");
157 entry.measured_hex = item.value("measured_rgb", "");
158
159 if (item.contains("components") && item["components"].is_array()) {
160 for (const auto& comp : item["components"]) {
161 if (comp.is_object()) {
162 entry.component_keys.push_back(comp.value("key", ""));
163 entry.component_hexes.push_back(comp.value("rgb", ""));
164 }
165 }
166 }
167 if (item.contains("ratios") && item["ratios"].is_array()) {
168 for (const auto& ratio : item["ratios"]) {
169 if (ratio.is_number_integer())
170 entry.ratios.push_back(ratio.get<int>());
171 }
172 }
173 if (item.contains("measured_lab") && item["measured_lab"].is_array() && item["measured_lab"].size() >= 3) {
174 entry.measured_lab = {
175 item["measured_lab"][0].get<double>(),
176 item["measured_lab"][1].get<double>(),
177 item["measured_lab"][2].get<double>()
178 };
179 } else {
180 ColorDecomposeRgb measured_rgb;
181 if (!color_decompose_hex_to_rgb(entry.measured_hex, measured_rgb))
182 continue;
183 entry.measured_lab = rgb_to_lab(measured_rgb);
184 }
185
186 if (entry.component_hexes.size() >= 2 && entry.component_hexes.size() == entry.ratios.size() &&
187 !entry.measured_hex.empty())
188 entries.push_back(std::move(entry));
189 }
190 return entries;
191}
std::vector< int > ratios
Definition ColorDecomposeRecipe.cpp:31
std::string source
Definition ColorDecomposeRecipe.cpp:28
std::string measured_hex
Definition ColorDecomposeRecipe.cpp:32
LabColor measured_lab
Definition ColorDecomposeRecipe.cpp:33
std::vector< std::string > component_keys
Definition ColorDecomposeRecipe.cpp:29
static ColorDecomposeRecipeMode parse_mode(const std::string &s)
Definition ColorDecomposeRecipe.cpp:131
ColorDecomposeRecipeMode mode
Definition ColorDecomposeRecipe.cpp:26
std::string material
Definition ColorDecomposeRecipe.cpp:27
std::vector< std::string > component_hexes
Definition ColorDecomposeRecipe.cpp:30
const std::string & resources_dir()
Definition utils.cpp:296

References Slic3r::color_decompose_hex_to_rgb(), Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::StandardRecipeEntry::component_hexes, Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::StandardRecipeEntry::component_keys, load_standard_entries(), Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::StandardRecipeEntry::material, Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::StandardRecipeEntry::measured_hex, Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::StandardRecipeEntry::measured_lab, Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::StandardRecipeEntry::mode, parse_mode(), Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::StandardRecipeEntry::ratios, Slic3r::resources_dir(), rgb_to_lab(), and Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::StandardRecipeEntry::source.

Referenced by load_standard_entries(), and standard_entries().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ material_matches()

bool Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::material_matches ( const std::string & a,
const std::string & b )
static
108{
109 if (a.empty() || b.empty())
110 return false;
111 return a == b || a == b + " Basic" || b == a + " Basic";
112}

References material_matches().

Referenced by material_matches().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ parse_mode()

ColorDecomposeRecipeMode Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::parse_mode ( const std::string & s)
static
132{
133 if (s == "RYBW" || s == "RGBY")
136}
@ RYBW
Definition ColorDecomposeRecipe.hpp:12
@ CMYW
Definition ColorDecomposeRecipe.hpp:11

References Slic3r::CMYW, parse_mode(), and Slic3r::RYBW.

Referenced by load_standard_entries(), and parse_mode().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ratio_grid()

std::vector< std::vector< int > > Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::ratio_grid ( size_t n)
static
115{
116 std::vector<std::vector<int>> out;
117 if (n == 2) {
118 for (int a = 20; a <= 80; a += 5)
119 out.push_back({a, 100 - a});
120 } else if (n == 3) {
121 for (int a = 20; a <= 60; a += 5)
122 for (int b = 20; b <= 80 - a; b += 5) {
123 const int c = 100 - a - b;
124 if (c >= 20)
125 out.push_back({a, b, c});
126 }
127 }
128 return out;
129}

References ratio_grid().

Referenced by ratio_grid().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ rgb_to_lab()

LabColor Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::rgb_to_lab ( const ColorDecomposeRgb & rgb)
static
50{
51 const double r = srgb_to_linear(rgb.r);
52 const double g = srgb_to_linear(rgb.g);
53 const double b = srgb_to_linear(rgb.b);
54
55 const double x = (0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / 0.95047;
56 const double y = (0.2126729 * r + 0.7151522 * g + 0.0721750 * b);
57 const double z = (0.0193339 * r + 0.1191920 * g + 0.9503041 * b) / 1.08883;
58
59 const double fx = xyz_to_lab_component(x);
60 const double fy = xyz_to_lab_component(y);
61 const double fz = xyz_to_lab_component(z);
62
63 return {116.0 * fy - 16.0, 500.0 * (fx - fy), 200.0 * (fy - fz)};
64}
static double xyz_to_lab_component(double v)
Definition ColorDecomposeRecipe.cpp:42
static double srgb_to_linear(double v)
Definition ColorDecomposeRecipe.cpp:36
unsigned char g
Definition ColorDecomposeRecipe.hpp:17
unsigned char b
Definition ColorDecomposeRecipe.hpp:18
unsigned char r
Definition ColorDecomposeRecipe.hpp:16

References Slic3r::ColorDecomposeRgb::b, Slic3r::ColorDecomposeRgb::g, Slic3r::ColorDecomposeRgb::r, rgb_to_lab(), srgb_to_linear(), and xyz_to_lab_component().

Referenced by evaluate_candidate(), load_standard_entries(), and rgb_to_lab().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ srgb_to_linear()

double Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::srgb_to_linear ( double v)
static
37{
38 v /= 255.0;
39 return v <= 0.04045 ? v / 12.92 : std::pow((v + 0.055) / 1.055, 2.4);
40}

References srgb_to_linear().

Referenced by rgb_to_lab(), and srgb_to_linear().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ standard_entries()

const std::vector< StandardRecipeEntry > & Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::standard_entries ( )
static
194{
195 static const std::vector<StandardRecipeEntry> entries = load_standard_entries();
196 return entries;
197}
static std::vector< StandardRecipeEntry > load_standard_entries()
Definition ColorDecomposeRecipe.cpp:138

References load_standard_entries(), and standard_entries().

Referenced by standard_entries().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ xyz_to_lab_component()

double Slic3r::anonymous_namespace{ColorDecomposeRecipe.cpp}::xyz_to_lab_component ( double v)
static
43{
44 constexpr double eps = 216.0 / 24389.0;
45 constexpr double kappa = 24389.0 / 27.0;
46 return v > eps ? std::cbrt(v) : (kappa * v + 16.0) / 116.0;
47}

References xyz_to_lab_component().

Referenced by rgb_to_lab(), and xyz_to_lab_component().

Here is the call graph for this function:
Here is the caller graph for this function: