这是indexloc提供的服务,不要输入任何密码
Skip to content

Create 256 color palette #36

@nobe4

Description

@nobe4

https://github.com/termstandard/colors

msgcat code dump
origin	git://git.savannah.gnu.org/gettext.git (fetch)
origin	git://git.savannah.gnu.org/gettext.git (push)
/* Print a color test page.  */
void
print_color_test ()
{
  /* Code copied from test-term-ostream.c.  */
  static struct { const char *name; term_color_t c; int r; int g; int b; }
         colors[] =
    {
      { "black",   -2,   0,   0,   0 },
      { "blue",    -2,   0,   0, 255 },
      { "green",   -2,   0, 255,   0 },
      { "cyan",    -2,   0, 255, 255 },
      { "red",     -2, 255,   0,   0 },
      { "magenta", -2, 255,   0, 255 },
      { "yellow",  -2, 255, 255,   0 },
      { "white",   -2, 255, 255, 255 },
      { "default", COLOR_DEFAULT, /* unused: */ -1, -1, -1 }
    };
  term_ostream_t stream;
  int i, row, col;

  stream = term_ostream_create (1, "stdout", TTYCTL_AUTO);

  for (i = 0; i < 8; i++)
    colors[i].c =
      term_ostream_rgb_to_color (stream, colors[i].r, colors[i].g, colors[i].b);

  ostream_write_str (stream, "Colors (foreground/background):\n");
  ostream_write_str (stream, "       ");
  for (col = 0; col <= 8; col++)
    {
      const char *name = colors[col].name;
      ostream_write_str (stream, "|");
      ostream_write_str (stream, name);
      ostream_write_mem (stream, "        ", 7 - strlen (name));
    }
  ostream_write_str (stream, "\n");
  for (row = 0; row <= 8; row++)
    {
      const char *name = colors[row].name;
      ostream_write_str (stream, name);
      ostream_write_mem (stream, "        ", 7 - strlen (name));
      for (col = 0; col <= 8; col++)
        {
          term_color_t row_color = colors[row].c;
          term_color_t col_color = colors[col].c;

          ostream_write_str (stream, "|");
          term_ostream_set_color (stream, row_color);
          term_ostream_set_bgcolor (stream, col_color);
          if (!(term_ostream_get_color (stream) == row_color
                && term_ostream_get_bgcolor (stream) == col_color))
            abort ();
          ostream_write_str (stream, " Words ");
          term_ostream_set_color (stream, COLOR_DEFAULT);
          term_ostream_set_bgcolor (stream, COLOR_DEFAULT);
          if (!(term_ostream_get_color (stream) == COLOR_DEFAULT
                && term_ostream_get_bgcolor (stream) == COLOR_DEFAULT))
            abort ();
        }
      ostream_write_str (stream, "\n");
    }
  ostream_write_str (stream, "\n");

  ostream_write_str (stream, "Colors (hue/saturation):\n");
  /* Hue from 0 to 1.  */
  for (row = 0; row <= 17; row++)
    {
      ostream_write_str (stream, row == 0 ? "red:     " : "         ");
      for (col = 0; col <= 64; col++)
        {
          int r = 255;
          int b = (int) (255.0f / 64.0f * col + 0.5f);
          int g = b + (int) (row / 17.0f * (r - b) + 0.5f);
          term_color_t c = term_ostream_rgb_to_color (stream, r, g, b);
          term_ostream_set_bgcolor (stream, c);
          ostream_write_str (stream, " ");
          term_ostream_set_bgcolor (stream, COLOR_DEFAULT);
        }
      ostream_write_str (stream, "\n");
    }
  /* Hue from 1 to 2.  */
  for (row = 17; row >= 0; row--)
    {
      ostream_write_str (stream, row == 17 ? "yellow:  " : "         ");
      for (col = 0; col <= 64; col++)
        {
          int g = 255;
          int b = (int) (255.0f / 64.0f * col + 0.5f);
          int r = b + (int) (row / 17.0f * (g - b) + 0.5f);
          term_color_t c = term_ostream_rgb_to_color (stream, r, g, b);
          term_ostream_set_bgcolor (stream, c);
          ostream_write_str (stream, " ");
          term_ostream_set_bgcolor (stream, COLOR_DEFAULT);
        }
      ostream_write_str (stream, "\n");
    }
  /* Hue from 2 to 3.  */
  for (row = 0; row <= 17; row++)
    {
      ostream_write_str (stream, row == 0 ? "green:   " : "         ");
      for (col = 0; col <= 64; col++)
        {
          int g = 255;
          int r = (int) (255.0f / 64.0f * col + 0.5f);
          int b = r + (int) (row / 17.0f * (g - r) + 0.5f);
          term_color_t c = term_ostream_rgb_to_color (stream, r, g, b);
          term_ostream_set_bgcolor (stream, c);
          ostream_write_str (stream, " ");
          term_ostream_set_bgcolor (stream, COLOR_DEFAULT);
        }
      ostream_write_str (stream, "\n");
    }
  /* Hue from 3 to 4.  */
  for (row = 17; row >= 0; row--)
    {
      ostream_write_str (stream, row == 17 ? "cyan:    " : "         ");
      for (col = 0; col <= 64; col++)
        {
          int b = 255;
          int r = (int) (255.0f / 64.0f * col + 0.5f);
          int g = r + (int) (row / 17.0f * (b - r) + 0.5f);
          term_color_t c = term_ostream_rgb_to_color (stream, r, g, b);
          term_ostream_set_bgcolor (stream, c);
          ostream_write_str (stream, " ");
          term_ostream_set_bgcolor (stream, COLOR_DEFAULT);
        }
      ostream_write_str (stream, "\n");
    }
  /* Hue from 4 to 5.  */
  for (row = 0; row <= 17; row++)
    {
      ostream_write_str (stream, row == 0 ? "blue:    " : "         ");
      for (col = 0; col <= 64; col++)
        {
          int b = 255;
          int g = (int) (255.0f / 64.0f * col + 0.5f);
          int r = g + (int) (row / 17.0f * (b - g) + 0.5f);
          term_color_t c = term_ostream_rgb_to_color (stream, r, g, b);
          term_ostream_set_bgcolor (stream, c);
          ostream_write_str (stream, " ");
          term_ostream_set_bgcolor (stream, COLOR_DEFAULT);
        }
      ostream_write_str (stream, "\n");
    }
  /* Hue from 5 to 6.  */
  for (row = 17; row >= 0; row--)
    {
      ostream_write_str (stream, row == 17 ? "magenta: " :
                                 row == 0 ? "red:     " : "         ");
      for (col = 0; col <= 64; col++)
        {
          int r = 255;
          int g = (int) (255.0f / 64.0f * col + 0.5f);
          int b = g + (int) (row / 17.0f * (r - g) + 0.5f);
          term_color_t c = term_ostream_rgb_to_color (stream, r, g, b);
          term_ostream_set_bgcolor (stream, c);
          ostream_write_str (stream, " ");
          term_ostream_set_bgcolor (stream, COLOR_DEFAULT);
        }
      ostream_write_str (stream, "\n");
    }
  ostream_write_str (stream, "\n");

  ostream_write_str (stream, "Weights:\n");
  term_ostream_set_weight (stream, WEIGHT_NORMAL);
  if (term_ostream_get_weight (stream) != WEIGHT_NORMAL)
    abort ();
  ostream_write_str (stream, "normal, ");
  term_ostream_set_weight (stream, WEIGHT_BOLD);
  if (term_ostream_get_weight (stream) != WEIGHT_BOLD)
    abort ();
  ostream_write_str (stream, "bold, ");
  term_ostream_set_weight (stream, WEIGHT_DEFAULT);
  if (term_ostream_get_weight (stream) != WEIGHT_DEFAULT)
    abort ();
  ostream_write_str (stream, "default \n");
  ostream_write_str (stream, "\n");

  ostream_write_str (stream, "Postures:\n");
  term_ostream_set_posture (stream, POSTURE_NORMAL);
  if (term_ostream_get_posture (stream) != POSTURE_NORMAL)
    abort ();
  ostream_write_str (stream, "normal, ");
  term_ostream_set_posture (stream, POSTURE_ITALIC);
  if (term_ostream_get_posture (stream) != POSTURE_ITALIC)
    abort ();
  ostream_write_str (stream, "italic, ");
  term_ostream_set_posture (stream, POSTURE_DEFAULT);
  if (term_ostream_get_posture (stream) != POSTURE_DEFAULT)
    abort ();
  ostream_write_str (stream, "default \n");
  ostream_write_str (stream, "\n");

  ostream_write_str (stream, "Text decorations:\n");
  term_ostream_set_underline (stream, UNDERLINE_OFF);
  if (term_ostream_get_underline (stream) != UNDERLINE_OFF)
    abort ();
  ostream_write_str (stream, "normal, ");
  term_ostream_set_underline (stream, UNDERLINE_ON);
  if (term_ostream_get_underline (stream) != UNDERLINE_ON)
    abort ();
  ostream_write_str (stream, "underlined, ");
  term_ostream_set_underline (stream, UNDERLINE_DEFAULT);
  if (term_ostream_get_underline (stream) != UNDERLINE_DEFAULT)
    abort ();
  ostream_write_str (stream, "default \n");
  ostream_write_str (stream, "\n");

  ostream_write_str (stream, "Colors (foreground) mixed with attributes:\n");
  for (row = 0; row <= 8; row++)
    {
      const char *name = colors[row].name;
      ostream_write_str (stream, name);
      ostream_write_mem (stream, "        ", 7 - strlen (name));
      term_ostream_set_color (stream, colors[row].c);
      ostream_write_str (stream, "|normal|");
      term_ostream_set_weight (stream, WEIGHT_BOLD);
      ostream_write_str (stream, "bold");
      term_ostream_set_weight (stream, WEIGHT_NORMAL);
      ostream_write_str (stream, "|normal|");
      term_ostream_set_posture (stream, POSTURE_ITALIC);
      ostream_write_str (stream, "italic");
      term_ostream_set_posture (stream, POSTURE_NORMAL);
      ostream_write_str (stream, "|normal|");
      term_ostream_set_underline (stream, UNDERLINE_ON);
      ostream_write_str (stream, "underlined");
      term_ostream_set_underline (stream, UNDERLINE_OFF);
      ostream_write_str (stream, "|normal|");
      term_ostream_set_color (stream, COLOR_DEFAULT);
      ostream_write_str (stream, "\n       ");
      term_ostream_set_color (stream, colors[row].c);
      ostream_write_str (stream, "|normal|");
      term_ostream_set_weight (stream, WEIGHT_BOLD);
      term_ostream_set_posture (stream, POSTURE_ITALIC);
      ostream_write_str (stream, "bold+italic");
      term_ostream_set_weight (stream, WEIGHT_NORMAL);
      term_ostream_set_posture (stream, POSTURE_NORMAL);
      ostream_write_str (stream, "|normal|");
      term_ostream_set_weight (stream, WEIGHT_BOLD);
      term_ostream_set_underline (stream, UNDERLINE_ON);
      ostream_write_str (stream, "bold+underl");
      term_ostream_set_weight (stream, WEIGHT_NORMAL);
      term_ostream_set_underline (stream, UNDERLINE_OFF);
      ostream_write_str (stream, "|normal|");
      term_ostream_set_posture (stream, POSTURE_ITALIC);
      term_ostream_set_underline (stream, UNDERLINE_ON);
      ostream_write_str (stream, "italic+underl");
      term_ostream_set_posture (stream, POSTURE_NORMAL);
      term_ostream_set_underline (stream, UNDERLINE_OFF);
      ostream_write_str (stream, "|normal|");
      term_ostream_set_color (stream, COLOR_DEFAULT);
      ostream_write_str (stream, "\n");
    }
  ostream_write_str (stream, "\n");

  ostream_write_str (stream, "Colors (background) mixed with attributes:\n");
  for (row = 0; row <= 8; row++)
    {
      const char *name = colors[row].name;
      ostream_write_str (stream, name);
      ostream_write_mem (stream, "        ", 7 - strlen (name));
      term_ostream_set_bgcolor (stream, colors[row].c);
      ostream_write_str (stream, "|normal|");
      term_ostream_set_weight (stream, WEIGHT_BOLD);
      ostream_write_str (stream, "bold");
      term_ostream_set_weight (stream, WEIGHT_NORMAL);
      ostream_write_str (stream, "|normal|");
      term_ostream_set_posture (stream, POSTURE_ITALIC);
      ostream_write_str (stream, "italic");
      term_ostream_set_posture (stream, POSTURE_NORMAL);
      ostream_write_str (stream, "|normal|");
      term_ostream_set_underline (stream, UNDERLINE_ON);
      ostream_write_str (stream, "underlined");
      term_ostream_set_underline (stream, UNDERLINE_OFF);
      ostream_write_str (stream, "|normal|");
      term_ostream_set_bgcolor (stream, COLOR_DEFAULT);
      ostream_write_str (stream, "\n       ");
      term_ostream_set_bgcolor (stream, colors[row].c);
      ostream_write_str (stream, "|normal|");
      term_ostream_set_weight (stream, WEIGHT_BOLD);
      term_ostream_set_posture (stream, POSTURE_ITALIC);
      ostream_write_str (stream, "bold+italic");
      term_ostream_set_weight (stream, WEIGHT_NORMAL);
      term_ostream_set_posture (stream, POSTURE_NORMAL);
      ostream_write_str (stream, "|normal|");
      term_ostream_set_weight (stream, WEIGHT_BOLD);
      term_ostream_set_underline (stream, UNDERLINE_ON);
      ostream_write_str (stream, "bold+underl");
      term_ostream_set_weight (stream, WEIGHT_NORMAL);
      term_ostream_set_underline (stream, UNDERLINE_OFF);
      ostream_write_str (stream, "|normal|");
      term_ostream_set_posture (stream, POSTURE_ITALIC);
      term_ostream_set_underline (stream, UNDERLINE_ON);
      ostream_write_str (stream, "italic+underl");
      term_ostream_set_posture (stream, POSTURE_NORMAL);
      term_ostream_set_underline (stream, UNDERLINE_OFF);
      ostream_write_str (stream, "|normal|");
      term_ostream_set_bgcolor (stream, COLOR_DEFAULT);
      ostream_write_str (stream, "\n");
    }
  ostream_write_str (stream, "\n");

  ostream_free (stream);
}

/* Conversion of a color in RGB to HSV format.  */
static void
rgb_to_hsv (rgb_t c, hsv_t *result)
{
  unsigned int r = c.red;
  unsigned int g = c.green;
  unsigned int b = c.blue;

  if (r > g)
    {
      if (b > r)
        {
          /* b > r > g, so max = b, min = g */
          result->hue = 4.0f + (float) (r - g) / (float) (b - g);
          result->saturation = 1.0f - (float) g / (float) b;
          result->brightness = (float) b / 255.0f;
        }
      else if (b <= g)
        {
          /* r > g >= b, so max = r, min = b */
          result->hue = 0.0f + (float) (g - b) / (float) (r - b);
          result->saturation = 1.0f - (float) b / (float) r;
          result->brightness = (float) r / 255.0f;
        }
      else
        {
          /* r >= b > g, so max = r, min = g */
          result->hue = 6.0f - (float) (b - g) / (float) (r - g);
          result->saturation = 1.0f - (float) g / (float) r;
          result->brightness = (float) r / 255.0f;
        }
    }
  else
    {
      if (b > g)
        {
          /* b > g >= r, so max = b, min = r */
          result->hue = 4.0f - (float) (g - r) / (float) (b - r);
          result->saturation = 1.0f - (float) r / (float) b;
          result->brightness = (float) b / 255.0f;
        }
      else if (b < r)
        {
          /* g >= r > b, so max = g, min = b */
          result->hue = 2.0f - (float) (r - b) / (float) (g - b);
          result->saturation = 1.0f - (float) b / (float) g;
          result->brightness = (float) g / 255.0f;
        }
      else if (g > r)
        {
          /* g >= b >= r, g > r, so max = g, min = r */
          result->hue = 2.0f + (float) (b - r) / (float) (g - r);
          result->saturation = 1.0f - (float) r / (float) g;
          result->brightness = (float) g / 255.0f;
        }
      else
        {
          /* r = g = b.  A grey color.  */
          result->hue = 0; /* arbitrary */
          result->saturation = 0;
          result->brightness = (float) r / 255.0f;
        }
    }
}

/* Square of distance of two colors.  */
static float
color_distance (const hsv_t *color1, const hsv_t *color2)
{
#if 0
  /* Formula taken from "John Smith: Color Similarity",
       http://www.ctr.columbia.edu/~jrsmith/html/pubs/acmmm96/node8.html.  */
  float angle1 = color1->hue * 1.04719755f; /* normalize to [0,2π] */
  float angle2 = color2->hue * 1.04719755f; /* normalize to [0,2π] */
  float delta_x = color1->saturation * cosf (angle1)
                  - color2->saturation * cosf (angle2);
  float delta_y = color1->saturation * sinf (angle1)
                  - color2->saturation * sinf (angle2);
  float delta_v = color1->brightness
                  - color2->brightness;

  return delta_x * delta_x + delta_y * delta_y + delta_v * delta_v;
#else
  /* Formula that considers hue differences with more weight than saturation
     or brightness differences, like the human eye does.  */
  float delta_hue =
    (color1->hue >= color2->hue
     ? (color1->hue - color2->hue >= 3.0f
        ? 6.0f + color2->hue - color1->hue
        : color1->hue - color2->hue)
     : (color2->hue - color1->hue >= 3.0f
        ? 6.0f + color1->hue - color2->hue
        : color2->hue - color1->hue));
  float min_saturation =
    (color1->saturation < color2->saturation
     ? color1->saturation
     : color2->saturation);
  float delta_saturation = color1->saturation - color2->saturation;
  float delta_brightness = color1->brightness - color2->brightness;

  return delta_hue * delta_hue * min_saturation
         + delta_saturation * delta_saturation * 0.2f
         + delta_brightness * delta_brightness * 0.8f;
#endif
}

/* Return the index of the color in a color table that is nearest to a given
   color.  */
static unsigned int
nearest_color (rgb_t given, const rgb_t *table, unsigned int table_size)
{
  hsv_t given_hsv;
  unsigned int best_index;
  float best_distance;
  unsigned int i;

  assert (table_size > 0);

  rgb_to_hsv (given, &given_hsv);

  best_index = 0;
  best_distance = 1000000.0f;
  for (i = 0; i < table_size; i++)
    {
      hsv_t i_hsv;

      rgb_to_hsv (table[i], &i_hsv);

      /* Avoid converting a color to grey, or fading out a color too much.  */
      if (i_hsv.saturation > given_hsv.saturation * 0.5f)
        {
          float distance = color_distance (&given_hsv, &i_hsv);
          if (distance < best_distance)
            {
              best_index = i;
              best_distance = distance;
            }
        }
    }

#if 0 /* Debugging code */
  hsv_t best_hsv;
  rgb_to_hsv (table[best_index], &best_hsv);
  fprintf (stderr, "nearest: (%d,%d,%d) = (%f,%f,%f)\n    -> (%f,%f,%f) = (%d,%d,%d)\n",
                   given.red, given.green, given.blue,
                   (double)given_hsv.hue, (double)given_hsv.saturation, (double)given_hsv.brightness,
                   (double)best_hsv.hue, (double)best_hsv.saturation, (double)best_hsv.brightness,
                   table[best_index].red, table[best_index].green, table[best_index].blue);
#endif

  return best_index;
}

/* The luminance of a color.  This is the brightness of the color, as it
   appears to the human eye.  This must be used in color to grey conversion.  */
static float
color_luminance (int r, int g, int b)
{
  /* Use the luminance model used by NTSC and JPEG.
     Taken from http://www.fho-emden.de/~hoffmann/gray10012001.pdf .
     No need to care about rounding errors leading to luminance > 1;
     this cannot happen.  */
  return (0.299f * r + 0.587f * g + 0.114f * b) / 255.0f;
}

static inline term_color_t
rgb_to_color_xterm256 (int r, int g, int b)
{
  rgb_t color;
  hsv_t hsv;

  color.red = r; color.green = g; color.blue = b;
  rgb_to_hsv (color, &hsv);

  if (hsv.saturation < 0.065f)
    {
      /* Greyscale approximation.  */
      float luminance = color_luminance (r, g, b);
      if (luminance < 0.015f)
        return 0;
      else if (luminance < 0.051f)
        return 232;
      else if (luminance < 0.090f)
        return 233;
      else if (luminance < 0.129f)
        return 234;
      else if (luminance < 0.157f)
        return 235;
      else if (luminance < 0.177f)
        return 59;
      else if (luminance < 0.207f)
        return 236;
      else if (luminance < 0.247f)
        return 237;
      else if (luminance < 0.284f)
        return 238;
      else if (luminance < 0.304f)
        return 8;
      else if (luminance < 0.319f)
        return 239;
      else if (luminance < 0.339f)
        return 102;
      else if (luminance < 0.364f)
        return 240;
      else if (luminance < 0.404f)
        return 241;
      else if (luminance < 0.443f)
        return 242;
      else if (luminance < 0.480f)
        return 243;
      else if (luminance < 0.500f)
        return 145;
      else if (luminance < 0.521f)
        return 244;
      else if (luminance < 0.560f)
        return 245;
      else if (luminance < 0.600f)
        return 246;
      else if (luminance < 0.639f)
        return 247;
      else if (luminance < 0.663f)
        return 248;
      else if (luminance < 0.682f)
        return 188;
      else if (luminance < 0.717f)
        return 249;
      else if (luminance < 0.756f)
        return 250;
      else if (luminance < 0.796f)
        return 251;
      else if (luminance < 0.823f)
        return 252;
      else if (luminance < 0.843f)
        return 231;
      else if (luminance < 0.874f)
        return 253;
      else if (luminance < 0.896f)
        return 254;
      else if (luminance < 0.915f)
        return 7;
      else if (luminance < 0.966f)
        return 255;
      else
        return 15;
    }
  else
    /* Color approximation.  */
    return nearest_color (color, colors_of_xterm256, 256);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions