Skip to content

ColorSeriesPatches

vtk-examples/Cxx/Visualization/ColorSeriesPatches

Description

This example shows how to produce a HTML page called VTKColorSeriesPatches showing the available colors series in vtkColorSeries.

It also shows how to select the text color based on luminance. In this case, Digital CCIR601 is used, which gives less weight to the red and blue components of a color.

Other languages

See (Python)

Question

If you have a question about this example, please use the VTK Discourse Forum

Code

ColorSeriesPatches.cxx

/*
 * Produce a HTML page called VTKColorSeriesPatches.html showing the available
 * color series in vtkColorSeries.
 *
 * It also shows how to select the text color based on luminance.
 * In this case Digital CCIR601 is used which gives less weight to the red and
 * blue components of a color.
 *
 */

#include <vtkColorSeries.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>

#include <algorithm>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <map>
#include <regex>
#include <sstream>
#include <string>
#include <vector>

namespace {

//! Convert to and from HTML color strings.
class HTMLToFromRGBAColor
{
public:
  HTMLToFromRGBAColor() = default;
  virtual ~HTMLToFromRGBAColor() = default;

public:
  bool IsValidHTMLColorString(std::string const& s);
  std::string RGBToHTMLColor(vtkColor3ub const& rgb);
  vtkColor3ub HTMLColorToRGB(std::string const& colorString);
  double RGBToLumaCCIR601(vtkColor3ub const& rgb);
};

/**
 * Holds the color series id, name and colors.
 */
class ColorStructures
{
public:
  ColorStructures() : max_colors(0)
  {
    this->Init();
  }

  virtual ~ColorStructures() = default;

private:
  void Init();

public:
  std::map<int, std::pair<std::string, std::vector<vtkColor3ub>>> cs_colors;
  int max_colors;
};

/**
 * This class creates a HTML Table displaying all the colors in
 * the class vtkColorSeries.
 */
class HTMLTableMaker
{

public:
  HTMLTableMaker() = default;

  ~HTMLTableMaker() = default;

public:
  std::string MakeHTMLTable();

private:
  std::string MakeHTMLStyle();
  std::string MakeHTMLHeader();
  std::string MakeTableHeader();
  std::string MakeTD1(int const idx, std::string const& name);
  std::string MakeTD2(std::vector<vtkColor3ub> const& rgb);
  std::string MakeTable();

private:
  vtkNew<vtkNamedColors> nc;
  ColorStructures cs = ColorStructures();
  HTMLToFromRGBAColor htmlRGBA = HTMLToFromRGBAColor();
};
} // namespace

int main(int argc, char* argv[])
{
  HTMLTableMaker ncpt;

  std::ofstream outputFile;
  outputFile.open("VTKColorSeriesPatches.html",
                  ios::out | ios::trunc | ios::binary);
  outputFile << ncpt.MakeHTMLTable();
  outputFile.close();

  return EXIT_SUCCESS;
}

namespace {

bool HTMLToFromRGBAColor::IsValidHTMLColorString(std::string const& s)
{
  if (s.size() == 7 || s.size() == 9) // #rrggbb or #rrggbbaa
  {
    if (s.compare(0, 1, "#") == 0 &&
        s.find_first_not_of("0123456789abcdefABCDEF", 1) == std::string::npos)
    {
      return true;
    }
  }
  return false;
}

std::string HTMLToFromRGBAColor::RGBToHTMLColor(vtkColor3ub const& rgb)
{
  std::string s = "#";
  std::ostringstream os;
  os << std::setfill('0') << std::hex << std::setw(2)
     << static_cast<unsigned int>(rgb.GetRed()) << std::setw(2)
     << static_cast<unsigned int>(rgb.GetGreen()) << std::setw(2)
     << static_cast<unsigned int>(rgb.GetBlue());
  s += os.str();
  return s;
}

vtkColor3ub HTMLToFromRGBAColor::HTMLColorToRGB(std::string const& colorString)
{
  vtkColor3ub c(0, 0, 0);
  if (IsValidHTMLColorString(colorString) && colorString.size() == 7)
  {
    auto i = 1;
    while (i < static_cast<int>(colorString.size()))
    {
      std::istringstream is(colorString.substr(i, 2));
      int x;
      is >> std::hex >> x;
      c[(i - 1) / 2] = x;
      i += 2;
    }
  }
  return c;
}

double HTMLToFromRGBAColor::RGBToLumaCCIR601(vtkColor3ub const& rgb)
{
  return 0.299 * rgb.GetRed() + 0.587 * rgb.GetGreen() + 0.114 * rgb.GetBlue();
}

void ColorStructures::Init()
{
  auto cs = vtkColorSeries::New();
  std::vector<int> sizes;
  for (auto i = 0; i < cs->GetNumberOfColorSchemes(); ++i)
  {
    cs->SetColorScheme(i);
    sizes.push_back(cs->GetNumberOfColors());
    std::vector<vtkColor3ub> vc;
    for (auto j = 0; j < cs->GetNumberOfColors(); ++j)
    {
      vc.push_back(cs->GetColor(j));
    }
    this->cs_colors[i] = std::pair<std::string, std::vector<vtkColor3ub>>(
        cs->GetColorSchemeName(), vc);
  }
  this->max_colors = *std::max_element(sizes.begin(), sizes.end());
}

std::string HTMLTableMaker::MakeHTMLStyle()
{
  std::string s = "  <style>\n";
  s += "\n";
  s += "  body {\n";
  s += "    background-color: snow\n";
  s += "  }\n";
  s += "  h1 {text-align:left;}\n";
  s += "  h2 {text-align:left;}\n";
  s += "  h3 {text-align:left;}\n";
  s += "  h4 {text-align:left;}\n";
  s += "  h5 {text-align:left;}\n";
  s += "  h6 {text-align:left;}\n";
  s += "\n";
  s += "  p {text-align:left;}\n";
  s += "\n";
  s += "  table {\n";
  s += "    font-family: arial, sans-serif;\n";
  s += "    border-collapse: collapse;\n";
  s += "    font-size: medium;\n";
  s += "    padding: 4px;\n";
  s += "  }\n";
  s += "\n";
  s += "  th {\n";
  s += "    background: LightSteelBlue;\n";
  s += "    font-size: medium;\n";
  s += "  }\n";
  s += "\n";
  s += "  th[colspan]:not([colspan=\"1\"]) {\n";
  s += "    background: LightSteelBlue;\n";
  s += "    font-size: medium;\n";
  s += "    text-align : center;\n";
  s += "    vertical-align : top;\n";
  s += "  }\n";
  s += "\n";
  s += "  tr {\n";
  s += "    background: MintCream;\n";
  s += "    vertical-align : top;\n";
  s += "  }\n";
  s += "\n";
  s += "  td {\n";
  s += "    background: MintCream;\n";
  s += "    border: 1px solid #dddddd;\n";
  s += "    text-align: left;\n";
  s += "    padding: 8px;\n";
  s += "    font-family: monospace;\n";
  s += "    font-size: medium;\n";
  s += "    font-weight: bold;\n";
  s += "  }\n";
  s += "\n";
  s += "  td[colspan]:not([colspan=\"1\"]) {\n";
  s += "    text-align : center;\n";
  s += "  }\n";
  s += "\n";
  s += "  .cour {\n";
  s += "    font-family: Courier;\n";
  s += "  }\n";
  s += "\n";
  s += "  html, body {\n";
  s += "    height: 100%;\n";
  s += "  }\n";
  s += "\n";
  s += "  html {\n";
  s += "    display: table;\n";
  s += "    margin: auto;\n";
  s += "  }\n";
  s += "\n";
  s += "  body {\n";
  s += "    display: table-cell;\n";
  s += "    vertical-align: middle;\n";
  s += "  }\n";
  s += "\n";
  s += "  thead {color: DarkGreen;}\n";
  s += "  tbody {color: MidnightBlue;}\n";
  s += "  tfoot {color: SaddleBrown;}\n";
  s += "\n";
  s += "  </style>\n";
  return s;
}

std::string HTMLTableMaker::MakeHTMLHeader()
{
  std::string s = "<!DOCTYPE html>\n";
  s += "<html lang=\"en\">\n";
  s += "<head>\n";
  s += "<meta charset=\"UTF-8\" />\n";
  s += "<title>vtkColorSeries</title>\n";
  s += this->MakeHTMLStyle();
  s += "</head>\n";
  return s;
}

std::string HTMLTableMaker::MakeTableHeader()
{
  std::string s = "<tr>\n";
  s += "<th>Index</th>\n";
  s +=
      "<th colspan=\"" + std::to_string(this->cs.max_colors) + "\">Name</th>\n";
  s += "</tr>\n";
  s += "<tr>\n";
  s += "<th></th>\n";
  s += "<th colspan=\"" + std::to_string(this->cs.max_colors) +
      "\">Colors in the Series</th>\n";
  s += "</tr>\n";
  return s;
}

std::string HTMLTableMaker::MakeTD1(int const idx, std::string const& name)
{
  std::string s = "<tr>\n";
  s += "<td>";
  s += "<b>" + std::to_string(idx) + "</b>";
  s += "</td>\n";

  s += "<td colspan=\"" + std::to_string(this->cs.max_colors) + "\">";
  s += "<b>" + name + "</b>";
  s += "</td>\n";
  s += "</tr>\n";
  return s;
}
std::string HTMLTableMaker::MakeTD2(std::vector<vtkColor3ub> const& rgbs)
{
  std::string s = "<tr>\n";
  s += "<td></td>\n";

  auto cnt = 0;
  for (auto p : rgbs)
  {
    std::ostringstream os;
    os << std::setw(3) << cnt << "&#160;&#160;";
    auto ss = std::regex_replace(os.str(), std::regex(" "), "&#160;");
    auto y = this->htmlRGBA.RGBToLumaCCIR601(p);
    std::string textColor{"#000000"}; // Black
    if (y < 255 / 2.0)
    {
      textColor = "#ffffff"; // White
    }
    s += "<td style=\"background:" + this->htmlRGBA.RGBToHTMLColor(p) +
        ";color:" + textColor;
    s += "\">" + ss + "</td>\n";
    ++cnt;
  }
  if (cnt < this->cs.max_colors)
  {
    s += "<td colspan=\"" + std::to_string(this->cs.max_colors - cnt) +
        "\"> &#160; </td>\n";
  }
  s += "</tr>\n";
  return s;
}

std::string HTMLTableMaker::MakeTable()
{
  auto res = this->MakeTableHeader();
  for (auto const& p : this->cs.cs_colors)
  {
    auto idx = p.first;
    auto name = p.second.first;
    res += this->MakeTD1(idx, name);
    res += this->MakeTD2(p.second.second);
  }
  return res;
}

std::string HTMLTableMaker::MakeHTMLTable()
{
  auto res = this->MakeHTMLHeader();
  res += "<body>\n";
  res += "<h1>Color series available in vtkColorSeries</h1>\n";
  res += "<table>\n";
  res += this->MakeTable();
  res += "</table>\n";
  res += "</body>\n";
  return res;
}

} // namespace

CMakeLists.txt

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)

project(ColorSeriesPatches)

find_package(VTK COMPONENTS 
  CommonColor
  CommonCore
)

if (NOT VTK_FOUND)
  message(FATAL_ERROR "ColorSeriesPatches: Unable to find the VTK build folder.")
endif()

# Prevent a "command line is too long" failure in Windows.
set(CMAKE_NINJA_FORCE_RESPONSE_FILE "ON" CACHE BOOL "Force Ninja to use response files.")
add_executable(ColorSeriesPatches MACOSX_BUNDLE ColorSeriesPatches.cxx )
  target_link_libraries(ColorSeriesPatches PRIVATE ${VTK_LIBRARIES}
)
# vtk_module_autoinit is needed
vtk_module_autoinit(
  TARGETS ColorSeriesPatches
  MODULES ${VTK_LIBRARIES}
)

Download and Build ColorSeriesPatches

Click here to download ColorSeriesPatches and its CMakeLists.txt file. Once the tarball ColorSeriesPatches.tar has been downloaded and extracted,

cd ColorSeriesPatches/build

If VTK is installed:

cmake ..

If VTK is not installed but compiled on your system, you will need to specify the path to your VTK build:

cmake -DVTK_DIR:PATH=/home/me/vtk_build ..

Build the project:

make

and run it:

./ColorSeriesPatches

WINDOWS USERS

Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.