diff --git a/Makefile b/Makefile index aaa291c..e40bb20 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ LIB_DIR = lib STATIC_INCLUDE_DIR = include -CPPFLAGS = -Isrc/imgui -Isrc/material-colors -g -D ASSET_DIR=\"$(ASSET_PREFIX)\" +CPPFLAGS = -Isrc/imgui -g -D ASSET_DIR=\"$(ASSET_PREFIX)\" CFLAGS = -g -D ASSET_DIR=\"$(ASSET_PREFIX)\" LDFLAGS = -g #global LDLIBS @@ -51,23 +51,6 @@ C_SRC += $(wildcard $(SRC_DIR)/*.c) #GET LIST OF ALL C FILES CPP_SRC += $(wildcard $(SRC_DIR)/*.cpp) #GET LIST OF ALL CPP FILES CPP_SRC += $(wildcard $(SRC_DIR)/rlImGui/*.cpp) #GET LIST OF ALL CPP FILES - -# BUILD MATERIAL_COLORS SYSETM -CPP_SRC += $(wildcard $(SRC_DIR)/material-colors/cpp/quantize/celebi.cpp) -CPP_SRC += $(wildcard $(SRC_DIR)/material-colors/cpp/quantize/wsmeans.cpp) -CPP_SRC += $(wildcard $(SRC_DIR)/material-colors/cpp/quantize/wu.cpp) -CPP_SRC += $(wildcard $(SRC_DIR)/material-colors/cpp/quantize/lab.cpp) -CPP_SRC += $(wildcard $(SRC_DIR)/material-colors/cpp/utils/utils.cpp) -CPP_SRC += $(wildcard $(SRC_DIR)/material-colors/cpp/cam/cam.cpp) -CPP_SRC += $(wildcard $(SRC_DIR)/material-colors/cpp/cam/hct.cpp) -CPP_SRC += $(wildcard $(SRC_DIR)/material-colors/cpp/cam/hct_solver.cpp) -CPP_SRC += $(wildcard $(SRC_DIR)/material-colors/cpp/cam/viewing_conditions.cpp) -CPP_SRC += $(wildcard $(SRC_DIR)/material-colors/cpp/score/score.cpp) -EXTRA_DIRS += $(OBJ_DIR)/material-colors/cpp/quantize -EXTRA_DIRS += $(OBJ_DIR)/material-colors/cpp/utils -EXTRA_DIRS += $(OBJ_DIR)/material-colors/cpp/score -EXTRA_DIRS += $(OBJ_DIR)/material-colors/cpp/cam - ifeq ($(IMGUI_MODE), BUILD) CPP_SRC += $(wildcard $(SRC_DIR)/imgui/*.cpp) #GET LIST OF ALL CPP FILES EXTRA_DIRS += $(OBJ_DIR)/imgui diff --git a/assets/null.png b/assets/null.png new file mode 100644 index 0000000..ad7c667 Binary files /dev/null and b/assets/null.png differ diff --git a/mpris-miniplayer.desktop b/mpris-miniplayer.desktop deleted file mode 100644 index 97be375..0000000 --- a/mpris-miniplayer.desktop +++ /dev/null @@ -1,10 +0,0 @@ -[Desktop Entry] -Type=Application -Version=1.0 -Name=mpris-miniplayer -GenericName=Miniplayer -Comment=Miniplayer to display album art for MPRIS media. -Exec=mpris-miniplayer -Terminal=false -Categories=System;Audio;Music -Keywords=music,audio,album diff --git a/src/main.cpp b/src/main.cpp index 444297c..6af0a68 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,7 +8,6 @@ #define IMGUI_DEFINE_MATH_OPERATORS #include "raylib.h" #include "raymath.h" -#include "rlgl.h" #include #include #include @@ -21,12 +20,11 @@ #include "stdio.h" -#include #include #include -#include #include #include +#include extern "C" { #include "testc.h" } @@ -128,9 +126,9 @@ std::vector GetMprisServices() { } void DrawPlay(Vector2 Pos, float scale, Color color) { - Vector2 backtop = (Vector2){.x = -0.29f, .y = -0.40f}; - Vector2 backbot = (Vector2){.x = -0.29f, .y = 0.40f}; - Vector2 front = (Vector2){.x = 0.5f, .y = 0}; + Vector2 backtop = (Vector2) { .x=-0.29f, .y=-0.40f }; + Vector2 backbot = (Vector2) { .x=-0.29f, .y=0.40f}; + Vector2 front = (Vector2) {.x = 0.5f, .y=0}; backtop = Vector2Scale(backtop, scale); backbot = Vector2Scale(backbot, scale); @@ -144,9 +142,9 @@ void DrawPlay(Vector2 Pos, float scale, Color color) { } void DrawNext(Vector2 Pos, float scale, Color color) { - Vector2 backtop = (Vector2){.x = -0.35f, .y = -0.35f}; - Vector2 backbot = (Vector2){.x = -0.35f, .y = 0.35f}; - Vector2 front = (Vector2){.x = 0.28f, .y = 0}; + Vector2 backtop = (Vector2) { .x=-0.35f, .y=-0.35f }; + Vector2 backbot = (Vector2) { .x=-0.35f, .y=0.35f}; + Vector2 front = (Vector2) {.x = 0.28f, .y=0}; backtop = Vector2Scale(backtop, scale); backbot = Vector2Scale(backbot, scale); @@ -158,22 +156,26 @@ void DrawNext(Vector2 Pos, float scale, Color color) { DrawTriangle(backtop, backbot, front, color); - Vector2 topleft = (Vector2){.x = -0.29f, .y = -0.4f}; + Vector2 topleft = (Vector2) {.x = -0.29f, .y = -0.4f }; - Vector2 bar2topleft = Vector2Add(topleft, (Vector2){0.706f * 0.6f, .y = 0}); + + + Vector2 bar2topleft = Vector2Add(topleft, (Vector2) {0.706f*0.6f, .y=0}); bar2topleft = Vector2Scale(bar2topleft, scale); bar2topleft = Vector2Add(bar2topleft, Pos); - Vector2 size = (Vector2){.x = 0.706f * 0.2f, .y = 0.8f}; + Vector2 size = (Vector2) {.x=0.706f *0.2f, .y = 0.8f }; size = Vector2Scale(size, scale); + DrawRectangleV(bar2topleft, size, color); } + void DrawBack(Vector2 Pos, float scale, Color color) { - Vector2 backtop = (Vector2){.x = 0.35f, .y = -0.35f}; - Vector2 backbot = (Vector2){.x = 0.35f, .y = 0.35f}; - Vector2 front = (Vector2){.x = -0.28f, .y = 0}; + Vector2 backtop = (Vector2) { .x=0.35f, .y=-0.35f }; + Vector2 backbot = (Vector2) { .x=0.35f, .y=0.35f}; + Vector2 front = (Vector2) {.x = -0.28f, .y=0}; backtop = Vector2Scale(backtop, scale); backbot = Vector2Scale(backbot, scale); @@ -183,25 +185,27 @@ void DrawBack(Vector2 Pos, float scale, Color color) { backbot = Vector2Add(backbot, Pos); front = Vector2Add(front, Pos); - // DrawTriangle(backtop, backbot, front, color); + //DrawTriangle(backtop, backbot, front, color); DrawTriangle(front, backbot, backtop, color); - Vector2 topleft = (Vector2){.x = -0.29f, .y = -0.4f}; + Vector2 topleft = (Vector2) {.x = -0.29f, .y = -0.4f }; + Vector2 bar1topleft = Vector2Scale(topleft, scale); bar1topleft = Vector2Add(bar1topleft, Pos); - Vector2 size = (Vector2){.x = 0.706f * 0.2f, .y = 0.8f}; + Vector2 size = (Vector2) {.x=0.706f *0.2f, .y = 0.8f }; size = Vector2Scale(size, scale); + DrawRectangleV(bar1topleft, size, color); } void DrawStop(Vector2 Pos, float scale, Color color) { - Vector2 topleft = (Vector2){.x = -0.353f, .y = -0.353f}; - Vector2 botright = (Vector2){.x = 0.353f, .y = 0.353f}; + Vector2 topleft = (Vector2) {.x = -0.353f, .y = -0.353f }; + Vector2 botright = (Vector2) {.x = 0.353f, .y = 0.353f }; topleft = Vector2Scale(topleft, scale); - botright = Vector2Scale(botright, scale * 2); + botright = Vector2Scale(botright, scale*2); topleft = Vector2Add(topleft, Pos); @@ -209,16 +213,17 @@ void DrawStop(Vector2 Pos, float scale, Color color) { } void DrawPause(Vector2 Pos, float scale, Color color) { - Vector2 topleft = (Vector2){.x = -0.353f, .y = -0.353f}; + Vector2 topleft = (Vector2) {.x = -0.353f, .y = -0.353f }; + Vector2 bar1topleft = Vector2Scale(topleft, scale); bar1topleft = Vector2Add(bar1topleft, Pos); - Vector2 bar2topleft = Vector2Add(topleft, (Vector2){0.706f * 0.6f, .y = 0}); + Vector2 bar2topleft = Vector2Add(topleft, (Vector2) {0.706f*0.6f, .y=0}); bar2topleft = Vector2Scale(bar2topleft, scale); bar2topleft = Vector2Add(bar2topleft, Pos); - Vector2 size = (Vector2){.x = 0.706f * 0.4f, .y = 0.706f}; + Vector2 size = (Vector2) {.x=0.706f *0.4f, .y = 0.706f }; size = Vector2Scale(size, scale); topleft = Vector2Add(topleft, Pos); @@ -228,48 +233,23 @@ void DrawPause(Vector2 Pos, float scale, Color color) { } float ScaleToFit(Vector2 src, Vector2 dst) { - float ratio = std::min(dst.x / src.x, dst.y / src.y); + float ratio = std::min(dst.x/src.x, dst.y/src.y); return ratio; - // return Vector2Scale(src, ratio); -} - -void GenCircleOverlay(MprisPlayer *current_player, RenderTexture tex, bool trans, bool accent) { - BeginTextureMode(tex); - if (trans) { - ClearBackground(WHITE); - } else { - if (accent) { - ClearBackground(current_player->GetPrimaryColor()); - } else { - ClearBackground(BLACK); - } - } - BeginBlendMode(BLEND_SUBTRACT_COLORS); - if (trans) { - DrawCircle(GetScreenWidth() / 2, GetScreenHeight() / 2, - std::min(GetScreenWidth() / 2, GetScreenHeight() / 2), WHITE); - } else { - DrawCircle(GetScreenWidth() / 2, GetScreenHeight() / 2, - std::min(GetScreenWidth() / 2, GetScreenHeight() / 2), (Color{0, 0, 0, 0})); - } - EndBlendMode(); - EndTextureMode(); + //return Vector2Scale(src, ratio); } int main(int argc, char *argv[]) { // Initialization //-------------------------------------------------------------------------------------- - int screenWidth = 800; + int screenWidth = 1280; int screenHeight = 800; // SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_WINDOW_RESIZABLE); - // SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_VSYNC_HINT | FLAG_WINDOW_RESIZABLE); - SetConfigFlags(FLAG_WINDOW_TRANSPARENT | FLAG_MSAA_4X_HINT | FLAG_WINDOW_RESIZABLE); + SetConfigFlags(FLAG_MSAA_4X_HINT | FLAG_VSYNC_HINT | FLAG_WINDOW_RESIZABLE); InitWindow(screenWidth, screenHeight, "raylib-Extras [ImGui] example - Docking"); SetTargetFPS(244); rlImGuiSetup(true); ImGui::GetStyle().AntiAliasedLinesUseTex = false; - // SetWindowState(FLAG_WINDOW_UNDECORATED); TestC(); TestCPPFunc(); @@ -285,152 +265,72 @@ int main(int argc, char *argv[]) { auto current_player = MprisPlayer("org.mpris.MediaPlayer2.playerctld"); double lasttime = 0.0; - bool discmode = false; - DiscObject disc(0); // Main game loop - bool goodstate = false; - bool trans = false; - bool accent = true; - - long imagecount = -1; - - bool showMetricsWindow = false; - - RenderTexture recordoverlay = LoadRenderTexture(screenWidth, screenHeight); - GenCircleOverlay(¤t_player, recordoverlay, trans, accent); - while (!WindowShouldClose() && run) // Detect window close button or ESC key, or a quit from the menu { - if (IsWindowResized()) { - UnloadRenderTexture(recordoverlay); - recordoverlay = LoadRenderTexture(GetScreenWidth(), GetScreenHeight()); - GenCircleOverlay(¤t_player, recordoverlay, trans, accent); - } - - if (current_player.imagecount > imagecount) { - imagecount = current_player.imagecount; - GenCircleOverlay(¤t_player, recordoverlay, trans, accent); - } - - if (GetTime() > lasttime + 3) { + if (GetTime() > lasttime+3 ) { lasttime = GetTime(); current_player.Refresh(); } BeginDrawing(); - if (trans) { - ClearBackground((Color){0, 0, 0, 0}); - } else { - ClearBackground(BLACK); - } - Vector2 winwidth = (Vector2){(float)GetScreenWidth(), (float)GetScreenHeight()}; - Vector2 imagesize = - (Vector2){(float)current_player.tex.tex.width, (float)current_player.tex.tex.height}; + ClearBackground(BLACK); + + Vector2 winwidth = (Vector2) {(float) GetScreenWidth(), (float) GetScreenHeight()}; + Vector2 imagesize = (Vector2) {(float) current_player.tex.tex.width, (float) current_player.tex.tex.height}; Vector2 scaledsize = Vector2Scale(imagesize, ScaleToFit(imagesize, winwidth)); Vector2 fpos; - fpos.x = (winwidth.x * 0.5) - (scaledsize.x * 0.5f); - fpos.y = (winwidth.y * 0.5) - (scaledsize.y * 0.5f); - // DrawTextureEx(current_player.tex.tex, fpos, 0, ScaleToFit(imagesize, winwidth), WHITE); - Rectangle src = (Rectangle){0, 0, (float)current_player.tex.tex.width, - (float)current_player.tex.tex.height}; - Rectangle dst = (Rectangle){fpos.x + scaledsize.x / 2, fpos.y + scaledsize.y / 2, - scaledsize.x, scaledsize.y}; + fpos.x = (winwidth.x *0.5) - (scaledsize.x * 0.5f); + fpos.y = (winwidth.y *0.5) - (scaledsize.y * 0.5f); + DrawTextureEx(current_player.tex.tex, fpos, 0, ScaleToFit(imagesize, winwidth), WHITE); - DrawTexturePro(current_player.tex.tex, src, dst, (Vector2){dst.width / 2, dst.height / 2}, - disc.pos, WHITE); - if (IsWindowFocused()) { + + if ( IsWindowFocused() ) { const float buttonsize = 0.1; - Vector2 screen = (Vector2){(float)GetScreenWidth(), (float)GetScreenHeight()}; + Vector2 screen = (Vector2) {(float) GetScreenWidth(), (float) GetScreenHeight()}; Vector2 centerline; centerline.x = screen.x / 2; centerline.y = screen.y * 0.8; Color transblack = BLACK; transblack.a = (200); - DrawCircleV(centerline, 0.05 * GetScreenWidth(), transblack); + DrawCircleV(centerline, 0.05*GetScreenWidth(), transblack); if (current_player.playstate == "Playing") { - DrawPause(centerline, 0.1 * GetScreenWidth(), WHITE); + DrawPause(centerline, 0.1*GetScreenWidth(), WHITE); } else { - DrawPlay(centerline, 0.1 * GetScreenWidth(), WHITE); + DrawPlay(centerline, 0.1*GetScreenWidth(), WHITE); } - Vector2 next = Vector2Add(centerline, (Vector2){screen.x * 0.2f, 0.0f}); - DrawCircleV(next, 0.05 * GetScreenWidth(), transblack); - DrawNext(next, 0.1 * GetScreenWidth(), WHITE); + Vector2 next = Vector2Add(centerline, (Vector2) {screen.x * 0.2f, 0.0f}); + DrawCircleV(next, 0.05*GetScreenWidth(), transblack); + DrawNext(next, 0.1*GetScreenWidth(), WHITE); - Vector2 back = Vector2Add(centerline, (Vector2){screen.x * -0.2f, 0.0f}); - DrawCircleV(back, 0.05 * GetScreenWidth(), transblack); - DrawBack(back, 0.1 * GetScreenWidth(), WHITE); + Vector2 back = Vector2Add(centerline, (Vector2) {screen.x * -0.2f, 0.0f}); + DrawCircleV(back, 0.05*GetScreenWidth(), transblack); + DrawBack(back, 0.1*GetScreenWidth(), WHITE); - if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && - CheckCollisionPointCircle(GetMousePosition(), centerline, - 0.05 * GetScreenWidth())) { + if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && CheckCollisionPointCircle(GetMousePosition(), centerline, 0.05*GetScreenWidth()) ) { current_player.PausePlay(); - current_player.playstate = - current_player.playstate == "Playing" ? "Paused" : "Playing"; - } else if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && - CheckCollisionPointCircle(GetMousePosition(), next, - 0.05 * GetScreenWidth())) { + current_player.playstate = current_player.playstate == "Playing" ? "Paused" : "Playing"; + } + + if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && CheckCollisionPointCircle(GetMousePosition(), next, 0.05*GetScreenWidth()) ) { current_player.Next(); - current_player.playstate = - current_player.playstate == "Playing" ? "Paused" : "Playing"; - } else if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && - CheckCollisionPointCircle(GetMousePosition(), back, - 0.05 * GetScreenWidth())) { + current_player.playstate = current_player.playstate == "Playing" ? "Paused" : "Playing"; + } + + if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && CheckCollisionPointCircle(GetMousePosition(), back, 0.05*GetScreenWidth()) ) { current_player.Prev(); - current_player.playstate = - current_player.playstate == "Playing" ? "Paused" : "Playing"; - } else if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) && disc.enabled) { - float initmouserot; - Vector2 initmousepos; - if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { - initmouserot = disc.pos; - initmousepos = GetMousePosition(); - initmousepos = - Vector2Add(initmousepos, (Vector2){-screen.x / 2, -screen.y / 2}); - goodstate = true; - } - if (goodstate) { - Vector2 mouse = GetMousePosition(); - Vector2 mousecentered = - Vector2Add(mouse, (Vector2){-screen.x / 2, -screen.y / 2}); - disc.velo = 0; - disc.UpdatePos( - initmouserot + - (((180.0f * atan2(mousecentered.y, mousecentered.x)) / M_PI) - - ((180.0f * atan2(initmousepos.y, initmousepos.x)) / M_PI)), - GetFrameTime()); - } + current_player.playstate = current_player.playstate == "Playing" ? "Paused" : "Playing"; } - } - if (!goodstate) { - disc.UpdatePos(GetFrameTime()); - // Ease from velo to target - if (current_player.playstate == "Playing") { - disc.target = 100; - } else { - disc.target = 0; - } - disc.accel = disc.target - disc.velo; - } - if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) { - goodstate = false; + + } - if (disc.active) { - if (trans) { - rlSetBlendFactors(1, 1, 0x800B); - BeginBlendMode(BLEND_CUSTOM); - } - DrawTexture(recordoverlay.texture, 0, 0, WHITE); - if (trans) { - EndBlendMode(); - } - } if (IsKeyPressed(KEY_SLASH) || IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) { showIMgui = !showIMgui; @@ -439,7 +339,6 @@ int main(int argc, char *argv[]) { // start ImGui content if (showIMgui) { - disc.enabled = false; rlImGuiBegin(); // if you want windows to dock to the viewport, call this. @@ -459,40 +358,16 @@ int main(int argc, char *argv[]) { current_player = MprisPlayer(item); } } - if (ImGui::MenuItem("Refresh")) { - serviceList = GetMprisServices(); - } ImGui::EndMenu(); } if (ImGui::BeginMenu("Window")) { if (ImGui::MenuItem("Demo Window", nullptr, showDemoWindow)) showDemoWindow = !showDemoWindow; - if (ImGui::MenuItem("Record Spin !!", nullptr, disc.active)) { - disc.Activate(); - } - if (ImGui::MenuItem("Trans Mode !!", nullptr, trans)) { - trans = !trans; - GenCircleOverlay(¤t_player, recordoverlay, trans, accent); - } - if (ImGui::MenuItem("Accent Mode !!", nullptr, accent)) { - accent = !accent; - GenCircleOverlay(¤t_player, recordoverlay, trans, accent); - } - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Tools")) { - if (ImGui::MenuItem("Debug Window", nullptr, showMetricsWindow)) { - showMetricsWindow = !showMetricsWindow; - } - ImGui::EndMenu(); - } + ImGui::EndMenu(); + } ImGui::EndMainMenuBar(); - - if (showMetricsWindow) { - ImGui::ShowMetricsWindow(); - } } // show some windows @@ -500,6 +375,7 @@ int main(int argc, char *argv[]) { if (ImGui::Begin("Player Control")) { ImGui::Text("%s", current_player.GetIdentity().c_str()); + if (ImGui::Button("Prev")) { current_player.Prev(); } @@ -516,25 +392,8 @@ int main(int argc, char *argv[]) { current_player.Refresh(); current_player.UpdateTexture(); } - - // ImGui::SliderFloat("erm", &rotation, -180, 180, "Rotation"); - // rlImGuiImage(¤t_player.tex.tex); - ImGui::Separator(); - ImGui::LabelText("Disc Info", "P: %f, V: %f, A: %f", disc.pos, disc.velo, - disc.accel); - rlImGuiImageSize(¤t_player.tex.tex, 300, 300); - - ImGui::Separator(); - int inc = 0; - for (auto obj : current_player.accent_colors) { - - float col[3] = {0, 0, 0}; - col[0] = ((float)obj.r) / 255; - col[1] = ((float)obj.g) / 255; - col[2] = ((float)obj.b) / 255; - ImGui::ColorEdit3(("lf" + std::to_string(inc)).c_str(), col); - inc++; - } + //rlImGuiImage(¤t_player.tex.tex); + rlImGuiImageSize(¤t_player.tex.tex,300,300); } ImGui::End(); @@ -543,18 +402,17 @@ int main(int argc, char *argv[]) { // end ImGui Content rlImGuiEnd(); - } else { - disc.enabled = true; } EndDrawing(); //---------------------------------------------------------------------------------- } rlImGuiShutdown(); + // De-Initialization //-------------------------------------------------------------------------------------- CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- curl_global_cleanup(); return 0; -} +} \ No newline at end of file diff --git a/src/material-colors/cpp/blend/blend.cpp b/src/material-colors/cpp/blend/blend.cpp deleted file mode 100644 index 4b8c34b..0000000 --- a/src/material-colors/cpp/blend/blend.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/blend/blend.h" - -#include -#include - -#include "cpp/cam/cam.h" -#include "cpp/cam/hct.h" -#include "cpp/cam/viewing_conditions.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -Argb BlendHarmonize(const Argb design_color, const Argb key_color) { - Hct from_hct(design_color); - Hct to_hct(key_color); - double difference_degrees = DiffDegrees(from_hct.get_hue(), to_hct.get_hue()); - double rotation_degrees = std::min(difference_degrees * 0.5, 15.0); - double output_hue = SanitizeDegreesDouble( - from_hct.get_hue() + - rotation_degrees * - RotationDirection(from_hct.get_hue(), to_hct.get_hue())); - from_hct.set_hue(output_hue); - return from_hct.ToInt(); -} - -Argb BlendHctHue(const Argb from, const Argb to, const double amount) { - int ucs = BlendCam16Ucs(from, to, amount); - Hct ucs_hct(ucs); - Hct from_hct(from); - from_hct.set_hue(ucs_hct.get_hue()); - return from_hct.ToInt(); -} - -Argb BlendCam16Ucs(const Argb from, const Argb to, const double amount) { - Cam from_cam = CamFromInt(from); - Cam to_cam = CamFromInt(to); - - const double a_j = from_cam.jstar; - const double a_a = from_cam.astar; - const double a_b = from_cam.bstar; - - const double b_j = to_cam.jstar; - const double b_a = to_cam.astar; - const double b_b = to_cam.bstar; - - const double jstar = a_j + (b_j - a_j) * amount; - const double astar = a_a + (b_a - a_a) * amount; - const double bstar = a_b + (b_b - a_b) * amount; - - const Cam blended = CamFromUcsAndViewingConditions(jstar, astar, bstar, - kDefaultViewingConditions); - return IntFromCam(blended); -} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/blend/blend.h b/src/material-colors/cpp/blend/blend.h deleted file mode 100644 index ca730ae..0000000 --- a/src/material-colors/cpp/blend/blend.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_BLEND_BLEND_H_ -#define CPP_BLEND_BLEND_H_ - -#include - -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -Argb BlendHarmonize(const Argb design_color, const Argb key_color); -Argb BlendHctHue(const Argb from, const Argb to, const double amount); -Argb BlendCam16Ucs(const Argb from, const Argb to, const double amount); - -} // namespace material_color_utilities -#endif // CPP_BLEND_BLEND_H_ diff --git a/src/material-colors/cpp/blend/blend_test.cpp b/src/material-colors/cpp/blend/blend_test.cpp deleted file mode 100644 index 20462d2..0000000 --- a/src/material-colors/cpp/blend/blend_test.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/blend/blend.h" - -#include "testing/base/public/gunit.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -namespace { -TEST(BlendTest, RedToBlue) { - int blended = BlendHctHue(0xffff0000, 0xff0000ff, 0.8); - EXPECT_EQ(HexFromArgb(blended), "ff905eff"); -} -} // namespace - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/cam/cam.cpp b/src/material-colors/cpp/cam/cam.cpp deleted file mode 100644 index 769cd1a..0000000 --- a/src/material-colors/cpp/cam/cam.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/cam/cam.h" - -#include -#include - -#include "cpp/cam/hct_solver.h" -#include "cpp/cam/viewing_conditions.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -Cam CamFromJchAndViewingConditions(double j, double c, double h, - ViewingConditions viewing_conditions); - -Cam CamFromUcsAndViewingConditions( - double jstar, double astar, double bstar, - const ViewingConditions &viewing_conditions) { - const double a = astar; - const double b = bstar; - const double m = sqrt(a * a + b * b); - const double m_2 = (exp(m * 0.0228) - 1.0) / 0.0228; - const double c = m_2 / viewing_conditions.fl_root; - double h = atan2(b, a) * (180.0 / kPi); - if (h < 0.0) { - h += 360.0; - } - const double j = jstar / (1 - (jstar - 100) * 0.007); - return CamFromJchAndViewingConditions(j, c, h, viewing_conditions); -} - -Cam CamFromIntAndViewingConditions( - Argb argb, const ViewingConditions &viewing_conditions) { - // XYZ from ARGB, inlined. - int red = (argb & 0x00ff0000) >> 16; - int green = (argb & 0x0000ff00) >> 8; - int blue = (argb & 0x000000ff); - double red_l = Linearized(red); - double green_l = Linearized(green); - double blue_l = Linearized(blue); - double x = 0.41233895 * red_l + 0.35762064 * green_l + 0.18051042 * blue_l; - double y = 0.2126 * red_l + 0.7152 * green_l + 0.0722 * blue_l; - double z = 0.01932141 * red_l + 0.11916382 * green_l + 0.95034478 * blue_l; - - // Convert XYZ to 'cone'/'rgb' responses - double r_c = 0.401288 * x + 0.650173 * y - 0.051461 * z; - double g_c = -0.250268 * x + 1.204414 * y + 0.045854 * z; - double b_c = -0.002079 * x + 0.048952 * y + 0.953127 * z; - - // Discount illuminant. - double r_d = viewing_conditions.rgb_d[0] * r_c; - double g_d = viewing_conditions.rgb_d[1] * g_c; - double b_d = viewing_conditions.rgb_d[2] * b_c; - - // Chromatic adaptation. - double r_af = pow(viewing_conditions.fl * fabs(r_d) / 100.0, 0.42); - double g_af = pow(viewing_conditions.fl * fabs(g_d) / 100.0, 0.42); - double b_af = pow(viewing_conditions.fl * fabs(b_d) / 100.0, 0.42); - double r_a = Signum(r_d) * 400.0 * r_af / (r_af + 27.13); - double g_a = Signum(g_d) * 400.0 * g_af / (g_af + 27.13); - double b_a = Signum(b_d) * 400.0 * b_af / (b_af + 27.13); - - // Redness-greenness - double a = (11.0 * r_a + -12.0 * g_a + b_a) / 11.0; - double b = (r_a + g_a - 2.0 * b_a) / 9.0; - double u = (20.0 * r_a + 20.0 * g_a + 21.0 * b_a) / 20.0; - double p2 = (40.0 * r_a + 20.0 * g_a + b_a) / 20.0; - - double radians = atan2(b, a); - double degrees = radians * 180.0 / kPi; - double hue = SanitizeDegreesDouble(degrees); - double hue_radians = hue * kPi / 180.0; - double ac = p2 * viewing_conditions.nbb; - - double j = 100.0 * pow(ac / viewing_conditions.aw, - viewing_conditions.c * viewing_conditions.z); - double q = (4.0 / viewing_conditions.c) * sqrt(j / 100.0) * - (viewing_conditions.aw + 4.0) * viewing_conditions.fl_root; - double hue_prime = hue < 20.14 ? hue + 360 : hue; - double e_hue = 0.25 * (cos(hue_prime * kPi / 180.0 + 2.0) + 3.8); - double p1 = - 50000.0 / 13.0 * e_hue * viewing_conditions.n_c * viewing_conditions.ncb; - double t = p1 * sqrt(a * a + b * b) / (u + 0.305); - double alpha = - pow(t, 0.9) * - pow(1.64 - pow(0.29, viewing_conditions.background_y_to_white_point_y), - 0.73); - double c = alpha * sqrt(j / 100.0); - double m = c * viewing_conditions.fl_root; - double s = 50.0 * sqrt((alpha * viewing_conditions.c) / - (viewing_conditions.aw + 4.0)); - double jstar = (1.0 + 100.0 * 0.007) * j / (1.0 + 0.007 * j); - double mstar = 1.0 / 0.0228 * log(1.0 + 0.0228 * m); - double astar = mstar * cos(hue_radians); - double bstar = mstar * sin(hue_radians); - return {hue, c, j, q, m, s, jstar, astar, bstar}; -} - -Cam CamFromInt(Argb argb) { - return CamFromIntAndViewingConditions(argb, kDefaultViewingConditions); -} - -Argb IntFromCamAndViewingConditions(Cam cam, - ViewingConditions viewing_conditions) { - double alpha = (cam.chroma == 0.0 || cam.j == 0.0) - ? 0.0 - : cam.chroma / sqrt(cam.j / 100.0); - double t = pow( - alpha / pow(1.64 - pow(0.29, - viewing_conditions.background_y_to_white_point_y), - 0.73), - 1.0 / 0.9); - double h_rad = cam.hue * kPi / 180.0; - double e_hue = 0.25 * (cos(h_rad + 2.0) + 3.8); - double ac = - viewing_conditions.aw * - pow(cam.j / 100.0, 1.0 / viewing_conditions.c / viewing_conditions.z); - double p1 = e_hue * (50000.0 / 13.0) * viewing_conditions.n_c * - viewing_conditions.ncb; - double p2 = ac / viewing_conditions.nbb; - double h_sin = sin(h_rad); - double h_cos = cos(h_rad); - double gamma = 23.0 * (p2 + 0.305) * t / - (23.0 * p1 + 11.0 * t * h_cos + 108.0 * t * h_sin); - double a = gamma * h_cos; - double b = gamma * h_sin; - double r_a = (460.0 * p2 + 451.0 * a + 288.0 * b) / 1403.0; - double g_a = (460.0 * p2 - 891.0 * a - 261.0 * b) / 1403.0; - double b_a = (460.0 * p2 - 220.0 * a - 6300.0 * b) / 1403.0; - - double r_c_base = fmax(0, (27.13 * fabs(r_a)) / (400.0 - fabs(r_a))); - double r_c = - Signum(r_a) * (100.0 / viewing_conditions.fl) * pow(r_c_base, 1.0 / 0.42); - double g_c_base = fmax(0, (27.13 * fabs(g_a)) / (400.0 - fabs(g_a))); - double g_c = - Signum(g_a) * (100.0 / viewing_conditions.fl) * pow(g_c_base, 1.0 / 0.42); - double b_c_base = fmax(0, (27.13 * fabs(b_a)) / (400.0 - fabs(b_a))); - double b_c = - Signum(b_a) * (100.0 / viewing_conditions.fl) * pow(b_c_base, 1.0 / 0.42); - double r_x = r_c / viewing_conditions.rgb_d[0]; - double g_x = g_c / viewing_conditions.rgb_d[1]; - double b_x = b_c / viewing_conditions.rgb_d[2]; - double x = 1.86206786 * r_x - 1.01125463 * g_x + 0.14918677 * b_x; - double y = 0.38752654 * r_x + 0.62144744 * g_x - 0.00897398 * b_x; - double z = -0.01584150 * r_x - 0.03412294 * g_x + 1.04996444 * b_x; - - // intFromXyz - double r_l = 3.2406 * x - 1.5372 * y - 0.4986 * z; - double g_l = -0.9689 * x + 1.8758 * y + 0.0415 * z; - double b_l = 0.0557 * x - 0.2040 * y + 1.0570 * z; - - int red = Delinearized(r_l); - int green = Delinearized(g_l); - int blue = Delinearized(b_l); - - return ArgbFromRgb(red, green, blue); -} - -Argb IntFromCam(Cam cam) { - return IntFromCamAndViewingConditions(cam, kDefaultViewingConditions); -} - -Cam CamFromJchAndViewingConditions(double j, double c, double h, - ViewingConditions viewing_conditions) { - double q = (4.0 / viewing_conditions.c) * sqrt(j / 100.0) * - (viewing_conditions.aw + 4.0) * (viewing_conditions.fl_root); - double m = c * viewing_conditions.fl_root; - double alpha = c / sqrt(j / 100.0); - double s = 50.0 * sqrt((alpha * viewing_conditions.c) / - (viewing_conditions.aw + 4.0)); - double hue_radians = h * kPi / 180.0; - double jstar = (1.0 + 100.0 * 0.007) * j / (1.0 + 0.007 * j); - double mstar = 1.0 / 0.0228 * log(1.0 + 0.0228 * m); - double astar = mstar * cos(hue_radians); - double bstar = mstar * sin(hue_radians); - return {h, c, j, q, m, s, jstar, astar, bstar}; -} - -double CamDistance(Cam a, Cam b) { - double d_j = a.jstar - b.jstar; - double d_a = a.astar - b.astar; - double d_b = a.bstar - b.bstar; - double d_e_prime = sqrt(d_j * d_j + d_a * d_a + d_b * d_b); - double d_e = 1.41 * pow(d_e_prime, 0.63); - return d_e; -} - -Argb IntFromHcl(double hue, double chroma, double lstar) { - return SolveToInt(hue, chroma, lstar); -} - -Cam CamFromXyzAndViewingConditions( - double x, double y, double z, const ViewingConditions &viewing_conditions) { - // Convert XYZ to 'cone'/'rgb' responses - double r_c = 0.401288 * x + 0.650173 * y - 0.051461 * z; - double g_c = -0.250268 * x + 1.204414 * y + 0.045854 * z; - double b_c = -0.002079 * x + 0.048952 * y + 0.953127 * z; - - // Discount illuminant. - double r_d = viewing_conditions.rgb_d[0] * r_c; - double g_d = viewing_conditions.rgb_d[1] * g_c; - double b_d = viewing_conditions.rgb_d[2] * b_c; - - // Chromatic adaptation. - double r_af = pow(viewing_conditions.fl * fabs(r_d) / 100.0, 0.42); - double g_af = pow(viewing_conditions.fl * fabs(g_d) / 100.0, 0.42); - double b_af = pow(viewing_conditions.fl * fabs(b_d) / 100.0, 0.42); - double r_a = Signum(r_d) * 400.0 * r_af / (r_af + 27.13); - double g_a = Signum(g_d) * 400.0 * g_af / (g_af + 27.13); - double b_a = Signum(b_d) * 400.0 * b_af / (b_af + 27.13); - - // Redness-greenness - double a = (11.0 * r_a + -12.0 * g_a + b_a) / 11.0; - double b = (r_a + g_a - 2.0 * b_a) / 9.0; - double u = (20.0 * r_a + 20.0 * g_a + 21.0 * b_a) / 20.0; - double p2 = (40.0 * r_a + 20.0 * g_a + b_a) / 20.0; - - double radians = atan2(b, a); - double degrees = radians * 180.0 / kPi; - double hue = SanitizeDegreesDouble(degrees); - double hue_radians = hue * kPi / 180.0; - double ac = p2 * viewing_conditions.nbb; - - double j = 100.0 * pow(ac / viewing_conditions.aw, - viewing_conditions.c * viewing_conditions.z); - double q = (4.0 / viewing_conditions.c) * sqrt(j / 100.0) * - (viewing_conditions.aw + 4.0) * viewing_conditions.fl_root; - double hue_prime = hue < 20.14 ? hue + 360 : hue; - double e_hue = 0.25 * (cos(hue_prime * kPi / 180.0 + 2.0) + 3.8); - double p1 = - 50000.0 / 13.0 * e_hue * viewing_conditions.n_c * viewing_conditions.ncb; - double t = p1 * sqrt(a * a + b * b) / (u + 0.305); - double alpha = - pow(t, 0.9) * - pow(1.64 - pow(0.29, viewing_conditions.background_y_to_white_point_y), - 0.73); - double c = alpha * sqrt(j / 100.0); - double m = c * viewing_conditions.fl_root; - double s = 50.0 * sqrt((alpha * viewing_conditions.c) / - (viewing_conditions.aw + 4.0)); - double jstar = (1.0 + 100.0 * 0.007) * j / (1.0 + 0.007 * j); - double mstar = 1.0 / 0.0228 * log(1.0 + 0.0228 * m); - double astar = mstar * cos(hue_radians); - double bstar = mstar * sin(hue_radians); - return {hue, c, j, q, m, s, jstar, astar, bstar}; -} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/cam/cam.h b/src/material-colors/cpp/cam/cam.h deleted file mode 100644 index 2ff5db5..0000000 --- a/src/material-colors/cpp/cam/cam.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_CAM_CAM_H_ -#define CPP_CAM_CAM_H_ - -#include "cpp/cam/viewing_conditions.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -struct Cam { - double hue = 0.0; - double chroma = 0.0; - double j = 0.0; - double q = 0.0; - double m = 0.0; - double s = 0.0; - - double jstar = 0.0; - double astar = 0.0; - double bstar = 0.0; -}; - -Cam CamFromInt(Argb argb); -Cam CamFromIntAndViewingConditions(Argb argb, - const ViewingConditions &viewing_conditions); -Argb IntFromHcl(double hue, double chroma, double lstar); -Argb IntFromCam(Cam cam); -Cam CamFromUcsAndViewingConditions(double jstar, double astar, double bstar, - const ViewingConditions &viewing_conditions); -/** - * Given color expressed in the XYZ color space and viewed - * in [viewingConditions], converts the color to CAM16. - */ -Cam CamFromXyzAndViewingConditions(double x, double y, double z, - const ViewingConditions &viewing_conditions); - -} // namespace material_color_utilities -#endif // CPP_CAM_CAM_H_ diff --git a/src/material-colors/cpp/cam/cam_test.cpp b/src/material-colors/cpp/cam/cam_test.cpp deleted file mode 100644 index 6dde7de..0000000 --- a/src/material-colors/cpp/cam/cam_test.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/cam/cam.h" - -#include "testing/base/public/gmock.h" -#include "testing/base/public/gunit.h" - -namespace material_color_utilities { - -namespace { -using testing::DoubleNear; - -using testing::Eq; - -Argb RED = 0xffff0000; -Argb GREEN = 0xff00ff00; -Argb BLUE = 0xff0000ff; -Argb WHITE = 0xffffffff; -Argb BLACK = 0xff000000; - -TEST(CamTest, Red) { - Cam cam = CamFromInt(RED); - - EXPECT_THAT(cam.hue, DoubleNear(27.408, 0.001)); - EXPECT_THAT(cam.chroma, DoubleNear(113.357, 0.001)); - EXPECT_THAT(cam.j, DoubleNear(46.445, 0.001)); - EXPECT_THAT(cam.m, DoubleNear(89.494, 0.001)); - EXPECT_THAT(cam.s, DoubleNear(91.889, 0.001)); - EXPECT_THAT(cam.q, DoubleNear(105.988, 0.001)); -} - -TEST(CamTest, Green) { - Cam cam = CamFromInt(GREEN); - - EXPECT_THAT(cam.hue, DoubleNear(142.139, 0.001)); - EXPECT_THAT(cam.chroma, DoubleNear(108.410, 0.001)); - EXPECT_THAT(cam.j, DoubleNear(79.331, 0.001)); - EXPECT_THAT(cam.m, DoubleNear(85.587, 0.001)); - EXPECT_THAT(cam.s, DoubleNear(78.604, 0.001)); - EXPECT_THAT(cam.q, DoubleNear(138.520, 0.001)); -} - -TEST(CamTest, Blue) { - Cam cam = CamFromInt(BLUE); - - EXPECT_THAT(cam.hue, DoubleNear(282.788, 0.001)); - EXPECT_THAT(cam.chroma, DoubleNear(87.230, 0.001)); - EXPECT_THAT(cam.j, DoubleNear(25.465, 0.001)); - EXPECT_THAT(cam.m, DoubleNear(68.867, 0.001)); - EXPECT_THAT(cam.s, DoubleNear(93.674, 0.001)); - EXPECT_THAT(cam.q, DoubleNear(78.481, 0.001)); -} - -TEST(CamTest, White) { - Cam cam = CamFromInt(WHITE); - - EXPECT_THAT(cam.hue, DoubleNear(209.492, 0.001)); - EXPECT_THAT(cam.chroma, DoubleNear(2.869, 0.001)); - EXPECT_THAT(cam.j, DoubleNear(100.0, 0.001)); - EXPECT_THAT(cam.m, DoubleNear(2.265, 0.001)); - EXPECT_THAT(cam.s, DoubleNear(12.068, 0.001)); - EXPECT_THAT(cam.q, DoubleNear(155.521, 0.001)); -} - -TEST(CamTest, Black) { - Cam cam = CamFromInt(BLACK); - - EXPECT_THAT(cam.hue, DoubleNear(0.0, 0.001)); - EXPECT_THAT(cam.chroma, DoubleNear(0.0, 0.001)); - EXPECT_THAT(cam.j, DoubleNear(0.0, 0.001)); - EXPECT_THAT(cam.m, DoubleNear(0.0, 0.001)); - EXPECT_THAT(cam.s, DoubleNear(0.0, 0.001)); - EXPECT_THAT(cam.q, DoubleNear(0.0, 0.001)); -} - -TEST(CamTest, RedRoundTrip) { - Cam cam = CamFromInt(RED); - Argb argb = IntFromCam(cam); - EXPECT_THAT(argb, Eq(RED)); -} - -TEST(CamTest, GreenRoundTrip) { - Cam cam = CamFromInt(GREEN); - Argb argb = IntFromCam(cam); - EXPECT_THAT(argb, Eq(GREEN)); -} - -TEST(CamTest, BlueRoundTrip) { - Cam cam = CamFromInt(BLUE); - Argb argb = IntFromCam(cam); - EXPECT_THAT(argb, Eq(BLUE)); -} -} // namespace - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/cam/hct.cpp b/src/material-colors/cpp/cam/hct.cpp deleted file mode 100644 index d165ca0..0000000 --- a/src/material-colors/cpp/cam/hct.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/cam/hct.h" - -#include "cpp/cam/hct_solver.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { -Hct::Hct(double hue, double chroma, double tone) { - SetInternalState(SolveToInt(hue, chroma, tone)); -} - -Hct::Hct(Argb argb) { SetInternalState(argb); } - -double Hct::get_hue() const { return hue_; } - -double Hct::get_chroma() const { return chroma_; } - -double Hct::get_tone() const { return tone_; } - -Argb Hct::ToInt() const { return argb_; } - -void Hct::set_hue(double new_hue) { - SetInternalState(SolveToInt(new_hue, chroma_, tone_)); -} - -void Hct::set_chroma(double new_chroma) { - SetInternalState(SolveToInt(hue_, new_chroma, tone_)); -} - -void Hct::set_tone(double new_tone) { - SetInternalState(SolveToInt(hue_, chroma_, new_tone)); -} - -void Hct::SetInternalState(Argb argb) { - argb_ = argb; - Cam cam = CamFromInt(argb); - hue_ = cam.hue; - chroma_ = cam.chroma; - tone_ = LstarFromArgb(argb); -} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/cam/hct.h b/src/material-colors/cpp/cam/hct.h deleted file mode 100644 index e8e02f3..0000000 --- a/src/material-colors/cpp/cam/hct.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_CAM_HCT_H_ -#define CPP_CAM_HCT_H_ - -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -/** - * HCT: hue, chroma, and tone. - * - * A color system built using CAM16 hue and chroma, and L* (lightness) from - * the L*a*b* color space, providing a perceptually accurate - * color measurement system that can also accurately render what colors - * will appear as in different lighting environments. - * - * Using L* creates a link between the color system, contrast, and thus - * accessibility. Contrast ratio depends on relative luminance, or Y in the XYZ - * color space. L*, or perceptual luminance can be calculated from Y. - * - * Unlike Y, L* is linear to human perception, allowing trivial creation of - * accurate color tones. - * - * Unlike contrast ratio, measuring contrast in L* is linear, and simple to - * calculate. A difference of 40 in HCT tone guarantees a contrast ratio >= 3.0, - * and a difference of 50 guarantees a contrast ratio >= 4.5. - */ -class Hct { - public: - /** - * Creates an HCT color from hue, chroma, and tone. - * - * @param hue 0 <= hue < 360; invalid values are corrected. - * @param chroma >= 0; the maximum value of chroma depends on the hue - * and tone. May be lower than the requested chroma. - * @param tone 0 <= tone <= 100; invalid values are corrected. - * @return HCT representation of a color in default viewing conditions. - */ - Hct(double hue, double chroma, double tone); - - /** - * Creates an HCT color from a color. - * - * @param argb ARGB representation of a color. - * @return HCT representation of a color in default viewing conditions - */ - explicit Hct(Argb argb); - - /** - * Returns the hue of the color. - * - * @return hue of the color, in degrees. - */ - double get_hue() const; - - /** - * Returns the chroma of the color. - * - * @return chroma of the color. - */ - double get_chroma() const; - - /** - * Returns the tone of the color. - * - * @return tone of the color, satisfying 0 <= tone <= 100. - */ - double get_tone() const; - - /** - * Returns the color in ARGB format. - * - * @return an integer, representing the color in ARGB format. - */ - Argb ToInt() const; - - /** - * Sets the hue of this color. Chroma may decrease because chroma has a - * different maximum for any given hue and tone. - * - * @param new_hue 0 <= new_hue < 360; invalid values are corrected. - */ - void set_hue(double new_hue); - - /** - * Sets the chroma of this color. Chroma may decrease because chroma has a - * different maximum for any given hue and tone. - * - * @param new_chroma 0 <= new_chroma < ? - */ - void set_chroma(double new_chroma); - - /** - * Sets the tone of this color. Chroma may decrease because chroma has a - * different maximum for any given hue and tone. - * - * @param new_tone 0 <= new_tone <= 100; invalid valids are corrected. - */ - void set_tone(double new_tone); - - /** - * For using HCT as a key in a ordered map. - */ - bool operator<(const Hct& a) const { return hue_ < a.hue_; } - - private: - /** - * Sets the Hct object to represent an sRGB color. - * - * @param argb the new color as an integer in ARGB format. - */ - void SetInternalState(Argb argb); - - double hue_ = 0.0; - double chroma_ = 0.0; - double tone_ = 0.0; - Argb argb_ = 0; -}; - -} // namespace material_color_utilities - -#endif // CPP_CAM_HCT_H_ diff --git a/src/material-colors/cpp/cam/hct_solver.cpp b/src/material-colors/cpp/cam/hct_solver.cpp deleted file mode 100644 index fcf15ce..0000000 --- a/src/material-colors/cpp/cam/hct_solver.cpp +++ /dev/null @@ -1,526 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/cam/hct_solver.h" - -#include - -#include "cpp/cam/viewing_conditions.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -constexpr double kScaledDiscountFromLinrgb[3][3] = { - { - 0.001200833568784504, - 0.002389694492170889, - 0.0002795742885861124, - }, - { - 0.0005891086651375999, - 0.0029785502573438758, - 0.0003270666104008398, - }, - { - 0.00010146692491640572, - 0.0005364214359186694, - 0.0032979401770712076, - }, -}; - -constexpr double kLinrgbFromScaledDiscount[3][3] = { - { - 1373.2198709594231, - -1100.4251190754821, - -7.278681089101213, - }, - { - -271.815969077903, - 559.6580465940733, - -32.46047482791194, - }, - { - 1.9622899599665666, - -57.173814538844006, - 308.7233197812385, - }, -}; - -constexpr double kYFromLinrgb[3] = {0.2126, 0.7152, 0.0722}; - -constexpr double kCriticalPlanes[255] = { - 0.015176349177441876, 0.045529047532325624, 0.07588174588720938, - 0.10623444424209313, 0.13658714259697685, 0.16693984095186062, - 0.19729253930674434, 0.2276452376616281, 0.2579979360165119, - 0.28835063437139563, 0.3188300904430532, 0.350925934958123, - 0.3848314933096426, 0.42057480301049466, 0.458183274052838, - 0.4976837250274023, 0.5391024159806381, 0.5824650784040898, - 0.6277969426914107, 0.6751227633498623, 0.7244668422128921, - 0.775853049866786, 0.829304845476233, 0.8848452951698498, - 0.942497089126609, 1.0022825574869039, 1.0642236851973577, - 1.1283421258858297, 1.1946592148522128, 1.2631959812511864, - 1.3339731595349034, 1.407011200216447, 1.4823302800086415, - 1.5599503113873272, 1.6398909516233677, 1.7221716113234105, - 1.8068114625156377, 1.8938294463134073, 1.9832442801866852, - 2.075074464868551, 2.1693382909216234, 2.2660538449872063, - 2.36523901573795, 2.4669114995532007, 2.5710888059345764, - 2.6777882626779785, 2.7870270208169257, 2.898822059350997, - 3.0131901897720907, 3.1301480604002863, 3.2497121605402226, - 3.3718988244681087, 3.4967242352587946, 3.624204428461639, - 3.754355295633311, 3.887192587735158, 4.022731918402185, - 4.160988767090289, 4.301978482107941, 4.445716283538092, - 4.592217266055746, 4.741496401646282, 4.893568542229298, - 5.048448422192488, 5.20615066083972, 5.3666897647573375, - 5.5300801301023865, 5.696336044816294, 5.865471690767354, - 6.037501145825082, 6.212438385869475, 6.390297286737924, - 6.571091626112461, 6.7548350853498045, 6.941541251256611, - 7.131223617812143, 7.323895587840543, 7.5195704746346665, - 7.7182615035334345, 7.919981813454504, 8.124744458384042, - 8.332562408825165, 8.543448553206703, 8.757415699253682, - 8.974476575321063, 9.194643831691977, 9.417930041841839, - 9.644347703669503, 9.873909240696694, 10.106627003236781, - 10.342513269534024, 10.58158024687427, 10.8238400726681, - 11.069304815507364, 11.317986476196008, 11.569896988756009, - 11.825048221409341, 12.083451977536606, 12.345119996613247, - 12.610063955123938, 12.878295467455942, 13.149826086772048, - 13.42466730586372, 13.702830557985108, 13.984327217668513, - 14.269168601521828, 14.55736596900856, 14.848930523210871, - 15.143873411576273, 15.44220572664832, 15.743938506781891, - 16.04908273684337, 16.35764934889634, 16.66964922287304, - 16.985093187232053, 17.30399201960269, 17.62635644741625, - 17.95219714852476, 18.281524751807332, 18.614349837764564, - 18.95068293910138, 19.290534541298456, 19.633915083172692, - 19.98083495742689, 20.331304511189067, 20.685334046541502, - 21.042933821039977, 21.404114048223256, 21.76888489811322, - 22.137256497705877, 22.50923893145328, 22.884842241736916, - 23.264076429332462, 23.6469514538663, 24.033477234264016, - 24.42366364919083, 24.817520537484558, 25.21505769858089, - 25.61628489293138, 26.021211842414342, 26.429848230738664, - 26.842203703840827, 27.258287870275353, 27.678110301598522, - 28.10168053274597, 28.529008062403893, 28.96010235337422, - 29.39497283293396, 29.83362889318845, 30.276079891419332, - 30.722335150426627, 31.172403958865512, 31.62629557157785, - 32.08401920991837, 32.54558406207592, 33.010999283389665, - 33.4802739966603, 33.953417292456834, 34.430438229418264, - 34.911345834551085, 35.39614910352207, 35.88485700094671, - 36.37747846067349, 36.87402238606382, 37.37449765026789, - 37.87891309649659, 38.38727753828926, 38.89959975977785, - 39.41588851594697, 39.93615253289054, 40.460400508064545, - 40.98864111053629, 41.520882981230194, 42.05713473317016, - 42.597404951718396, 43.141702194811224, 43.6900349931913, - 44.24241185063697, 44.798841244188324, 45.35933162437017, - 45.92389141541209, 46.49252901546552, 47.065252796817916, - 47.64207110610409, 48.22299226451468, 48.808024568002054, - 49.3971762874833, 49.9904556690408, 50.587870934119984, - 51.189430279724725, 51.79514187861014, 52.40501387947288, - 53.0190544071392, 53.637271562750364, 54.259673423945976, - 54.88626804504493, 55.517063457223934, 56.15206766869424, - 56.79128866487574, 57.43473440856916, 58.08241284012621, - 58.734331877617365, 59.39049941699807, 60.05092333227251, - 60.715611475655585, 61.38457167773311, 62.057811747619894, - 62.7353394731159, 63.417162620860914, 64.10328893648692, - 64.79372614476921, 65.48848194977529, 66.18756403501224, - 66.89098006357258, 67.59873767827808, 68.31084450182222, - 69.02730813691093, 69.74813616640164, 70.47333615344107, - 71.20291564160104, 71.93688215501312, 72.67524319850172, - 73.41800625771542, 74.16517879925733, 74.9167682708136, - 75.67278210128072, 76.43322770089146, 77.1981124613393, - 77.96744375590167, 78.74122893956174, 79.51947534912904, - 80.30219030335869, 81.08938110306934, 81.88105503125999, - 82.67721935322541, 83.4778813166706, 84.28304815182372, - 85.09272707154808, 85.90692527145302, 86.72564993000343, - 87.54890820862819, 88.3767072518277, 89.2090541872801, - 90.04595612594655, 90.88742016217518, 91.73345337380438, - 92.58406282226491, 93.43925555268066, 94.29903859396902, - 95.16341895893969, 96.03240364439274, 96.9059996312159, - 97.78421388448044, 98.6670533535366, 99.55452497210776, -}; - -/** - * Sanitizes a small enough angle in radians. - * - * @param angle An angle in radians; must not deviate too much from 0. - * @return A coterminal angle between 0 and 2pi. - */ -double SanitizeRadians(double angle) { return fmod(angle + kPi * 8, kPi * 2); } - -/** - * Delinearizes an RGB component, returning a floating-point number. - * - * @param rgb_component 0.0 <= rgb_component <= 100.0, represents linear R/G/B - * channel - * @return 0.0 <= output <= 255.0, color channel converted to regular RGB space - */ -double TrueDelinearized(double rgb_component) { - double normalized = rgb_component / 100.0; - double delinearized = 0.0; - if (normalized <= 0.0031308) { - delinearized = normalized * 12.92; - } else { - delinearized = 1.055 * pow(normalized, 1.0 / 2.4) - 0.055; - } - return delinearized * 255.0; -} - -double ChromaticAdaptation(double component) { - double af = pow(abs(component), 0.42); - return Signum(component) * 400.0 * af / (af + 27.13); -} - -/** - * Returns the hue of a linear RGB color in CAM16. - * - * @param linrgb The linear RGB coordinates of a color. - * @return The hue of the color in CAM16, in radians. - */ -double HueOf(Vec3 linrgb) { - Vec3 scaledDiscount = MatrixMultiply(linrgb, kScaledDiscountFromLinrgb); - double r_a = ChromaticAdaptation(scaledDiscount.a); - double g_a = ChromaticAdaptation(scaledDiscount.b); - double b_a = ChromaticAdaptation(scaledDiscount.c); - // redness-greenness - double a = (11.0 * r_a + -12.0 * g_a + b_a) / 11.0; - // yellowness-blueness - double b = (r_a + g_a - 2.0 * b_a) / 9.0; - return atan2(b, a); -} - -bool AreInCyclicOrder(double a, double b, double c) { - double delta_a_b = SanitizeRadians(b - a); - double delta_a_c = SanitizeRadians(c - a); - return delta_a_b < delta_a_c; -} - -/** - * Solves the lerp equation. - * - * @param source The starting number. - * @param mid The number in the middle. - * @param target The ending number. - * @return A number t such that lerp(source, target, t) = mid. - */ -double Intercept(double source, double mid, double target) { - return (mid - source) / (target - source); -} - -Vec3 LerpPoint(Vec3 source, double t, Vec3 target) { - return (Vec3){ - source.a + (target.a - source.a) * t, - source.b + (target.b - source.b) * t, - source.c + (target.c - source.c) * t, - }; -} - -double GetAxis(Vec3 vector, int axis) { - switch (axis) { - case 0: - return vector.a; - case 1: - return vector.b; - case 2: - return vector.c; - default: - return -1.0; - } -} - -/** - * Intersects a segment with a plane. - * - * @param source The coordinates of point A. - * @param coordinate The R-, G-, or B-coordinate of the plane. - * @param target The coordinates of point B. - * @param axis The axis the plane is perpendicular with. (0: R, 1: G, 2: B) - * @return The intersection point of the segment AB with the plane R=coordinate, - * G=coordinate, or B=coordinate - */ -Vec3 SetCoordinate(Vec3 source, double coordinate, Vec3 target, int axis) { - double t = - Intercept(GetAxis(source, axis), coordinate, GetAxis(target, axis)); - return LerpPoint(source, t, target); -} - -bool IsBounded(double x) { return 0.0 <= x && x <= 100.0; } - -/** - * Returns the nth possible vertex of the polygonal intersection. - * - * @param y The Y value of the plane. - * @param n The zero-based index of the point. 0 <= n <= 11. - * @return The nth possible vertex of the polygonal intersection of the y plane - * and the RGB cube, in linear RGB coordinates, if it exists. If this possible - * vertex lies outside of the cube, - * [-1.0, -1.0, -1.0] is returned. - */ -Vec3 NthVertex(double y, int n) { - double k_r = kYFromLinrgb[0]; - double k_g = kYFromLinrgb[1]; - double k_b = kYFromLinrgb[2]; - double coord_a = n % 4 <= 1 ? 0.0 : 100.0; - double coord_b = n % 2 == 0 ? 0.0 : 100.0; - if (n < 4) { - double g = coord_a; - double b = coord_b; - double r = (y - g * k_g - b * k_b) / k_r; - if (IsBounded(r)) { - return (Vec3){r, g, b}; - } else { - return (Vec3){-1.0, -1.0, -1.0}; - } - } else if (n < 8) { - double b = coord_a; - double r = coord_b; - double g = (y - r * k_r - b * k_b) / k_g; - if (IsBounded(g)) { - return (Vec3){r, g, b}; - } else { - return (Vec3){-1.0, -1.0, -1.0}; - } - } else { - double r = coord_a; - double g = coord_b; - double b = (y - r * k_r - g * k_g) / k_b; - if (IsBounded(b)) { - return (Vec3){r, g, b}; - } else { - return (Vec3){-1.0, -1.0, -1.0}; - } - } -} - -/** - * Finds the segment containing the desired color. - * - * @param y The Y value of the color. - * @param target_hue The hue of the color. - * @return A list of two sets of linear RGB coordinates, each corresponding to - * an endpoint of the segment containing the desired color. - */ -void BisectToSegment(double y, double target_hue, Vec3 out[2]) { - Vec3 left = (Vec3){-1.0, -1.0, -1.0}; - Vec3 right = left; - double left_hue = 0.0; - double right_hue = 0.0; - bool initialized = false; - bool uncut = true; - for (int n = 0; n < 12; n++) { - Vec3 mid = NthVertex(y, n); - if (mid.a < 0) { - continue; - } - double mid_hue = HueOf(mid); - if (!initialized) { - left = mid; - right = mid; - left_hue = mid_hue; - right_hue = mid_hue; - initialized = true; - continue; - } - if (uncut || AreInCyclicOrder(left_hue, mid_hue, right_hue)) { - uncut = false; - if (AreInCyclicOrder(left_hue, target_hue, mid_hue)) { - right = mid; - right_hue = mid_hue; - } else { - left = mid; - left_hue = mid_hue; - } - } - } - out[0] = left; - out[1] = right; -} - -Vec3 Midpoint(Vec3 a, Vec3 b) { - return (Vec3){ - (a.a + b.a) / 2, - (a.b + b.b) / 2, - (a.c + b.c) / 2, - }; -} - -int CriticalPlaneBelow(double x) { return (int)floor(x - 0.5); } - -int CriticalPlaneAbove(double x) { return (int)ceil(x - 0.5); } - -/** - * Finds a color with the given Y and hue on the boundary of the cube. - * - * @param y The Y value of the color. - * @param target_hue The hue of the color. - * @return The desired color, in linear RGB coordinates. - */ -Vec3 BisectToLimit(double y, double target_hue) { - Vec3 segment[2]; - BisectToSegment(y, target_hue, segment); - Vec3 left = segment[0]; - double left_hue = HueOf(left); - Vec3 right = segment[1]; - for (int axis = 0; axis < 3; axis++) { - if (GetAxis(left, axis) != GetAxis(right, axis)) { - int l_plane = -1; - int r_plane = 255; - if (GetAxis(left, axis) < GetAxis(right, axis)) { - l_plane = CriticalPlaneBelow(TrueDelinearized(GetAxis(left, axis))); - r_plane = CriticalPlaneAbove(TrueDelinearized(GetAxis(right, axis))); - } else { - l_plane = CriticalPlaneAbove(TrueDelinearized(GetAxis(left, axis))); - r_plane = CriticalPlaneBelow(TrueDelinearized(GetAxis(right, axis))); - } - for (int i = 0; i < 8; i++) { - if (abs(r_plane - l_plane) <= 1) { - break; - } else { - int m_plane = (int)floor((l_plane + r_plane) / 2.0); - double mid_plane_coordinate = kCriticalPlanes[m_plane]; - Vec3 mid = SetCoordinate(left, mid_plane_coordinate, right, axis); - double mid_hue = HueOf(mid); - if (AreInCyclicOrder(left_hue, target_hue, mid_hue)) { - right = mid; - r_plane = m_plane; - } else { - left = mid; - left_hue = mid_hue; - l_plane = m_plane; - } - } - } - } - } - return Midpoint(left, right); -} - -double InverseChromaticAdaptation(double adapted) { - double adapted_abs = abs(adapted); - double base = fmax(0, 27.13 * adapted_abs / (400.0 - adapted_abs)); - return Signum(adapted) * pow(base, 1.0 / 0.42); -} - -/** - * Finds a color with the given hue, chroma, and Y. - * - * @param hue_radians The desired hue in radians. - * @param chroma The desired chroma. - * @param y The desired Y. - * @return The desired color as a hexadecimal integer, if found; 0 otherwise. - */ -Argb FindResultByJ(double hue_radians, double chroma, double y) { - // Initial estimate of j. - double j = sqrt(y) * 11.0; - // =========================================================== - // Operations inlined from Cam16 to avoid repeated calculation - // =========================================================== - ViewingConditions viewing_conditions = kDefaultViewingConditions; - double t_inner_coeff = - 1 / - pow(1.64 - pow(0.29, viewing_conditions.background_y_to_white_point_y), - 0.73); - double e_hue = 0.25 * (cos(hue_radians + 2.0) + 3.8); - double p1 = e_hue * (50000.0 / 13.0) * viewing_conditions.n_c * - viewing_conditions.ncb; - double h_sin = sin(hue_radians); - double h_cos = cos(hue_radians); - for (int iteration_round = 0; iteration_round < 5; iteration_round++) { - // =========================================================== - // Operations inlined from Cam16 to avoid repeated calculation - // =========================================================== - double j_normalized = j / 100.0; - double alpha = - chroma == 0.0 || j == 0.0 ? 0.0 : chroma / sqrt(j_normalized); - double t = pow(alpha * t_inner_coeff, 1.0 / 0.9); - double ac = - viewing_conditions.aw * - pow(j_normalized, 1.0 / viewing_conditions.c / viewing_conditions.z); - double p2 = ac / viewing_conditions.nbb; - double gamma = 23.0 * (p2 + 0.305) * t / - (23.0 * p1 + 11 * t * h_cos + 108.0 * t * h_sin); - double a = gamma * h_cos; - double b = gamma * h_sin; - double r_a = (460.0 * p2 + 451.0 * a + 288.0 * b) / 1403.0; - double g_a = (460.0 * p2 - 891.0 * a - 261.0 * b) / 1403.0; - double b_a = (460.0 * p2 - 220.0 * a - 6300.0 * b) / 1403.0; - double r_c_scaled = InverseChromaticAdaptation(r_a); - double g_c_scaled = InverseChromaticAdaptation(g_a); - double b_c_scaled = InverseChromaticAdaptation(b_a); - Vec3 scaled = (Vec3){r_c_scaled, g_c_scaled, b_c_scaled}; - Vec3 linrgb = MatrixMultiply(scaled, kLinrgbFromScaledDiscount); - // =========================================================== - // Operations inlined from Cam16 to avoid repeated calculation - // =========================================================== - if (linrgb.a < 0 || linrgb.b < 0 || linrgb.c < 0) { - return 0; - } - double k_r = kYFromLinrgb[0]; - double k_g = kYFromLinrgb[1]; - double k_b = kYFromLinrgb[2]; - double fnj = k_r * linrgb.a + k_g * linrgb.b + k_b * linrgb.c; - if (fnj <= 0) { - return 0; - } - if (iteration_round == 4 || abs(fnj - y) < 0.002) { - if (linrgb.a > 100.01 || linrgb.b > 100.01 || linrgb.c > 100.01) { - return 0; - } - return ArgbFromLinrgb(linrgb); - } - // Iterates with Newton method, - // Using 2 * fn(j) / j as the approximation of fn'(j) - j = j - (fnj - y) * j / (2 * fnj); - } - return 0; -} - -/** - * Finds an sRGB color with the given hue, chroma, and L*, if possible. - * - * @param hue_degrees The desired hue, in degrees. - * @param chroma The desired chroma. - * @param lstar The desired L*. - * @return A hexadecimal representing the sRGB color. The color has sufficiently - * close hue, chroma, and L* to the desired values, if possible; otherwise, the - * hue and L* will be sufficiently close, and chroma will be maximized. - */ -Argb SolveToInt(double hue_degrees, double chroma, double lstar) { - if (chroma < 0.0001 || lstar < 0.0001 || lstar > 99.9999) { - return IntFromLstar(lstar); - } - hue_degrees = SanitizeDegreesDouble(hue_degrees); - double hue_radians = hue_degrees / 180 * kPi; - double y = YFromLstar(lstar); - Argb exact_answer = FindResultByJ(hue_radians, chroma, y); - if (exact_answer != 0) { - return exact_answer; - } - Vec3 linrgb = BisectToLimit(y, hue_radians); - return ArgbFromLinrgb(linrgb); -} - -/** - * Finds an sRGB color with the given hue, chroma, and L*, if possible. - * - * @param hue_degrees The desired hue, in degrees. - * @param chroma The desired chroma. - * @param lstar The desired L*. - * @return An CAM16 object representing the sRGB color. The color has - * sufficiently close hue, chroma, and L* to the desired values, if possible; - * otherwise, the hue and L* will be sufficiently close, and chroma will be - * maximized. - */ -Cam SolveToCam(double hue_degrees, double chroma, double lstar) { - return CamFromInt(SolveToInt(hue_degrees, chroma, lstar)); -} -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/cam/hct_solver.h b/src/material-colors/cpp/cam/hct_solver.h deleted file mode 100644 index b426af8..0000000 --- a/src/material-colors/cpp/cam/hct_solver.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_CAM_HCT_SOLVER_H_ -#define CPP_CAM_HCT_SOLVER_H_ - -#include "cpp/cam/cam.h" - -namespace material_color_utilities { - -Argb SolveToInt(double hue_degrees, double chroma, double lstar); -Cam SolveToCam(double hue_degrees, double chroma, double lstar); - -} // namespace material_color_utilities -#endif // CPP_CAM_HCT_SOLVER_H_ diff --git a/src/material-colors/cpp/cam/hct_solver_test.cpp b/src/material-colors/cpp/cam/hct_solver_test.cpp deleted file mode 100644 index fbaa2e7..0000000 --- a/src/material-colors/cpp/cam/hct_solver_test.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/cam/hct_solver.h" - -#include "testing/base/public/gmock.h" -#include "testing/base/public/gunit.h" -#include "cpp/cam/cam.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -namespace { -using testing::Eq; - -TEST(HctSolverTest, Red) { - // Compute HCT - Argb color = 0xFFFE0315; - Cam cam = CamFromInt(color); - double tone = LstarFromArgb(color); - - // Compute input - Argb recovered = SolveToInt(cam.hue, cam.chroma, tone); - EXPECT_THAT(recovered, Eq(color)); -} - -TEST(HctSolverTest, Green) { - // Compute HCT - Argb color = 0xFF15FE03; - Cam cam = CamFromInt(color); - double tone = LstarFromArgb(color); - - // Compute input - Argb recovered = SolveToInt(cam.hue, cam.chroma, tone); - EXPECT_THAT(recovered, Eq(color)); -} - -TEST(HctSolverTest, Blue) { - // Compute HCT - Argb color = 0xFF0315FE; - Cam cam = CamFromInt(color); - double tone = LstarFromArgb(color); - - // Compute input - Argb recovered = SolveToInt(cam.hue, cam.chroma, tone); - EXPECT_THAT(recovered, Eq(color)); -} - -TEST(HctSolverTest, Exhaustive) { - for (int colorIndex = 0; colorIndex <= 0xFFFFFF; colorIndex++) { - Argb color = 0xFF000000 | colorIndex; - Cam cam = CamFromInt(color); - double tone = LstarFromArgb(color); - - // Compute input - Argb recovered = SolveToInt(cam.hue, cam.chroma, tone); - EXPECT_THAT(recovered, Eq(color)); - } -} -} // namespace -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/cam/hct_test.cpp b/src/material-colors/cpp/cam/hct_test.cpp deleted file mode 100644 index b40e818..0000000 --- a/src/material-colors/cpp/cam/hct_test.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/cam/hct.h" - -#include - -#include "testing/base/public/gmock.h" -#include "testing/base/public/gunit.h" -#include "cpp/cam/cam.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -namespace { -using ::testing::Combine; -using ::testing::DoubleNear; -using ::testing::Eq; -using ::testing::Lt; -using ::testing::TestWithParam; -using ::testing::Values; - -TEST(HctTest, LimitedToSRGB) { - // Ensures that the HCT class can only represent sRGB colors. - // An impossibly high chroma is used. - Hct hct(/*hue=*/120.0, /*chroma=*/200.0, /*tone=*/50.0); - Argb argb = hct.ToInt(); - - // The hue, chroma, and tone members of hct should actually - // represent the sRGB color. - EXPECT_THAT(CamFromInt(argb).hue, Eq(hct.get_hue())); - EXPECT_THAT(CamFromInt(argb).chroma, Eq(hct.get_chroma())); - EXPECT_THAT(LstarFromArgb(argb), Eq(hct.get_tone())); -} - -TEST(HctTest, TruncatesColors) { - // Ensures that HCT truncates colors. - Hct hct(/*hue=*/120.0, /*chroma=*/60.0, /*tone=*/50.0); - double chroma = hct.get_chroma(); - EXPECT_THAT(chroma, Lt(60.0)); - - // The new chroma should be lower than the original. - hct.set_tone(180.0); - EXPECT_THAT(hct.get_chroma(), Lt(chroma)); -} - -bool IsOnBoundary(int rgb_component) { - return rgb_component == 0 || rgb_component == 255; -} - -bool ColorIsOnBoundary(int argb) { - return IsOnBoundary(RedFromInt(argb)) || IsOnBoundary(GreenFromInt(argb)) || - IsOnBoundary(BlueFromInt(argb)); -} - -using HctTest = TestWithParam>; - -TEST_P(HctTest, Correctness) { - std::tuple hctTuple = GetParam(); - int hue = std::get<0>(hctTuple); - int chroma = std::get<1>(hctTuple); - int tone = std::get<2>(hctTuple); - - Hct color(hue, chroma, tone); - - if (chroma > 0) { - EXPECT_THAT(color.get_hue(), DoubleNear(hue, 4.0)); - } - - EXPECT_THAT(color.get_chroma(), Lt(chroma + 2.5)); - - if (color.get_chroma() < chroma - 2.5) { - EXPECT_TRUE(ColorIsOnBoundary(color.ToInt())); - } - - EXPECT_THAT(color.get_tone(), DoubleNear(tone, 0.5)); -} - -INSTANTIATE_TEST_SUITE_P( - HctTests, HctTest, - Combine(/*hues*/ Values(15, 45, 75, 105, 135, 165, 195, 225, 255, 285, 315, - 345), - /*chromas*/ Values(0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100), - /*tones*/ Values(20, 30, 40, 50, 60, 70, 80))); - -} // namespace -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/cam/viewing_conditions.cpp b/src/material-colors/cpp/cam/viewing_conditions.cpp deleted file mode 100644 index 28c5763..0000000 --- a/src/material-colors/cpp/cam/viewing_conditions.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/cam/viewing_conditions.h" - -#include -#include - -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -static double lerp(double start, double stop, double amount) { - return (1.0 - amount) * start + amount * stop; -} - -ViewingConditions CreateViewingConditions(const double white_point[3], - const double adapting_luminance, - const double background_lstar, - const double surround, - const bool discounting_illuminant) { - double background_lstar_corrected = - (background_lstar < 30.0) ? 30.0 : background_lstar; - double rgb_w[3] = { - 0.401288 * white_point[0] + 0.650173 * white_point[1] - - 0.051461 * white_point[2], - -0.250268 * white_point[0] + 1.204414 * white_point[1] + - 0.045854 * white_point[2], - -0.002079 * white_point[0] + 0.048952 * white_point[1] + - 0.953127 * white_point[2], - }; - double f = 0.8 + (surround / 10.0); - double c = f >= 0.9 ? lerp(0.59, 0.69, (f - 0.9) * 10.0) - : lerp(0.525, 0.59, (f - 0.8) * 10.0); - double d = discounting_illuminant - ? 1.0 - : f * (1.0 - ((1.0 / 3.6) * - exp((-adapting_luminance - 42.0) / 92.0))); - d = d > 1.0 ? 1.0 : d < 0.0 ? 0.0 : d; - double nc = f; - double rgb_d[3] = {(d * (100.0 / rgb_w[0]) + 1.0 - d), - (d * (100.0 / rgb_w[1]) + 1.0 - d), - (d * (100.0 / rgb_w[2]) + 1.0 - d)}; - - double k = 1.0 / (5.0 * adapting_luminance + 1.0); - double k4 = k * k * k * k; - double k4f = 1.0 - k4; - double fl = (k4 * adapting_luminance) + - (0.1 * k4f * k4f * pow(5.0 * adapting_luminance, 1.0 / 3.0)); - double fl_root = pow(fl, 0.25); - double n = YFromLstar(background_lstar_corrected) / white_point[1]; - double z = 1.48 + sqrt(n); - double nbb = 0.725 / pow(n, 0.2); - double ncb = nbb; - double rgb_a_factors[3] = {pow(fl * rgb_d[0] * rgb_w[0] / 100.0, 0.42), - pow(fl * rgb_d[1] * rgb_w[1] / 100.0, 0.42), - pow(fl * rgb_d[2] * rgb_w[2] / 100.0, 0.42)}; - double rgb_a[3] = { - 400.0 * rgb_a_factors[0] / (rgb_a_factors[0] + 27.13), - 400.0 * rgb_a_factors[1] / (rgb_a_factors[1] + 27.13), - 400.0 * rgb_a_factors[2] / (rgb_a_factors[2] + 27.13), - }; - double aw = (40.0 * rgb_a[0] + 20.0 * rgb_a[1] + rgb_a[2]) / 20.0 * nbb; - ViewingConditions viewingConditions = { - adapting_luminance, - background_lstar_corrected, - surround, - discounting_illuminant, - n, - aw, - nbb, - ncb, - c, - nc, - fl, - fl_root, - z, - {white_point[0], white_point[1], white_point[2]}, - {rgb_d[0], rgb_d[1], rgb_d[2]}, - }; - return viewingConditions; -} - -ViewingConditions DefaultWithBackgroundLstar(const double background_lstar) { - return CreateViewingConditions(kWhitePointD65, - (200.0 / kPi * YFromLstar(50.0) / 100.0), - background_lstar, 2.0, 0); -} - -void PrintDefaultFrame() { - ViewingConditions frame = CreateViewingConditions( - kWhitePointD65, (200.0 / kPi * YFromLstar(50.0) / 100.0), 50.0, 2.0, 0); - printf( - "(Frame){%0.9lf,\n %0.9lf,\n %0.9lf,\n %s\n, %0.9lf,\n " - "%0.9lf,\n%0.9lf,\n%0.9lf,\n%0.9lf,\n%0.9lf,\n" - "%0.9lf,\n%0.9lf,\n%0.9lf,\n%0.9lf,\n" - "%0.9lf,\n%0.9lf\n};", - frame.adapting_luminance, frame.background_lstar, frame.surround, - frame.discounting_illuminant ? "true" : "false", - frame.background_y_to_white_point_y, frame.aw, frame.nbb, frame.ncb, - frame.c, frame.n_c, frame.fl, frame.fl_root, frame.z, frame.rgb_d[0], - frame.rgb_d[1], frame.rgb_d[2]); -} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/cam/viewing_conditions.h b/src/material-colors/cpp/cam/viewing_conditions.h deleted file mode 100644 index 5864379..0000000 --- a/src/material-colors/cpp/cam/viewing_conditions.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_CAM_VIEWING_CONDITIONS_H_ -#define CPP_CAM_VIEWING_CONDITIONS_H_ - -namespace material_color_utilities { - -struct ViewingConditions { - double adapting_luminance = 0.0; - double background_lstar = 0.0; - double surround = 0.0; - bool discounting_illuminant = false; - double background_y_to_white_point_y = 0.0; - double aw = 0.0; - double nbb = 0.0; - double ncb = 0.0; - double c = 0.0; - double n_c = 0.0; - double fl = 0.0; - double fl_root = 0.0; - double z = 0.0; - - double white_point[3] = {0.0, 0.0, 0.0}; - double rgb_d[3] = {0.0, 0.0, 0.0}; -}; - -ViewingConditions CreateViewingConditions(const double white_point[3], - const double adapting_luminance, - const double background_lstar, - const double surround, - const bool discounting_illuminant); - -ViewingConditions DefaultWithBackgroundLstar(const double background_lstar); - -static const ViewingConditions kDefaultViewingConditions = (ViewingConditions){ - 11.725676537, - 50.000000000, - 2.000000000, - false, - 0.184186503, - 29.981000900, - 1.016919255, - 1.016919255, - 0.689999998, - 1.000000000, - 0.388481468, - 0.789482653, - 1.909169555, - {95.047, 100.0, 108.883}, - {1.021177769, 0.986307740, 0.933960497}, -}; - -} // namespace material_color_utilities -#endif // CPP_CAM_VIEWING_CONDITIONS_H_ diff --git a/src/material-colors/cpp/contrast/contrast.cpp b/src/material-colors/cpp/contrast/contrast.cpp deleted file mode 100644 index c94d444..0000000 --- a/src/material-colors/cpp/contrast/contrast.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/contrast/contrast.h" - -#include -#include - -#include "cpp/utils/utils.h" - -namespace material_color_utilities { -// Given a color and a contrast ratio to reach, the luminance of a color that -// reaches that ratio with the color can be calculated. However, that luminance -// may not contrast as desired, i.e. the contrast ratio of the input color -// and the returned luminance may not reach the contrast ratio asked for. -// -// When the desired contrast ratio and the result contrast ratio differ by -// more than this amount, an error value should be returned, or the method -// should be documented as 'unsafe', meaning, it will return a valid luminance -// but that luminance may not meet the requested contrast ratio. -// -// 0.04 selected because it ensures the resulting ratio rounds to the -// same tenth. -constexpr double CONTRAST_RATIO_EPSILON = 0.04; - -// Color spaces that measure luminance, such as Y in XYZ, L* in L*a*b*, -// or T in HCT, are known as perceptual accurate color spaces. -// -// To be displayed, they must gamut map to a "display space", one that has -// a defined limit on the number of colors. Display spaces include sRGB, -// more commonly understood as RGB/HSL/HSV/HSB. -// -// Gamut mapping is undefined and not defined by the color space. Any -// gamut mapping algorithm must choose how to sacrifice accuracy in hue, -// saturation, and/or lightness. -// -// A principled solution is to maintain lightness, thus maintaining -// contrast/a11y, maintain hue, thus maintaining aesthetic intent, and reduce -// chroma until the color is in gamut. -// -// HCT chooses this solution, but, that doesn't mean it will _exactly_ matched -// desired lightness, if only because RGB is quantized: RGB is expressed as -// a set of integers: there may be an RGB color with, for example, -// 47.892 lightness, but not 47.891. -// -// To allow for this inherent incompatibility between perceptually accurate -// color spaces and display color spaces, methods that take a contrast ratio -// and luminance, and return a luminance that reaches that contrast ratio for -// the input luminance, purposefully darken/lighten their result such that -// the desired contrast ratio will be reached even if inaccuracy is introduced. -// -// 0.4 is generous, ex. HCT requires much less delta. It was chosen because -// it provides a rough guarantee that as long as a percetual color space -// gamut maps lightness such that the resulting lightness rounds to the same -// as the requested, the desired contrast ratio will be reached. -constexpr double LUMINANCE_GAMUT_MAP_TOLERANCE = 0.4; - -double RatioOfYs(double y1, double y2) { - double lighter = y1 > y2 ? y1 : y2; - double darker = (lighter == y2) ? y1 : y2; - return (lighter + 5.0) / (darker + 5.0); -} - -double RatioOfTones(double tone_a, double tone_b) { - tone_a = std::clamp(tone_a, 0.0, 100.0); - tone_b = std::clamp(tone_b, 0.0, 100.0); - return RatioOfYs(YFromLstar(tone_a), YFromLstar(tone_b)); -} - -double Lighter(double tone, double ratio) { - if (tone < 0.0 || tone > 100.0) { - return -1.0; - } - - double dark_y = YFromLstar(tone); - double light_y = ratio * (dark_y + 5.0) - 5.0; - double real_contrast = RatioOfYs(light_y, dark_y); - double delta = abs(real_contrast - ratio); - if (real_contrast < ratio && delta > CONTRAST_RATIO_EPSILON) { - return -1; - } - - // ensure gamut mapping, which requires a 'range' on tone, will still result - // the correct ratio by darkening slightly. - double value = LstarFromY(light_y) + LUMINANCE_GAMUT_MAP_TOLERANCE; - if (value < 0 || value > 100) { - return -1; - } - return value; -} - -double Darker(double tone, double ratio) { - if (tone < 0.0 || tone > 100.0) { - return -1.0; - } - - double light_y = YFromLstar(tone); - double dark_y = ((light_y + 5.0) / ratio) - 5.0; - double real_contrast = RatioOfYs(light_y, dark_y); - - double delta = abs(real_contrast - ratio); - if (real_contrast < ratio && delta > CONTRAST_RATIO_EPSILON) { - return -1; - } - - // ensure gamut mapping, which requires a 'range' on tone, will still result - // the correct ratio by darkening slightly. - double value = LstarFromY(dark_y) - LUMINANCE_GAMUT_MAP_TOLERANCE; - if (value < 0 || value > 100) { - return -1; - } - return value; -} - -double LighterUnsafe(double tone, double ratio) { - double lighter_safe = Lighter(tone, ratio); - return (lighter_safe < 0.0) ? 100.0 : lighter_safe; -} - -double DarkerUnsafe(double tone, double ratio) { - double darker_safe = Darker(tone, ratio); - return (darker_safe < 0.0) ? 0.0 : darker_safe; -} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/contrast/contrast.h b/src/material-colors/cpp/contrast/contrast.h deleted file mode 100644 index 6ff0bde..0000000 --- a/src/material-colors/cpp/contrast/contrast.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_CONTRAST_CONTRAST_H_ -#define CPP_CONTRAST_CONTRAST_H_ - -/** - * Utility methods for calculating contrast given two colors, or calculating a - * color given one color and a contrast ratio. - * - * Contrast ratio is calculated using XYZ's Y. When linearized to match human - * perception, Y becomes HCT's tone and L*a*b*'s' L*. Informally, this is the - * lightness of a color. - * - * Methods refer to tone, T in the the HCT color space. - * Tone is equivalent to L* in the L*a*b* color space, or L in the LCH color - * space. - */ -namespace material_color_utilities { -/** - * @return a contrast ratio, which ranges from 1 to 21. - * @param tone_a Tone between 0 and 100. Values outside will be clamped. - * @param tone_b Tone between 0 and 100. Values outside will be clamped. - */ -double RatioOfTones(double tone_a, double tone_b); - -/** - * @return a tone >= [tone] that ensures [ratio]. - * Return value is between 0 and 100. - * Returns -1 if [ratio] cannot be achieved with [tone]. - * - * @param tone Tone return value must contrast with. - * Range is 0 to 100. Invalid values will result in -1 being returned. - * @param ratio Contrast ratio of return value and [tone]. - * Range is 1 to 21, invalid values have undefined behavior. - */ -double Lighter(double tone, double ratio); - -/** - * @return a tone <= [tone] that ensures [ratio]. - * Return value is between 0 and 100. - * Returns -1 if [ratio] cannot be achieved with [tone]. - * - * @param tone Tone return value must contrast with. - * Range is 0 to 100. Invalid values will result in -1 being returned. - * @param ratio Contrast ratio of return value and [tone]. - * Range is 1 to 21, invalid values have undefined behavior. - */ -double Darker(double tone, double ratio); - -/** - * @return a tone >= [tone] that ensures [ratio]. - * Return value is between 0 and 100. - * Returns 100 if [ratio] cannot be achieved with [tone]. - * - * This method is unsafe because the returned value is guaranteed to be in - * bounds for tone, i.e. between 0 and 100. However, that value may not reach - * the [ratio] with [tone]. For example, there is no color lighter than T100. - * - * @param tone Tone return value must contrast with. - * Range is 0 to 100. Invalid values will result in 100 being returned. - * @param ratio Desired contrast ratio of return value and tone parameter. - * Range is 1 to 21, invalid values have undefined behavior. - */ -double LighterUnsafe(double tone, double ratio); - -/** - * @return a tone <= [tone] that ensures [ratio]. - * Return value is between 0 and 100. - * Returns 0 if [ratio] cannot be achieved with [tone]. - * - * This method is unsafe because the returned value is guaranteed to be in - * bounds for tone, i.e. between 0 and 100. However, that value may not reach - * the [ratio] with [tone]. For example, there is no color darker than T0. - * - * @param tone Tone return value must contrast with. - * Range is 0 to 100. Invalid values will result in 0 being returned. - * @param ratio Desired contrast ratio of return value and tone parameter. - * Range is 1 to 21, invalid values have undefined behavior. - */ -double DarkerUnsafe(double tone, double ratio); -} // namespace material_color_utilities - -#endif // CPP_CONTRAST_CONTRAST_H_ diff --git a/src/material-colors/cpp/contrast/contrast_test.cpp b/src/material-colors/cpp/contrast/contrast_test.cpp deleted file mode 100644 index 38a85c0..0000000 --- a/src/material-colors/cpp/contrast/contrast_test.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/contrast/contrast.h" - -#include "testing/base/public/gunit.h" - -namespace material_color_utilities { - -namespace { -TEST(ContrastTest, RatioOfTonesOutOfBoundsInput) { - EXPECT_NEAR(RatioOfTones(-10.0, 110.0), 21.0, 0.001); -} - -TEST(ContrastTest, LighterImpossibleRatioErrors) { - EXPECT_NEAR(Lighter(90.0, 10.0), -1.0, 0.001); -} - -TEST(ContrastTest, LighterOutOfBoundsInputAboveErrors) { - EXPECT_NEAR(Lighter(110.0, 2.0), -1.0, 0.001); -} - -TEST(ContrastTest, LighterOutOfBoundsInputBelowErrors) { - EXPECT_NEAR(Lighter(-10.0, 2.0), -1.0, 0.001); -} - -TEST(ContrastTest, LighterUnsafeReturnsMaxTone) { - EXPECT_NEAR(LighterUnsafe(100.0, 2.0), 100, 0.001); -} - -TEST(ContrastTest, DarkerImpossibleRatioErrors) { - EXPECT_NEAR(Darker(10.0, 20.0), -1.0, 0.001); -} - -TEST(ContrastTest, DarkerOutOfBoundsInputAboveErrors) { - EXPECT_NEAR(Darker(110.0, 2.0), -1.0, 0.001); -} - -TEST(ContrastTest, DarkerOutOfBoundsInputBelowErrors) { - EXPECT_NEAR(Darker(-10.0, 2.0), -1.0, 0.001); -} - -TEST(ContrastTest, DarkerUnsafeReturnsMinTone) { - EXPECT_NEAR(DarkerUnsafe(0.0, 2.0), 0.0, 0.001); -} -} // namespace - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/dislike/dislike.cpp b/src/material-colors/cpp/dislike/dislike.cpp deleted file mode 100644 index a07f360..0000000 --- a/src/material-colors/cpp/dislike/dislike.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/dislike/dislike.h" - -#include - -#include "cpp/cam/hct.h" - -namespace material_color_utilities { - -bool IsDisliked(Hct hct) { - double roundedHue = std::round(hct.get_hue()); - - bool hue_passes = roundedHue >= 90.0 && roundedHue <= 111.0; - bool chroma_passes = std::round(hct.get_chroma()) > 16.0; - bool tone_passes = std::round(hct.get_tone()) < 65.0; - - return hue_passes && chroma_passes && tone_passes; -} - -Hct FixIfDisliked(Hct hct) { - if (IsDisliked(hct)) { - return Hct(hct.get_hue(), hct.get_chroma(), 70.0); - } - - return hct; -} -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/dislike/dislike.h b/src/material-colors/cpp/dislike/dislike.h deleted file mode 100644 index 3d09fab..0000000 --- a/src/material-colors/cpp/dislike/dislike.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_DISLIKE_DISLIKE_H_ -#define CPP_DISLIKE_DISLIKE_H_ - -#include "cpp/cam/hct.h" - -namespace material_color_utilities { - -/** - * Checks and/or fixes universally disliked colors. - * - * Color science studies of color preference indicate universal distaste for - * dark yellow-greens, and also show this is correlated to distate for - * biological waste and rotting food. - * - * See Palmer and Schloss, 2010 or Schloss and Palmer's Chapter 21 in Handbook - * of Color Psychology (2015). - */ - -/** - * @return whether the color is disliked. - * - * Disliked is defined as a dark yellow-green that is not neutral. - * @param hct The color to be tested. - */ -bool IsDisliked(Hct hct); - -/** - * If a color is disliked, lightens it to make it likable. - * - * The original color is not modified. - * - * @param hct The color to be tested (and fixed, if needed). - * @return The original color if it is not disliked; otherwise, the fixed - * color. - */ -Hct FixIfDisliked(Hct hct); -} // namespace material_color_utilities - -#endif // CPP_DISLIKE_DISLIKE_H_ diff --git a/src/material-colors/cpp/dislike/dislike_test.cpp b/src/material-colors/cpp/dislike/dislike_test.cpp deleted file mode 100644 index 0d2b207..0000000 --- a/src/material-colors/cpp/dislike/dislike_test.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/dislike/dislike.h" - -#include "testing/base/public/gunit.h" -#include "cpp/cam/hct.h" - -namespace material_color_utilities { - -namespace { - -using testing::TestWithParam; -using testing::Values; -using SkinToneTest = TestWithParam; - -TEST_P(SkinToneTest, MonkSkinToneScaleColorsLiked) { - int argb = GetParam(); - - EXPECT_FALSE(IsDisliked(Hct(argb))); -} - -INSTANTIATE_TEST_SUITE_P(DislikeTest, SkinToneTest, - Values(0xfff6ede4, 0xfff3e7db, 0xfff7ead0, 0xffeadaba, - 0xffd7bd96, 0xffa07e56, 0xff825c43, 0xff604134, - 0xff3a312a, 0xff292420)); - -using BileTest = TestWithParam; - -TEST_P(BileTest, BileColorsDisliked) { - int argb = GetParam(); - - EXPECT_TRUE(IsDisliked(Hct(argb))); -} - -INSTANTIATE_TEST_SUITE_P(DislikeTest, BileTest, - Values(0xff95884B, 0xff716B40, 0xffB08E00, 0xff4C4308, - 0xff464521)); - -using BileFixingTest = TestWithParam; - -TEST_P(BileFixingTest, BileColorsFixed) { - int argb = GetParam(); - - Hct bile_color = Hct(argb); - EXPECT_TRUE(IsDisliked(bile_color)); - Hct fixed_bile_color = FixIfDisliked(bile_color); - EXPECT_FALSE(IsDisliked(fixed_bile_color)); -} - -INSTANTIATE_TEST_SUITE_P(DislikeTest, BileFixingTest, - Values(0xff95884B, 0xff716B40, 0xffB08E00, 0xff4C4308, - 0xff464521)); - - -TEST(DislikeTest, Tone67Liked) { - Hct color = Hct(100.0, 50.0, 67.0); - EXPECT_FALSE(IsDisliked(color)); - EXPECT_EQ(FixIfDisliked(color).ToInt(), color.ToInt()); -} - -} // namespace - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/dynamiccolor/contrast_curve.h b/src/material-colors/cpp/dynamiccolor/contrast_curve.h deleted file mode 100644 index 864e8cf..0000000 --- a/src/material-colors/cpp/dynamiccolor/contrast_curve.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_DYNAMICCOLOR_CONTRAST_CURVE_H_ -#define CPP_DYNAMICCOLOR_CONTRAST_CURVE_H_ - -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -/** - * A class containing a value that changes with the contrast level. - * - * Usually represents the contrast requirements for a dynamic color on its - * background. The four values correspond to values for contrast levels -1.0, - * 0.0, 0.5, and 1.0, respectively. - */ -struct ContrastCurve { - double low; - double normal; - double medium; - double high; - - /** - * Creates a `ContrastCurve` object. - * - * @param low Value for contrast level -1.0 - * @param normal Value for contrast level 0.0 - * @param medium Value for contrast level 0.5 - * @param high Value for contrast level 1.0 - */ - ContrastCurve(double low, double normal, double medium, double high) - : low(low), normal(normal), medium(medium), high(high) {} - - /** - * Returns the value at a given contrast level. - * - * @param contrastLevel The contrast level. 0.0 is the default (normal); -1.0 - * is the lowest; 1.0 is the highest. - * @return The value. For contrast ratios, a number between 1.0 and 21.0. - */ - double get(double contrastLevel) { - if (contrastLevel <= -1.0) { - return low; - } else if (contrastLevel < 0.0) { - return Lerp(low, normal, (contrastLevel - (-1)) / 1); - } else if (contrastLevel < 0.5) { - return Lerp(normal, medium, (contrastLevel - 0) / 0.5); - } else if (contrastLevel < 1.0) { - return Lerp(medium, high, (contrastLevel - 0.5) / 0.5); - } else { - return high; - } - } -}; - -} // namespace material_color_utilities - -#endif // CPP_DYNAMICCOLOR_CONTRAST_CURVE_H_ diff --git a/src/material-colors/cpp/dynamiccolor/dynamic_color.cpp b/src/material-colors/cpp/dynamiccolor/dynamic_color.cpp deleted file mode 100644 index 3f4259d..0000000 --- a/src/material-colors/cpp/dynamiccolor/dynamic_color.cpp +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/dynamiccolor/dynamic_color.h" - -#include -#include -#include -#include -#include -#include - -#include "cpp/cam/hct.h" -#include "cpp/contrast/contrast.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" -#include "cpp/dynamiccolor/tone_delta_pair.h" -#include "cpp/palettes/tones.h" - -namespace material_color_utilities { - -using std::function; -using std::nullopt; -using std::optional; - -using DoubleFunction = function; - -template -optional SafeCall(optional(const T&)>> f, const T& x) { - if (f == nullopt) { - return nullopt; - } else { - return f.value()(x); - } -} - -template -optional SafeCallCleanResult(optional> f, T x) { - if (f == nullopt) { - return nullopt; - } else { - return f.value()(x); - } -} - -double ForegroundTone(double bg_tone, double ratio) { - double lighter_tone = LighterUnsafe(/*tone*/ bg_tone, /*ratio*/ ratio); - double darker_tone = DarkerUnsafe(/*tone*/ bg_tone, /*ratio*/ ratio); - double lighter_ratio = RatioOfTones(lighter_tone, bg_tone); - double darker_ratio = RatioOfTones(darker_tone, bg_tone); - double prefer_lighter = TonePrefersLightForeground(bg_tone); - - if (prefer_lighter) { - double negligible_difference = - (abs(lighter_ratio - darker_ratio) < 0.1 && lighter_ratio < ratio && - darker_ratio < ratio); - return lighter_ratio >= ratio || lighter_ratio >= darker_ratio || - negligible_difference - ? lighter_tone - : darker_tone; - } else { - return darker_ratio >= ratio || darker_ratio >= lighter_ratio - ? darker_tone - : lighter_tone; - } -} - -double EnableLightForeground(double tone) { - if (TonePrefersLightForeground(tone) && !ToneAllowsLightForeground(tone)) { - return 49.0; - } - return tone; -} - -bool TonePrefersLightForeground(double tone) { return round(tone) < 60; } - -bool ToneAllowsLightForeground(double tone) { return round(tone) <= 49; } - -/** - * Default constructor. - */ -DynamicColor::DynamicColor( - std::string name, std::function palette, - std::function tone, bool is_background, - - std::optional> background, - std::optional> - second_background, - std::optional contrast_curve, - std::optional> - tone_delta_pair) - : name_(name), - palette_(palette), - tone_(tone), - is_background_(is_background), - background_(background), - second_background_(second_background), - contrast_curve_(contrast_curve), - tone_delta_pair_(tone_delta_pair) {} - -DynamicColor DynamicColor::FromPalette( - std::string name, std::function palette, - std::function tone) { - return DynamicColor(name, palette, tone, - /*is_background=*/false, - /*background=*/nullopt, - /*second_background=*/nullopt, - /*contrast_curve=*/nullopt, - /*tone_delta_pair=*/nullopt); -} - -Argb DynamicColor::GetArgb(const DynamicScheme& scheme) { - return palette_(scheme).get(GetTone(scheme)); -} - -Hct DynamicColor::GetHct(const DynamicScheme& scheme) { - return Hct(GetArgb(scheme)); -} - -double DynamicColor::GetTone(const DynamicScheme& scheme) { - bool decreasingContrast = scheme.contrast_level < 0; - - // Case 1: dual foreground, pair of colors with delta constraint. - if (tone_delta_pair_ != std::nullopt) { - ToneDeltaPair tone_delta_pair = tone_delta_pair_.value()(scheme); - DynamicColor role_a = tone_delta_pair.role_a_; - DynamicColor role_b = tone_delta_pair.role_b_; - double delta = tone_delta_pair.delta_; - TonePolarity polarity = tone_delta_pair.polarity_; - bool stay_together = tone_delta_pair.stay_together_; - - DynamicColor bg = background_.value()(scheme); - double bg_tone = bg.GetTone(scheme); - - bool a_is_nearer = - (polarity == TonePolarity::kNearer || - (polarity == TonePolarity::kLighter && !scheme.is_dark) || - (polarity == TonePolarity::kDarker && scheme.is_dark)); - DynamicColor nearer = a_is_nearer ? role_a : role_b; - DynamicColor farther = a_is_nearer ? role_b : role_a; - bool am_nearer = this->name_ == nearer.name_; - double expansion_dir = scheme.is_dark ? 1 : -1; - - // 1st round: solve to min, each - double n_contrast = - nearer.contrast_curve_.value().get(scheme.contrast_level); - double f_contrast = - farther.contrast_curve_.value().get(scheme.contrast_level); - - // If a color is good enough, it is not adjusted. - // Initial and adjusted tones for `nearer` - double n_initial_tone = nearer.tone_(scheme); - double n_tone = RatioOfTones(bg_tone, n_initial_tone) >= n_contrast - ? n_initial_tone - : ForegroundTone(bg_tone, n_contrast); - // Initial and adjusted tones for `farther` - double f_initial_tone = farther.tone_(scheme); - double f_tone = RatioOfTones(bg_tone, f_initial_tone) >= f_contrast - ? f_initial_tone - : ForegroundTone(bg_tone, f_contrast); - - if (decreasingContrast) { - // If decreasing contrast, adjust color to the "bare minimum" - // that satisfies contrast. - n_tone = ForegroundTone(bg_tone, n_contrast); - f_tone = ForegroundTone(bg_tone, f_contrast); - } - - if ((f_tone - n_tone) * expansion_dir >= delta) { - // Good! Tones satisfy the constraint; no change needed. - } else { - // 2nd round: expand farther to match delta. - f_tone = std::clamp(n_tone + delta * expansion_dir, 0.0, 100.0); - if ((f_tone - n_tone) * expansion_dir >= delta) { - // Good! Tones now satisfy the constraint; no change needed. - } else { - // 3rd round: contract nearer to match delta. - n_tone = std::clamp(f_tone - delta * expansion_dir, 0.0, 100.0); - } - } - - // Avoids the 50-59 awkward zone. - if (50 <= n_tone && n_tone < 60) { - // If `nearer` is in the awkward zone, move it away, together with - // `farther`. - if (expansion_dir > 0) { - n_tone = 60; - f_tone = std::max(f_tone, n_tone + delta * expansion_dir); - } else { - n_tone = 49; - f_tone = std::min(f_tone, n_tone + delta * expansion_dir); - } - } else if (50 <= f_tone && f_tone < 60) { - if (stay_together) { - // Fixes both, to avoid two colors on opposite sides of the "awkward - // zone". - if (expansion_dir > 0) { - n_tone = 60; - f_tone = std::max(f_tone, n_tone + delta * expansion_dir); - } else { - n_tone = 49; - f_tone = std::min(f_tone, n_tone + delta * expansion_dir); - } - } else { - // Not required to stay together; fixes just one. - if (expansion_dir > 0) { - f_tone = 60; - } else { - f_tone = 49; - } - } - } - - // Returns `n_tone` if this color is `nearer`, otherwise `f_tone`. - return am_nearer ? n_tone : f_tone; - } else { - // Case 2: No contrast pair; just solve for itself. - double answer = tone_(scheme); - - if (background_ == std::nullopt) { - return answer; // No adjustment for colors with no background. - } - - double bg_tone = background_.value()(scheme).GetTone(scheme); - - double desired_ratio = contrast_curve_.value().get(scheme.contrast_level); - - if (RatioOfTones(bg_tone, answer) >= desired_ratio) { - // Don't "improve" what's good enough. - } else { - // Rough improvement. - answer = ForegroundTone(bg_tone, desired_ratio); - } - - if (decreasingContrast) { - answer = ForegroundTone(bg_tone, desired_ratio); - } - - if (is_background_ && 50 <= answer && answer < 60) { - // Must adjust - if (RatioOfTones(49, bg_tone) >= desired_ratio) { - answer = 49; - } else { - answer = 60; - } - } - - if (second_background_ != std::nullopt) { - // Case 3: Adjust for dual backgrounds. - - double bg_tone_1 = background_.value()(scheme).GetTone(scheme); - double bg_tone_2 = second_background_.value()(scheme).GetTone(scheme); - - double upper = std::max(bg_tone_1, bg_tone_2); - double lower = std::min(bg_tone_1, bg_tone_2); - - if (RatioOfTones(upper, answer) >= desired_ratio && - RatioOfTones(lower, answer) >= desired_ratio) { - return answer; - } - - // The darkest light tone that satisfies the desired ratio, - // or -1 if such ratio cannot be reached. - double lightOption = Lighter(upper, desired_ratio); - - // The lightest dark tone that satisfies the desired ratio, - // or -1 if such ratio cannot be reached. - double darkOption = Darker(lower, desired_ratio); - - // Tones suitable for the foreground. - std::vector availables; - if (lightOption != -1) { - availables.push_back(lightOption); - } - if (darkOption != -1) { - availables.push_back(darkOption); - } - - bool prefersLight = TonePrefersLightForeground(bg_tone_1) || - TonePrefersLightForeground(bg_tone_2); - if (prefersLight) { - return (lightOption < 0) ? 100 : lightOption; - } - if (availables.size() == 1) { - return availables[0]; - } - return (darkOption < 0) ? 0 : darkOption; - } - - return answer; - } -} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/dynamiccolor/dynamic_color.h b/src/material-colors/cpp/dynamiccolor/dynamic_color.h deleted file mode 100644 index 92ad227..0000000 --- a/src/material-colors/cpp/dynamiccolor/dynamic_color.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_DYNAMICCOLOR_DYNAMIC_COLOR_H_ -#define CPP_DYNAMICCOLOR_DYNAMIC_COLOR_H_ - -#include -#include -#include - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/contrast_curve.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -struct ToneDeltaPair; - -/** - * Given a background tone, find a foreground tone, while ensuring they reach - * a contrast ratio that is as close to [ratio] as possible. - * - * [bgTone] Tone in HCT. Range is 0 to 100, undefined behavior when it falls - * outside that range. - * [ratio] The contrast ratio desired between [bgTone] and the return value. - */ -double ForegroundTone(double bg_tone, double ratio); - -/** - * Adjust a tone such that white has 4.5 contrast, if the tone is - * reasonably close to supporting it. - */ -double EnableLightForeground(double tone); - -/** - * Returns whether [tone] prefers a light foreground. - * - * People prefer white foregrounds on ~T60-70. Observed over time, and also - * by Andrew Somers during research for APCA. - * - * T60 used as to create the smallest discontinuity possible when skipping - * down to T49 in order to ensure light foregrounds. - * - * Since `tertiaryContainer` in dark monochrome scheme requires a tone of - * 60, it should not be adjusted. Therefore, 60 is excluded here. - */ -bool TonePrefersLightForeground(double tone); - -/** - * Returns whether [tone] can reach a contrast ratio of 4.5 with a lighter - * color. - */ -bool ToneAllowsLightForeground(double tone); - -/** - * @param name_ The name of the dynamic color. - * @param palette_ Function that provides a TonalPalette given - * DynamicScheme. A TonalPalette is defined by a hue and chroma, so this - * replaces the need to specify hue/chroma. By providing a tonal palette, when - * contrast adjustments are made, intended chroma can be preserved. - * @param tone_ Function that provides a tone given DynamicScheme. - * @param is_background_ Whether this dynamic color is a background, with - * some other color as the foreground. - * @param background_ The background of the dynamic color (as a function of a - * `DynamicScheme`), if it exists. - * @param second_background_ A second background of the dynamic color (as a - * function of a `DynamicScheme`), if it - * exists. - * @param contrast_curve_ A `ContrastCurve` object specifying how its contrast - * against its background should behave in various contrast levels options. - * @param tone_delta_pair_ A `ToneDeltaPair` object specifying a tone delta - * constraint between two colors. One of them must be the color being - * constructed. - */ -struct DynamicColor { - std::string name_; - std::function palette_; - std::function tone_; - bool is_background_; - - std::optional> background_; - std::optional> - second_background_; - std::optional contrast_curve_; - std::optional> - tone_delta_pair_; - - /** A convenience constructor, only requiring name, palette, and tone. */ - static DynamicColor FromPalette( - std::string name, - std::function palette, - std::function tone); - - Argb GetArgb(const DynamicScheme& scheme); - - Hct GetHct(const DynamicScheme& scheme); - - double GetTone(const DynamicScheme& scheme); - - /** The default constructor. */ - DynamicColor(std::string name, - std::function palette, - std::function tone, - bool is_background, - - std::optional> - background, - std::optional> - second_background, - std::optional contrast_curve, - std::optional> - tone_delta_pair); -}; - -} // namespace material_color_utilities - -#endif // CPP_DYNAMICCOLOR_DYNAMIC_COLOR_H_ diff --git a/src/material-colors/cpp/dynamiccolor/dynamic_scheme.cpp b/src/material-colors/cpp/dynamiccolor/dynamic_scheme.cpp deleted file mode 100644 index 170e99c..0000000 --- a/src/material-colors/cpp/dynamiccolor/dynamic_scheme.cpp +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/dynamiccolor/dynamic_scheme.h" - -#include -#include - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/material_dynamic_colors.h" -#include "cpp/dynamiccolor/variant.h" -#include "cpp/palettes/tones.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -DynamicScheme::DynamicScheme(Hct source_color_hct, Variant variant, - double contrast_level, bool is_dark, - TonalPalette primary_palette, - TonalPalette secondary_palette, - TonalPalette tertiary_palette, - TonalPalette neutral_palette, - TonalPalette neutral_variant_palette, - std::optional error_palette) - : source_color_hct(source_color_hct), - variant(variant), - is_dark(is_dark), - contrast_level(contrast_level), - primary_palette(primary_palette), - secondary_palette(secondary_palette), - tertiary_palette(tertiary_palette), - neutral_palette(neutral_palette), - neutral_variant_palette(neutral_variant_palette), - error_palette(error_palette.value_or(TonalPalette(25.0, 84.0))) {} - -double DynamicScheme::GetRotatedHue(Hct source_color, std::vector hues, - std::vector rotations) { - double source_hue = source_color.get_hue(); - - if (rotations.size() == 1) { - return SanitizeDegreesDouble(source_color.get_hue() + rotations[0]); - } - int size = hues.size(); - for (int i = 0; i <= (size - 2); ++i) { - double this_hue = hues[i]; - double next_hue = hues[i + 1]; - if (this_hue < source_hue && source_hue < next_hue) { - return SanitizeDegreesDouble(source_hue + rotations[i]); - } - } - - return source_hue; -} - -Argb DynamicScheme::SourceColorArgb() const { return source_color_hct.ToInt(); } - -Argb DynamicScheme::GetPrimaryPaletteKeyColor() const { - return MaterialDynamicColors::PrimaryPaletteKeyColor().GetArgb(*this); -} - -Argb DynamicScheme::GetSecondaryPaletteKeyColor() const { - return MaterialDynamicColors::SecondaryPaletteKeyColor().GetArgb(*this); -} - -Argb DynamicScheme::GetTertiaryPaletteKeyColor() const { - return MaterialDynamicColors::TertiaryPaletteKeyColor().GetArgb(*this); -} - -Argb DynamicScheme::GetNeutralPaletteKeyColor() const { - return MaterialDynamicColors::NeutralPaletteKeyColor().GetArgb(*this); -} - -Argb DynamicScheme::GetNeutralVariantPaletteKeyColor() const { - return MaterialDynamicColors::NeutralVariantPaletteKeyColor().GetArgb(*this); -} - -Argb DynamicScheme::GetBackground() const { - return MaterialDynamicColors::Background().GetArgb(*this); -} - -Argb DynamicScheme::GetOnBackground() const { - return MaterialDynamicColors::OnBackground().GetArgb(*this); -} - -Argb DynamicScheme::GetSurface() const { - return MaterialDynamicColors::Surface().GetArgb(*this); -} - -Argb DynamicScheme::GetSurfaceDim() const { - return MaterialDynamicColors::SurfaceDim().GetArgb(*this); -} - -Argb DynamicScheme::GetSurfaceBright() const { - return MaterialDynamicColors::SurfaceBright().GetArgb(*this); -} - -Argb DynamicScheme::GetSurfaceContainerLowest() const { - return MaterialDynamicColors::SurfaceContainerLowest().GetArgb(*this); -} - -Argb DynamicScheme::GetSurfaceContainerLow() const { - return MaterialDynamicColors::SurfaceContainerLow().GetArgb(*this); -} - -Argb DynamicScheme::GetSurfaceContainer() const { - return MaterialDynamicColors::SurfaceContainer().GetArgb(*this); -} - -Argb DynamicScheme::GetSurfaceContainerHigh() const { - return MaterialDynamicColors::SurfaceContainerHigh().GetArgb(*this); -} - -Argb DynamicScheme::GetSurfaceContainerHighest() const { - return MaterialDynamicColors::SurfaceContainerHighest().GetArgb(*this); -} - -Argb DynamicScheme::GetOnSurface() const { - return MaterialDynamicColors::OnSurface().GetArgb(*this); -} - -Argb DynamicScheme::GetSurfaceVariant() const { - return MaterialDynamicColors::SurfaceVariant().GetArgb(*this); -} - -Argb DynamicScheme::GetOnSurfaceVariant() const { - return MaterialDynamicColors::OnSurfaceVariant().GetArgb(*this); -} - -Argb DynamicScheme::GetInverseSurface() const { - return MaterialDynamicColors::InverseSurface().GetArgb(*this); -} - -Argb DynamicScheme::GetInverseOnSurface() const { - return MaterialDynamicColors::InverseOnSurface().GetArgb(*this); -} - -Argb DynamicScheme::GetOutline() const { - return MaterialDynamicColors::Outline().GetArgb(*this); -} - -Argb DynamicScheme::GetOutlineVariant() const { - return MaterialDynamicColors::OutlineVariant().GetArgb(*this); -} - -Argb DynamicScheme::GetShadow() const { - return MaterialDynamicColors::Shadow().GetArgb(*this); -} - -Argb DynamicScheme::GetScrim() const { - return MaterialDynamicColors::Scrim().GetArgb(*this); -} - -Argb DynamicScheme::GetSurfaceTint() const { - return MaterialDynamicColors::SurfaceTint().GetArgb(*this); -} - -Argb DynamicScheme::GetPrimary() const { - return MaterialDynamicColors::Primary().GetArgb(*this); -} - -Argb DynamicScheme::GetOnPrimary() const { - return MaterialDynamicColors::OnPrimary().GetArgb(*this); -} - -Argb DynamicScheme::GetPrimaryContainer() const { - return MaterialDynamicColors::PrimaryContainer().GetArgb(*this); -} - -Argb DynamicScheme::GetOnPrimaryContainer() const { - return MaterialDynamicColors::OnPrimaryContainer().GetArgb(*this); -} - -Argb DynamicScheme::GetInversePrimary() const { - return MaterialDynamicColors::InversePrimary().GetArgb(*this); -} - -Argb DynamicScheme::GetSecondary() const { - return MaterialDynamicColors::Secondary().GetArgb(*this); -} - -Argb DynamicScheme::GetOnSecondary() const { - return MaterialDynamicColors::OnSecondary().GetArgb(*this); -} - -Argb DynamicScheme::GetSecondaryContainer() const { - return MaterialDynamicColors::SecondaryContainer().GetArgb(*this); -} - -Argb DynamicScheme::GetOnSecondaryContainer() const { - return MaterialDynamicColors::OnSecondaryContainer().GetArgb(*this); -} - -Argb DynamicScheme::GetTertiary() const { - return MaterialDynamicColors::Tertiary().GetArgb(*this); -} - -Argb DynamicScheme::GetOnTertiary() const { - return MaterialDynamicColors::OnTertiary().GetArgb(*this); -} - -Argb DynamicScheme::GetTertiaryContainer() const { - return MaterialDynamicColors::TertiaryContainer().GetArgb(*this); -} - -Argb DynamicScheme::GetOnTertiaryContainer() const { - return MaterialDynamicColors::OnTertiaryContainer().GetArgb(*this); -} - -Argb DynamicScheme::GetError() const { - return MaterialDynamicColors::Error().GetArgb(*this); -} - -Argb DynamicScheme::GetOnError() const { - return MaterialDynamicColors::OnError().GetArgb(*this); -} - -Argb DynamicScheme::GetErrorContainer() const { - return MaterialDynamicColors::ErrorContainer().GetArgb(*this); -} - -Argb DynamicScheme::GetOnErrorContainer() const { - return MaterialDynamicColors::OnErrorContainer().GetArgb(*this); -} - -Argb DynamicScheme::GetPrimaryFixed() const { - return MaterialDynamicColors::PrimaryFixed().GetArgb(*this); -} - -Argb DynamicScheme::GetPrimaryFixedDim() const { - return MaterialDynamicColors::PrimaryFixedDim().GetArgb(*this); -} - -Argb DynamicScheme::GetOnPrimaryFixed() const { - return MaterialDynamicColors::OnPrimaryFixed().GetArgb(*this); -} - -Argb DynamicScheme::GetOnPrimaryFixedVariant() const { - return MaterialDynamicColors::OnPrimaryFixedVariant().GetArgb(*this); -} - -Argb DynamicScheme::GetSecondaryFixed() const { - return MaterialDynamicColors::SecondaryFixed().GetArgb(*this); -} - -Argb DynamicScheme::GetSecondaryFixedDim() const { - return MaterialDynamicColors::SecondaryFixedDim().GetArgb(*this); -} - -Argb DynamicScheme::GetOnSecondaryFixed() const { - return MaterialDynamicColors::OnSecondaryFixed().GetArgb(*this); -} - -Argb DynamicScheme::GetOnSecondaryFixedVariant() const { - return MaterialDynamicColors::OnSecondaryFixedVariant().GetArgb(*this); -} - -Argb DynamicScheme::GetTertiaryFixed() const { - return MaterialDynamicColors::TertiaryFixed().GetArgb(*this); -} - -Argb DynamicScheme::GetTertiaryFixedDim() const { - return MaterialDynamicColors::TertiaryFixedDim().GetArgb(*this); -} - -Argb DynamicScheme::GetOnTertiaryFixed() const { - return MaterialDynamicColors::OnTertiaryFixed().GetArgb(*this); -} - -Argb DynamicScheme::GetOnTertiaryFixedVariant() const { - return MaterialDynamicColors::OnTertiaryFixedVariant().GetArgb(*this); -} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/dynamiccolor/dynamic_scheme.h b/src/material-colors/cpp/dynamiccolor/dynamic_scheme.h deleted file mode 100644 index 473287f..0000000 --- a/src/material-colors/cpp/dynamiccolor/dynamic_scheme.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_DYNAMICCOLOR_DYNAMIC_SCHEME_H_ -#define CPP_DYNAMICCOLOR_DYNAMIC_SCHEME_H_ - -#include -#include - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/variant.h" -#include "cpp/palettes/tones.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -struct DynamicScheme { - Hct source_color_hct; - Variant variant; - bool is_dark; - double contrast_level; - - TonalPalette primary_palette; - TonalPalette secondary_palette; - TonalPalette tertiary_palette; - TonalPalette neutral_palette; - TonalPalette neutral_variant_palette; - TonalPalette error_palette; - - DynamicScheme(Hct source_color_hct, Variant variant, double contrast_level, - bool is_dark, TonalPalette primary_palette, - TonalPalette secondary_palette, TonalPalette tertiary_palette, - TonalPalette neutral_palette, - TonalPalette neutral_variant_palette, - std::optional error_palette = std::nullopt); - - static double GetRotatedHue(Hct source_color, std::vector hues, - std::vector rotations); - - Argb SourceColorArgb() const; - - Argb GetPrimaryPaletteKeyColor() const; - Argb GetSecondaryPaletteKeyColor() const; - Argb GetTertiaryPaletteKeyColor() const; - Argb GetNeutralPaletteKeyColor() const; - Argb GetNeutralVariantPaletteKeyColor() const; - Argb GetBackground() const; - Argb GetOnBackground() const; - Argb GetSurface() const; - Argb GetSurfaceDim() const; - Argb GetSurfaceBright() const; - Argb GetSurfaceContainerLowest() const; - Argb GetSurfaceContainerLow() const; - Argb GetSurfaceContainer() const; - Argb GetSurfaceContainerHigh() const; - Argb GetSurfaceContainerHighest() const; - Argb GetOnSurface() const; - Argb GetSurfaceVariant() const; - Argb GetOnSurfaceVariant() const; - Argb GetInverseSurface() const; - Argb GetInverseOnSurface() const; - Argb GetOutline() const; - Argb GetOutlineVariant() const; - Argb GetShadow() const; - Argb GetScrim() const; - Argb GetSurfaceTint() const; - Argb GetPrimary() const; - Argb GetOnPrimary() const; - Argb GetPrimaryContainer() const; - Argb GetOnPrimaryContainer() const; - Argb GetInversePrimary() const; - Argb GetSecondary() const; - Argb GetOnSecondary() const; - Argb GetSecondaryContainer() const; - Argb GetOnSecondaryContainer() const; - Argb GetTertiary() const; - Argb GetOnTertiary() const; - Argb GetTertiaryContainer() const; - Argb GetOnTertiaryContainer() const; - Argb GetError() const; - Argb GetOnError() const; - Argb GetErrorContainer() const; - Argb GetOnErrorContainer() const; - Argb GetPrimaryFixed() const; - Argb GetPrimaryFixedDim() const; - Argb GetOnPrimaryFixed() const; - Argb GetOnPrimaryFixedVariant() const; - Argb GetSecondaryFixed() const; - Argb GetSecondaryFixedDim() const; - Argb GetOnSecondaryFixed() const; - Argb GetOnSecondaryFixedVariant() const; - Argb GetTertiaryFixed() const; - Argb GetTertiaryFixedDim() const; - Argb GetOnTertiaryFixed() const; - Argb GetOnTertiaryFixedVariant() const; -}; - -} // namespace material_color_utilities - -#endif // CPP_DYNAMICCOLOR_DYNAMIC_SCHEME_H_ diff --git a/src/material-colors/cpp/dynamiccolor/material_dynamic_colors.cpp b/src/material-colors/cpp/dynamiccolor/material_dynamic_colors.cpp deleted file mode 100644 index 26ddb76..0000000 --- a/src/material-colors/cpp/dynamiccolor/material_dynamic_colors.cpp +++ /dev/null @@ -1,1153 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/dynamiccolor/material_dynamic_colors.h" - -#include - -#include "cpp/cam/cam.h" -#include "cpp/cam/hct.h" -#include "cpp/dislike/dislike.h" -#include "cpp/dynamiccolor/contrast_curve.h" -#include "cpp/dynamiccolor/dynamic_color.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" -#include "cpp/dynamiccolor/tone_delta_pair.h" -#include "cpp/dynamiccolor/variant.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -using std::nullopt; - -bool IsFidelity(const DynamicScheme& scheme) { - return scheme.variant == Variant::kFidelity || - scheme.variant == Variant::kContent; -} - -bool IsMonochrome(const DynamicScheme& scheme) { - return scheme.variant == Variant::kMonochrome; -} - -Vec3 XyzInViewingConditions(Cam cam, ViewingConditions viewing_conditions) { - double alpha = (cam.chroma == 0.0 || cam.j == 0.0) - ? 0.0 - : cam.chroma / sqrt(cam.j / 100.0); - - double t = pow( - alpha / pow(1.64 - pow(0.29, - viewing_conditions.background_y_to_white_point_y), - 0.73), - 1.0 / 0.9); - double h_rad = cam.hue * M_PI / 180.0; - - double e_hue = 0.25 * (cos(h_rad + 2.0) + 3.8); - double ac = - viewing_conditions.aw * - pow(cam.j / 100.0, 1.0 / viewing_conditions.c / viewing_conditions.z); - double p1 = e_hue * (50000.0 / 13.0) * viewing_conditions.n_c * - viewing_conditions.ncb; - - double p2 = (ac / viewing_conditions.nbb); - - double h_sin = sin(h_rad); - double h_cos = cos(h_rad); - - double gamma = 23.0 * (p2 + 0.305) * t / - (23.0 * p1 + 11 * t * h_cos + 108.0 * t * h_sin); - double a = gamma * h_cos; - double b = gamma * h_sin; - double r_a = (460.0 * p2 + 451.0 * a + 288.0 * b) / 1403.0; - double g_a = (460.0 * p2 - 891.0 * a - 261.0 * b) / 1403.0; - double b_a = (460.0 * p2 - 220.0 * a - 6300.0 * b) / 1403.0; - - double r_c_base = fmax(0, (27.13 * fabs(r_a)) / (400.0 - fabs(r_a))); - double r_c = - Signum(r_a) * (100.0 / viewing_conditions.fl) * pow(r_c_base, 1.0 / 0.42); - double g_c_base = fmax(0, (27.13 * fabs(g_a)) / (400.0 - fabs(g_a))); - double g_c = - Signum(g_a) * (100.0 / viewing_conditions.fl) * pow(g_c_base, 1.0 / 0.42); - double b_c_base = fmax(0, (27.13 * fabs(b_a)) / (400.0 - fabs(b_a))); - double b_c = - Signum(b_a) * (100.0 / viewing_conditions.fl) * pow(b_c_base, 1.0 / 0.42); - double r_f = r_c / viewing_conditions.rgb_d[0]; - double g_f = g_c / viewing_conditions.rgb_d[1]; - double b_f = b_c / viewing_conditions.rgb_d[2]; - - double x = 1.86206786 * r_f - 1.01125463 * g_f + 0.14918677 * b_f; - double y = 0.38752654 * r_f + 0.62144744 * g_f - 0.00897398 * b_f; - double z = -0.01584150 * r_f - 0.03412294 * g_f + 1.04996444 * b_f; - - return {x, y, z}; -} - -Hct InViewingConditions(Hct hct, ViewingConditions vc) { - // 1. Use CAM16 to find XYZ coordinates of color in specified VC. - Cam cam16 = CamFromInt(hct.ToInt()); - Vec3 viewed_in_vc = XyzInViewingConditions(cam16, vc); - - // 2. Create CAM16 of those XYZ coordinates in default VC. - Cam recast_in_vc = - CamFromXyzAndViewingConditions(viewed_in_vc.a, viewed_in_vc.b, - viewed_in_vc.c, kDefaultViewingConditions); - - // 3. Create HCT from: - // - CAM16 using default VC with XYZ coordinates in specified VC. - // - L* converted from Y in XYZ coordinates in specified VC. - Hct recast_hct = - Hct(recast_in_vc.hue, recast_in_vc.chroma, LstarFromY(viewed_in_vc.b)); - return recast_hct; -} - -double FindDesiredChromaByTone(double hue, double chroma, double tone, - bool by_decreasing_tone) { - double answer = tone; - - Hct closest_to_chroma = Hct(hue, chroma, tone); - if (closest_to_chroma.get_chroma() < chroma) { - double chroma_peak = closest_to_chroma.get_chroma(); - while (closest_to_chroma.get_chroma() < chroma) { - answer += by_decreasing_tone ? -1.0 : 1.0; - Hct potential_solution = Hct(hue, chroma, answer); - if (chroma_peak > potential_solution.get_chroma()) { - break; - } - if (abs(potential_solution.get_chroma() - chroma) < 0.4) { - break; - } - - double potential_delta = abs(potential_solution.get_chroma() - chroma); - double current_delta = abs(closest_to_chroma.get_chroma() - chroma); - if (potential_delta < current_delta) { - closest_to_chroma = potential_solution; - } - chroma_peak = fmax(chroma_peak, potential_solution.get_chroma()); - } - } - - return answer; -} - -constexpr double kContentAccentToneDelta = 15.0; -DynamicColor highestSurface(const DynamicScheme& s) { - return s.is_dark ? MaterialDynamicColors::SurfaceBright() - : MaterialDynamicColors::SurfaceDim(); -} - -// Compatibility Keys Colors for Android -DynamicColor MaterialDynamicColors::PrimaryPaletteKeyColor() { - return DynamicColor::FromPalette( - "primary_palette_key_color", - [](const DynamicScheme& s) -> TonalPalette { return s.primary_palette; }, - [](const DynamicScheme& s) -> double { - return s.primary_palette.get_key_color().get_tone(); - }); -} - -DynamicColor MaterialDynamicColors::SecondaryPaletteKeyColor() { - return DynamicColor::FromPalette( - "secondary_palette_key_color", - [](const DynamicScheme& s) -> TonalPalette { - return s.secondary_palette; - }, - [](const DynamicScheme& s) -> double { - return s.secondary_palette.get_key_color().get_tone(); - }); -} - -DynamicColor MaterialDynamicColors::TertiaryPaletteKeyColor() { - return DynamicColor::FromPalette( - "tertiary_palette_key_color", - [](const DynamicScheme& s) -> TonalPalette { return s.tertiary_palette; }, - [](const DynamicScheme& s) -> double { - return s.tertiary_palette.get_key_color().get_tone(); - }); -} - -DynamicColor MaterialDynamicColors::NeutralPaletteKeyColor() { - return DynamicColor::FromPalette( - "neutral_palette_key_color", - [](const DynamicScheme& s) -> TonalPalette { return s.neutral_palette; }, - [](const DynamicScheme& s) -> double { - return s.neutral_palette.get_key_color().get_tone(); - }); -} - -DynamicColor MaterialDynamicColors::NeutralVariantPaletteKeyColor() { - return DynamicColor::FromPalette( - "neutral_variant_palette_key_color", - [](const DynamicScheme& s) -> TonalPalette { - return s.neutral_variant_palette; - }, - [](const DynamicScheme& s) -> double { - return s.neutral_variant_palette.get_key_color().get_tone(); - }); -} - -DynamicColor MaterialDynamicColors::Background() { - return DynamicColor( - /* name= */ "background", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.neutral_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { return s.is_dark ? 6.0 : 98.0; }, - /* isBackground= */ true, - /* background= */ nullopt, - /* secondBackground= */ nullopt, - /* contrastCurve= */ nullopt, - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::OnBackground() { - return DynamicColor( - /* name= */ "on_background", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.neutral_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { return s.is_dark ? 90.0 : 10.0; }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return Background(); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(3.0, 3.0, 4.5, 7.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::Surface() { - return DynamicColor( - /* name= */ "surface", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.neutral_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { return s.is_dark ? 6.0 : 98.0; }, - /* isBackground= */ true, - /* background= */ nullopt, - /* secondBackground= */ nullopt, - /* contrastCurve= */ nullopt, - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::SurfaceDim() { - return DynamicColor( - /* name= */ "surface_dim", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.neutral_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return s.is_dark ? 6.0 - : ContrastCurve(87.0, 87.0, 80.0, 75.0) - .get(s.contrast_level); - }, - /* isBackground= */ true, - /* background= */ nullopt, - /* secondBackground= */ nullopt, - /* contrastCurve= */ nullopt, - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::SurfaceBright() { - return DynamicColor( - /* name= */ "surface_bright", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.neutral_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return s.is_dark - ? ContrastCurve(24.0, 24.0, 29.0, 34.0).get(s.contrast_level) - : 98.0; - }, - /* isBackground= */ true, - /* background= */ nullopt, - /* secondBackground= */ nullopt, - /* contrastCurve= */ nullopt, - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::SurfaceContainerLowest() { - return DynamicColor( - /* name= */ "surface_container_lowest", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.neutral_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return s.is_dark - ? ContrastCurve(4.0, 4.0, 2.0, 0.0).get(s.contrast_level) - : 100.0; - }, - /* isBackground= */ true, - /* background= */ nullopt, - /* secondBackground= */ nullopt, - /* contrastCurve= */ nullopt, - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::SurfaceContainerLow() { - return DynamicColor( - /* name= */ "surface_container_low", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.neutral_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return s.is_dark - ? ContrastCurve(10.0, 10.0, 11.0, 12.0).get(s.contrast_level) - : ContrastCurve(96.0, 96.0, 96.0, 95.0) - .get(s.contrast_level); - }, - /* isBackground= */ true, - /* background= */ nullopt, - /* secondBackground= */ nullopt, - /* contrastCurve= */ nullopt, - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::SurfaceContainer() { - return DynamicColor( - /* name= */ "surface_container", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.neutral_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return s.is_dark - ? ContrastCurve(12.0, 12.0, 16.0, 20.0).get(s.contrast_level) - : ContrastCurve(94.0, 94.0, 92.0, 90.0) - .get(s.contrast_level); - }, - /* isBackground= */ true, - /* background= */ nullopt, - /* secondBackground= */ nullopt, - /* contrastCurve= */ nullopt, - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::SurfaceContainerHigh() { - return DynamicColor( - /* name= */ "surface_container_high", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.neutral_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return s.is_dark - ? ContrastCurve(17.0, 17.0, 21.0, 25.0).get(s.contrast_level) - : ContrastCurve(92.0, 92.0, 88.0, 85.0) - .get(s.contrast_level); - }, - /* isBackground= */ true, - /* background= */ nullopt, - /* secondBackground= */ nullopt, - /* contrastCurve= */ nullopt, - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::SurfaceContainerHighest() { - return DynamicColor( - /* name= */ "surface_container_highest", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.neutral_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return s.is_dark - ? ContrastCurve(22.0, 22.0, 26.0, 30.0).get(s.contrast_level) - : ContrastCurve(90.0, 90.0, 84.0, 80.0) - .get(s.contrast_level); - }, - /* isBackground= */ true, - /* background= */ nullopt, - /* secondBackground= */ nullopt, - /* contrastCurve= */ nullopt, - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::OnSurface() { - return DynamicColor( - /* name= */ "on_surface", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.neutral_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { return s.is_dark ? 90.0 : 10.0; }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(4.5, 7.0, 11.0, 21.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::SurfaceVariant() { - return DynamicColor( - /* name= */ "surface_variant", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { - return s.neutral_variant_palette; - }, - /* tone= */ - [](const DynamicScheme& s) -> double { return s.is_dark ? 30.0 : 90.0; }, - /* isBackground= */ true, - /* background= */ nullopt, - /* secondBackground= */ nullopt, - /* contrastCurve= */ nullopt, - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::OnSurfaceVariant() { - return DynamicColor( - /* name= */ "on_surface_variant", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { - return s.neutral_variant_palette; - }, - /* tone= */ - [](const DynamicScheme& s) -> double { return s.is_dark ? 80.0 : 30.0; }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(3.0, 4.5, 7.0, 11.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::InverseSurface() { - return DynamicColor( - /* name= */ "inverse_surface", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.neutral_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { return s.is_dark ? 90.0 : 20.0; }, - /* isBackground= */ false, - /* background= */ nullopt, - /* secondBackground= */ nullopt, - /* contrastCurve= */ nullopt, - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::InverseOnSurface() { - return DynamicColor( - /* name= */ "inverse_on_surface", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.neutral_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { return s.is_dark ? 20.0 : 95.0; }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return InverseSurface(); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(4.5, 7.0, 11.0, 21.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::Outline() { - return DynamicColor( - /* name= */ "outline", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { - return s.neutral_variant_palette; - }, - /* tone= */ - [](const DynamicScheme& s) -> double { return s.is_dark ? 60.0 : 50.0; }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(1.5, 3.0, 4.5, 7.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::OutlineVariant() { - return DynamicColor( - /* name= */ "outline_variant", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { - return s.neutral_variant_palette; - }, - /* tone= */ - [](const DynamicScheme& s) -> double { return s.is_dark ? 30.0 : 80.0; }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(1.0, 1.0, 3.0, 4.5), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::Shadow() { - return DynamicColor( - /* name= */ "shadow", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.neutral_palette; }, - /* tone= */ [](const DynamicScheme& s) -> double { return 0.0; }, - /* isBackground= */ false, - /* background= */ nullopt, - /* secondBackground= */ nullopt, - /* contrastCurve= */ nullopt, - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::Scrim() { - return DynamicColor( - /* name= */ "scrim", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.neutral_palette; }, - /* tone= */ [](const DynamicScheme& s) -> double { return 0.0; }, - /* isBackground= */ false, - /* background= */ nullopt, - /* secondBackground= */ nullopt, - /* contrastCurve= */ nullopt, - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::SurfaceTint() { - return DynamicColor( - /* name= */ "surface_tint", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.primary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { return s.is_dark ? 80.0 : 40.0; }, - /* isBackground= */ true, - /* background= */ nullopt, - /* secondBackground= */ nullopt, - /* contrastCurve= */ nullopt, - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::Primary() { - return DynamicColor( - /* name= */ "primary", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.primary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - if (IsMonochrome(s)) { - return s.is_dark ? 100.0 : 0.0; - } - return s.is_dark ? 80.0 : 40.0; - }, - /* isBackground= */ true, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(3.0, 4.5, 7.0, 7.0), - /* toneDeltaPair= */ - [](const DynamicScheme& s) -> ToneDeltaPair { - return ToneDeltaPair(PrimaryContainer(), Primary(), 10.0, - TonePolarity::kNearer, false); - }); -} - -DynamicColor MaterialDynamicColors::OnPrimary() { - return DynamicColor( - /* name= */ "on_primary", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.primary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - if (IsMonochrome(s)) { - return s.is_dark ? 10.0 : 90.0; - } - return s.is_dark ? 20.0 : 100.0; - }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return Primary(); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(4.5, 7.0, 11.0, 21.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::PrimaryContainer() { - return DynamicColor( - /* name= */ "primary_container", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.primary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - if (IsFidelity(s)) { - return s.source_color_hct.get_tone(); - } - if (IsMonochrome(s)) { - return s.is_dark ? 85.0 : 25.0; - } - return s.is_dark ? 30.0 : 90.0; - }, - /* isBackground= */ true, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(1.0, 1.0, 3.0, 4.5), - /* toneDeltaPair= */ - [](const DynamicScheme& s) -> ToneDeltaPair { - return ToneDeltaPair(PrimaryContainer(), Primary(), 10.0, - TonePolarity::kNearer, false); - }); -} - -DynamicColor MaterialDynamicColors::OnPrimaryContainer() { - return DynamicColor( - /* name= */ - "on_primary_container", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.primary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - if (IsFidelity(s)) { - return ForegroundTone(PrimaryContainer().tone_(s), 4.5); - } - if (IsMonochrome(s)) { - return s.is_dark ? 0.0 : 100.0; - } - return s.is_dark ? 90.0 : 30.0; - }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return PrimaryContainer(); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(3.0, 4.5, 7.0, 11.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::InversePrimary() { - return DynamicColor( - /* name= */ "inverse_primary", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.primary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { return s.is_dark ? 40.0 : 80.0; }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return InverseSurface(); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(3.0, 4.5, 7.0, 7.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::Secondary() { - return DynamicColor( - /* name= */ "secondary", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { - return s.secondary_palette; - }, - /* tone= */ - [](const DynamicScheme& s) -> double { return s.is_dark ? 80.0 : 40.0; }, - /* isBackground= */ true, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(3.0, 4.5, 7.0, 7.0), - /* toneDeltaPair= */ - [](const DynamicScheme& s) -> ToneDeltaPair { - return ToneDeltaPair(SecondaryContainer(), Secondary(), 10.0, - TonePolarity::kNearer, false); - }); -} - -DynamicColor MaterialDynamicColors::OnSecondary() { - return DynamicColor( - /* name= */ "on_secondary", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { - return s.secondary_palette; - }, - /* tone= */ - [](const DynamicScheme& s) -> double { - if (IsMonochrome(s)) { - return s.is_dark ? 10.0 : 100.0; - } else { - return s.is_dark ? 20.0 : 100.0; - } - }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return Secondary(); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(4.5, 7.0, 11.0, 21.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::SecondaryContainer() { - return DynamicColor( - /* name= */ "secondary_container", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { - return s.secondary_palette; - }, - /* tone= */ - [](const DynamicScheme& s) -> double { - double initialTone = s.is_dark ? 30.0 : 90.0; - if (IsMonochrome(s)) { - return s.is_dark ? 30.0 : 85.0; - } - if (!IsFidelity(s)) { - return initialTone; - } - return FindDesiredChromaByTone(s.secondary_palette.get_hue(), - s.secondary_palette.get_chroma(), - initialTone, s.is_dark ? false : true); - }, - /* isBackground= */ true, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(1.0, 1.0, 3.0, 4.5), - /* toneDeltaPair= */ - [](const DynamicScheme& s) -> ToneDeltaPair { - return ToneDeltaPair(SecondaryContainer(), Secondary(), 10.0, - TonePolarity::kNearer, false); - }); -} - -DynamicColor MaterialDynamicColors::OnSecondaryContainer() { - return DynamicColor( - /* name= */ - "on_secondary_container", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { - return s.secondary_palette; - }, - /* tone= */ - [](const DynamicScheme& s) -> double { - if (IsMonochrome(s)) { - return s.is_dark ? 90.0 : 10.0; - } - if (!IsFidelity(s)) { - return s.is_dark ? 90.0 : 30.0; - } - return ForegroundTone(SecondaryContainer().tone_(s), 4.5); - }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { - return SecondaryContainer(); - }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(3.0, 4.5, 7.0, 11.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::Tertiary() { - return DynamicColor( - /* name= */ "tertiary", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.tertiary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - if (IsMonochrome(s)) { - return s.is_dark ? 90.0 : 25.0; - } - return s.is_dark ? 80.0 : 40.0; - }, - /* isBackground= */ true, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(3.0, 4.5, 7.0, 7.0), - /* toneDeltaPair= */ - [](const DynamicScheme& s) -> ToneDeltaPair { - return ToneDeltaPair(TertiaryContainer(), Tertiary(), 10.0, - TonePolarity::kNearer, false); - }); -} - -DynamicColor MaterialDynamicColors::OnTertiary() { - return DynamicColor( - /* name= */ "on_tertiary", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.tertiary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - if (IsMonochrome(s)) { - return s.is_dark ? 10.0 : 90.0; - } - return s.is_dark ? 20.0 : 100.0; - }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return Tertiary(); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(4.5, 7.0, 11.0, 21.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::TertiaryContainer() { - return DynamicColor( - /* name= */ "tertiary_container", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.tertiary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - if (IsMonochrome(s)) { - return s.is_dark ? 60.0 : 49.0; - } - if (!IsFidelity(s)) { - return s.is_dark ? 30.0 : 90.0; - } - Hct proposedHct = - Hct(s.tertiary_palette.get(s.source_color_hct.get_tone())); - return FixIfDisliked(proposedHct).get_tone(); - }, - /* isBackground= */ true, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(1.0, 1.0, 3.0, 4.5), - /* toneDeltaPair= */ - [](const DynamicScheme& s) -> ToneDeltaPair { - return ToneDeltaPair(TertiaryContainer(), Tertiary(), 10.0, - TonePolarity::kNearer, false); - }); -} - -DynamicColor MaterialDynamicColors::OnTertiaryContainer() { - return DynamicColor( - /* name= */ - "on_tertiary_container", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.tertiary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - if (IsMonochrome(s)) { - return s.is_dark ? 0.0 : 100.0; - } - if (!IsFidelity(s)) { - return s.is_dark ? 90.0 : 30.0; - } - return ForegroundTone(TertiaryContainer().tone_(s), 4.5); - }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { - return TertiaryContainer(); - }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(3.0, 4.5, 7.0, 11.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::Error() { - return DynamicColor( - /* name= */ "error", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.error_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { return s.is_dark ? 80.0 : 40.0; }, - /* isBackground= */ true, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(3.0, 4.5, 7.0, 7.0), - /* toneDeltaPair= */ - [](const DynamicScheme& s) -> ToneDeltaPair { - return ToneDeltaPair(ErrorContainer(), Error(), 10.0, - TonePolarity::kNearer, false); - }); -} - -DynamicColor MaterialDynamicColors::OnError() { - return DynamicColor( - /* name= */ "on_error", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.error_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { return s.is_dark ? 20.0 : 100.0; }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return Error(); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(4.5, 7.0, 11.0, 21.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::ErrorContainer() { - return DynamicColor( - /* name= */ "error_container", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.error_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { return s.is_dark ? 30.0 : 90.0; }, - /* isBackground= */ true, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(1.0, 1.0, 3.0, 4.5), - /* toneDeltaPair= */ - [](const DynamicScheme& s) -> ToneDeltaPair { - return ToneDeltaPair(ErrorContainer(), Error(), 10.0, - TonePolarity::kNearer, false); - }); -} - -DynamicColor MaterialDynamicColors::OnErrorContainer() { - return DynamicColor( - /* name= */ - "on_error_container", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.error_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - if (IsMonochrome(s)) { - return s.is_dark ? 90.0 : 10.0; - } - return s.is_dark ? 90.0 : 30.0; - }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return ErrorContainer(); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(3.0, 4.5, 7.0, 11.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::PrimaryFixed() { - return DynamicColor( - /* name= */ "primary_fixed", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.primary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return IsMonochrome(s) ? 40.0 : 90.0; - }, - /* isBackground= */ true, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(1.0, 1.0, 3.0, 4.5), - /* toneDeltaPair= */ - [](const DynamicScheme& s) -> ToneDeltaPair { - return ToneDeltaPair(PrimaryFixed(), PrimaryFixedDim(), 10.0, - TonePolarity::kLighter, true); - }); -} - -DynamicColor MaterialDynamicColors::PrimaryFixedDim() { - return DynamicColor( - /* name= */ "primary_fixed_dim", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.primary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return IsMonochrome(s) ? 30.0 : 80.0; - }, - /* isBackground= */ true, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(1.0, 1.0, 3.0, 4.5), - /* toneDeltaPair= */ - [](const DynamicScheme& s) -> ToneDeltaPair { - return ToneDeltaPair(PrimaryFixed(), PrimaryFixedDim(), 10.0, - TonePolarity::kLighter, true); - }); -} - -DynamicColor MaterialDynamicColors::OnPrimaryFixed() { - return DynamicColor( - /* name= */ "on_primary_fixed", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.primary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return IsMonochrome(s) ? 100.0 : 10.0; - }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return PrimaryFixedDim(); }, - /* secondBackground= */ - [](const DynamicScheme& s) -> DynamicColor { return PrimaryFixed(); }, - /* contrastCurve= */ ContrastCurve(4.5, 7.0, 11.0, 21.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::OnPrimaryFixedVariant() { - return DynamicColor( - /* name= */ "on_primary_fixed_variant", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.primary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return IsMonochrome(s) ? 90.0 : 30.0; - }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return PrimaryFixedDim(); }, - /* secondBackground= */ - [](const DynamicScheme& s) -> DynamicColor { return PrimaryFixed(); }, - /* contrastCurve= */ ContrastCurve(3.0, 4.5, 7.0, 11.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::SecondaryFixed() { - return DynamicColor( - /* name= */ "secondary_fixed", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { - return s.secondary_palette; - }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return IsMonochrome(s) ? 80.0 : 90.0; - }, - /* isBackground= */ true, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(1.0, 1.0, 3.0, 4.5), - /* toneDeltaPair= */ - [](const DynamicScheme& s) -> ToneDeltaPair { - return ToneDeltaPair(SecondaryFixed(), SecondaryFixedDim(), 10.0, - TonePolarity::kLighter, true); - }); -} - -DynamicColor MaterialDynamicColors::SecondaryFixedDim() { - return DynamicColor( - /* name= */ "secondary_fixed_dim", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { - return s.secondary_palette; - }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return IsMonochrome(s) ? 70.0 : 80.0; - }, - /* isBackground= */ true, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(1.0, 1.0, 3.0, 4.5), - /* toneDeltaPair= */ - [](const DynamicScheme& s) -> ToneDeltaPair { - return ToneDeltaPair(SecondaryFixed(), SecondaryFixedDim(), 10.0, - TonePolarity::kLighter, true); - }); -} - -DynamicColor MaterialDynamicColors::OnSecondaryFixed() { - return DynamicColor( - /* name= */ "on_secondary_fixed", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { - return s.secondary_palette; - }, - /* tone= */ [](const DynamicScheme& s) -> double { return 10.0; }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { - return SecondaryFixedDim(); - }, - /* secondBackground= */ - [](const DynamicScheme& s) -> DynamicColor { return SecondaryFixed(); }, - /* contrastCurve= */ ContrastCurve(4.5, 7.0, 11.0, 21.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::OnSecondaryFixedVariant() { - return DynamicColor( - /* name= */ "on_secondary_fixed_variant", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { - return s.secondary_palette; - }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return IsMonochrome(s) ? 25.0 : 30.0; - }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { - return SecondaryFixedDim(); - }, - /* secondBackground= */ - [](const DynamicScheme& s) -> DynamicColor { return SecondaryFixed(); }, - /* contrastCurve= */ ContrastCurve(3.0, 4.5, 7.0, 11.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::TertiaryFixed() { - return DynamicColor( - /* name= */ "tertiary_fixed", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.tertiary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return IsMonochrome(s) ? 40.0 : 90.0; - }, - /* isBackground= */ true, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(1.0, 1.0, 3.0, 4.5), - /* toneDeltaPair= */ - [](const DynamicScheme& s) -> ToneDeltaPair { - return ToneDeltaPair(TertiaryFixed(), TertiaryFixedDim(), 10.0, - TonePolarity::kLighter, true); - }); -} - -DynamicColor MaterialDynamicColors::TertiaryFixedDim() { - return DynamicColor( - /* name= */ "tertiary_fixed_dim", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.tertiary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return IsMonochrome(s) ? 30.0 : 80.0; - }, - /* isBackground= */ true, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return highestSurface(s); }, - /* secondBackground= */ nullopt, - /* contrastCurve= */ ContrastCurve(1.0, 1.0, 3.0, 4.5), - /* toneDeltaPair= */ - [](const DynamicScheme& s) -> ToneDeltaPair { - return ToneDeltaPair(TertiaryFixed(), TertiaryFixedDim(), 10.0, - TonePolarity::kLighter, true); - }); -} - -DynamicColor MaterialDynamicColors::OnTertiaryFixed() { - return DynamicColor( - /* name= */ "on_tertiary_fixed", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.tertiary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return IsMonochrome(s) ? 100.0 : 10.0; - }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return TertiaryFixedDim(); }, - /* secondBackground= */ - [](const DynamicScheme& s) -> DynamicColor { return TertiaryFixed(); }, - /* contrastCurve= */ ContrastCurve(4.5, 7.0, 11.0, 21.0), - /* toneDeltaPair= */ nullopt); -} - -DynamicColor MaterialDynamicColors::OnTertiaryFixedVariant() { - return DynamicColor( - /* name= */ "on_tertiary_fixed_variant", - /* palette= */ - [](const DynamicScheme& s) -> TonalPalette { return s.tertiary_palette; }, - /* tone= */ - [](const DynamicScheme& s) -> double { - return IsMonochrome(s) ? 90.0 : 30.0; - }, - /* isBackground= */ false, - /* background= */ - [](const DynamicScheme& s) -> DynamicColor { return TertiaryFixedDim(); }, - /* secondBackground= */ - [](const DynamicScheme& s) -> DynamicColor { return TertiaryFixed(); }, - /* contrastCurve= */ ContrastCurve(3.0, 4.5, 7.0, 11.0), - /* toneDeltaPair= */ nullopt); -} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/dynamiccolor/material_dynamic_colors.h b/src/material-colors/cpp/dynamiccolor/material_dynamic_colors.h deleted file mode 100644 index 35a0af5..0000000 --- a/src/material-colors/cpp/dynamiccolor/material_dynamic_colors.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_DYNAMICCOLOR_MATERIAL_DYNAMIC_COLORS_H_ -#define CPP_DYNAMICCOLOR_MATERIAL_DYNAMIC_COLORS_H_ - -#include "cpp/dynamiccolor/dynamic_color.h" - -namespace material_color_utilities { - -class MaterialDynamicColors { - public: - static DynamicColor PrimaryPaletteKeyColor(); - static DynamicColor SecondaryPaletteKeyColor(); - static DynamicColor TertiaryPaletteKeyColor(); - static DynamicColor NeutralPaletteKeyColor(); - static DynamicColor NeutralVariantPaletteKeyColor(); - static DynamicColor Background(); - static DynamicColor OnBackground(); - static DynamicColor Surface(); - static DynamicColor SurfaceDim(); - static DynamicColor SurfaceBright(); - static DynamicColor SurfaceContainerLowest(); - static DynamicColor SurfaceContainerLow(); - static DynamicColor SurfaceContainer(); - static DynamicColor SurfaceContainerHigh(); - static DynamicColor SurfaceContainerHighest(); - static DynamicColor OnSurface(); - static DynamicColor SurfaceVariant(); - static DynamicColor OnSurfaceVariant(); - static DynamicColor InverseSurface(); - static DynamicColor InverseOnSurface(); - static DynamicColor Outline(); - static DynamicColor OutlineVariant(); - static DynamicColor Shadow(); - static DynamicColor Scrim(); - static DynamicColor SurfaceTint(); - static DynamicColor Primary(); - static DynamicColor OnPrimary(); - static DynamicColor PrimaryContainer(); - static DynamicColor OnPrimaryContainer(); - static DynamicColor InversePrimary(); - static DynamicColor Secondary(); - static DynamicColor OnSecondary(); - static DynamicColor SecondaryContainer(); - static DynamicColor OnSecondaryContainer(); - static DynamicColor Tertiary(); - static DynamicColor OnTertiary(); - static DynamicColor TertiaryContainer(); - static DynamicColor OnTertiaryContainer(); - static DynamicColor Error(); - static DynamicColor OnError(); - static DynamicColor ErrorContainer(); - static DynamicColor OnErrorContainer(); - static DynamicColor PrimaryFixed(); - static DynamicColor PrimaryFixedDim(); - static DynamicColor OnPrimaryFixed(); - static DynamicColor OnPrimaryFixedVariant(); - static DynamicColor SecondaryFixed(); - static DynamicColor SecondaryFixedDim(); - static DynamicColor OnSecondaryFixed(); - static DynamicColor OnSecondaryFixedVariant(); - static DynamicColor TertiaryFixed(); - static DynamicColor TertiaryFixedDim(); - static DynamicColor OnTertiaryFixed(); - static DynamicColor OnTertiaryFixedVariant(); -}; - -} // namespace material_color_utilities - -#endif // CPP_DYNAMICCOLOR_MATERIAL_DYNAMIC_COLORS_H_ diff --git a/src/material-colors/cpp/dynamiccolor/tone_delta_pair.h b/src/material-colors/cpp/dynamiccolor/tone_delta_pair.h deleted file mode 100644 index 1e44950..0000000 --- a/src/material-colors/cpp/dynamiccolor/tone_delta_pair.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_DYNAMICCOLOR_TONE_DELTA_PAIR_H_ -#define CPP_DYNAMICCOLOR_TONE_DELTA_PAIR_H_ - -#include "cpp/dynamiccolor/dynamic_color.h" - -namespace material_color_utilities { - -/** - * Describes the different in tone between colors. - */ -enum class TonePolarity { kDarker, kLighter, kNearer, kFarther }; - -/** - * Documents a constraint between two DynamicColors, in which their tones must - * have a certain distance from each other. - * - * Prefer a DynamicColor with a background, this is for special cases when - * designers want tonal distance, literally contrast, between two colors that - * don't have a background / foreground relationship or a contrast guarantee. - */ -struct ToneDeltaPair { - DynamicColor role_a_; - DynamicColor role_b_; - double delta_; - TonePolarity polarity_; - bool stay_together_; - - /** - * Documents a constraint in tone distance between two DynamicColors. - * - * The polarity is an adjective that describes "A", compared to "B". - * - * For instance, ToneDeltaPair(A, B, 15, 'darker', stayTogether) states that - * A's tone should be at least 15 darker than B's. - * - * 'nearer' and 'farther' describes closeness to the surface roles. For - * instance, ToneDeltaPair(A, B, 10, 'nearer', stayTogether) states that A - * should be 10 lighter than B in light mode, and 10 darker than B in dark - * mode. - * - * @param roleA The first role in a pair. - * @param roleB The second role in a pair. - * @param delta Required difference between tones. Absolute value, negative - * values have undefined behavior. - * @param polarity The relative relation between tones of roleA and roleB, - * as described above. - * @param stayTogether Whether these two roles should stay on the same side of - * the "awkward zone" (T50-59). This is necessary for certain cases where - * one role has two backgrounds. - */ - ToneDeltaPair(DynamicColor role_a, DynamicColor role_b, double delta, - TonePolarity polarity, bool stay_together) - : role_a_(role_a), - role_b_(role_b), - delta_(delta), - polarity_(polarity), - stay_together_(stay_together) {} -}; - -} // namespace material_color_utilities - -#endif // CPP_DYNAMICCOLOR_TONE_DELTA_PAIR_H_ diff --git a/src/material-colors/cpp/dynamiccolor/variant.h b/src/material-colors/cpp/dynamiccolor/variant.h deleted file mode 100644 index 2dc3dd4..0000000 --- a/src/material-colors/cpp/dynamiccolor/variant.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_DYNAMICCOLOR_VARIANT_H_ -#define CPP_DYNAMICCOLOR_VARIANT_H_ - -namespace material_color_utilities { - -enum class Variant { - kMonochrome, - kNeutral, - kTonalSpot, - kVibrant, - kExpressive, - kFidelity, - kContent, - kRainbow, - kFruitSalad, -}; - -} // namespace material_color_utilities - -#endif // CPP_DYNAMICCOLOR_VARIANT_H_ diff --git a/src/material-colors/cpp/palettes/core.h b/src/material-colors/cpp/palettes/core.h deleted file mode 100644 index 66fb030..0000000 --- a/src/material-colors/cpp/palettes/core.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_PALETTES_CORE_H_ -#define CPP_PALETTES_CORE_H_ - -#include "cpp/palettes/tones.h" - -namespace material_color_utilities { - -/** - * Comprises foundational palettes to build a color scheme. Generated from a - * source color, these palettes will then be part of a [DynamicScheme] together - * with appearance preferences. -*/ -typedef struct { - TonalPalette primary; - TonalPalette secondary; - TonalPalette tertiary; - TonalPalette neutral; - TonalPalette neutral_variant; -} CorePalettes; - -} // namespace material_color_utilities - -#endif // CPP_PALETTES_CORE_H_ diff --git a/src/material-colors/cpp/palettes/tones.cpp b/src/material-colors/cpp/palettes/tones.cpp deleted file mode 100644 index cc5d1b9..0000000 --- a/src/material-colors/cpp/palettes/tones.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/palettes/tones.h" - -#include - -#include "cpp/cam/cam.h" -#include "cpp/cam/hct.h" - -namespace material_color_utilities { - -TonalPalette::TonalPalette(Argb argb) : key_color_(0.0, 0.0, 0.0) { - Cam cam = CamFromInt(argb); - hue_ = cam.hue; - chroma_ = cam.chroma; - key_color_ = KeyColor(cam.hue, cam.chroma).create(); -} - -TonalPalette::TonalPalette(Hct hct) - : key_color_(hct.get_hue(), hct.get_chroma(), hct.get_tone()) { - hue_ = hct.get_hue(); - chroma_ = hct.get_chroma(); -} - -TonalPalette::TonalPalette(double hue, double chroma) - : key_color_(hue, chroma, 0.0) { - hue_ = hue; - chroma_ = chroma; - key_color_ = KeyColor(hue, chroma).create(); -} - -TonalPalette::TonalPalette(double hue, double chroma, Hct key_color) - : key_color_(key_color.get_hue(), key_color.get_chroma(), - key_color.get_tone()) { - hue_ = hue; - chroma_ = chroma; -} - -Argb TonalPalette::get(double tone) const { - return IntFromHcl(hue_, chroma_, tone); -} - -KeyColor::KeyColor(double hue, double requested_chroma) - : hue_(hue), requested_chroma_(requested_chroma) {} - -Hct KeyColor::create() { - // Pivot around T50 because T50 has the most chroma available, on - // average. Thus it is most likely to have a direct answer. - const int pivot_tone = 50; - const int tone_step_size = 1; - // Epsilon to accept values slightly higher than the requested chroma. - const double epsilon = 0.01; - - // Binary search to find the tone that can provide a chroma that is closest - // to the requested chroma. - int lower_tone = 0; - int upper_tone = 100; - while (lower_tone < upper_tone) { - const int mid_tone = (lower_tone + upper_tone) / 2; - bool is_ascending = - max_chroma(mid_tone) < max_chroma(mid_tone + tone_step_size); - bool sufficient_chroma = - max_chroma(mid_tone) >= requested_chroma_ - epsilon; - - if (sufficient_chroma) { - // Either range [lower_tone, mid_tone] or [mid_tone, upper_tone] has - // the answer, so search in the range that is closer the pivot tone. - if (abs(lower_tone - pivot_tone) < abs(upper_tone - pivot_tone)) { - upper_tone = mid_tone; - } else { - if (lower_tone == mid_tone) { - return Hct(hue_, requested_chroma_, lower_tone); - } - lower_tone = mid_tone; - } - } else { - // As there's no sufficient chroma in the mid_tone, follow the direction - // to the chroma peak. - if (is_ascending) { - lower_tone = mid_tone + tone_step_size; - } else { - // Keep mid_tone for potential chroma peak. - upper_tone = mid_tone; - } - } - } - - return Hct(hue_, requested_chroma_, lower_tone); -} - -double KeyColor::max_chroma(double tone) { - auto it = chroma_cache_.find(tone); - if (it != chroma_cache_.end()) { - return it->second; - } - - double chroma = Hct(hue_, max_chroma_value_, tone).get_chroma(); - chroma_cache_[tone] = chroma; - return chroma; -}; - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/palettes/tones.h b/src/material-colors/cpp/palettes/tones.h deleted file mode 100644 index 2c4e64d..0000000 --- a/src/material-colors/cpp/palettes/tones.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_PALETTES_TONES_H_ -#define CPP_PALETTES_TONES_H_ - -#include - -#include "cpp/cam/hct.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -class TonalPalette { - public: - explicit TonalPalette(Argb argb); - TonalPalette(Hct hct); - TonalPalette(double hue, double chroma); - TonalPalette(double hue, double chroma, Hct key_color); - - /** - * Returns the color for a given tone in this palette. - * - * @param tone 0.0 <= tone <= 100.0 - * @return a color as an integer, in ARGB format. - */ - Argb get(double tone) const; - - double get_hue() const { return hue_; } - double get_chroma() const { return chroma_; } - Hct get_key_color() const { return key_color_; } - - private: - double hue_; - double chroma_; - Hct key_color_; -}; - -/** - * Key color is a color that represents the hue and chroma of a tonal palette - */ -class KeyColor { - public: - KeyColor(double hue, double requested_chroma); - /** - * Creates a key color from a [hue] and a [chroma]. - * The key color is the first tone, starting from T50, matching the given hue - * and chroma. - * - * @return Key color in Hct. - */ - Hct create(); - - private: - const double max_chroma_value_ = 200.0; - double hue_; - double requested_chroma_; - // Cache that maps tone to max chroma to avoid duplicated HCT calculation. - std::unordered_map chroma_cache_; - - double max_chroma(double tone); -}; - -} // namespace material_color_utilities -#endif // CPP_PALETTES_TONES_H_ diff --git a/src/material-colors/cpp/palettes/tones_test.cpp b/src/material-colors/cpp/palettes/tones_test.cpp deleted file mode 100644 index 8da3d11..0000000 --- a/src/material-colors/cpp/palettes/tones_test.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/palettes/tones.h" - -#include "testing/base/public/gunit.h" -#include "cpp/cam/hct.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -namespace { - -TEST(TonesTest, Blue) { - Argb color = 0xff0000ff; - TonalPalette tonal_palette = TonalPalette(color); - EXPECT_EQ(HexFromArgb(tonal_palette.get(100)), "ffffffff"); - EXPECT_EQ(HexFromArgb(tonal_palette.get(95)), "fff1efff"); - EXPECT_EQ(HexFromArgb(tonal_palette.get(90)), "ffe0e0ff"); - EXPECT_EQ(HexFromArgb(tonal_palette.get(80)), "ffbec2ff"); - EXPECT_EQ(HexFromArgb(tonal_palette.get(70)), "ff9da3ff"); - EXPECT_EQ(HexFromArgb(tonal_palette.get(60)), "ff7c84ff"); - EXPECT_EQ(HexFromArgb(tonal_palette.get(50)), "ff5a64ff"); - EXPECT_EQ(HexFromArgb(tonal_palette.get(40)), "ff343dff"); - EXPECT_EQ(HexFromArgb(tonal_palette.get(30)), "ff0000ef"); - EXPECT_EQ(HexFromArgb(tonal_palette.get(20)), "ff0001ac"); - EXPECT_EQ(HexFromArgb(tonal_palette.get(10)), "ff00006e"); - EXPECT_EQ(HexFromArgb(tonal_palette.get(0)), "ff000000"); -} - -TEST(KeyColorTests, ExactChromaAvailable) { - // Requested chroma is exactly achievable at a certain tone. - TonalPalette palette = TonalPalette(50.0, 60.0); - Hct result = palette.get_key_color(); - - EXPECT_NEAR(result.get_hue(), 50.0, 10.0); - EXPECT_NEAR(result.get_chroma(), 60.0, 0.5); - // Tone might vary, but should be within the range from 0 to 100. - EXPECT_GT(result.get_tone(), 0); - EXPECT_LT(result.get_tone(), 100); -} - -TEST(KeyColorTests, UnusuallyHighChroma) { - // Requested chroma is above what is achievable. For Hue 149, chroma peak - // is 89.6 at Tone 87.9. The result key color's chroma should be close to the - // chroma peak. - TonalPalette palette = TonalPalette(149.0, 200.0); - Hct result = palette.get_key_color(); - - EXPECT_NEAR(result.get_hue(), 149.0, 10.0); - EXPECT_GT(result.get_chroma(), 89.0); - // Tone might vary, but should be within the range from 0 to 100. - EXPECT_GT(result.get_tone(), 0); - EXPECT_LT(result.get_tone(), 100); -} - -TEST(KeyColorTests, UnusuallyLowChroma) { - // By definition, the key color should be the first tone, starting from Tone - // 50, matching the given hue and chroma. When requesting a very low chroma, - // the result should be close to Tone 50, since most tones can produce a low - // chroma. - TonalPalette palette = TonalPalette(50.0, 3.0); - Hct result = palette.get_key_color(); - - // Higher error tolerance for hue when the requested chroma is unusually low. - EXPECT_NEAR(result.get_hue(), 50.0, 10.0); - EXPECT_NEAR(result.get_chroma(), 3.0, 0.5); - EXPECT_NEAR(result.get_tone(), 50.0, 0.5); -} - -} // namespace -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/quantize/celebi.cpp b/src/material-colors/cpp/quantize/celebi.cpp deleted file mode 100644 index 857979e..0000000 --- a/src/material-colors/cpp/quantize/celebi.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/quantize/celebi.h" - -#include -#include -#include -#include - -#include "cpp/quantize/wsmeans.h" -#include "cpp/quantize/wu.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -QuantizerResult QuantizeCelebi(const std::vector& pixels, - uint16_t max_colors) { - if (max_colors == 0 || pixels.empty()) { - return QuantizerResult(); - } - - if (max_colors > 256) { - max_colors = 256; - } - - int pixel_count = pixels.size(); - - std::vector opaque_pixels; - opaque_pixels.reserve(pixel_count); - for (int i = 0; i < pixel_count; i++) { - int pixel = pixels[i]; - if (!IsOpaque(pixel)) { - continue; - } - opaque_pixels.push_back(pixel); - } - - std::vector wu_result = QuantizeWu(opaque_pixels, max_colors); - - QuantizerResult result = - QuantizeWsmeans(opaque_pixels, wu_result, max_colors); - - return result; -} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/quantize/celebi.h b/src/material-colors/cpp/quantize/celebi.h deleted file mode 100644 index f2f9d57..0000000 --- a/src/material-colors/cpp/quantize/celebi.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_QUANTIZE_CELEBI_H_ -#define CPP_QUANTIZE_CELEBI_H_ - -#include -#include - -#include - -#include "cpp/quantize/wsmeans.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -QuantizerResult QuantizeCelebi(const std::vector& pixels, - uint16_t max_colors); - -} // namespace material_color_utilities - -#endif // CPP_QUANTIZE_CELEBI_H_ diff --git a/src/material-colors/cpp/quantize/celebi_test.cpp b/src/material-colors/cpp/quantize/celebi_test.cpp deleted file mode 100644 index 4317764..0000000 --- a/src/material-colors/cpp/quantize/celebi_test.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/quantize/celebi.h" - -#include -#include - -#include "testing/base/public/gunit.h" - -namespace material_color_utilities { - -namespace { - -TEST(CelebiTest, FullImage) { - std::vector pixels(12544); - for (size_t i = 0; i < pixels.size(); i++) { - // Creates 128 distinct colors - pixels[i] = i % 8000; - } - - int iterations = 1; - uint16_t max_colors = 128; - double sum = 0; - - for (int i = 0; i < iterations; i++) { - clock_t begin = clock(); - QuantizeCelebi(pixels, max_colors); - clock_t end = clock(); - double time_spent = static_cast(end - begin) / CLOCKS_PER_SEC; - sum += time_spent; - } -} - -TEST(CelebiTest, OneRed) { - std::vector pixels; - pixels.push_back(0xffff0000); - QuantizerResult result = QuantizeCelebi(pixels, 256); - EXPECT_EQ(result.color_to_count.size(), 1u); - EXPECT_EQ(result.color_to_count[0xffff0000], 1u); -} - -TEST(CelebiTest, OneGreen) { - std::vector pixels; - pixels.push_back(0xff00ff00); - QuantizerResult result = QuantizeCelebi(pixels, 256); - EXPECT_EQ(result.color_to_count.size(), 1u); - EXPECT_EQ(result.color_to_count[0xff00ff00], 1u); -} - -TEST(CelebiTest, OneBlue) { - std::vector pixels; - pixels.push_back(0xff0000ff); - QuantizerResult result = QuantizeCelebi(pixels, 256); - EXPECT_EQ(result.color_to_count.size(), 1u); - EXPECT_EQ(result.color_to_count[0xff0000ff], 1u); -} - -TEST(CelebiTest, FiveBlue) { - std::vector pixels; - for (int i = 0; i < 5; i++) { - pixels.push_back(0xff0000ff); - } - QuantizerResult result = QuantizeCelebi(pixels, 256); - EXPECT_EQ(result.color_to_count.size(), 1u); - EXPECT_EQ(result.color_to_count[0xff0000ff], 5u); -} - -TEST(CelebiTest, OneRedOneGreenOneBlue) { - std::vector pixels; - pixels.push_back(0xffff0000); - pixels.push_back(0xff00ff00); - pixels.push_back(0xff0000ff); - QuantizerResult result = QuantizeCelebi(pixels, 256); - EXPECT_EQ(result.color_to_count.size(), 3u); - EXPECT_EQ(result.color_to_count[0xffff0000], 1u); - EXPECT_EQ(result.color_to_count[0xff00ff00], 1u); - EXPECT_EQ(result.color_to_count[0xff0000ff], 1u); -} - -TEST(CelebiTest, TwoRedThreeGreen) { - std::vector pixels; - pixels.push_back(0xffff0000); - pixels.push_back(0xffff0000); - pixels.push_back(0xff00ff00); - pixels.push_back(0xff00ff00); - pixels.push_back(0xff00ff00); - QuantizerResult result = QuantizeCelebi(pixels, 256); - EXPECT_EQ(result.color_to_count.size(), 2u); - EXPECT_EQ(result.color_to_count[0xffff0000], 2u); - EXPECT_EQ(result.color_to_count[0xff00ff00], 3u); -} - -TEST(CelebiTest, NoColors) { - std::vector pixels; - pixels.push_back(0xFFFFFFFF); - QuantizerResult result = QuantizeCelebi(pixels, 0); - EXPECT_TRUE(result.color_to_count.empty()); - EXPECT_TRUE(result.input_pixel_to_cluster_pixel.empty()); -} - -TEST(CelebiTest, SingleTransparent) { - std::vector pixels; - pixels.push_back(0x20F93013); - QuantizerResult result = QuantizeCelebi(pixels, 1); - EXPECT_TRUE(result.color_to_count.empty()); - EXPECT_TRUE(result.input_pixel_to_cluster_pixel.empty()); -} - -TEST(CelebiTest, TooManyColors) { - std::vector pixels; - QuantizerResult result = QuantizeCelebi(pixels, 32767); - EXPECT_TRUE(result.color_to_count.empty()); - EXPECT_TRUE(result.input_pixel_to_cluster_pixel.empty()); -} - -} // namespace -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/quantize/lab.cpp b/src/material-colors/cpp/quantize/lab.cpp deleted file mode 100644 index caa575b..0000000 --- a/src/material-colors/cpp/quantize/lab.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/quantize/lab.h" - -#include - -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -Argb IntFromLab(const Lab lab) { - double e = 216.0 / 24389.0; - double kappa = 24389.0 / 27.0; - double ke = 8.0; - - double fy = (lab.l + 16.0) / 116.0; - double fx = (lab.a / 500.0) + fy; - double fz = fy - (lab.b / 200.0); - double fx3 = fx * fx * fx; - double x_normalized = (fx3 > e) ? fx3 : (116.0 * fx - 16.0) / kappa; - double y_normalized = (lab.l > ke) ? fy * fy * fy : (lab.l / kappa); - double fz3 = fz * fz * fz; - double z_normalized = (fz3 > e) ? fz3 : (116.0 * fz - 16.0) / kappa; - double x = x_normalized * kWhitePointD65[0]; - double y = y_normalized * kWhitePointD65[1]; - double z = z_normalized * kWhitePointD65[2]; - - // intFromXyz - double rL = 3.2406 * x - 1.5372 * y - 0.4986 * z; - double gL = -0.9689 * x + 1.8758 * y + 0.0415 * z; - double bL = 0.0557 * x - 0.2040 * y + 1.0570 * z; - - int red = Delinearized(rL); - int green = Delinearized(gL); - int blue = Delinearized(bL); - - return ArgbFromRgb(red, green, blue); -} - -Lab LabFromInt(const Argb argb) { - int red = (argb & 0x00ff0000) >> 16; - int green = (argb & 0x0000ff00) >> 8; - int blue = (argb & 0x000000ff); - double red_l = Linearized(red); - double green_l = Linearized(green); - double blue_l = Linearized(blue); - double x = 0.41233895 * red_l + 0.35762064 * green_l + 0.18051042 * blue_l; - double y = 0.2126 * red_l + 0.7152 * green_l + 0.0722 * blue_l; - double z = 0.01932141 * red_l + 0.11916382 * green_l + 0.95034478 * blue_l; - double y_normalized = y / kWhitePointD65[1]; - double e = 216.0 / 24389.0; - double kappa = 24389.0 / 27.0; - double fy; - if (y_normalized > e) { - fy = pow(y_normalized, 1.0 / 3.0); - } else { - fy = (kappa * y_normalized + 16) / 116; - } - - double x_normalized = x / kWhitePointD65[0]; - double fx; - if (x_normalized > e) { - fx = pow(x_normalized, 1.0 / 3.0); - } else { - fx = (kappa * x_normalized + 16) / 116; - } - - double z_normalized = z / kWhitePointD65[2]; - double fz; - if (z_normalized > e) { - fz = pow(z_normalized, 1.0 / 3.0); - } else { - fz = (kappa * z_normalized + 16) / 116; - } - - double l = 116.0 * fy - 16; - double a = 500.0 * (fx - fy); - double b = 200.0 * (fy - fz); - return {l, a, b}; -} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/quantize/lab.h b/src/material-colors/cpp/quantize/lab.h deleted file mode 100644 index b983c73..0000000 --- a/src/material-colors/cpp/quantize/lab.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_QUANTIZE_LAB_H_ -#define CPP_QUANTIZE_LAB_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -struct Lab { - double l = 0.0; - double a = 0.0; - double b = 0.0; - - double DeltaE(const Lab& lab) { - double d_l = l - lab.l; - double d_a = a - lab.a; - double d_b = b - lab.b; - return (d_l * d_l) + (d_a * d_a) + (d_b * d_b); - } - - std::string ToString() { - return "Lab: L* " + std::to_string(l) + " a* " + std::to_string(a) + - " b* " + std::to_string(b); - } -}; - -Argb IntFromLab(const Lab lab); -Lab LabFromInt(const Argb argb); - -} // namespace material_color_utilities -#endif // CPP_QUANTIZE_LAB_H_ diff --git a/src/material-colors/cpp/quantize/wsmeans.cpp b/src/material-colors/cpp/quantize/wsmeans.cpp deleted file mode 100644 index 7c6c2b6..0000000 --- a/src/material-colors/cpp/quantize/wsmeans.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/quantize/wsmeans.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpp/quantize/lab.h" - -constexpr int kMaxIterations = 100; -constexpr double kMinDeltaE = 3.0; - -namespace material_color_utilities { - -struct Swatch { - Argb argb = 0; - int population = 0; - - bool operator<(const Swatch& b) const { return population > b.population; } -}; - -struct DistanceToIndex { - double distance = 0.0; - int index = 0; - - bool operator<(const DistanceToIndex& a) const { - return distance < a.distance; - } -}; - -QuantizerResult QuantizeWsmeans(const std::vector& input_pixels, - const std::vector& starting_clusters, - uint16_t max_colors) { - if (max_colors == 0 || input_pixels.empty()) { - return QuantizerResult(); - } - - if (max_colors > 256) { - // If colors is outside the range, just set it the max. - max_colors = 256; - } - - uint32_t pixel_count = input_pixels.size(); - //absl::flat_hash_map pixel_to_count; - std::unordered_map pixel_to_count; - - std::vector pixels; - pixels.reserve(pixel_count); - std::vector points; - points.reserve(pixel_count); - for (Argb pixel : input_pixels) { - // tested over 1000 runs with 128 colors, 12544 (112 x 112) - // std::map 10.9 ms - // std::unordered_map 10.2 ms - // absl::btree_map 9.0 ms - // absl::flat_hash_map 8.0 ms - auto it = pixel_to_count.find(pixel); - if (it != pixel_to_count.end()) { - it->second++; - - } else { - pixels.push_back(pixel); - points.push_back(LabFromInt(pixel)); - pixel_to_count[pixel] = 1; - } - } - - int cluster_count = std::min((int)max_colors, (int)points.size()); - - if (!starting_clusters.empty()) { - cluster_count = std::min(cluster_count, (int)starting_clusters.size()); - } - - int pixel_count_sums[256] = {}; - std::vector clusters; - clusters.reserve(starting_clusters.size()); - for (int argb : starting_clusters) { - clusters.push_back(LabFromInt(argb)); - } - - srand(42688); - int additional_clusters_needed = cluster_count - clusters.size(); - if (starting_clusters.empty() && additional_clusters_needed > 0) { - for (int i = 0; i < additional_clusters_needed; i++) { - // Adds a random Lab color to clusters. - double l = rand() / (static_cast(RAND_MAX)) * (100.0) + 0.0; - double a = - rand() / (static_cast(RAND_MAX)) * (100.0 - -100.0) - 100.0; - double b = - rand() / (static_cast(RAND_MAX)) * (100.0 - -100.0) - 100.0; - clusters.push_back({l, a, b}); - } - } - - std::vector cluster_indices; - cluster_indices.reserve(points.size()); - - srand(42688); - for (size_t i = 0; i < points.size(); i++) { - cluster_indices.push_back(rand() % cluster_count); - } - - std::vector> index_matrix( - cluster_count, std::vector(cluster_count, 0)); - - std::vector> distance_to_index_matrix( - cluster_count, std::vector(cluster_count)); - - for (int iteration = 0; iteration < kMaxIterations; iteration++) { - // Calculate cluster distances - for (int i = 0; i < cluster_count; i++) { - distance_to_index_matrix[i][i].distance = 0; - distance_to_index_matrix[i][i].index = i; - for (int j = i + 1; j < cluster_count; j++) { - double distance = clusters[i].DeltaE(clusters[j]); - - distance_to_index_matrix[j][i].distance = distance; - distance_to_index_matrix[j][i].index = i; - distance_to_index_matrix[i][j].distance = distance; - distance_to_index_matrix[i][j].index = j; - } - - std::vector row = distance_to_index_matrix[i]; - std::sort(row.begin(), row.end()); - - for (int j = 0; j < cluster_count; j++) { - index_matrix[i][j] = row[j].index; - } - } - - // Reassign points - bool color_moved = false; - for (size_t i = 0; i < points.size(); i++) { - Lab point = points[i]; - - int previous_cluster_index = cluster_indices[i]; - Lab previous_cluster = clusters[previous_cluster_index]; - double previous_distance = point.DeltaE(previous_cluster); - double minimum_distance = previous_distance; - int new_cluster_index = -1; - - for (int j = 0; j < cluster_count; j++) { - if (distance_to_index_matrix[previous_cluster_index][j].distance >= - 4 * previous_distance) { - continue; - } - double distance = point.DeltaE(clusters[j]); - if (distance < minimum_distance) { - minimum_distance = distance; - new_cluster_index = j; - } - } - if (new_cluster_index != -1) { - double distanceChange = - abs(sqrt(minimum_distance) - sqrt(previous_distance)); - if (distanceChange > kMinDeltaE) { - color_moved = true; - cluster_indices[i] = new_cluster_index; - } - } - } - - if (!color_moved && (iteration != 0)) { - break; - } - - // Recalculate cluster centers - double component_a_sums[256] = {}; - double component_b_sums[256] = {}; - double component_c_sums[256] = {}; - for (int i = 0; i < cluster_count; i++) { - pixel_count_sums[i] = 0; - } - - for (size_t i = 0; i < points.size(); i++) { - int clusterIndex = cluster_indices[i]; - Lab point = points[i]; - int count = pixel_to_count[pixels[i]]; - - pixel_count_sums[clusterIndex] += count; - component_a_sums[clusterIndex] += (point.l * count); - component_b_sums[clusterIndex] += (point.a * count); - component_c_sums[clusterIndex] += (point.b * count); - } - - for (int i = 0; i < cluster_count; i++) { - int count = pixel_count_sums[i]; - if (count == 0) { - clusters[i] = {0, 0, 0}; - continue; - } - double a = component_a_sums[i] / count; - double b = component_b_sums[i] / count; - double c = component_c_sums[i] / count; - clusters[i] = {a, b, c}; - } - } - - std::vector swatches; - std::vector cluster_argbs; - std::vector all_cluster_argbs; - for (int i = 0; i < cluster_count; i++) { - Argb possible_new_cluster = IntFromLab(clusters[i]); - all_cluster_argbs.push_back(possible_new_cluster); - - int count = pixel_count_sums[i]; - if (count == 0) { - continue; - } - int use_new_cluster = 1; - for (size_t j = 0; j < swatches.size(); j++) { - if (swatches[j].argb == possible_new_cluster) { - swatches[j].population += count; - use_new_cluster = 0; - break; - } - } - - if (use_new_cluster == 0) { - continue; - } - cluster_argbs.push_back(possible_new_cluster); - swatches.push_back({possible_new_cluster, count}); - } - std::sort(swatches.begin(), swatches.end()); - - // Constructs the quantizer result to return. - - std::map color_to_count; - for (size_t i = 0; i < swatches.size(); i++) { - color_to_count[swatches[i].argb] = swatches[i].population; - } - - std::map input_pixel_to_cluster_pixel; - for (size_t i = 0; i < points.size(); i++) { - int pixel = pixels[i]; - int cluster_index = cluster_indices[i]; - int cluster_argb = all_cluster_argbs[cluster_index]; - input_pixel_to_cluster_pixel[pixel] = cluster_argb; - } - - return {color_to_count, input_pixel_to_cluster_pixel}; -} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/quantize/wsmeans.h b/src/material-colors/cpp/quantize/wsmeans.h deleted file mode 100644 index 807ef72..0000000 --- a/src/material-colors/cpp/quantize/wsmeans.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_QUANTIZE_WSMEANS_H_ -#define CPP_QUANTIZE_WSMEANS_H_ -#include - -#include -#include - -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -struct QuantizerResult { - std::map color_to_count; - std::map input_pixel_to_cluster_pixel; -}; - -QuantizerResult QuantizeWsmeans(const std::vector& input_pixels, - const std::vector& starting_clusters, - uint16_t max_colors); -} // namespace material_color_utilities - -#endif // CPP_QUANTIZE_WSMEANS_H_ diff --git a/src/material-colors/cpp/quantize/wsmeans_test.cpp b/src/material-colors/cpp/quantize/wsmeans_test.cpp deleted file mode 100644 index 083cdd4..0000000 --- a/src/material-colors/cpp/quantize/wsmeans_test.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/quantize/wsmeans.h" - -#include - -#include "testing/base/public/gunit.h" - -namespace material_color_utilities { - -namespace { -TEST(WsmeansTest, FullImage) { - std::vector pixels(12544); - for (size_t i = 0; i < pixels.size(); i++) { - // Creates 128 distinct colors - pixels[i] = i % 8000; - } - std::vector starting_clusters; - - int iterations = 1; - int max_colors = 128; - - double sum = 0; - - for (int i = 0; i < iterations; i++) { - clock_t begin = clock(); - QuantizeWsmeans(pixels, starting_clusters, max_colors); - clock_t end = clock(); - double time_spent = static_cast(end - begin) / CLOCKS_PER_SEC; - sum += time_spent; - } -} - -TEST(WsmeansTest, OneRedAndO) { - std::vector pixels; - pixels.push_back(0xff141216); - std::vector starting_clusters; - QuantizerResult result = QuantizeWsmeans(pixels, starting_clusters, 256); - EXPECT_EQ(result.color_to_count.size(), 1u); - EXPECT_EQ(result.color_to_count[0xff141216], 1u); -} - -TEST(WsmeansTest, OneRed) { - std::vector pixels; - pixels.push_back(0xffff0000); - std::vector starting_clusters; - QuantizerResult result = QuantizeWsmeans(pixels, starting_clusters, 256); - EXPECT_EQ(result.color_to_count.size(), 1u); - EXPECT_EQ(result.color_to_count[0xffff0000], 1u); -} - -TEST(WsmeansTest, OneGreen) { - std::vector pixels; - pixels.push_back(0xff00ff00); - std::vector starting_clusters; - QuantizerResult result = QuantizeWsmeans(pixels, starting_clusters, 256); - EXPECT_EQ(result.color_to_count.size(), 1u); - EXPECT_EQ(result.color_to_count[0xff00ff00], 1u); -} - -TEST(WsmeansTest, OneBlue) { - std::vector pixels; - pixels.push_back(0xff0000ff); - std::vector starting_clusters; - QuantizerResult result = QuantizeWsmeans(pixels, starting_clusters, 256); - EXPECT_EQ(result.color_to_count.size(), 1u); - EXPECT_EQ(result.color_to_count[0xff0000ff], 1u); -} - -TEST(WsmeansTest, FiveBlue) { - std::vector pixels; - for (int i = 0; i < 5; i++) { - pixels.push_back(0xff0000ff); - } - std::vector starting_clusters; - QuantizerResult result = QuantizeWsmeans(pixels, starting_clusters, 256); - EXPECT_EQ(result.color_to_count.size(), 1u); - EXPECT_EQ(result.color_to_count[0xff0000ff], 5u); -} - -} // namespace -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/quantize/wu.cpp b/src/material-colors/cpp/quantize/wu.cpp deleted file mode 100644 index a1dc0df..0000000 --- a/src/material-colors/cpp/quantize/wu.cpp +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/quantize/wu.h" - -#include - -#include -#include -#include -#include - -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -struct Box { - int r0 = 0; - int r1 = 0; - int g0 = 0; - int g1 = 0; - int b0 = 0; - int b1 = 0; - int vol = 0; -}; - -enum class Direction { - kRed, - kGreen, - kBlue, -}; - -constexpr int kIndexBits = 5; -constexpr int kIndexCount = ((1 << kIndexBits) + 1); -constexpr int kTotalSize = (kIndexCount * kIndexCount * kIndexCount); -constexpr int kMaxColors = 256; - -using IntArray = std::vector; -using DoubleArray = std::vector; - -int GetIndex(int r, int g, int b) { - return (r << (kIndexBits * 2)) + (r << (kIndexBits + 1)) + (g << kIndexBits) + - r + g + b; -} - -void ConstructHistogram(const std::vector& pixels, IntArray& weights, - IntArray& m_r, IntArray& m_g, IntArray& m_b, - DoubleArray& moments) { - for (size_t i = 0; i < pixels.size(); i++) { - Argb pixel = pixels[i]; - int red = RedFromInt(pixel); - int green = GreenFromInt(pixel); - int blue = BlueFromInt(pixel); - - int bits_to_remove = 8 - kIndexBits; - int index_r = (red >> bits_to_remove) + 1; - int index_g = (green >> bits_to_remove) + 1; - int index_b = (blue >> bits_to_remove) + 1; - int index = GetIndex(index_r, index_g, index_b); - - weights[index]++; - m_r[index] += red; - m_g[index] += green; - m_b[index] += blue; - moments[index] += (red * red) + (green * green) + (blue * blue); - } -} - -void ComputeMoments(IntArray& weights, IntArray& m_r, IntArray& m_g, - IntArray& m_b, DoubleArray& moments) { - for (int r = 1; r < kIndexCount; r++) { - int64_t area[kIndexCount] = {}; - int64_t area_r[kIndexCount] = {}; - int64_t area_g[kIndexCount] = {}; - int64_t area_b[kIndexCount] = {}; - double area_2[kIndexCount] = {}; - for (int g = 1; g < kIndexCount; g++) { - int64_t line = 0; - int64_t line_r = 0; - int64_t line_g = 0; - int64_t line_b = 0; - double line_2 = 0.0; - for (int b = 1; b < kIndexCount; b++) { - int index = GetIndex(r, g, b); - line += weights[index]; - line_r += m_r[index]; - line_g += m_g[index]; - line_b += m_b[index]; - line_2 += moments[index]; - - area[b] += line; - area_r[b] += line_r; - area_g[b] += line_g; - area_b[b] += line_b; - area_2[b] += line_2; - - int previous_index = GetIndex(r - 1, g, b); - weights[index] = weights[previous_index] + area[b]; - m_r[index] = m_r[previous_index] + area_r[b]; - m_g[index] = m_g[previous_index] + area_g[b]; - m_b[index] = m_b[previous_index] + area_b[b]; - moments[index] = moments[previous_index] + area_2[b]; - } - } - } -} - -int64_t Top(const Box& cube, const Direction direction, const int position, - const IntArray& moment) { - if (direction == Direction::kRed) { - return (moment[GetIndex(position, cube.g1, cube.b1)] - - moment[GetIndex(position, cube.g1, cube.b0)] - - moment[GetIndex(position, cube.g0, cube.b1)] + - moment[GetIndex(position, cube.g0, cube.b0)]); - } else if (direction == Direction::kGreen) { - return (moment[GetIndex(cube.r1, position, cube.b1)] - - moment[GetIndex(cube.r1, position, cube.b0)] - - moment[GetIndex(cube.r0, position, cube.b1)] + - moment[GetIndex(cube.r0, position, cube.b0)]); - } else { - return (moment[GetIndex(cube.r1, cube.g1, position)] - - moment[GetIndex(cube.r1, cube.g0, position)] - - moment[GetIndex(cube.r0, cube.g1, position)] + - moment[GetIndex(cube.r0, cube.g0, position)]); - } -} - -int64_t Bottom(const Box& cube, const Direction direction, - const IntArray& moment) { - if (direction == Direction::kRed) { - return (-moment[GetIndex(cube.r0, cube.g1, cube.b1)] + - moment[GetIndex(cube.r0, cube.g1, cube.b0)] + - moment[GetIndex(cube.r0, cube.g0, cube.b1)] - - moment[GetIndex(cube.r0, cube.g0, cube.b0)]); - } else if (direction == Direction::kGreen) { - return (-moment[GetIndex(cube.r1, cube.g0, cube.b1)] + - moment[GetIndex(cube.r1, cube.g0, cube.b0)] + - moment[GetIndex(cube.r0, cube.g0, cube.b1)] - - moment[GetIndex(cube.r0, cube.g0, cube.b0)]); - } else { - return (-moment[GetIndex(cube.r1, cube.g1, cube.b0)] + - moment[GetIndex(cube.r1, cube.g0, cube.b0)] + - moment[GetIndex(cube.r0, cube.g1, cube.b0)] - - moment[GetIndex(cube.r0, cube.g0, cube.b0)]); - } -} - -int64_t Vol(const Box& cube, const IntArray& moment) { - return (moment[GetIndex(cube.r1, cube.g1, cube.b1)] - - moment[GetIndex(cube.r1, cube.g1, cube.b0)] - - moment[GetIndex(cube.r1, cube.g0, cube.b1)] + - moment[GetIndex(cube.r1, cube.g0, cube.b0)] - - moment[GetIndex(cube.r0, cube.g1, cube.b1)] + - moment[GetIndex(cube.r0, cube.g1, cube.b0)] + - moment[GetIndex(cube.r0, cube.g0, cube.b1)] - - moment[GetIndex(cube.r0, cube.g0, cube.b0)]); -} - -double Variance(const Box& cube, const IntArray& weights, const IntArray& m_r, - const IntArray& m_g, const IntArray& m_b, - const DoubleArray& moments) { - double dr = Vol(cube, m_r); - double dg = Vol(cube, m_g); - double db = Vol(cube, m_b); - double xx = moments[GetIndex(cube.r1, cube.g1, cube.b1)] - - moments[GetIndex(cube.r1, cube.g1, cube.b0)] - - moments[GetIndex(cube.r1, cube.g0, cube.b1)] + - moments[GetIndex(cube.r1, cube.g0, cube.b0)] - - moments[GetIndex(cube.r0, cube.g1, cube.b1)] + - moments[GetIndex(cube.r0, cube.g1, cube.b0)] + - moments[GetIndex(cube.r0, cube.g0, cube.b1)] - - moments[GetIndex(cube.r0, cube.g0, cube.b0)]; - double hypotenuse = dr * dr + dg * dg + db * db; - double volume = Vol(cube, weights); - return xx - hypotenuse / volume; -} - -double Maximize(const Box& cube, const Direction direction, const int first, - const int last, int* cut, const int64_t whole_w, - const int64_t whole_r, const int64_t whole_g, - const int64_t whole_b, const IntArray& weights, - const IntArray& m_r, const IntArray& m_g, const IntArray& m_b) { - int64_t bottom_r = Bottom(cube, direction, m_r); - int64_t bottom_g = Bottom(cube, direction, m_g); - int64_t bottom_b = Bottom(cube, direction, m_b); - int64_t bottom_w = Bottom(cube, direction, weights); - - double max = 0.0; - *cut = -1; - - int64_t half_r, half_g, half_b, half_w; - for (int i = first; i < last; i++) { - half_r = bottom_r + Top(cube, direction, i, m_r); - half_g = bottom_g + Top(cube, direction, i, m_g); - half_b = bottom_b + Top(cube, direction, i, m_b); - half_w = bottom_w + Top(cube, direction, i, weights); - if (half_w == 0) { - continue; - } - - double temp = (static_cast(half_r) * half_r + - static_cast(half_g) * half_g + - static_cast(half_b) * half_b) / - static_cast(half_w); - - half_r = whole_r - half_r; - half_g = whole_g - half_g; - half_b = whole_b - half_b; - half_w = whole_w - half_w; - if (half_w == 0) { - continue; - } - temp += (static_cast(half_r) * half_r + - static_cast(half_g) * half_g + - static_cast(half_b) * half_b) / - static_cast(half_w); - - if (temp > max) { - max = temp; - *cut = i; - } - } - return max; -} - -bool Cut(Box& box1, Box& box2, const IntArray& weights, const IntArray& m_r, - const IntArray& m_g, const IntArray& m_b) { - int64_t whole_r = Vol(box1, m_r); - int64_t whole_g = Vol(box1, m_g); - int64_t whole_b = Vol(box1, m_b); - int64_t whole_w = Vol(box1, weights); - - int cut_r, cut_g, cut_b; - double max_r = - Maximize(box1, Direction::kRed, box1.r0 + 1, box1.r1, &cut_r, whole_w, - whole_r, whole_g, whole_b, weights, m_r, m_g, m_b); - double max_g = - Maximize(box1, Direction::kGreen, box1.g0 + 1, box1.g1, &cut_g, whole_w, - whole_r, whole_g, whole_b, weights, m_r, m_g, m_b); - double max_b = - Maximize(box1, Direction::kBlue, box1.b0 + 1, box1.b1, &cut_b, whole_w, - whole_r, whole_g, whole_b, weights, m_r, m_g, m_b); - - Direction direction; - if (max_r >= max_g && max_r >= max_b) { - direction = Direction::kRed; - if (cut_r < 0) { - return false; - } - } else if (max_g >= max_r && max_g >= max_b) { - direction = Direction::kGreen; - } else { - direction = Direction::kBlue; - } - - box2.r1 = box1.r1; - box2.g1 = box1.g1; - box2.b1 = box1.b1; - - if (direction == Direction::kRed) { - box2.r0 = box1.r1 = cut_r; - box2.g0 = box1.g0; - box2.b0 = box1.b0; - } else if (direction == Direction::kGreen) { - box2.r0 = box1.r0; - box2.g0 = box1.g1 = cut_g; - box2.b0 = box1.b0; - } else { - box2.r0 = box1.r0; - box2.g0 = box1.g0; - box2.b0 = box1.b1 = cut_b; - } - - box1.vol = (box1.r1 - box1.r0) * (box1.g1 - box1.g0) * (box1.b1 - box1.b0); - box2.vol = (box2.r1 - box2.r0) * (box2.g1 - box2.g0) * (box2.b1 - box2.b0); - return true; -} - -std::vector QuantizeWu(const std::vector& pixels, - uint16_t max_colors) { - if (max_colors <= 0 || max_colors > 256 || pixels.empty()) { - return std::vector(); - } - - IntArray weights(kTotalSize, 0); - IntArray moments_red(kTotalSize, 0); - IntArray moments_green(kTotalSize, 0); - IntArray moments_blue(kTotalSize, 0); - DoubleArray moments(kTotalSize, 0.0); - ConstructHistogram(pixels, weights, moments_red, moments_green, moments_blue, - moments); - ComputeMoments(weights, moments_red, moments_green, moments_blue, moments); - - std::vector cubes(kMaxColors); - cubes[0].r0 = cubes[0].g0 = cubes[0].b0 = 0; - cubes[0].r1 = cubes[0].g1 = cubes[0].b1 = kIndexCount - 1; - - std::vector volume_variance(kMaxColors); - int next = 0; - for (int i = 1; i < max_colors; ++i) { - if (Cut(cubes[next], cubes[i], weights, moments_red, moments_green, - moments_blue)) { - volume_variance[next] = - cubes[next].vol > 1 ? Variance(cubes[next], weights, moments_red, - moments_green, moments_blue, moments) - : 0.0; - volume_variance[i] = cubes[i].vol > 1 - ? Variance(cubes[i], weights, moments_red, - moments_green, moments_blue, moments) - : 0.0; - } else { - volume_variance[next] = 0.0; - i--; - } - - next = 0; - double temp = volume_variance[0]; - for (int j = 1; j <= i; j++) { - if (volume_variance[j] > temp) { - temp = volume_variance[j]; - next = j; - } - } - if (temp <= 0.0) { - max_colors = i + 1; - break; - } - } - - std::vector out_colors; - for (int i = 0; i < max_colors; ++i) { - int64_t weight = Vol(cubes[i], weights); - if (weight > 0) { - int32_t red = Vol(cubes[i], moments_red) / weight; - int32_t green = Vol(cubes[i], moments_green) / weight; - int32_t blue = Vol(cubes[i], moments_blue) / weight; - uint32_t argb = ArgbFromRgb(red, green, blue); - out_colors.push_back(argb); - } - } - - return out_colors; -} -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/quantize/wu.h b/src/material-colors/cpp/quantize/wu.h deleted file mode 100644 index 36f496b..0000000 --- a/src/material-colors/cpp/quantize/wu.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_QUANTIZE_WU_H_ -#define CPP_QUANTIZE_WU_H_ - -#include - -#include - -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -std::vector QuantizeWu(const std::vector& pixels, - uint16_t max_colors); -} -#endif // CPP_QUANTIZE_WU_H_ diff --git a/src/material-colors/cpp/quantize/wu_test.cpp b/src/material-colors/cpp/quantize/wu_test.cpp deleted file mode 100644 index 5341e97..0000000 --- a/src/material-colors/cpp/quantize/wu_test.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/quantize/wu.h" - -#include -#include - -#include "testing/base/public/gunit.h" - -namespace material_color_utilities { - -namespace { - -TEST(WuTest, FullImage) { - std::vector pixels(12544); - for (size_t i = 0; i < pixels.size(); i++) { - // Creates 128 distinct colors - pixels[i] = i % 8000; - } - - uint16_t max_colors = 128; - - QuantizeWu(pixels, max_colors); -} - -TEST(WuTest, TwoRedThreeGreen) { - std::vector pixels; - pixels.push_back(0xffff0000); - pixels.push_back(0xffff0000); - pixels.push_back(0xffff0000); - pixels.push_back(0xff00ff00); - pixels.push_back(0xff00ff00); - std::vector result = QuantizeWu(pixels, 256); - EXPECT_EQ(result.size(), 2u); -} - -TEST(WuTest, OneRed) { - std::vector pixels; - pixels.push_back(0xffff0000); - std::vector result = QuantizeWu(pixels, 256); - EXPECT_EQ(result.size(), 1u); - EXPECT_EQ(result[0], 0xffff0000); -} - -TEST(WuTest, OneGreen) { - std::vector pixels; - pixels.push_back(0xff00ff00); - std::vector result = QuantizeWu(pixels, 256); - EXPECT_EQ(result.size(), 1u); - EXPECT_EQ(result[0], 0xff00ff00); -} - -TEST(WuTest, OneBlue) { - std::vector pixels; - pixels.push_back(0xff0000ff); - std::vector result = QuantizeWu(pixels, 256); - EXPECT_EQ(result.size(), 1u); - EXPECT_EQ(result[0], 0xff0000ff); -} - -TEST(WuTest, FiveBlue) { - std::vector pixels; - for (int i = 0; i < 5; i++) { - pixels.push_back(0xff0000ff); - } - std::vector result = QuantizeWu(pixels, 256); - EXPECT_EQ(result.size(), 1u); - EXPECT_EQ(result[0], 0xff0000ff); -} - -TEST(WuTest, OneRedAndO) { - std::vector pixels; - pixels.push_back(0xff141216); - std::vector result = QuantizeWu(pixels, 256); - EXPECT_EQ(result.size(), 1u); - EXPECT_EQ(result[0], 0xff141216); -} - -TEST(WuTest, RedGreenBlue) { - std::vector pixels; - pixels.push_back(0xffff0000); - pixels.push_back(0xff00ff00); - pixels.push_back(0xff0000ff); - std::vector result = QuantizeWu(pixels, 256); - EXPECT_EQ(result.size(), 3u); - EXPECT_EQ(result[0], 0xff0000ff); - EXPECT_EQ(result[1], 0xffff0000); - EXPECT_EQ(result[2], 0xff00ff00); -} - -TEST(WuTest, Testonly) { - std::vector pixels; - pixels.push_back(0xff010203); - pixels.push_back(0xff665544); - pixels.push_back(0xff708090); - pixels.push_back(0xffc0ffee); - pixels.push_back(0xfffedcba); - std::vector result = QuantizeWu(pixels, 256); -} - -} // namespace -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/scheme/scheme_content.cpp b/src/material-colors/cpp/scheme/scheme_content.cpp deleted file mode 100644 index 50347af..0000000 --- a/src/material-colors/cpp/scheme/scheme_content.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/scheme/scheme_content.h" - -#include - -#include "cpp/cam/hct.h" -#include "cpp/dislike/dislike.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" -#include "cpp/dynamiccolor/variant.h" -#include "cpp/palettes/tones.h" -#include "cpp/temperature/temperature_cache.h" - -namespace material_color_utilities { - -SchemeContent::SchemeContent(Hct set_source_color_hct, bool set_is_dark, - double set_contrast_level) - : DynamicScheme( - /*set_source_color_hct:*/ set_source_color_hct, - /*variant:*/ Variant::kContent, - /*contrast_level:*/ set_contrast_level, - /*is_dark:*/ set_is_dark, - /*primary_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), - set_source_color_hct.get_chroma()), - /*secondary_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), - fmax(set_source_color_hct.get_chroma() - 32.0, - set_source_color_hct.get_chroma() * 0.5)), - /*tertiary_palette:*/ - TonalPalette(FixIfDisliked(TemperatureCache(set_source_color_hct) - .GetAnalogousColors(3, 6) - .at(2))), - /*neutral_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), - set_source_color_hct.get_chroma() / 8.0), - /*neutral_variant_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), - set_source_color_hct.get_chroma() / 8.0 + 4.0)) {} - -SchemeContent::SchemeContent(Hct set_source_color_hct, bool set_is_dark) - : SchemeContent::SchemeContent(set_source_color_hct, set_is_dark, 0.0) {} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/scheme/scheme_content.h b/src/material-colors/cpp/scheme/scheme_content.h deleted file mode 100644 index 15377a0..0000000 --- a/src/material-colors/cpp/scheme/scheme_content.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_SCHEME_SCHEME_CONTENT_H_ -#define CPP_SCHEME_SCHEME_CONTENT_H_ - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" - -namespace material_color_utilities { - -struct SchemeContent : public DynamicScheme { - SchemeContent(Hct set_source_color_hct, bool set_is_dark, - double set_contrast_level); - SchemeContent(Hct set_source_color_hct, bool set_is_dark); -}; - -} // namespace material_color_utilities - -#endif // CPP_SCHEME_SCHEME_CONTENT_H_ diff --git a/src/material-colors/cpp/scheme/scheme_expressive.cpp b/src/material-colors/cpp/scheme/scheme_expressive.cpp deleted file mode 100644 index ecc0060..0000000 --- a/src/material-colors/cpp/scheme/scheme_expressive.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/scheme/scheme_expressive.h" - -#include - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" -#include "cpp/dynamiccolor/variant.h" -#include "cpp/palettes/tones.h" - -namespace material_color_utilities { - -const std::vector kHues = {0, 21, 51, 121, 151, 191, 271, 321, 360}; - -const std::vector kSecondaryRotations = {45, 95, 45, 20, 45, - 90, 45, 45, 45}; - -const std::vector kTertiaryRotations = {120, 120, 20, 45, 20, - 15, 20, 120, 120}; - -SchemeExpressive::SchemeExpressive(Hct set_source_color_hct, bool set_is_dark, - double set_contrast_level) - : DynamicScheme( - /*set_source_color_hct:*/ set_source_color_hct, - /*variant:*/ Variant::kExpressive, - /*contrast_level:*/ set_contrast_level, - /*is_dark:*/ set_is_dark, - /*primary_palette:*/ - TonalPalette(set_source_color_hct.get_hue() + 240.0, 40.0), - /*secondary_palette:*/ - TonalPalette(DynamicScheme::GetRotatedHue(set_source_color_hct, kHues, - kSecondaryRotations), - 24.0), - /*tertiary_palette:*/ - TonalPalette(DynamicScheme::GetRotatedHue(set_source_color_hct, kHues, - kTertiaryRotations), - 32.0), - /*neutral_palette:*/ - TonalPalette(set_source_color_hct.get_hue() + 15.0, 8.0), - /*neutral_variant_palette:*/ - TonalPalette(set_source_color_hct.get_hue() + 15, 12.0)) {} - -SchemeExpressive::SchemeExpressive(Hct set_source_color_hct, bool set_is_dark) - : SchemeExpressive::SchemeExpressive(set_source_color_hct, set_is_dark, - 0.0) {} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/scheme/scheme_expressive.h b/src/material-colors/cpp/scheme/scheme_expressive.h deleted file mode 100644 index 92d915f..0000000 --- a/src/material-colors/cpp/scheme/scheme_expressive.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_SCHEME_SCHEME_EXPRESSIVE_H_ -#define CPP_SCHEME_SCHEME_EXPRESSIVE_H_ - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" - -namespace material_color_utilities { - -struct SchemeExpressive : public DynamicScheme { - SchemeExpressive(Hct source_color_hct, bool is_dark, double contrast_level); - SchemeExpressive(Hct source_color_hct, bool is_dark); -}; - -} // namespace material_color_utilities - -#endif // CPP_SCHEME_SCHEME_EXPRESSIVE_H_ diff --git a/src/material-colors/cpp/scheme/scheme_fidelity.cpp b/src/material-colors/cpp/scheme/scheme_fidelity.cpp deleted file mode 100644 index f2f2ca1..0000000 --- a/src/material-colors/cpp/scheme/scheme_fidelity.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/scheme/scheme_fidelity.h" - -#include - -#include "cpp/cam/hct.h" -#include "cpp/dislike/dislike.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" -#include "cpp/dynamiccolor/variant.h" -#include "cpp/palettes/tones.h" -#include "cpp/temperature/temperature_cache.h" - -namespace material_color_utilities { - -SchemeFidelity::SchemeFidelity(Hct set_source_color_hct, bool set_is_dark, - double set_contrast_level) - : DynamicScheme( - /*set_source_color_hct:*/ set_source_color_hct, - /*variant:*/ Variant::kFidelity, - /*contrast_level:*/ set_contrast_level, - /*is_dark:*/ set_is_dark, - /*primary_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), - set_source_color_hct.get_chroma()), - /*secondary_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), - fmax(set_source_color_hct.get_chroma() - 32.0, - set_source_color_hct.get_chroma() * 0.5)), - /*tertiary_palette:*/ - TonalPalette(FixIfDisliked( - TemperatureCache(set_source_color_hct).GetComplement())), - /*neutral_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), - set_source_color_hct.get_chroma() / 8.0), - /*neutral_variant_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), - set_source_color_hct.get_chroma() / 8.0 + 4.0)) {} - -SchemeFidelity::SchemeFidelity(Hct set_source_color_hct, bool set_is_dark) - : SchemeFidelity::SchemeFidelity(set_source_color_hct, set_is_dark, 0.0) {} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/scheme/scheme_fidelity.h b/src/material-colors/cpp/scheme/scheme_fidelity.h deleted file mode 100644 index a77afc3..0000000 --- a/src/material-colors/cpp/scheme/scheme_fidelity.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_SCHEME_SCHEME_FIDELITY_H_ -#define CPP_SCHEME_SCHEME_FIDELITY_H_ - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" - -namespace material_color_utilities { - -struct SchemeFidelity : public DynamicScheme { - SchemeFidelity(Hct set_source_color_hct, bool set_is_dark, - double set_contrast_level); - SchemeFidelity(Hct set_source_color_hct, bool set_is_dark); -}; - -} // namespace material_color_utilities - -#endif // CPP_SCHEME_SCHEME_FIDELITY_H_ diff --git a/src/material-colors/cpp/scheme/scheme_fruit_salad.cpp b/src/material-colors/cpp/scheme/scheme_fruit_salad.cpp deleted file mode 100644 index 4c112cc..0000000 --- a/src/material-colors/cpp/scheme/scheme_fruit_salad.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/scheme/scheme_fruit_salad.h" - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" -#include "cpp/dynamiccolor/variant.h" -#include "cpp/palettes/tones.h" - -namespace material_color_utilities { - -SchemeFruitSalad::SchemeFruitSalad(Hct set_source_color_hct, bool set_is_dark, - double set_contrast_level) - : DynamicScheme( - /*set_source_color_hct:*/ set_source_color_hct, - /*variant:*/ Variant::kFruitSalad, - /*contrast_level:*/ set_contrast_level, - /*is_dark:*/ set_is_dark, - /*primary_palette:*/ - TonalPalette( - SanitizeDegreesDouble(set_source_color_hct.get_hue() - 50.0), - 48.0), - /*secondary_palette:*/ - TonalPalette( - SanitizeDegreesDouble(set_source_color_hct.get_hue() - 50.0), - 36.0), - /*tertiary_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 36.0), - /*neutral_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 10.0), - /*neutral_variant_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 16.0)) {} - -SchemeFruitSalad::SchemeFruitSalad(Hct set_source_color_hct, bool set_is_dark) - : SchemeFruitSalad::SchemeFruitSalad(set_source_color_hct, set_is_dark, - 0.0) {} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/scheme/scheme_fruit_salad.h b/src/material-colors/cpp/scheme/scheme_fruit_salad.h deleted file mode 100644 index 45366f1..0000000 --- a/src/material-colors/cpp/scheme/scheme_fruit_salad.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_SCHEME_SCHEME_FRUIT_SALAD_H_ -#define CPP_SCHEME_SCHEME_FRUIT_SALAD_H_ - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" - -namespace material_color_utilities { - -struct SchemeFruitSalad : public DynamicScheme { - SchemeFruitSalad(Hct source_color_hct, bool is_dark, double contrast_level); - SchemeFruitSalad(Hct source_color_hct, bool is_dark); -}; - -} // namespace material_color_utilities - -#endif // CPP_SCHEME_SCHEME_FRUIT_SALAD_H_ diff --git a/src/material-colors/cpp/scheme/scheme_monochrome.cpp b/src/material-colors/cpp/scheme/scheme_monochrome.cpp deleted file mode 100644 index 64b60ef..0000000 --- a/src/material-colors/cpp/scheme/scheme_monochrome.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/scheme/scheme_monochrome.h" - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" -#include "cpp/dynamiccolor/variant.h" -#include "cpp/palettes/tones.h" - -namespace material_color_utilities { - -SchemeMonochrome::SchemeMonochrome(Hct set_source_color_hct, bool set_is_dark, - double set_contrast_level) - : DynamicScheme( - /*set_source_color_hct:*/ set_source_color_hct, - /*variant:*/ Variant::kMonochrome, - /*contrast_level:*/ set_contrast_level, - /*is_dark:*/ set_is_dark, - /*primary_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 0.0), - /*secondary_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 0.0), - /*tertiary_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 0.0), - /*neutral_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 0.0), - /*neutral_variant_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 0.0)) {} - -SchemeMonochrome::SchemeMonochrome(Hct set_source_color_hct, bool set_is_dark) - : SchemeMonochrome::SchemeMonochrome(set_source_color_hct, set_is_dark, - 0.0) {} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/scheme/scheme_monochrome.h b/src/material-colors/cpp/scheme/scheme_monochrome.h deleted file mode 100644 index 96de361..0000000 --- a/src/material-colors/cpp/scheme/scheme_monochrome.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_SCHEME_SCHEME_MONOCHROME_H_ -#define CPP_SCHEME_SCHEME_MONOCHROME_H_ - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" - -namespace material_color_utilities { - -struct SchemeMonochrome : public DynamicScheme { - SchemeMonochrome(Hct source_color_hct, bool is_dark, double contrast_level); - SchemeMonochrome(Hct source_color_hct, bool is_dark); -}; - -} // namespace material_color_utilities - -#endif // CPP_SCHEME_SCHEME_MONOCHROME_H_ diff --git a/src/material-colors/cpp/scheme/scheme_monochrome_test.cpp b/src/material-colors/cpp/scheme/scheme_monochrome_test.cpp deleted file mode 100644 index 77a6544..0000000 --- a/src/material-colors/cpp/scheme/scheme_monochrome_test.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/scheme/scheme_monochrome.h" - -#include "testing/base/public/gunit.h" -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/material_dynamic_colors.h" - -namespace material_color_utilities { - -namespace { -TEST(SchemeMonochromeTest, darkTheme_monochromeSpec) { - SchemeMonochrome scheme = SchemeMonochrome(Hct(0xff0000ff), true, 0.0); - EXPECT_NEAR(MaterialDynamicColors::Primary().GetHct(scheme).get_tone(), 100.0, - 1.0); - EXPECT_NEAR(MaterialDynamicColors::OnPrimary().GetHct(scheme).get_tone(), - 10.0, 1.0); - EXPECT_NEAR( - MaterialDynamicColors::PrimaryContainer().GetHct(scheme).get_tone(), 85.0, - 1.0); - EXPECT_NEAR( - MaterialDynamicColors::OnPrimaryContainer().GetHct(scheme).get_tone(), - 0.0, 1.0); - EXPECT_NEAR(MaterialDynamicColors::Secondary().GetHct(scheme).get_tone(), - 80.0, 1.0); - EXPECT_NEAR(MaterialDynamicColors::OnSecondary().GetHct(scheme).get_tone(), - 10.0, 1.0); - EXPECT_NEAR( - MaterialDynamicColors::SecondaryContainer().GetHct(scheme).get_tone(), - 30.0, 1.0); - EXPECT_NEAR( - MaterialDynamicColors::OnSecondaryContainer().GetHct(scheme).get_tone(), - 90.0, 1.0); - EXPECT_NEAR(MaterialDynamicColors::Tertiary().GetHct(scheme).get_tone(), 90.0, - 1.0); - EXPECT_NEAR(MaterialDynamicColors::OnTertiary().GetHct(scheme).get_tone(), - 10.0, 1.0); - EXPECT_NEAR( - MaterialDynamicColors::TertiaryContainer().GetHct(scheme).get_tone(), - 60.0, 1.0); - EXPECT_NEAR( - MaterialDynamicColors::OnTertiaryContainer().GetHct(scheme).get_tone(), - 0.0, 1.0); -} - -TEST(SchemeMonochromeTest, lightTheme_monochromeSpec) { - SchemeMonochrome scheme = SchemeMonochrome(Hct(0xff0000ff), false, 0.0); - EXPECT_NEAR(MaterialDynamicColors::Primary().GetHct(scheme).get_tone(), 0.0, - 1.0); - EXPECT_NEAR(MaterialDynamicColors::OnPrimary().GetHct(scheme).get_tone(), - 90.0, 1.0); - EXPECT_NEAR( - MaterialDynamicColors::PrimaryContainer().GetHct(scheme).get_tone(), 25.0, - 1.0); - EXPECT_NEAR( - MaterialDynamicColors::OnPrimaryContainer().GetHct(scheme).get_tone(), - 100.0, 1.0); - EXPECT_NEAR(MaterialDynamicColors::Secondary().GetHct(scheme).get_tone(), - 40.0, 1.0); - EXPECT_NEAR(MaterialDynamicColors::OnSecondary().GetHct(scheme).get_tone(), - 100.0, 1.0); - EXPECT_NEAR( - MaterialDynamicColors::SecondaryContainer().GetHct(scheme).get_tone(), - 85.0, 1.0); - EXPECT_NEAR( - MaterialDynamicColors::OnSecondaryContainer().GetHct(scheme).get_tone(), - 10.0, 1.0); - EXPECT_NEAR(MaterialDynamicColors::Tertiary().GetHct(scheme).get_tone(), 25.0, - 1.0); - EXPECT_NEAR(MaterialDynamicColors::OnTertiary().GetHct(scheme).get_tone(), - 90.0, 1.0); - EXPECT_NEAR( - MaterialDynamicColors::TertiaryContainer().GetHct(scheme).get_tone(), - 49.0, 1.0); - EXPECT_NEAR( - MaterialDynamicColors::OnTertiaryContainer().GetHct(scheme).get_tone(), - 100.0, 1.0); -} - -} // namespace -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/scheme/scheme_neutral.cpp b/src/material-colors/cpp/scheme/scheme_neutral.cpp deleted file mode 100644 index f5d37f8..0000000 --- a/src/material-colors/cpp/scheme/scheme_neutral.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/scheme/scheme_neutral.h" - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" -#include "cpp/dynamiccolor/variant.h" -#include "cpp/palettes/tones.h" - -namespace material_color_utilities { - -SchemeNeutral::SchemeNeutral(Hct set_source_color_hct, bool set_is_dark, - double set_contrast_level) - : DynamicScheme( - /*set_source_color_hct:*/ set_source_color_hct, - /*variant:*/ Variant::kNeutral, - /*contrast_level:*/ set_contrast_level, - /*is_dark:*/ set_is_dark, - /*primary_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 12.0), - /*secondary_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 8.0), - /*tertiary_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 16.0), - /*neutral_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 2.0), - /*neutral_variant_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 2.0)) {} - -SchemeNeutral::SchemeNeutral(Hct set_source_color_hct, bool set_is_dark) - : SchemeNeutral::SchemeNeutral(set_source_color_hct, set_is_dark, 0.0) {} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/scheme/scheme_neutral.h b/src/material-colors/cpp/scheme/scheme_neutral.h deleted file mode 100644 index 7b44fae..0000000 --- a/src/material-colors/cpp/scheme/scheme_neutral.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_SCHEME_SCHEME_NEUTRAL_H_ -#define CPP_SCHEME_SCHEME_NEUTRAL_H_ - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" - -namespace material_color_utilities { - -struct SchemeNeutral : public DynamicScheme { - SchemeNeutral(Hct source_color_hct, bool is_dark, double contrast_level); - SchemeNeutral(Hct source_color_hct, bool is_dark); -}; - -} // namespace material_color_utilities - -#endif // CPP_SCHEME_SCHEME_NEUTRAL_H_ diff --git a/src/material-colors/cpp/scheme/scheme_rainbow.cpp b/src/material-colors/cpp/scheme/scheme_rainbow.cpp deleted file mode 100644 index 6ac19ba..0000000 --- a/src/material-colors/cpp/scheme/scheme_rainbow.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/scheme/scheme_rainbow.h" - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" -#include "cpp/dynamiccolor/variant.h" -#include "cpp/palettes/tones.h" - -namespace material_color_utilities { - -SchemeRainbow::SchemeRainbow(Hct set_source_color_hct, bool set_is_dark, - double set_contrast_level) - : DynamicScheme( - /*set_source_color_hct:*/ set_source_color_hct, - /*variant:*/ Variant::kRainbow, - /*contrast_level:*/ set_contrast_level, - /*is_dark:*/ set_is_dark, - /*primary_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 48.0), - /*secondary_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 16.0), - /*tertiary_palette:*/ - TonalPalette( - SanitizeDegreesDouble(set_source_color_hct.get_hue() + 60.0), - 24.0), - /*neutral_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 0.0), - /*neutral_variant_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 0.0)) {} - -SchemeRainbow::SchemeRainbow(Hct set_source_color_hct, bool set_is_dark) - : SchemeRainbow::SchemeRainbow(set_source_color_hct, set_is_dark, 0.0) {} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/scheme/scheme_rainbow.h b/src/material-colors/cpp/scheme/scheme_rainbow.h deleted file mode 100644 index 39ff698..0000000 --- a/src/material-colors/cpp/scheme/scheme_rainbow.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_SCHEME_SCHEME_RAINBOW_H_ -#define CPP_SCHEME_SCHEME_RAINBOW_H_ - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" - -namespace material_color_utilities { - -struct SchemeRainbow : public DynamicScheme { - SchemeRainbow(Hct source_color_hct, bool is_dark, double contrast_level); - SchemeRainbow(Hct source_color_hct, bool is_dark); -}; - -} // namespace material_color_utilities - -#endif // CPP_SCHEME_SCHEME_RAINBOW_H_ diff --git a/src/material-colors/cpp/scheme/scheme_tonal_spot.cpp b/src/material-colors/cpp/scheme/scheme_tonal_spot.cpp deleted file mode 100644 index 41176f7..0000000 --- a/src/material-colors/cpp/scheme/scheme_tonal_spot.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/scheme/scheme_tonal_spot.h" - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" -#include "cpp/dynamiccolor/variant.h" -#include "cpp/palettes/tones.h" - -namespace material_color_utilities { - -SchemeTonalSpot::SchemeTonalSpot(Hct set_source_color_hct, bool set_is_dark, - double set_contrast_level) - : DynamicScheme( - /*set_source_color_hct:*/ set_source_color_hct, - /*variant:*/ Variant::kTonalSpot, - /*contrast_level:*/ set_contrast_level, - /*is_dark:*/ set_is_dark, - /*primary_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 36.0), - /*secondary_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 16.0), - /*tertiary_palette:*/ - TonalPalette( - SanitizeDegreesDouble(set_source_color_hct.get_hue() + 60), 24.0), - /*neutral_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 6.0), - /*neutral_variant_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 8.0)) {} - -SchemeTonalSpot::SchemeTonalSpot(Hct set_source_color_hct, bool set_is_dark) - : SchemeTonalSpot::SchemeTonalSpot(set_source_color_hct, set_is_dark, 0.0) { -} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/scheme/scheme_tonal_spot.h b/src/material-colors/cpp/scheme/scheme_tonal_spot.h deleted file mode 100644 index b77a38a..0000000 --- a/src/material-colors/cpp/scheme/scheme_tonal_spot.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_SCHEME_SCHEME_TONAL_SPOT_H_ -#define CPP_SCHEME_SCHEME_TONAL_SPOT_H_ - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" - -namespace material_color_utilities { - -struct SchemeTonalSpot : public DynamicScheme { - SchemeTonalSpot(Hct source_color_hct, bool is_dark, double contrast_level); - SchemeTonalSpot(Hct source_color_hct, bool is_dark); -}; - -} // namespace material_color_utilities - -#endif // CPP_SCHEME_SCHEME_TONAL_SPOT_H_ diff --git a/src/material-colors/cpp/scheme/scheme_vibrant.cpp b/src/material-colors/cpp/scheme/scheme_vibrant.cpp deleted file mode 100644 index 2b498e4..0000000 --- a/src/material-colors/cpp/scheme/scheme_vibrant.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/scheme/scheme_vibrant.h" - -#include - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" -#include "cpp/dynamiccolor/variant.h" -#include "cpp/palettes/tones.h" - -namespace material_color_utilities { - -const std::vector kHues = {0, 41, 61, 101, 131, 181, 251, 301, 360}; - -const std::vector kSecondaryRotations = {18, 15, 10, 12, 15, - 18, 15, 12, 12}; - -const std::vector kTertiaryRotations = {35, 30, 20, 25, 30, - 35, 30, 25, 25}; - -SchemeVibrant::SchemeVibrant(Hct set_source_color_hct, bool set_is_dark, - double set_contrast_level) - : DynamicScheme( - /*set_source_color_hct:*/ set_source_color_hct, - /*variant:*/ Variant::kVibrant, - /*contrast_level:*/ set_contrast_level, - /*is_dark:*/ set_is_dark, - /*primary_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 200.0), - /*secondary_palette:*/ - TonalPalette(DynamicScheme::GetRotatedHue(set_source_color_hct, kHues, - kSecondaryRotations), - 24.0), - /*tertiary_palette:*/ - TonalPalette(DynamicScheme::GetRotatedHue(set_source_color_hct, kHues, - kTertiaryRotations), - 32.0), - /*neutral_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 10.0), - /*neutral_variant_palette:*/ - TonalPalette(set_source_color_hct.get_hue(), 12.0)) {} - -SchemeVibrant::SchemeVibrant(Hct set_source_color_hct, bool set_is_dark) - : SchemeVibrant::SchemeVibrant(set_source_color_hct, set_is_dark, 0.0) {} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/scheme/scheme_vibrant.h b/src/material-colors/cpp/scheme/scheme_vibrant.h deleted file mode 100644 index fdc8110..0000000 --- a/src/material-colors/cpp/scheme/scheme_vibrant.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2023 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_SCHEME_SCHEME_VARIANT_H_ -#define CPP_SCHEME_SCHEME_VARIANT_H_ - -#include "cpp/cam/hct.h" -#include "cpp/dynamiccolor/dynamic_scheme.h" - -namespace material_color_utilities { - -struct SchemeVibrant : public DynamicScheme { - SchemeVibrant(Hct source_color_hct, bool is_dark, double contrast_level); - SchemeVibrant(Hct source_color_hct, bool is_dark); -}; - -} // namespace material_color_utilities - -#endif // CPP_SCHEME_SCHEME_VARIANT_H_ diff --git a/src/material-colors/cpp/score/score.cpp b/src/material-colors/cpp/score/score.cpp deleted file mode 100644 index c2c0278..0000000 --- a/src/material-colors/cpp/score/score.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/score/score.h" - -#include -#include -#include -#include -#include -#include - -#include "cpp/cam/hct.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -constexpr double kTargetChroma = 48.0; // A1 Chroma -constexpr double kWeightProportion = 0.7; -constexpr double kWeightChromaAbove = 0.3; -constexpr double kWeightChromaBelow = 0.1; -constexpr double kCutoffChroma = 5.0; -constexpr double kCutoffExcitedProportion = 0.01; - -bool CompareScoredHCT(const std::pair& a, - const std::pair& b) { - return a.second > b.second; -} - -std::vector RankedSuggestions( - const std::map& argb_to_population, - const ScoreOptions& options) { - // Get the HCT color for each Argb value, while finding the per hue count and - // total count. - std::vector colors_hct; - std::vector hue_population(360, 0); - double population_sum = 0; - for (const auto& [argb, population] : argb_to_population) { - Hct hct(argb); - colors_hct.push_back(hct); - int hue = floor(hct.get_hue()); - hue_population[hue] += population; - population_sum += population; - } - - // Hues with more usage in neighboring 30 degree slice get a larger number. - std::vector hue_excited_proportions(360, 0.0); - for (int hue = 0; hue < 360; hue++) { - double proportion = hue_population[hue] / population_sum; - for (int i = hue - 14; i < hue + 16; i++) { - int neighbor_hue = SanitizeDegreesInt(i); - hue_excited_proportions[neighbor_hue] += proportion; - } - } - - // Scores each HCT color based on usage and chroma, while optionally - // filtering out values that do not have enough chroma or usage. - std::vector> scored_hcts; - for (Hct hct : colors_hct) { - int hue = SanitizeDegreesInt(round(hct.get_hue())); - double proportion = hue_excited_proportions[hue]; - if (options.filter && (hct.get_chroma() < kCutoffChroma || - proportion <= kCutoffExcitedProportion)) { - continue; - } - - double proportion_score = proportion * 100.0 * kWeightProportion; - double chroma_weight = hct.get_chroma() < kTargetChroma - ? kWeightChromaBelow - : kWeightChromaAbove; - double chroma_score = (hct.get_chroma() - kTargetChroma) * chroma_weight; - double score = proportion_score + chroma_score; - scored_hcts.push_back({hct, score}); - } - // Sorted so that colors with higher scores come first. - sort(scored_hcts.begin(), scored_hcts.end(), CompareScoredHCT); - - // Iterates through potential hue differences in degrees in order to select - // the colors with the largest distribution of hues possible. Starting at - // 90 degrees(maximum difference for 4 colors) then decreasing down to a - // 15 degree minimum. - std::vector chosen_colors; - for (int difference_degrees = 90; difference_degrees >= 15; - difference_degrees--) { - chosen_colors.clear(); - for (auto entry : scored_hcts) { - Hct hct = entry.first; - auto duplicate_hue = std::find_if( - chosen_colors.begin(), chosen_colors.end(), - [&hct, difference_degrees](Hct chosen_hct) { - return DiffDegrees(hct.get_hue(), chosen_hct.get_hue()) < - difference_degrees; - }); - if (duplicate_hue == chosen_colors.end()) { - chosen_colors.push_back(hct); - if (chosen_colors.size() >= options.desired) break; - } - } - if (chosen_colors.size() >= options.desired) break; - } - std::vector colors; - if (chosen_colors.empty()) { - colors.push_back(options.fallback_color_argb); - } - for (auto chosen_hct : chosen_colors) { - colors.push_back(chosen_hct.ToInt()); - } - return colors; -} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/score/score.h b/src/material-colors/cpp/score/score.h deleted file mode 100644 index 5bd2b82..0000000 --- a/src/material-colors/cpp/score/score.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_SCORE_SCORE_H_ -#define CPP_SCORE_SCORE_H_ - -#include -#include -#include - -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -/** - * Default options for ranking colors based on usage counts. - * `desired`: is the max count of the colors returned. - * `fallback_color_argb`: Is the default color that should be used if no - * other colors are suitable. - * `filter`: controls if the resulting colors should be filtered to not include - * hues that are not used often enough, and colors that are effectively - * grayscale. - */ -struct ScoreOptions { - size_t desired = 4; // 4 colors matches the Android wallpaper picker. - int fallback_color_argb = 0xff4285f4; // Google Blue. - bool filter = true; // Avoid unsuitable colors. -}; - -/** - * Given a map with keys of colors and values of how often the color appears, - * rank the colors based on suitability for being used for a UI theme. - * - * The list returned is of length <= [desired]. The recommended color is the - * first item, the least suitable is the last. There will always be at least - * one color returned. If all the input colors were not suitable for a theme, - * a default fallback color will be provided, Google Blue, or supplied fallback - * color. The default number of colors returned is 4, simply because that's the - * # of colors display in Android 12's wallpaper picker. - */ -std::vector RankedSuggestions( - const std::map& argb_to_population, - const ScoreOptions& options = {}); -} // namespace material_color_utilities - -#endif // CPP_SCORE_SCORE_H_ diff --git a/src/material-colors/cpp/score/score_test.cpp b/src/material-colors/cpp/score/score_test.cpp deleted file mode 100644 index 8f8100d..0000000 --- a/src/material-colors/cpp/score/score_test.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/score/score.h" - -#include -#include -#include - -#include "testing/base/public/gunit.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -namespace { - -TEST(ScoreTest, PrioritizesChroma) { - std::map argb_to_population = { - {0xff000000, 1}, {0xffffffff, 1}, {0xff0000ff, 1}}; - - std::vector ranked = - RankedSuggestions(argb_to_population, {.desired = 4}); - - EXPECT_EQ(ranked.size(), 1u); - EXPECT_EQ(ranked[0], 0xff0000ff); -} - -TEST(ScoreTest, PrioritizesChromaWhenProportionsEqual) { - std::map argb_to_population = { - {0xffff0000, 1}, {0xff00ff00, 1}, {0xff0000ff, 1}}; - - std::vector ranked = - RankedSuggestions(argb_to_population, {.desired = 4}); - - EXPECT_EQ(ranked.size(), 3u); - EXPECT_EQ(ranked[0], 0xffff0000); - EXPECT_EQ(ranked[1], 0xff00ff00); - EXPECT_EQ(ranked[2], 0xff0000ff); -} - -TEST(ScoreTest, GeneratesGblueWhenNoColorsAvailable) { - std::map argb_to_population = {{0xff000000, 1}}; - - std::vector ranked = - RankedSuggestions(argb_to_population, {.desired = 4}); - - EXPECT_EQ(ranked.size(), 1u); - EXPECT_EQ(ranked[0], 0xff4285f4); -} - -TEST(ScoreTest, DedupesNearbyHues) { - std::map argb_to_population = { - {0xff008772, 1}, // H 180 C 42 T 50 - {0xff318477, 1} // H 184 C 35 T 50 - }; - - std::vector ranked = - RankedSuggestions(argb_to_population, {.desired = 4}); - - EXPECT_EQ(ranked.size(), 1u); - EXPECT_EQ(ranked[0], 0xff008772); -} - -TEST(ScoreTest, MaximizesHueDistance) { - std::map argb_to_population = { - {0xff008772, 1}, // H 180 C 42 T 50 - {0xff008587, 1}, // H 198 C 50 T 50 - {0xff007ebc, 1} // H 245 C 50 T 50 - }; - - std::vector ranked = - RankedSuggestions(argb_to_population, {.desired = 2}); - - EXPECT_EQ(ranked.size(), 2u); - EXPECT_EQ(ranked[0], 0xff007ebc); - EXPECT_EQ(ranked[1], 0xff008772); -} - -TEST(ScoreTest, GeneratedScenarioOne) { - std::map argb_to_population = { - {0xff7ea16d, 67}, - {0xffd8ccae, 67}, - {0xff835c0d, 49}, - }; - - std::vector ranked = RankedSuggestions( - argb_to_population, - {.desired = 3, .fallback_color_argb = (int)0xff8d3819, .filter = false}); - - EXPECT_EQ(ranked.size(), 3u); - EXPECT_EQ(ranked[0], 0xff7ea16d); - EXPECT_EQ(ranked[1], 0xffd8ccae); - EXPECT_EQ(ranked[2], 0xff835c0d); -} - -TEST(ScoreTest, GeneratedScenarioTwo) { - std::map argb_to_population = { - {0xffd33881, 14}, - {0xff3205cc, 77}, - {0xff0b48cf, 36}, - {0xffa08f5d, 81}, - }; - - std::vector ranked = RankedSuggestions( - argb_to_population, - {.desired = 4, .fallback_color_argb = (int)0xff7d772b, .filter = true}); - - EXPECT_EQ(ranked.size(), 3u); - EXPECT_EQ(ranked[0], 0xff3205cc); - EXPECT_EQ(ranked[1], 0xffa08f5d); - EXPECT_EQ(ranked[2], 0xffd33881); -} - -TEST(ScoreTest, GeneratedScenarioThree) { - std::map argb_to_population = { - {0xffbe94a6, 23}, - {0xffc33fd7, 42}, - {0xff899f36, 90}, - {0xff94c574, 82}, - }; - - std::vector ranked = RankedSuggestions( - argb_to_population, - {.desired = 3, .fallback_color_argb = (int)0xffaa79a4, .filter = true}); - - EXPECT_EQ(ranked.size(), 3u); - EXPECT_EQ(ranked[0], 0xff94c574); - EXPECT_EQ(ranked[1], 0xffc33fd7); - EXPECT_EQ(ranked[2], 0xffbe94a6); -} - -TEST(ScoreTest, GeneratedScenarioFour) { - std::map argb_to_population = { - {0xffdf241c, 85}, {0xff685859, 44}, {0xffd06d5f, 34}, - {0xff561c54, 27}, {0xff713090, 88}, - }; - - std::vector ranked = RankedSuggestions( - argb_to_population, - {.desired = 5, .fallback_color_argb = (int)0xff58c19c, .filter = false}); - - EXPECT_EQ(ranked.size(), 2u); - EXPECT_EQ(ranked[0], 0xffdf241c); - EXPECT_EQ(ranked[1], 0xff561c54); -} - -TEST(ScoreTest, GeneratedScenarioFive) { - std::map argb_to_population = { - {0xffbe66f8, 41}, {0xff4bbda9, 88}, {0xff80f6f9, 44}, - {0xffab8017, 43}, {0xffe89307, 65}, - }; - - std::vector ranked = RankedSuggestions( - argb_to_population, - {.desired = 3, .fallback_color_argb = (int)0xff916691, .filter = false}); - - EXPECT_EQ(ranked.size(), 3u); - EXPECT_EQ(ranked[0], 0xffab8017); - EXPECT_EQ(ranked[1], 0xff4bbda9); - EXPECT_EQ(ranked[2], 0xffbe66f8); -} - -TEST(ScoreTest, GeneratedScenarioSix) { - std::map argb_to_population = { - {0xff18ea8f, 93}, {0xff327593, 18}, {0xff066a18, 53}, - {0xfffa8a23, 74}, {0xff04ca1f, 62}, - }; - - std::vector ranked = RankedSuggestions( - argb_to_population, - {.desired = 2, .fallback_color_argb = (int)0xff4c377a, .filter = false}); - - EXPECT_EQ(ranked.size(), 2u); - EXPECT_EQ(ranked[0], 0xff18ea8f); - EXPECT_EQ(ranked[1], 0xfffa8a23); -} - -TEST(ScoreTest, GeneratedScenarioSeven) { - std::map argb_to_population = { - {0xff2e05ed, 23}, {0xff153e55, 90}, {0xff9ab220, 23}, - {0xff153379, 66}, {0xff68bcc3, 81}, - }; - - std::vector ranked = RankedSuggestions( - argb_to_population, - {.desired = 2, .fallback_color_argb = (int)0xfff588dc, .filter = true}); - - EXPECT_EQ(ranked.size(), 2u); - EXPECT_EQ(ranked[0], 0xff2e05ed); - EXPECT_EQ(ranked[1], 0xff9ab220); -} - -TEST(ScoreTest, GeneratedScenarioEight) { - std::map argb_to_population = { - {0xff816ec5, 24}, - {0xff6dcb94, 19}, - {0xff3cae91, 98}, - {0xff5b542f, 25}, - }; - - std::vector ranked = RankedSuggestions( - argb_to_population, - {.desired = 1, .fallback_color_argb = (int)0xff84b0fd, .filter = false}); - - EXPECT_EQ(ranked.size(), 1u); - EXPECT_EQ(ranked[0], 0xff3cae91); -} - -TEST(ScoreTest, GeneratedScenarioNine) { - std::map argb_to_population = { - {0xff206f86, 52}, {0xff4a620d, 96}, {0xfff51401, 85}, - {0xff2b8ebf, 3}, {0xff277766, 59}, - }; - - std::vector ranked = RankedSuggestions( - argb_to_population, - {.desired = 3, .fallback_color_argb = (int)0xff02b415, .filter = true}); - - EXPECT_EQ(ranked.size(), 3u); - EXPECT_EQ(ranked[0], 0xfff51401); - EXPECT_EQ(ranked[1], 0xff4a620d); - EXPECT_EQ(ranked[2], 0xff2b8ebf); -} - -TEST(ScoreTest, GeneratedScenarioTen) { - std::map argb_to_population = { - {0xff8b1d99, 54}, - {0xff27effe, 43}, - {0xff6f558d, 2}, - {0xff77fdf2, 78}, - }; - - std::vector ranked = RankedSuggestions( - argb_to_population, - {.desired = 4, .fallback_color_argb = (int)0xff5e7a10, .filter = true}); - - EXPECT_EQ(ranked.size(), 3u); - EXPECT_EQ(ranked[0], 0xff27effe); - EXPECT_EQ(ranked[1], 0xff8b1d99); - EXPECT_EQ(ranked[2], 0xff6f558d); -} - -} // namespace -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/temperature/temperature_cache.cpp b/src/material-colors/cpp/temperature/temperature_cache.cpp deleted file mode 100644 index 4fec3a2..0000000 --- a/src/material-colors/cpp/temperature/temperature_cache.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/temperature/temperature_cache.h" - -#include -#include -#include - -#include "cpp/cam/hct.h" -#include "cpp/quantize/lab.h" -#include "cpp/utils/utils.h" - -namespace material_color_utilities { - -TemperatureCache::TemperatureCache(Hct input) : input_(input) {} - -Hct TemperatureCache::GetComplement() { - if (precomputed_complement_.has_value()) { - return precomputed_complement_.value(); - } - - double coldest_hue = GetColdest().get_hue(); - double coldest_temp = GetTempsByHct().at(GetColdest()); - - double warmest_hue = GetWarmest().get_hue(); - double warmest_temp = GetTempsByHct().at(GetWarmest()); - double range = warmest_temp - coldest_temp; - bool start_hue_is_coldest_to_warmest = - IsBetween(input_.get_hue(), coldest_hue, warmest_hue); - double start_hue = - start_hue_is_coldest_to_warmest ? warmest_hue : coldest_hue; - double end_hue = start_hue_is_coldest_to_warmest ? coldest_hue : warmest_hue; - double direction_of_rotation = 1.0; - double smallest_error = 1000.0; - Hct answer = GetHctsByHue().at((int)round(input_.get_hue())); - - double complement_relative_temp = (1.0 - GetRelativeTemperature(input_)); - // Find the color in the other section, closest to the inverse percentile - // of the input color. This is the complement. - for (double hue_addend = 0.0; hue_addend <= 360.0; hue_addend += 1.0) { - double hue = - SanitizeDegreesDouble(start_hue + direction_of_rotation * hue_addend); - if (!IsBetween(hue, start_hue, end_hue)) { - continue; - } - Hct possible_answer = GetHctsByHue().at((int)round(hue)); - double relative_temp = - (GetTempsByHct().at(possible_answer) - coldest_temp) / range; - double error = abs(complement_relative_temp - relative_temp); - if (error < smallest_error) { - smallest_error = error; - answer = possible_answer; - } - } - precomputed_complement_ = answer; - return precomputed_complement_.value(); -} - -std::vector TemperatureCache::GetAnalogousColors() { - return GetAnalogousColors(5, 12); -} - -std::vector TemperatureCache::GetAnalogousColors(int count, - int divisions) { - // The starting hue is the hue of the input color. - int start_hue = (int)round(input_.get_hue()); - Hct start_hct = GetHctsByHue().at(start_hue); - double last_temp = GetRelativeTemperature(start_hct); - - std::vector all_colors; - all_colors.push_back(start_hct); - - double absolute_total_temp_delta = 0.0; - for (int i = 0; i < 360; i++) { - int hue = SanitizeDegreesInt(start_hue + i); - Hct hct = GetHctsByHue().at(hue); - double temp = GetRelativeTemperature(hct); - double temp_delta = abs(temp - last_temp); - last_temp = temp; - absolute_total_temp_delta += temp_delta; - } - - int hue_addend = 1; - double temp_step = absolute_total_temp_delta / (double)divisions; - double total_temp_delta = 0.0; - last_temp = GetRelativeTemperature(start_hct); - while (all_colors.size() < static_cast(divisions)) { - int hue = SanitizeDegreesInt(start_hue + hue_addend); - Hct hct = GetHctsByHue().at(hue); - double temp = GetRelativeTemperature(hct); - double temp_delta = abs(temp - last_temp); - total_temp_delta += temp_delta; - - double desired_total_temp_delta_for_index = (all_colors.size() * temp_step); - bool index_satisfied = - total_temp_delta >= desired_total_temp_delta_for_index; - int index_addend = 1; - // Keep adding this hue to the answers until its temperature is - // insufficient. This ensures consistent behavior when there aren't - // `divisions` discrete steps between 0 and 360 in hue with `temp_step` - // delta in temperature between them. - // - // For example, white and black have no analogues: there are no other - // colors at T100/T0. Therefore, they should just be added to the array - // as answers. - while (index_satisfied && - all_colors.size() < static_cast(divisions)) { - all_colors.push_back(hct); - desired_total_temp_delta_for_index = - ((all_colors.size() + index_addend) * temp_step); - index_satisfied = total_temp_delta >= desired_total_temp_delta_for_index; - index_addend++; - } - last_temp = temp; - hue_addend++; - - if (hue_addend > 360) { - while (all_colors.size() < static_cast(divisions)) { - all_colors.push_back(hct); - } - break; - } - } - - std::vector answers; - answers.push_back(input_); - - int ccw_count = (int)floor(((double)count - 1.0) / 2.0); - for (int i = 1; i < (ccw_count + 1); i++) { - int index = 0 - i; - while (index < 0) { - index = all_colors.size() + index; - } - if (static_cast(index) >= all_colors.size()) { - index = index % all_colors.size(); - } - answers.insert(answers.begin(), all_colors.at(index)); - } - - int cw_count = count - ccw_count - 1; - for (int i = 1; i < (cw_count + 1); i++) { - size_t index = i; - while (index < 0) { - index = all_colors.size() + index; - } - if (index >= all_colors.size()) { - index = index % all_colors.size(); - } - answers.push_back(all_colors.at(index)); - } - - return answers; -} - -double TemperatureCache::GetRelativeTemperature(Hct hct) { - double range = - GetTempsByHct().at(GetWarmest()) - GetTempsByHct().at(GetColdest()); - double difference_from_coldest = - GetTempsByHct().at(hct) - GetTempsByHct().at(GetColdest()); - // Handle when there's no difference in temperature between warmest and - // coldest: for example, at T100, only one color is available, white. - if (range == 0.) { - return 0.5; - } - return difference_from_coldest / range; -} - -double TemperatureCache::RawTemperature(Hct color) { - Lab lab = LabFromInt(color.ToInt()); - double hue = SanitizeDegreesDouble(atan2(lab.b, lab.a) * 180.0 / kPi); - double chroma = hypot(lab.a, lab.b); - return -0.5 + 0.02 * pow(chroma, 1.07) * - cos(SanitizeDegreesDouble(hue - 50.) * kPi / 180); -} - -Hct TemperatureCache::GetColdest() { return GetHctsByTemp().at(0); } - -std::vector TemperatureCache::GetHctsByHue() { - if (precomputed_hcts_by_hue_.has_value()) { - return precomputed_hcts_by_hue_.value(); - } - std::vector hcts; - for (double hue = 0.; hue <= 360.; hue += 1.) { - Hct color_at_hue(hue, input_.get_chroma(), input_.get_tone()); - hcts.push_back(color_at_hue); - } - precomputed_hcts_by_hue_ = hcts; - return precomputed_hcts_by_hue_.value(); -} - -std::vector TemperatureCache::GetHctsByTemp() { - if (precomputed_hcts_by_temp_.has_value()) { - return precomputed_hcts_by_temp_.value(); - } - - std::vector hcts(GetHctsByHue()); - hcts.push_back(input_); - std::map temps_by_hct(GetTempsByHct()); - sort(hcts.begin(), hcts.end(), - [temps_by_hct](const Hct a, const Hct b) -> bool { - return temps_by_hct.at(a) < temps_by_hct.at(b); - }); - precomputed_hcts_by_temp_ = hcts; - return precomputed_hcts_by_temp_.value(); -} - -std::map TemperatureCache::GetTempsByHct() { - if (precomputed_temps_by_hct_.has_value()) { - return precomputed_temps_by_hct_.value(); - } - - std::vector all_hcts(GetHctsByHue()); - all_hcts.push_back(input_); - - std::map temperatures_by_hct; - for (Hct hct : all_hcts) { - temperatures_by_hct[hct] = RawTemperature(hct); - } - - precomputed_temps_by_hct_ = temperatures_by_hct; - return precomputed_temps_by_hct_.value(); -} - -Hct TemperatureCache::GetWarmest() { - return GetHctsByTemp().at(GetHctsByTemp().size() - 1); -} - -bool TemperatureCache::IsBetween(double angle, double a, double b) { - if (a < b) { - return a <= angle && angle <= b; - } - return a <= angle || angle <= b; -} - -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/temperature/temperature_cache.h b/src/material-colors/cpp/temperature/temperature_cache.h deleted file mode 100644 index 17e7c17..0000000 --- a/src/material-colors/cpp/temperature/temperature_cache.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_TEMPERATURE_TEMPERATURE_CACHE_H_ -#define CPP_TEMPERATURE_TEMPERATURE_CACHE_H_ - -#include -#include - -#include "cpp/cam/hct.h" - -namespace material_color_utilities { - -/** - * Design utilities using color temperature theory. - * - *

Analogous colors, complementary color, and cache to efficiently, lazily, - * generate data for calculations when needed. - */ -class TemperatureCache { - public: - /** - * Create a cache that allows calculation of ex. complementary and analogous - * colors. - * - * @param input Color to find complement/analogous colors of. Any colors will - * have the same tone, and chroma as the input color, modulo any restrictions - * due to the other hues having lower limits on chroma. - */ - explicit TemperatureCache(Hct input); - - /** - * A color that complements the input color aesthetically. - * - *

In art, this is usually described as being across the color wheel. - * History of this shows intent as a color that is just as cool-warm as the - * input color is warm-cool. - */ - Hct GetComplement(); - - /** - * 5 colors that pair well with the input color. - * - *

The colors are equidistant in temperature and adjacent in hue. - */ - std::vector GetAnalogousColors(); - - /** - * A set of colors with differing hues, equidistant in temperature. - * - *

In art, this is usually described as a set of 5 colors on a color wheel - * divided into 12 sections. This method allows provision of either of those - * values. - * - *

Behavior is undefined when count or divisions is 0. When divisions < - * count, colors repeat. - * - * @param count The number of colors to return, includes the input color. - * @param divisions The number of divisions on the color wheel. - */ - std::vector GetAnalogousColors(int count, int divisions); - - /** - * Temperature relative to all colors with the same chroma and tone. - * - * @param hct HCT to find the relative temperature of. - * @return Value on a scale from 0 to 1. - */ - double GetRelativeTemperature(Hct hct); - - /** - * Value representing cool-warm factor of a color. Values below 0 are - * considered cool, above, warm. - * - *

Color science has researched emotion and harmony, which art uses to - * select colors. Warm-cool is the foundation of analogous and complementary - * colors. See: - Li-Chen Ou's Chapter 19 in Handbook of Color Psychology - * (2015). - Josef Albers' Interaction of Color chapters 19 and 21. - * - *

Implementation of Ou, Woodcock and Wright's algorithm, which uses - * Lab/LCH color space. Return value has these properties:
- * - Values below 0 are cool, above 0 are warm.
- * - Lower bound: -9.66. Chroma is infinite. Assuming max of Lab chroma - * 130.
- * - Upper bound: 8.61. Chroma is infinite. Assuming max of Lab chroma 130. - */ - static double RawTemperature(Hct color); - - private: - Hct input_; - - std::optional precomputed_complement_; - std::optional> precomputed_hcts_by_temp_; - std::optional> precomputed_hcts_by_hue_; - std::optional> precomputed_temps_by_hct_; - - /** Coldest color with same chroma and tone as input. */ - Hct GetColdest(); - - /** Warmest color with same chroma and tone as input. */ - Hct GetWarmest(); - - /** Determines if an angle is between two other angles, rotating clockwise. */ - static bool IsBetween(double angle, double a, double b); - - /** - * HCTs for all colors with the same chroma/tone as the input. - * - *

Sorted by hue, ex. index 0 is hue 0. - */ - std::vector GetHctsByHue(); - - /** - * HCTs for all colors with the same chroma/tone as the input. - * - *

Sorted from coldest first to warmest last. - */ - std::vector GetHctsByTemp(); - - /** Keys of HCTs in GetHctsByTemp, values of raw temperature. */ - std::map GetTempsByHct(); -}; - -} // namespace material_color_utilities - -#endif // CPP_TEMPERATURE_TEMPERATURE_CACHE_H_ diff --git a/src/material-colors/cpp/temperature/temperature_cache_test.cpp b/src/material-colors/cpp/temperature/temperature_cache_test.cpp deleted file mode 100644 index f4a6f83..0000000 --- a/src/material-colors/cpp/temperature/temperature_cache_test.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/temperature/temperature_cache.h" - -#include - -#include "testing/base/public/gunit.h" -#include "cpp/cam/hct.h" - -namespace material_color_utilities { - -namespace { - -TEST(TemperatureCacheTest, RawTemperature) { - Hct blue_hct(0xff0000ff); - double blue_temp = TemperatureCache::RawTemperature(blue_hct); - EXPECT_NEAR(-1.393, blue_temp, 0.001); - - Hct red_hct(0xffff0000); - double red_temp = TemperatureCache::RawTemperature(red_hct); - EXPECT_NEAR(2.351, red_temp, 0.001); - - Hct green_hct(0xff00ff00); - double green_temp = TemperatureCache::RawTemperature(green_hct); - EXPECT_NEAR(-0.267, green_temp, 0.001); - - Hct white_hct(0xffffffff); - double white_temp = TemperatureCache::RawTemperature(white_hct); - EXPECT_NEAR(-0.5, white_temp, 0.001); - - Hct black_hct(0xff000000); - double black_temp = TemperatureCache::RawTemperature(black_hct); - EXPECT_NEAR(-0.5, black_temp, 0.001); -} - -TEST(TemperatureCacheTest, Complement) { - unsigned int blue_complement = - TemperatureCache(Hct(0xff0000ff)).GetComplement().ToInt(); - EXPECT_EQ(0xff9d0002, blue_complement); - - unsigned int red_complement = - TemperatureCache(Hct(0xffff0000)).GetComplement().ToInt(); - EXPECT_EQ(0xff007bfc, red_complement); - - unsigned int green_complement = - TemperatureCache(Hct(0xff00ff00)).GetComplement().ToInt(); - EXPECT_EQ(0xffffd2c9, green_complement); - - unsigned int white_complement = - TemperatureCache(Hct(0xffffffff)).GetComplement().ToInt(); - EXPECT_EQ(0xffffffff, white_complement); - - unsigned int black_complement = - TemperatureCache(Hct(0xff000000)).GetComplement().ToInt(); - EXPECT_EQ(0xff000000, black_complement); -} - -TEST(TemperatureCacheTest, Analogous) { - std::vector blue_analogous = - TemperatureCache(Hct(0xff0000ff)).GetAnalogousColors(); - EXPECT_EQ(0xff00590c, blue_analogous.at(0).ToInt()); - EXPECT_EQ(0xff00564e, blue_analogous.at(1).ToInt()); - EXPECT_EQ(0xff0000ff, blue_analogous.at(2).ToInt()); - EXPECT_EQ(0xff6700cc, blue_analogous.at(3).ToInt()); - EXPECT_EQ(0xff81009f, blue_analogous.at(4).ToInt()); - - std::vector red_analogous = - TemperatureCache(Hct(0xffff0000)).GetAnalogousColors(); - EXPECT_EQ(0xfff60082, red_analogous.at(0).ToInt()); - EXPECT_EQ(0xfffc004c, red_analogous.at(1).ToInt()); - EXPECT_EQ(0xffff0000, red_analogous.at(2).ToInt()); - EXPECT_EQ(0xffd95500, red_analogous.at(3).ToInt()); - EXPECT_EQ(0xffaf7200, red_analogous.at(4).ToInt()); - - std::vector green_analogous = - TemperatureCache(Hct(0xff00ff00)).GetAnalogousColors(); - EXPECT_EQ(0xffcee900, green_analogous.at(0).ToInt()); - EXPECT_EQ(0xff92f500, green_analogous.at(1).ToInt()); - EXPECT_EQ(0xff00ff00, green_analogous.at(2).ToInt()); - EXPECT_EQ(0xff00fd6f, green_analogous.at(3).ToInt()); - EXPECT_EQ(0xff00fab3, green_analogous.at(4).ToInt()); - - std::vector black_analogous = - TemperatureCache(Hct(0xff000000)).GetAnalogousColors(); - EXPECT_EQ(0xff000000, black_analogous.at(0).ToInt()); - EXPECT_EQ(0xff000000, black_analogous.at(1).ToInt()); - EXPECT_EQ(0xff000000, black_analogous.at(2).ToInt()); - EXPECT_EQ(0xff000000, black_analogous.at(3).ToInt()); - EXPECT_EQ(0xff000000, black_analogous.at(4).ToInt()); - - std::vector white_analogous = - TemperatureCache(Hct(0xffffffff)).GetAnalogousColors(); - EXPECT_EQ(0xffffffff, white_analogous.at(0).ToInt()); - EXPECT_EQ(0xffffffff, white_analogous.at(1).ToInt()); - EXPECT_EQ(0xffffffff, white_analogous.at(2).ToInt()); - EXPECT_EQ(0xffffffff, white_analogous.at(3).ToInt()); - EXPECT_EQ(0xffffffff, white_analogous.at(4).ToInt()); -} - -} // namespace -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/utils/utils.cpp b/src/material-colors/cpp/utils/utils.cpp deleted file mode 100644 index 6b36d8d..0000000 --- a/src/material-colors/cpp/utils/utils.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/utils/utils.h" - -#include - -#include -#include -#include -#include -#include -#include - -//#include "absl/strings/str_cat.h" - -namespace material_color_utilities { - -int RedFromInt(const Argb argb) { return (argb & 0x00ff0000) >> 16; } - -int GreenFromInt(const Argb argb) { return (argb & 0x0000ff00) >> 8; } - -int BlueFromInt(const Argb argb) { return (argb & 0x000000ff); } - -Argb ArgbFromRgb(const int red, const int green, const int blue) { - return 0xFF000000 | ((red & 0xff) << 16) | ((green & 0xff) << 8) | - (blue & 0xff); -} - -// Converts a color from linear RGB components to ARGB format. -Argb ArgbFromLinrgb(Vec3 linrgb) { - int r = Delinearized(linrgb.a); - int g = Delinearized(linrgb.b); - int b = Delinearized(linrgb.c); - - return 0xFF000000 | ((r & 0x0ff) << 16) | ((g & 0x0ff) << 8) | (b & 0x0ff); -} - -int Delinearized(const double rgb_component) { - double normalized = rgb_component / 100; - double delinearized; - if (normalized <= 0.0031308) { - delinearized = normalized * 12.92; - } else { - delinearized = 1.055 * std::pow(normalized, 1.0 / 2.4) - 0.055; - } - return std::clamp((int)round(delinearized * 255.0), 0, 255); -} - -double Linearized(const int rgb_component) { - double normalized = rgb_component / 255.0; - if (normalized <= 0.040449936) { - return normalized / 12.92 * 100.0; - } else { - return std::pow((normalized + 0.055) / 1.055, 2.4) * 100.0; - } -} - -int AlphaFromInt(Argb argb) { return (argb & 0xff000000) >> 24; } - -bool IsOpaque(Argb argb) { return AlphaFromInt(argb) == 255; } - -double LstarFromArgb(Argb argb) { - // xyz from argb - int red = (argb & 0x00ff0000) >> 16; - int green = (argb & 0x0000ff00) >> 8; - int blue = (argb & 0x000000ff); - double red_l = Linearized(red); - double green_l = Linearized(green); - double blue_l = Linearized(blue); - double y = 0.2126 * red_l + 0.7152 * green_l + 0.0722 * blue_l; - return LstarFromY(y); -} - -double YFromLstar(double lstar) { - static const double ke = 8.0; - if (lstar > ke) { - double cube_root = (lstar + 16.0) / 116.0; - double cube = cube_root * cube_root * cube_root; - return cube * 100.0; - } else { - return lstar / (24389.0 / 27.0) * 100.0; - } -} - -double LstarFromY(double y) { - static const double e = 216.0 / 24389.0; - double yNormalized = y / 100.0; - if (yNormalized <= e) { - return (24389.0 / 27.0) * yNormalized; - } else { - return 116.0 * std::pow(yNormalized, 1.0 / 3.0) - 16.0; - } -} - -int SanitizeDegreesInt(const int degrees) { - if (degrees < 0) { - return (degrees % 360) + 360; - } else if (degrees >= 360.0) { - return degrees % 360; - } else { - return degrees; - } -} - -// Sanitizes a degree measure as a floating-point number. -// -// Returns a degree measure between 0.0 (inclusive) and 360.0 (exclusive). -double SanitizeDegreesDouble(const double degrees) { - if (degrees < 0.0) { - return fmod(degrees, 360.0) + 360; - } else if (degrees >= 360.0) { - return fmod(degrees, 360.0); - } else { - return degrees; - } -} - -double DiffDegrees(const double a, const double b) { - return 180.0 - abs(abs(a - b) - 180.0); -} - -double RotationDirection(const double from, const double to) { - double increasing_difference = SanitizeDegreesDouble(to - from); - return increasing_difference <= 180.0 ? 1.0 : -1.0; -} - -// Converts a color in ARGB format to a hexadecimal string in lowercase. -// -// For instance: hex_from_argb(0xff012345) == "ff012345" -std::string HexFromArgb(Argb argb) { return std::to_string(argb); } - -Argb IntFromLstar(const double lstar) { - double y = YFromLstar(lstar); - int component = Delinearized(y); - return ArgbFromRgb(component, component, component); -} - -// The signum function. -// -// Returns 1 if num > 0, -1 if num < 0, and 0 if num = 0 -int Signum(double num) { - if (num < 0) { - return -1; - } else if (num == 0) { - return 0; - } else { - return 1; - } -} - -double Lerp(double start, double stop, double amount) { - return (1.0 - amount) * start + amount * stop; -} - -Vec3 MatrixMultiply(Vec3 input, const double matrix[3][3]) { - double a = - input.a * matrix[0][0] + input.b * matrix[0][1] + input.c * matrix[0][2]; - double b = - input.a * matrix[1][0] + input.b * matrix[1][1] + input.c * matrix[1][2]; - double c = - input.a * matrix[2][0] + input.b * matrix[2][1] + input.c * matrix[2][2]; - return (Vec3){a, b, c}; -} -} // namespace material_color_utilities diff --git a/src/material-colors/cpp/utils/utils.h b/src/material-colors/cpp/utils/utils.h deleted file mode 100644 index c890895..0000000 --- a/src/material-colors/cpp/utils/utils.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CPP_UTILS_UTILS_H_ -#define CPP_UTILS_UTILS_H_ - -#include -#include - -namespace material_color_utilities { - -using Argb = uint32_t; - -/** - * A vector with three floating-point numbers as components. - */ -struct Vec3 { - double a = 0.0; - double b = 0.0; - double c = 0.0; -}; - -/** - * Value of pi. - */ -inline constexpr double kPi = 3.141592653589793; - -/** - * Returns the standard white point; white on a sunny day. - */ -inline constexpr double kWhitePointD65[] = {95.047, 100.0, 108.883}; - -/** - * Returns the red component of a color in ARGB format. - */ -int RedFromInt(const Argb argb); - -/** - * Returns the green component of a color in ARGB format. - */ -int GreenFromInt(const Argb argb); - -/** - * Returns the blue component of a color in ARGB format. - */ -int BlueFromInt(const Argb argb); - -/** - * Returns the alpha component of a color in ARGB format. - */ -int AlphaFromInt(const Argb argb); - -/** - * Converts a color from RGB components to ARGB format. - */ -Argb ArgbFromRgb(const int red, const int green, const int blue); - -/** - * Converts a color from linear RGB components to ARGB format. - */ -Argb ArgbFromLinrgb(Vec3 linrgb); - -/** - * Returns whether a color in ARGB format is opaque. - */ -bool IsOpaque(const Argb argb); - -/** - * Sanitizes a degree measure as an integer. - * - * @return a degree measure between 0 (inclusive) and 360 (exclusive). - */ -int SanitizeDegreesInt(const int degrees); - -/** - * Sanitizes a degree measure as an floating-point number. - * - * @return a degree measure between 0.0 (inclusive) and 360.0 (exclusive). - */ -double SanitizeDegreesDouble(const double degrees); - -/** - * Distance of two points on a circle, represented using degrees. - */ -double DiffDegrees(const double a, const double b); - -/** - * Sign of direction change needed to travel from one angle to - * another. - * - * For angles that are 180 degrees apart from each other, both - * directions have the same travel distance, so either direction is - * shortest. The value 1.0 is returned in this case. - * - * @param from The angle travel starts from, in degrees. - * - * @param to The angle travel ends at, in degrees. - * - * @return -1 if decreasing from leads to the shortest travel - * distance, 1 if increasing from leads to the shortest travel - * distance. - */ -double RotationDirection(const double from, const double to); - -/** - * Computes the L* value of a color in ARGB representation. - * - * @param argb ARGB representation of a color - * - * @return L*, from L*a*b*, coordinate of the color - */ -double LstarFromArgb(const Argb argb); - -/** - * Returns the hexadecimal representation of a color. - */ -std::string HexFromArgb(Argb argb); - -/** - * Linearizes an RGB component. - * - * @param rgb_component 0 <= rgb_component <= 255, represents R/G/B - * channel - * - * @return 0.0 <= output <= 100.0, color channel converted to - * linear RGB space - */ -double Linearized(const int rgb_component); - -/** - * Delinearizes an RGB component. - * - * @param rgb_component 0.0 <= rgb_component <= 100.0, represents linear - * R/G/B channel - * - * @return 0 <= output <= 255, color channel converted to regular - * RGB space - */ -int Delinearized(const double rgb_component); - -/** - * Converts an L* value to a Y value. - * - * L* in L*a*b* and Y in XYZ measure the same quantity, luminance. - * - * L* measures perceptual luminance, a linear scale. Y in XYZ - * measures relative luminance, a logarithmic scale. - * - * @param lstar L* in L*a*b*. 0.0 <= L* <= 100.0 - * - * @return Y in XYZ. 0.0 <= Y <= 100.0 - */ -double YFromLstar(const double lstar); - -/** - * Converts a Y value to an L* value. - * - * L* in L*a*b* and Y in XYZ measure the same quantity, luminance. - * - * L* measures perceptual luminance, a linear scale. Y in XYZ - * measures relative luminance, a logarithmic scale. - * - * @param y Y in XYZ. 0.0 <= Y <= 100.0 - * - * @return L* in L*a*b*. 0.0 <= L* <= 100.0 - */ -double LstarFromY(const double y); - -/** - * Converts an L* value to an ARGB representation. - * - * @param lstar L* in L*a*b*. 0.0 <= L* <= 100.0 - * - * @return ARGB representation of grayscale color with lightness matching L* - */ -Argb IntFromLstar(const double lstar); - -/** - * The signum function. - * - * @return 1 if num > 0, -1 if num < 0, and 0 if num = 0 - */ -int Signum(double num); - -/** - * The linear interpolation function. - * - * @return start if amount = 0 and stop if amount = 1 - */ -double Lerp(double start, double stop, double amount); - -/** - * Multiplies a 1x3 row vector with a 3x3 matrix, returning the product. - */ -Vec3 MatrixMultiply(Vec3 input, const double matrix[3][3]); - -} // namespace material_color_utilities -#endif // CPP_UTILS_UTILS_H_ diff --git a/src/material-colors/cpp/utils/utils_test.cpp b/src/material-colors/cpp/utils/utils_test.cpp deleted file mode 100644 index d84a1da..0000000 --- a/src/material-colors/cpp/utils/utils_test.cpp +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "cpp/utils/utils.h" - -#include - -#include "testing/base/public/gmock.h" -#include "testing/base/public/gunit.h" - -namespace material_color_utilities { - -namespace { - -using testing::DoubleNear; - -constexpr double kMatrix[3][3] = { - {1, 2, 3}, - {-4, 5, -6}, - {-7, -8, -9}, -}; - -TEST(ArgbFromRgbTest, ReturnsCorrectValueForBlack) { - EXPECT_EQ(ArgbFromRgb(0, 0, 0), 0xff000000); - EXPECT_EQ(ArgbFromRgb(0, 0, 0), 4278190080); -} - -TEST(ArgbFromRgbTest, ReturnsCorrectValueForWhite) { - EXPECT_EQ(ArgbFromRgb(255, 255, 255), 0xffffffff); - EXPECT_EQ(ArgbFromRgb(255, 255, 255), 4294967295); -} - -TEST(ArgbFromRgbTest, ReturnsCorrectValueForRandomColor) { - EXPECT_EQ(ArgbFromRgb(50, 150, 250), 0xff3296fa); - EXPECT_EQ(ArgbFromRgb(50, 150, 250), 4281505530); -} - -TEST(UtilsTest, Signum) { - EXPECT_EQ(Signum(0.001), 1); - EXPECT_EQ(Signum(3.0), 1); - EXPECT_EQ(Signum(100.0), 1); - EXPECT_EQ(Signum(-0.002), -1); - EXPECT_EQ(Signum(-4.0), -1); - EXPECT_EQ(Signum(-101.0), -1); - EXPECT_EQ(Signum(0.0), 0); -} - -TEST(UtilsTest, RotationIsPositiveForCounterclockwise) { - EXPECT_EQ(RotationDirection(0.0, 30.0), 1.0); - EXPECT_EQ(RotationDirection(0.0, 60.0), 1.0); - EXPECT_EQ(RotationDirection(0.0, 150.0), 1.0); - EXPECT_EQ(RotationDirection(90.0, 240.0), 1.0); - EXPECT_EQ(RotationDirection(300.0, 30.0), 1.0); - EXPECT_EQ(RotationDirection(270.0, 60.0), 1.0); - EXPECT_EQ(RotationDirection(360.0 * 2, 15.0), 1.0); - EXPECT_EQ(RotationDirection(360.0 * 3 + 15.0, -360.0 * 4 + 30.0), 1.0); -} - -TEST(UtilsTest, RotationIsNegativeForClockwise) { - EXPECT_EQ(RotationDirection(30.0, 0.0), -1.0); - EXPECT_EQ(RotationDirection(60.0, 0.0), -1.0); - EXPECT_EQ(RotationDirection(150.0, 0.0), -1.0); - EXPECT_EQ(RotationDirection(240.0, 90.0), -1.0); - EXPECT_EQ(RotationDirection(30.0, 300.0), -1.0); - EXPECT_EQ(RotationDirection(60.0, 270.0), -1.0); - EXPECT_EQ(RotationDirection(15.0, -360.0 * 2), -1.0); - EXPECT_EQ(RotationDirection(-360.0 * 4 + 270.0, 360.0 * 5 + 180.0), -1.0); -} - -TEST(UtilsTest, AngleDifference) { - EXPECT_EQ(DiffDegrees(0.0, 30.0), 30.0); - EXPECT_EQ(DiffDegrees(0.0, 60.0), 60.0); - EXPECT_EQ(DiffDegrees(0.0, 150.0), 150.0); - EXPECT_EQ(DiffDegrees(90.0, 240.0), 150.0); - EXPECT_EQ(DiffDegrees(300.0, 30.0), 90.0); - EXPECT_EQ(DiffDegrees(270.0, 60.0), 150.0); - - EXPECT_EQ(DiffDegrees(30.0, 0.0), 30.0); - EXPECT_EQ(DiffDegrees(60.0, 0.0), 60.0); - EXPECT_EQ(DiffDegrees(150.0, 0.0), 150.0); - EXPECT_EQ(DiffDegrees(240.0, 90.0), 150.0); - EXPECT_EQ(DiffDegrees(30.0, 300.0), 90.0); - EXPECT_EQ(DiffDegrees(60.0, 270.0), 150.0); -} - -TEST(UtilsTest, AngleSanitation) { - EXPECT_EQ(SanitizeDegreesInt(30), 30); - EXPECT_EQ(SanitizeDegreesInt(240), 240); - EXPECT_EQ(SanitizeDegreesInt(360), 0); - EXPECT_EQ(SanitizeDegreesInt(-30), 330); - EXPECT_EQ(SanitizeDegreesInt(-750), 330); - EXPECT_EQ(SanitizeDegreesInt(-54321), 39); - - EXPECT_THAT(SanitizeDegreesDouble(30.0), DoubleNear(30.0, 1e-4)); - EXPECT_THAT(SanitizeDegreesDouble(240.0), DoubleNear(240.0, 1e-4)); - EXPECT_THAT(SanitizeDegreesDouble(360.0), DoubleNear(0.0, 1e-4)); - EXPECT_THAT(SanitizeDegreesDouble(-30.0), DoubleNear(330.0, 1e-4)); - EXPECT_THAT(SanitizeDegreesDouble(-750.0), DoubleNear(330.0, 1e-4)); - EXPECT_THAT(SanitizeDegreesDouble(-54321.0), DoubleNear(39.0, 1e-4)); - EXPECT_THAT(SanitizeDegreesDouble(360.125), DoubleNear(0.125, 1e-4)); - EXPECT_THAT(SanitizeDegreesDouble(-11111.11), DoubleNear(48.89, 1e-4)); -} - -TEST(UtilsTest, MatrixMultiply) { - Vec3 vector_one = MatrixMultiply({1, 3, 5}, kMatrix); - EXPECT_THAT(vector_one.a, DoubleNear(22, 1e-4)); - EXPECT_THAT(vector_one.b, DoubleNear(-19, 1e-4)); - EXPECT_THAT(vector_one.c, DoubleNear(-76, 1e-4)); - - Vec3 vector_two = MatrixMultiply({-11.1, 22.2, -33.3}, kMatrix); - EXPECT_THAT(vector_two.a, DoubleNear(-66.6, 1e-4)); - EXPECT_THAT(vector_two.b, DoubleNear(355.2, 1e-4)); - EXPECT_THAT(vector_two.c, DoubleNear(199.8, 1e-4)); -} - -TEST(UtilsTest, AlphaFromInt) { - EXPECT_EQ(AlphaFromInt(0xff123456), 0xff); - EXPECT_EQ(AlphaFromInt(0xffabcdef), 0xff); -} - -TEST(UtilsTest, RedFromInt) { - EXPECT_EQ(RedFromInt(0xff123456), 0x12); - EXPECT_EQ(RedFromInt(0xffabcdef), 0xab); -} - -TEST(UtilsTest, GreenFromInt) { - EXPECT_EQ(GreenFromInt(0xff123456), 0x34); - EXPECT_EQ(GreenFromInt(0xffabcdef), 0xcd); -} - -TEST(UtilsTest, BlueFromInt) { - EXPECT_EQ(BlueFromInt(0xff123456), 0x56); - EXPECT_EQ(BlueFromInt(0xffabcdef), 0xef); -} - -TEST(UtilsTest, Opaqueness) { - EXPECT_TRUE(IsOpaque(0xff123456)); - EXPECT_FALSE(IsOpaque(0xf0123456)); - EXPECT_FALSE(IsOpaque(0x00123456)); -} - -TEST(UtilsTest, LinearizedComponents) { - EXPECT_THAT(Linearized(0), DoubleNear(0.0, 1e-4)); - EXPECT_THAT(Linearized(1), DoubleNear(0.0303527, 1e-4)); - EXPECT_THAT(Linearized(2), DoubleNear(0.0607054, 1e-4)); - EXPECT_THAT(Linearized(8), DoubleNear(0.242822, 1e-4)); - EXPECT_THAT(Linearized(9), DoubleNear(0.273174, 1e-4)); - EXPECT_THAT(Linearized(16), DoubleNear(0.518152, 1e-4)); - EXPECT_THAT(Linearized(32), DoubleNear(1.44438, 1e-4)); - EXPECT_THAT(Linearized(64), DoubleNear(5.12695, 1e-4)); - EXPECT_THAT(Linearized(128), DoubleNear(21.5861, 1e-4)); - EXPECT_THAT(Linearized(255), DoubleNear(100.0, 1e-4)); -} - -TEST(UtilsTest, DelinearizedComponents) { - EXPECT_EQ(Delinearized(0.0), 0); - EXPECT_EQ(Delinearized(0.0303527), 1); - EXPECT_EQ(Delinearized(0.0607054), 2); - EXPECT_EQ(Delinearized(0.242822), 8); - EXPECT_EQ(Delinearized(0.273174), 9); - EXPECT_EQ(Delinearized(0.518152), 16); - EXPECT_EQ(Delinearized(1.44438), 32); - EXPECT_EQ(Delinearized(5.12695), 64); - EXPECT_EQ(Delinearized(21.5861), 128); - EXPECT_EQ(Delinearized(100.0), 255); - - EXPECT_EQ(Delinearized(25.0), 137); - EXPECT_EQ(Delinearized(50.0), 188); - EXPECT_EQ(Delinearized(75.0), 225); - - // Delinearized clamps out-of-range inputs. - EXPECT_EQ(Delinearized(-1.0), 0); - EXPECT_EQ(Delinearized(-10000.0), 0); - EXPECT_EQ(Delinearized(101.0), 255); - EXPECT_EQ(Delinearized(10000.0), 255); -} - -TEST(UtilsTest, DelinearizedIsLeftInverseOfLinearized) { - EXPECT_EQ(Delinearized(Linearized(0)), 0); - EXPECT_EQ(Delinearized(Linearized(1)), 1); - EXPECT_EQ(Delinearized(Linearized(2)), 2); - EXPECT_EQ(Delinearized(Linearized(8)), 8); - EXPECT_EQ(Delinearized(Linearized(9)), 9); - EXPECT_EQ(Delinearized(Linearized(16)), 16); - EXPECT_EQ(Delinearized(Linearized(32)), 32); - EXPECT_EQ(Delinearized(Linearized(64)), 64); - EXPECT_EQ(Delinearized(Linearized(128)), 128); - EXPECT_EQ(Delinearized(Linearized(255)), 255); -} - -TEST(UtilsTest, ArgbFromLinrgb) { - EXPECT_EQ(static_cast(ArgbFromLinrgb({25.0, 50.0, 75.0})), - 0xff89bce1); - EXPECT_EQ(static_cast(ArgbFromLinrgb({0.03, 0.06, 0.12})), - 0xff010204); -} - -TEST(UtilsTest, LstarFromArgb) { - EXPECT_THAT(LstarFromArgb(0xff89bce1), DoubleNear(74.011, 1e-4)); - EXPECT_THAT(LstarFromArgb(0xff010204), DoubleNear(0.529651, 1e-4)); -} - -TEST(UtilsTest, HexFromArgb) { - EXPECT_EQ(HexFromArgb(0xff89bce1), "ff89bce1"); - EXPECT_EQ(HexFromArgb(0xff010204), "ff010204"); -} - -TEST(UtilsTest, IntFromLstar) { - // Given an L* brightness value in [0, 100], IntFromLstar returns a greyscale - // color in ARGB format with that brightness. - // For L* outside the domain [0, 100], returns black or white. - - EXPECT_EQ(static_cast(IntFromLstar(0.0)), 0xff000000); - EXPECT_EQ(static_cast(IntFromLstar(0.25)), 0xff010101); - EXPECT_EQ(static_cast(IntFromLstar(0.5)), 0xff020202); - EXPECT_EQ(static_cast(IntFromLstar(1.0)), 0xff040404); - EXPECT_EQ(static_cast(IntFromLstar(2.0)), 0xff070707); - EXPECT_EQ(static_cast(IntFromLstar(4.0)), 0xff0e0e0e); - EXPECT_EQ(static_cast(IntFromLstar(8.0)), 0xff181818); - EXPECT_EQ(static_cast(IntFromLstar(25.0)), 0xff3b3b3b); - EXPECT_EQ(static_cast(IntFromLstar(50.0)), 0xff777777); - EXPECT_EQ(static_cast(IntFromLstar(75.0)), 0xffb9b9b9); - EXPECT_EQ(static_cast(IntFromLstar(99.0)), 0xfffcfcfc); - EXPECT_EQ(static_cast(IntFromLstar(100.0)), 0xffffffff); - - EXPECT_EQ(static_cast(IntFromLstar(-1.0)), 0xff000000); - EXPECT_EQ(static_cast(IntFromLstar(-2.0)), 0xff000000); - EXPECT_EQ(static_cast(IntFromLstar(-3.0)), 0xff000000); - EXPECT_EQ(static_cast(IntFromLstar(-9999999.0)), 0xff000000); - - EXPECT_EQ(static_cast(IntFromLstar(101.0)), 0xffffffff); - EXPECT_EQ(static_cast(IntFromLstar(111.0)), 0xffffffff); - EXPECT_EQ(static_cast(IntFromLstar(9999999.0)), 0xffffffff); -} - -TEST(UtilsTest, LstarArgbRoundtripProperty) { - // Confirms that L* -> ARGB -> L* preserves original value - // (taking ARGB rounding into consideration). - EXPECT_THAT(LstarFromArgb(IntFromLstar(0.0)), DoubleNear(0.0, 1.0)); - EXPECT_THAT(LstarFromArgb(IntFromLstar(1.0)), DoubleNear(1.0, 1.0)); - EXPECT_THAT(LstarFromArgb(IntFromLstar(2.0)), DoubleNear(2.0, 1.0)); - EXPECT_THAT(LstarFromArgb(IntFromLstar(8.0)), DoubleNear(8.0, 1.0)); - EXPECT_THAT(LstarFromArgb(IntFromLstar(25.0)), DoubleNear(25.0, 1.0)); - EXPECT_THAT(LstarFromArgb(IntFromLstar(50.0)), DoubleNear(50.0, 1.0)); - EXPECT_THAT(LstarFromArgb(IntFromLstar(75.0)), DoubleNear(75.0, 1.0)); - EXPECT_THAT(LstarFromArgb(IntFromLstar(99.0)), DoubleNear(99.0, 1.0)); - EXPECT_THAT(LstarFromArgb(IntFromLstar(100.0)), DoubleNear(100.0, 1.0)); -} - -TEST(UtilsTest, ArgbLstarRoundtripProperty) { - // Confirms that ARGB -> L* -> ARGB preserves original value - // for greyscale colors. - EXPECT_EQ(static_cast(IntFromLstar(LstarFromArgb(0xff000000))), - 0xff000000); - EXPECT_EQ(static_cast(IntFromLstar(LstarFromArgb(0xff010101))), - 0xff010101); - EXPECT_EQ(static_cast(IntFromLstar(LstarFromArgb(0xff020202))), - 0xff020202); - EXPECT_EQ(static_cast(IntFromLstar(LstarFromArgb(0xff111111))), - 0xff111111); - EXPECT_EQ(static_cast(IntFromLstar(LstarFromArgb(0xff333333))), - 0xff333333); - EXPECT_EQ(static_cast(IntFromLstar(LstarFromArgb(0xff777777))), - 0xff777777); - EXPECT_EQ(static_cast(IntFromLstar(LstarFromArgb(0xffbbbbbb))), - 0xffbbbbbb); - EXPECT_EQ(static_cast(IntFromLstar(LstarFromArgb(0xfffefefe))), - 0xfffefefe); - EXPECT_EQ(static_cast(IntFromLstar(LstarFromArgb(0xffffffff))), - 0xffffffff); -} - -TEST(UtilsTest, YFromLstar) { - EXPECT_THAT(YFromLstar(0.0), DoubleNear(0.0, 1e-5)); - EXPECT_THAT(YFromLstar(0.1), DoubleNear(0.0110705, 1e-5)); - EXPECT_THAT(YFromLstar(0.2), DoubleNear(0.0221411, 1e-5)); - EXPECT_THAT(YFromLstar(0.3), DoubleNear(0.0332116, 1e-5)); - EXPECT_THAT(YFromLstar(0.4), DoubleNear(0.0442822, 1e-5)); - EXPECT_THAT(YFromLstar(0.5), DoubleNear(0.0553528, 1e-5)); - EXPECT_THAT(YFromLstar(1.0), DoubleNear(0.1107056, 1e-5)); - EXPECT_THAT(YFromLstar(2.0), DoubleNear(0.2214112, 1e-5)); - EXPECT_THAT(YFromLstar(3.0), DoubleNear(0.3321169, 1e-5)); - EXPECT_THAT(YFromLstar(4.0), DoubleNear(0.4428225, 1e-5)); - EXPECT_THAT(YFromLstar(5.0), DoubleNear(0.5535282, 1e-5)); - EXPECT_THAT(YFromLstar(8.0), DoubleNear(0.8856451, 1e-5)); - EXPECT_THAT(YFromLstar(10.0), DoubleNear(1.1260199, 1e-5)); - EXPECT_THAT(YFromLstar(15.0), DoubleNear(1.9085832, 1e-5)); - EXPECT_THAT(YFromLstar(20.0), DoubleNear(2.9890524, 1e-5)); - EXPECT_THAT(YFromLstar(25.0), DoubleNear(4.4154767, 1e-5)); - EXPECT_THAT(YFromLstar(30.0), DoubleNear(6.2359055, 1e-5)); - EXPECT_THAT(YFromLstar(40.0), DoubleNear(11.2509737, 1e-5)); - EXPECT_THAT(YFromLstar(50.0), DoubleNear(18.4186518, 1e-5)); - EXPECT_THAT(YFromLstar(60.0), DoubleNear(28.1233342, 1e-5)); - EXPECT_THAT(YFromLstar(70.0), DoubleNear(40.7494157, 1e-5)); - EXPECT_THAT(YFromLstar(80.0), DoubleNear(56.6812907, 1e-5)); - EXPECT_THAT(YFromLstar(90.0), DoubleNear(76.3033539, 1e-5)); - EXPECT_THAT(YFromLstar(95.0), DoubleNear(87.6183294, 1e-5)); - EXPECT_THAT(YFromLstar(99.0), DoubleNear(97.4360239, 1e-5)); - EXPECT_THAT(YFromLstar(100.0), DoubleNear(100.0, 1e-5)); -} - -TEST(UtilsTest, LstarFromY) { - EXPECT_THAT(LstarFromY(0.0), DoubleNear(0.0, 1e-5)); - EXPECT_THAT(LstarFromY(0.1), DoubleNear(0.9032962, 1e-5)); - EXPECT_THAT(LstarFromY(0.2), DoubleNear(1.8065925, 1e-5)); - EXPECT_THAT(LstarFromY(0.3), DoubleNear(2.7098888, 1e-5)); - EXPECT_THAT(LstarFromY(0.4), DoubleNear(3.6131851, 1e-5)); - EXPECT_THAT(LstarFromY(0.5), DoubleNear(4.5164814, 1e-5)); - EXPECT_THAT(LstarFromY(0.8856451), DoubleNear(8.0, 1e-5)); - EXPECT_THAT(LstarFromY(1.0), DoubleNear(8.9914424, 1e-5)); - EXPECT_THAT(LstarFromY(2.0), DoubleNear(15.4872443, 1e-5)); - EXPECT_THAT(LstarFromY(3.0), DoubleNear(20.0438970, 1e-5)); - EXPECT_THAT(LstarFromY(4.0), DoubleNear(23.6714419, 1e-5)); - EXPECT_THAT(LstarFromY(5.0), DoubleNear(26.7347653, 1e-5)); - EXPECT_THAT(LstarFromY(10.0), DoubleNear(37.8424304, 1e-5)); - EXPECT_THAT(LstarFromY(15.0), DoubleNear(45.6341970, 1e-5)); - EXPECT_THAT(LstarFromY(20.0), DoubleNear(51.8372115, 1e-5)); - EXPECT_THAT(LstarFromY(25.0), DoubleNear(57.0754208, 1e-5)); - EXPECT_THAT(LstarFromY(30.0), DoubleNear(61.6542222, 1e-5)); - EXPECT_THAT(LstarFromY(40.0), DoubleNear(69.4695307, 1e-5)); - EXPECT_THAT(LstarFromY(50.0), DoubleNear(76.0692610, 1e-5)); - EXPECT_THAT(LstarFromY(60.0), DoubleNear(81.8381891, 1e-5)); - EXPECT_THAT(LstarFromY(70.0), DoubleNear(86.9968642, 1e-5)); - EXPECT_THAT(LstarFromY(80.0), DoubleNear(91.6848609, 1e-5)); - EXPECT_THAT(LstarFromY(90.0), DoubleNear(95.9967686, 1e-5)); - EXPECT_THAT(LstarFromY(95.0), DoubleNear(98.0335184, 1e-5)); - EXPECT_THAT(LstarFromY(99.0), DoubleNear(99.6120372, 1e-5)); - EXPECT_THAT(LstarFromY(100.0), DoubleNear(100.0, 1e-5)); -} - -TEST(UtilsTest, YLstarRoundtripProperty) { - // Confirms that Y -> L* -> Y preserves original value. - for (double y = 0.0; y <= 100.0; y += 0.1) { - double lstar = LstarFromY(y); - double reconstructedY = YFromLstar(lstar); - EXPECT_THAT(reconstructedY, DoubleNear(y, 1e-8)); - } -} - -TEST(UtilsTest, LstarYRoundtripProperty) { - // Confirms that L* -> Y -> L* preserves original value. - for (double lstar = 0.0; lstar <= 100.0; lstar += 0.1) { - double y = YFromLstar(lstar); - double reconstructedLstar = LstarFromY(y); - EXPECT_THAT(reconstructedLstar, DoubleNear(lstar, 1e-8)); - } -} - -} // namespace -} // namespace material_color_utilities diff --git a/src/mpris_connection.cpp b/src/mpris_connection.cpp index 7212d23..8022d15 100644 --- a/src/mpris_connection.cpp +++ b/src/mpris_connection.cpp @@ -5,7 +5,6 @@ #define IMGUI_DEFINE_MATH_OPERATORS #include "imgui.h" -#include #include #include #include @@ -20,7 +19,6 @@ MprisPlayer::MprisPlayer(std::string servicename) { image_path_cache = "NULL"; PlayerProxy = sdbus::createProxy(dest, objec); mp2 = "org.mpris.MediaPlayer2.Player"; - imagecount = 0; Refresh(); } @@ -64,33 +62,6 @@ void MprisPlayer::Refresh() { if (current_metadata["mpris:artUrl"].get() != image_path_cache) { image_path_cache = current_metadata["mpris:artUrl"].get(); UpdateTexture(); - auto img = LoadImageFromTexture(tex.tex); - - std::vector argbs; - material_color_utilities::QuantizerResult res; - if (img.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) { - auto data = (char*) img.data; - for (int i = 0; i < img.width * img.height * 4; i += 4) { - material_color_utilities::Argb color = (data[i] << 16) | (data[i + 1] << 8) | (data[i + 2]) | (data[i + 3] << 24); - argbs.push_back(color); - } - res = material_color_utilities::QuantizeCelebi(argbs, 16); - } else if (img.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) { - auto data = (char*) img.data; - for (int i = 0; i < img.width * img.height * 3; i += 3) { - material_color_utilities::Argb color = (data[i] << 16) | (data[i + 1] << 8) | (data[i + 2] | (0xFF << 24)); - argbs.push_back(color); - } - res = material_color_utilities::QuantizeCelebi(argbs, 16); - } - - auto colors = material_color_utilities::RankedSuggestions(res.color_to_count, material_color_utilities::ScoreOptions()); - accent_colors.clear(); - for (auto obj : colors) { - accent_colors.push_back((Color) {.r=(unsigned char) ((obj >> 16) & 0xFF), .g=(unsigned char)( (obj >> 8) & 0xFF ), .b=(unsigned char)((obj >> 0) & 0xFF), .a=(unsigned char)((obj>>24) & 0xFF) }); - } - imagecount = imagecount + 1; - } } catch (const std::exception& e) {} return; @@ -206,72 +177,11 @@ void MprisPlayer::UpdateTexture() { } } -Color MprisPlayer::GetPrimaryColor() { - if (accent_colors.empty()) { - return BLACK; - } else { - std::cout << "here" << std::endl; - return accent_colors[0]; - } -} - - -DiscObject::DiscObject(float ia) { - pos = 0; - prevouspos = 0; - velo = 0; - accel = 0; - target = ia; - active = true; - enabled = true; -} - -void DiscObject::Activate() { - active = !active; - pos = 0; - prevouspos = 0; - velo = 0; - accel = 0; - target = 0; -} - - - -void DiscObject::UpdatePos(float dtime) { - if (active) { - prevouspos = pos; - pos = pos + velo * dtime; - velo = velo + accel * dtime; - accel = target; - } -} - -void DiscObject::UpdatePos(float new_pos, float dtime) { - if (active) { - prevouspos = pos; - pos = new_pos; - velo = (pos - prevouspos) / dtime; - accel = target; - } -} - - -void DiscObject::AddAccel(float ac) { - accel = accel + ac; -} - RayTexture::RayTexture() { - auto rtex = LoadRenderTexture(300,300); - BeginTextureMode(rtex); - DrawRectangle(0,0,300,300,BLACK); - EndTextureMode(); - auto img = LoadImageFromTexture(rtex.texture); - tex = LoadTextureFromImage(img); - UnloadImage(img); - UnloadRenderTexture(rtex); + tex = LoadTexture(ASSET_DIR "/null.png" ); GenTextureMipmaps(&tex); SetTextureFilter(tex, TEXTURE_FILTER_BILINEAR); - path = "null"; + path = ASSET_DIR "/null.png"; } RayTexture::RayTexture(Image img) { diff --git a/src/mpris_connection.hpp b/src/mpris_connection.hpp index 30c98bd..18a4b6b 100644 --- a/src/mpris_connection.hpp +++ b/src/mpris_connection.hpp @@ -10,7 +10,6 @@ #include #include #include -#include "cpp/quantize/celebi.h" class RayTexture { public: @@ -23,23 +22,6 @@ class RayTexture { ~RayTexture(); }; -class DiscObject { -public: - float prevouspos; - float pos; - float velo; - float accel; - float target; - bool active; - bool enabled; - DiscObject(float ia); - void UpdatePos(float dtime); - void UpdatePos(float pos, float dtime); - void AddAccel(float ac); - void Activate(); -}; - - class MprisPlayer { public: std::unique_ptr bus_connection; @@ -47,9 +29,7 @@ class MprisPlayer { sdbus::InterfaceName mp2; sdbus::MethodName playpause; RayTexture tex; - std::vector accent_colors; std::string image_path_cache; - long imagecount; explicit MprisPlayer(std::string servicename); void PausePlay(); void Refresh(); @@ -61,7 +41,6 @@ class MprisPlayer { std::string GetIdentity(); std::unordered_map current_metadata; std::unordered_map GetCurrentMetadata(); - Color GetPrimaryColor(); };