mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
hsl: add our own implementations of rgb-to-hsl and hsl-to-rgb
* New function: rgb_to_hsl() * New function: hsl_to_rgb() * Replace XTerm’s hls_to_rgb() with our own, hsl_to_rgb(). * Ensure hue/lum/sat values are within range before calling hsl_to_rgb() Note that sixels’ use the following primary hues: * blue: 0° * red: 120 * green: 240° While “standard” HSL uses: * red: 0° * green: 120° * blue: 240° Thus, we need to adjust the sixel’s hue value before calling hsl_to_rgb().
This commit is contained in:
parent
8e779b356e
commit
e0297daa1f
6 changed files with 124 additions and 136 deletions
89
hsl.c
Normal file
89
hsl.c
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
#include "hsl.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
rgb_to_hsl(uint32_t rgb, int *hue, int *sat, int *lum)
|
||||||
|
{
|
||||||
|
double r = (double)((rgb >> 16) & 0xff) / 255.;
|
||||||
|
double g = (double)((rgb >> 8) & 0xff) / 255.;
|
||||||
|
double b = (double)((rgb >> 0) & 0xff) / 255.;
|
||||||
|
|
||||||
|
double x_max = max(max(r, g), b);
|
||||||
|
double x_min = min(min(r, g), b);
|
||||||
|
double V = x_max;
|
||||||
|
|
||||||
|
double C = x_max - x_min;
|
||||||
|
double L = (x_max + x_min) / 2.;
|
||||||
|
|
||||||
|
*lum = 100 * L;
|
||||||
|
|
||||||
|
if (C == 0.0)
|
||||||
|
*hue = 0;
|
||||||
|
else if (V == r)
|
||||||
|
*hue = 60. * (0. + (g - b) / C);
|
||||||
|
else if (V == g)
|
||||||
|
*hue = 60. * (2. + (b - r) / C);
|
||||||
|
else if (V == b)
|
||||||
|
*hue = 60. * (4. + (r - g) / C);
|
||||||
|
if (*hue < 0)
|
||||||
|
*hue += 360;
|
||||||
|
|
||||||
|
double S = C == 0.0
|
||||||
|
? 0
|
||||||
|
: C / (1. - fabs(2. * L - 1.));
|
||||||
|
*sat = 100 * S;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
hsl_to_rgb(int hue, int sat, int lum)
|
||||||
|
{
|
||||||
|
double L = lum / 100.0;
|
||||||
|
double S = sat / 100.0;
|
||||||
|
double C = (1. - fabs(2. * L - 1.)) * S;
|
||||||
|
|
||||||
|
double X = C * (1. - fabs(fmod((double)hue / 60., 2.) - 1.));
|
||||||
|
double m = L - C / 2.;
|
||||||
|
|
||||||
|
double r, g, b;
|
||||||
|
if (hue >= 0 && hue <= 60) {
|
||||||
|
r = C;
|
||||||
|
g = X;
|
||||||
|
b = 0.;
|
||||||
|
} else if (hue >= 60 && hue <= 120) {
|
||||||
|
r = X;
|
||||||
|
g = C;
|
||||||
|
b = 0.;
|
||||||
|
} else if (hue >= 120 && hue <= 180) {
|
||||||
|
r = 0.;
|
||||||
|
g = C;
|
||||||
|
b = X;
|
||||||
|
} else if (hue >= 180 && hue <= 240) {
|
||||||
|
r = 0.;
|
||||||
|
g = X;
|
||||||
|
b = C;
|
||||||
|
} else if (hue >= 240 && hue <= 300) {
|
||||||
|
r = X;
|
||||||
|
g = 0.;
|
||||||
|
b = C;
|
||||||
|
} else if (hue >= 300 && hue <= 360) {
|
||||||
|
r = C;
|
||||||
|
g = 0.;
|
||||||
|
b = X;
|
||||||
|
} else {
|
||||||
|
r = 0.;
|
||||||
|
g = 0.;
|
||||||
|
b = 0.;
|
||||||
|
}
|
||||||
|
|
||||||
|
r += m;
|
||||||
|
g += m;
|
||||||
|
b += m;
|
||||||
|
|
||||||
|
return (
|
||||||
|
(int)round(r * 255.) << 16 |
|
||||||
|
(int)round(g * 255.) << 8 |
|
||||||
|
(int)round(b * 255.) << 0);
|
||||||
|
}
|
||||||
6
hsl.h
Normal file
6
hsl.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void rgb_to_hsl(uint32_t rgb, int *hue, int *sat, int *lum);
|
||||||
|
uint32_t hsl_to_rgb(int hue, int sat, int lum);
|
||||||
|
|
@ -111,6 +111,7 @@ executable(
|
||||||
'extract.c', 'extract.h',
|
'extract.c', 'extract.h',
|
||||||
'fdm.c', 'fdm.h',
|
'fdm.c', 'fdm.h',
|
||||||
'grid.c', 'grid.h',
|
'grid.c', 'grid.h',
|
||||||
|
'hsl.c', 'hsl.h',
|
||||||
'input.c', 'input.h',
|
'input.c', 'input.h',
|
||||||
'log.c', 'log.h',
|
'log.c', 'log.h',
|
||||||
'macros.h',
|
'macros.h',
|
||||||
|
|
@ -125,7 +126,6 @@ executable(
|
||||||
'server.c', 'server.h',
|
'server.c', 'server.h',
|
||||||
'shm.c', 'shm.h',
|
'shm.c', 'shm.h',
|
||||||
'sixel.c', 'sixel.h',
|
'sixel.c', 'sixel.h',
|
||||||
'sixel-hls.c', 'sixel-hls.h',
|
|
||||||
'slave.c', 'slave.h',
|
'slave.c', 'slave.h',
|
||||||
'spawn.c', 'spawn.h',
|
'spawn.c', 'spawn.h',
|
||||||
'terminal.c', 'terminal.h',
|
'terminal.c', 'terminal.h',
|
||||||
|
|
|
||||||
117
sixel-hls.c
117
sixel-hls.c
|
|
@ -1,117 +0,0 @@
|
||||||
// sixel.c (part of mintty)
|
|
||||||
// this function is derived from a part of graphics.c
|
|
||||||
// in Xterm pl#310 originally written by Ross Combs.
|
|
||||||
//
|
|
||||||
// Copyright 2013,2014 by Ross Combs
|
|
||||||
//
|
|
||||||
// All Rights Reserved
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
// copy of this software and associated documentation files (the
|
|
||||||
// "Software"), to deal in the Software without restriction, including
|
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
// permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
// the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included
|
|
||||||
// in all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
// IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
|
|
||||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
//
|
|
||||||
// Except as contained in this notice, the name(s) of the above copyright
|
|
||||||
// holders shall not be used in advertising or otherwise to promote the
|
|
||||||
// sale, use or other dealings in this Software without prior written
|
|
||||||
// authorization.
|
|
||||||
|
|
||||||
#include "sixel-hls.h"
|
|
||||||
|
|
||||||
#define SIXEL_RGB(r, g, b) (((r) << 16) + ((g) << 8) + (b))
|
|
||||||
|
|
||||||
int
|
|
||||||
hls_to_rgb(int hue, int lum, int sat)
|
|
||||||
{
|
|
||||||
double hs = (hue + 240) % 360;
|
|
||||||
double hv = hs / 360.0;
|
|
||||||
double lv = lum / 100.0;
|
|
||||||
double sv = sat / 100.0;
|
|
||||||
double c, x, m, c2;
|
|
||||||
double r1, g1, b1;
|
|
||||||
int r, g, b;
|
|
||||||
int hpi;
|
|
||||||
|
|
||||||
if (sat == 0) {
|
|
||||||
r = g = b = lum * 255 / 100;
|
|
||||||
return SIXEL_RGB(r, g, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((c2 = ((2.0 * lv) - 1.0)) < 0.0) {
|
|
||||||
c2 = -c2;
|
|
||||||
}
|
|
||||||
c = (1.0 - c2) * sv;
|
|
||||||
hpi = (int) (hv * 6.0);
|
|
||||||
x = (hpi & 1) ? c : 0.0;
|
|
||||||
m = lv - 0.5 * c;
|
|
||||||
|
|
||||||
switch (hpi) {
|
|
||||||
case 0:
|
|
||||||
r1 = c;
|
|
||||||
g1 = x;
|
|
||||||
b1 = 0.0;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
r1 = x;
|
|
||||||
g1 = c;
|
|
||||||
b1 = 0.0;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
r1 = 0.0;
|
|
||||||
g1 = c;
|
|
||||||
b1 = x;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
r1 = 0.0;
|
|
||||||
g1 = x;
|
|
||||||
b1 = c;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
r1 = x;
|
|
||||||
g1 = 0.0;
|
|
||||||
b1 = c;
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
r1 = c;
|
|
||||||
g1 = 0.0;
|
|
||||||
b1 = x;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return SIXEL_RGB(255, 255, 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
r = (int) ((r1 + m) * 100.0 + 0.5);
|
|
||||||
g = (int) ((g1 + m) * 100.0 + 0.5);
|
|
||||||
b = (int) ((b1 + m) * 100.0 + 0.5);
|
|
||||||
|
|
||||||
if (r < 0) {
|
|
||||||
r = 0;
|
|
||||||
} else if (r > 100) {
|
|
||||||
r = 100;
|
|
||||||
}
|
|
||||||
if (g < 0) {
|
|
||||||
g = 0;
|
|
||||||
} else if (g > 100) {
|
|
||||||
g = 100;
|
|
||||||
}
|
|
||||||
if (b < 0) {
|
|
||||||
b = 0;
|
|
||||||
} else if (b > 100) {
|
|
||||||
b = 100;
|
|
||||||
}
|
|
||||||
return SIXEL_RGB(r * 255 / 100, g * 255 / 100, b * 255 / 100);
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Primary color hues:
|
|
||||||
* blue: 0 degrees
|
|
||||||
* red: 120 degrees
|
|
||||||
* green: 240 degrees
|
|
||||||
*/
|
|
||||||
int hls_to_rgb(int hue, int lum, int sat);
|
|
||||||
37
sixel.c
37
sixel.c
|
|
@ -7,7 +7,7 @@
|
||||||
#define LOG_ENABLE_DBG 0
|
#define LOG_ENABLE_DBG 0
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "sixel-hls.h"
|
#include "hsl.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
|
|
||||||
|
|
@ -1052,23 +1052,42 @@ decgci(struct terminal *term, uint8_t c)
|
||||||
|
|
||||||
if (nparams > 4) {
|
if (nparams > 4) {
|
||||||
unsigned format = term->sixel.params[1];
|
unsigned format = term->sixel.params[1];
|
||||||
unsigned c1 = term->sixel.params[2];
|
int c1 = term->sixel.params[2];
|
||||||
unsigned c2 = term->sixel.params[3];
|
int c2 = term->sixel.params[3];
|
||||||
unsigned c3 = term->sixel.params[4];
|
int c3 = term->sixel.params[4];
|
||||||
|
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case 1: { /* HLS */
|
case 1: { /* HLS */
|
||||||
uint32_t rgb = hls_to_rgb(c1, c2, c3);
|
int hue = min(c1, 360);
|
||||||
|
int lum = min(c2, 100);
|
||||||
|
int sat = min(c3, 100);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sixel’s HLS use the following primary color hues:
|
||||||
|
* blue: 0°
|
||||||
|
* red: 120°
|
||||||
|
* green: 240°
|
||||||
|
*
|
||||||
|
* While “standard” HSL uses:
|
||||||
|
* red: 0°
|
||||||
|
* green: 120°
|
||||||
|
* blue: 240°
|
||||||
|
*/
|
||||||
|
hue = (hue + 240) % 360;
|
||||||
|
|
||||||
|
uint32_t rgb = hsl_to_rgb(hue, sat, lum);
|
||||||
|
|
||||||
LOG_DBG("setting palette #%d = HLS %hhu/%hhu/%hhu (0x%06x)",
|
LOG_DBG("setting palette #%d = HLS %hhu/%hhu/%hhu (0x%06x)",
|
||||||
term->sixel.color_idx, c1, c2, c3, rgb);
|
term->sixel.color_idx, hue, lum, sat, rgb);
|
||||||
|
|
||||||
term->sixel.palette[term->sixel.color_idx] = rgb;
|
term->sixel.palette[term->sixel.color_idx] = rgb;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 2: { /* RGB */
|
case 2: { /* RGB */
|
||||||
uint8_t r = 255 * c1 / 100;
|
uint8_t r = 255 * min(c1, 100) / 100;
|
||||||
uint8_t g = 255 * c2 / 100;
|
uint8_t g = 255 * min(c2, 100) / 100;
|
||||||
uint8_t b = 255 * c3 / 100;
|
uint8_t b = 255 * min(c3, 100) / 100;
|
||||||
|
|
||||||
LOG_DBG("setting palette #%d = RGB %hhu/%hhu/%hhu",
|
LOG_DBG("setting palette #%d = RGB %hhu/%hhu/%hhu",
|
||||||
term->sixel.color_idx, r, g, b);
|
term->sixel.color_idx, r, g, b);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue