Giter VIP home page Giter VIP logo

vivid-1's Introduction

vivid ๐ŸŒˆ

A simple-to-use cpp color library

  • color space conversions
  • perceptual color interpolation
  • popular and custom color maps
  • xterm names and ansi codes
  • ansi escape sequences and html encoding
  • (somewhat) unit tested in itself and against QColor
  • qmake and cmake support
using namespace vivid;

//  create and interpolate colors
Color c1( "indianred" );
Color c2( { 0.f, 0.4f, 0.5f }, Color::SpaceHsl );

auto interp = lerp( c1, c2, 0.5f );
std::string hex = interp.hex();

//  quick access to popular colormaps for data visualization
ColorMap cmap( ColorMap::Viridis );
Color mid = cmap.at( 0.5f );

//  ansi and html encodings
std::cout << ansi::fg( 163 ) << "woah!!" << ansi::reset;
fout << html::bg( "#abc123" ) << "styled background color" << html::close;

Content

Motivation

Things we create should be beautiful. Be it a console log message or a real-time volumetric data plot. I'm working with colors quite often, but found the available means to work with them lacking. Especially if you want to just get stuff (he said stuff) done and your ideas down in code. Over time, I gathered all the little snippets and helpers I had created, and thus this project was born.

vivid allows you to quickly create, lookup and convert colors. It provides perceptual color interpolation, easy access to color names, ascii escape codes and to some of the great data visualization color palettes out there.

Getting Started

git clone [email protected]:gurki/vivid.git
git submodule update --init

This repository comes with support for both qmake (vivid.pri) and cmake projects. You can try it out by simply opening up examples/qmake/vivid.pro in Qt Creator, or running

mkdir build && cd build
cmake .. && make
./examples/cmake/vivid_example

Dependencies

vivid depends on a small number of header-only libraries, which are mostly included as submodules.

Types

vivid provides a convenient Color class, which is intended to be flexible and easy to use. It stores colors as combination of float-triplet values (col_t โ‰ก glm::vec<3, float>) and their associated space โˆˆ {RGB, HSV, HSL, LCH}. It can be implicitly constructed from any of the supported color formats and spaces, e.g. Color col( "#abcdef" );. Conversions to other color spaces are directly available using e.g. col.hsl() or col.hex(). 8-bit colors are represented using either byte-triplets (col8_t โ‰ก glm::vec<3, uint8_t>) or compactly as uint32_t (ARGB), where alpha is set to 0xff by default. Lossy conversion, e.g. getting the name or index of some non-xterm color, will return the closest valid color/value in that space.

Color Spaces

Under the hood, vivid uses an extensive set of direct conversions (c.f. include/vivid/conversion.h). It additionally provides a bunch of shortcuts for multi-step conversions. All of these methods are built in a functional way, where colors get passed through converters, yielding new colors in different spaces. The caller must (to some degree) ensure the integrity of the input data passed. E.g. vivid::xyz::fromLab indeed assumes, that it is handed a vivid::col_t encoding a valid L*a*b color representation.

Direct Conversions

The following direct conversions are currently available.

adobe โ† xyz
hex โ† rgb8, index
hsl โ† rgb, index
hsv โ† rgb
index โ† rgb8, name
lab โ† xyz, lch
lch โ† lab
linear โ† srgb
name โ† index
rgb โ† rgb8, hsv, hsl
rgb32 โ† rgb, hex
rgb8 โ† rgb, rgb32, index
srgb โ† xyz
xyz โ† lab, srgb, adobe

RGB Working Spaces

vivid assumes a default sRGB working space. Specifically, the conversion between RGB and XYZ applies sRGB compounding and inverse compounding. You can also extend this using the low-level API. If you have no idea what I just said, don't worry - I didn't either a couple weeks ago :). You can use this library as high-level or low-level as you like.

//  manual wide gamut rgb to xyz conversion
static const float wideGamutGamma = 2.2f;
static const glm::mat3 wideToXyz = {    //  will be transposed due to column-major init
    0.7161046f, 0.1009296f, 0.1471858f,
    0.2581874f, 0.7249378f, 0.0168748f,
    0.0000000f, 0.0517813f, 0.7734287f
};

col_t wide = { 1.f, 0.f, 0.f };
auto linear = rgb::invGamma( wide, wideGamutGamma );
auto xyz = linear * wideToXyz;          //  post-multiply to save transposition

Interpolation

//  pseudo-code to generate the images in this section
for ( auto& pixel : image ) {
    const float t = pixel.x / image.width;
    const auto col = lerp( c1, c2, t );
    image.setColor( pixel, col );
}

Color interpolation is an interesting topic. What should the color halfway in-between red and green look like? There is a great article introducing this topic by Grego Aisch [^1]. In order to do a perceptually linear transition from one color to another, we can't simply linearly interpolate two RGB-vectors. Rather, we move to a more suitable color space, interpolate there, and then move back again. Namely, we use the CIE L*C*h(ab) space, or LCH, which matches the human visual system rather well. There are more suitable color spaces nowadays to do so, but LCH has a nice balance between complexity (code and computation) and outcome.

Compare the following table to get an idea of interpolating in different color spaces.

Color Space Linear Interpolation
RGB lerp-rgb
LCH lerp-lch
HSV lerp-hsv
HSL (Clamped) lerp-hsl-clamped

vivid provides low-level interpolations for the four main spaces RGB, HSL, HSV, LCH. They can be accessed directly via e.g. rgb::lerp( const col_t&, const col_t&, const float ), or implicitly via lerp( const Color&, const Color&, const float ). Note, that the latter requires the Color objects to be in the same space. Otherwise, an invalid color is returned.

[^1]] Grego Aisch (2011) - How To Avoid Equidistant HSV Colors

Color Maps

vivid comes with a set of pre-defined color maps, which I conveniently gathered under one umbrella. Thanks to the awesome community out there for their great work! [^2,\^3]]

As shown in the example in the beginning, it's quick and easy to query colors from a certain color map. You can also create your own maps by simply loading an according *.json file.

//  loading a custom color map
ColorMap cmap( VIVID_ROOT_PATH "res/colormaps/mycolormap.json" );
auto mid = cmap.at( 0.5f );
Name Image
Inferno inferno
Magma magma
Plasma plasma
Viridis viridis
Vivid vivid
Rainbow vivid
Hsl hsl
Hsl Pastel hsl-pastel
Blue-Yellow vivid
Cool-Warm vivid

[^2]] Stefan & Nathaniel - MPL Colormaps
[^3]] SciVisColor

Encodings

vivid provides encodings for ansi escape codes (pretty console <3) and html using spans.

ANSI

You can colorize console messages very simply using the vivid::ansi helpers.

std::cout << ansi::fg( 136 ) << "and tada, colorized font" << ansi::reset;

To get an overview of all color codes or quickly check if your console has 8-bit color support, you can call printColorTable() (shoutout to Gawin [^4] for the layout idea).

colortable

Escape codes can also be used in conjunction with ColorMaps to create some joyful effects.

ColorMap rainbowMap( ColorMap::PresetRainbow );
std::string text = "How can you tell? - Raaaaaaiiiinbooooooowwws.";
std::cout << ansi::colorize( text, rainbowMap ) << std::endl;

rainbows

HTML

One of my side projects is a tagged logging system, where one of the sinks goes to html. This has become very handy.

Color col( "LightSteelBlue" );
fout << html::fg( col ) << "colorized html text!" << html::close;
//  <span style='color:rgb(175, 175, 255)'>colorized html text!</span>

[^4] Gawin's xterm color demo

Attributions

Shoutout and thanks to the great reddit community over at r/cpp for comments, feedback and suggestions! <3

vivid-1's People

Contributors

gurki avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.