mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-09 21:55:29 +02:00
sRGB glyph composition: Use default values that give "close to native" rendering. Also use only a single option to control it.
This commit is contained in:
@@ -38,7 +38,7 @@ Detailed list of changes
|
|||||||
0.28.0 [future]
|
0.28.0 [future]
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
- Text rendering: Use sRGB correct linear gamma blending for nicer font rendering and better color accuracy with transparent windows. See the options :opt:`text_old_gamma`, :opt:`text_gamma_adjustment` and :opt:`text_contrast` (:pull:`5969`)
|
- Text rendering: Use sRGB correct linear gamma blending for nicer font rendering and better color accuracy with transparent windows. See the option :opt:`text_composition_strategy` for details. (:pull:`5969`)
|
||||||
|
|
||||||
|
|
||||||
0.27.1 [2023-02-07]
|
0.27.1 [2023-02-07]
|
||||||
|
|||||||
@@ -233,36 +233,30 @@ the curl will peak once per character, with dense twice.
|
|||||||
'''
|
'''
|
||||||
)
|
)
|
||||||
|
|
||||||
opt('text_old_gamma', 'no',
|
opt('text_composition_strategy', 'platform', ctype='!text_composition_strategy', long_text='''
|
||||||
option_type='to_bool', ctype='bool',
|
Control how kitty composites text glyphs onto the background color.
|
||||||
long_text='''
|
The default value of :code:`platform` tries for text rendering as
|
||||||
Revert to using the old (pre 0.28) gamma correction algorithm when rendering text.
|
close to "native" for the platform kitty is running on as possible.
|
||||||
This will make some text appear like the strokes are uneven. Dark text on bright backgrounds
|
|
||||||
will also look thicker while lighter text on darker backgrounds will look thinner.
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
|
|
||||||
opt('text_gamma_adjustment', '1.0',
|
A value of :code:`legacy` uses the old (pre kitty 0.28) strategy for how glyphs
|
||||||
option_type='positive_float', ctype='float',
|
are composited. This will make dark text on light backgrounds look thicker and
|
||||||
long_text='''
|
light text on dark backgrounds thinner. It might also make some text appear like
|
||||||
Adjust the thickness of darker text on lighter backgrounds. Increasing the value
|
the strokes are uneven.
|
||||||
setting will make the text appear thicker while decreasing the value will make it thinner. It
|
|
||||||
can compensate for some fonts looking too-thin when using the gamma-correct alpha blending.
|
|
||||||
|
|
||||||
|
You can fine tune the actual contrast curve used for glyph composition
|
||||||
|
by specifying two space separated numbers for this setting.
|
||||||
|
|
||||||
|
The first number is the gamma adjustment, which
|
||||||
|
controls the thickness of dark text on light backgrounds. Increasing the value will make text appear thicker.
|
||||||
|
The default value for this is 1.0 on Linux and 1.7 on macOS. Valid values are 0.01 and above.
|
||||||
The result is scaled based on the luminance difference between the background and the foreground.
|
The result is scaled based on the luminance difference between the background and the foreground.
|
||||||
Dark text on light backgrounds receives the full impact of the curve while light text on dark
|
Dark text on light backgrounds receives the full impact of the curve while light text on dark
|
||||||
backgrounds is affected very little. Valid values are 0.01 and above. For macOS like text rendering,
|
backgrounds is affected very little.
|
||||||
a value of ~1.7 usually works well.
|
|
||||||
'''
|
The second number is an additional multiplicative contrast. It is percentage ranging from 0 to 100.
|
||||||
)
|
The default value is zero On Linux and 30 on macOS.
|
||||||
|
''')
|
||||||
|
|
||||||
opt('text_contrast', '0',
|
|
||||||
option_type='positive_float', ctype='float',
|
|
||||||
long_text='''
|
|
||||||
Increase text contrast further. This will cause jagged edges due to over saturation if set too high.
|
|
||||||
The value is a percentage from 0 to 100. For macOS like text rendering, a value of 30 usually works well.
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
egr() # }}}
|
egr() # }}}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
10
kitty/options/parse.py
generated
10
kitty/options/parse.py
generated
@@ -1278,14 +1278,8 @@ class Parser:
|
|||||||
def term(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
def term(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||||
ans['term'] = str(val)
|
ans['term'] = str(val)
|
||||||
|
|
||||||
def text_contrast(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
def text_composition_strategy(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||||
ans['text_contrast'] = positive_float(val)
|
ans['text_composition_strategy'] = str(val)
|
||||||
|
|
||||||
def text_gamma_adjustment(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
|
||||||
ans['text_gamma_adjustment'] = positive_float(val)
|
|
||||||
|
|
||||||
def text_old_gamma(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
|
||||||
ans['text_old_gamma'] = to_bool(val)
|
|
||||||
|
|
||||||
def touch_scroll_multiplier(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
def touch_scroll_multiplier(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
|
||||||
ans['touch_scroll_multiplier'] = float(val)
|
ans['touch_scroll_multiplier'] = float(val)
|
||||||
|
|||||||
42
kitty/options/to-c-generated.h
generated
42
kitty/options/to-c-generated.h
generated
@@ -58,41 +58,15 @@ convert_from_opts_modify_font(PyObject *py_opts, Options *opts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
convert_from_python_text_old_gamma(PyObject *val, Options *opts) {
|
convert_from_python_text_composition_strategy(PyObject *val, Options *opts) {
|
||||||
opts->text_old_gamma = PyObject_IsTrue(val);
|
text_composition_strategy(val, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
convert_from_opts_text_old_gamma(PyObject *py_opts, Options *opts) {
|
convert_from_opts_text_composition_strategy(PyObject *py_opts, Options *opts) {
|
||||||
PyObject *ret = PyObject_GetAttrString(py_opts, "text_old_gamma");
|
PyObject *ret = PyObject_GetAttrString(py_opts, "text_composition_strategy");
|
||||||
if (ret == NULL) return;
|
if (ret == NULL) return;
|
||||||
convert_from_python_text_old_gamma(ret, opts);
|
convert_from_python_text_composition_strategy(ret, opts);
|
||||||
Py_DECREF(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
convert_from_python_text_gamma_adjustment(PyObject *val, Options *opts) {
|
|
||||||
opts->text_gamma_adjustment = PyFloat_AsFloat(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
convert_from_opts_text_gamma_adjustment(PyObject *py_opts, Options *opts) {
|
|
||||||
PyObject *ret = PyObject_GetAttrString(py_opts, "text_gamma_adjustment");
|
|
||||||
if (ret == NULL) return;
|
|
||||||
convert_from_python_text_gamma_adjustment(ret, opts);
|
|
||||||
Py_DECREF(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
convert_from_python_text_contrast(PyObject *val, Options *opts) {
|
|
||||||
opts->text_contrast = PyFloat_AsFloat(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
convert_from_opts_text_contrast(PyObject *py_opts, Options *opts) {
|
|
||||||
PyObject *ret = PyObject_GetAttrString(py_opts, "text_contrast");
|
|
||||||
if (ret == NULL) return;
|
|
||||||
convert_from_python_text_contrast(ret, opts);
|
|
||||||
Py_DECREF(ret);
|
Py_DECREF(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1081,11 +1055,7 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
|
|||||||
if (PyErr_Occurred()) return false;
|
if (PyErr_Occurred()) return false;
|
||||||
convert_from_opts_modify_font(py_opts, opts);
|
convert_from_opts_modify_font(py_opts, opts);
|
||||||
if (PyErr_Occurred()) return false;
|
if (PyErr_Occurred()) return false;
|
||||||
convert_from_opts_text_old_gamma(py_opts, opts);
|
convert_from_opts_text_composition_strategy(py_opts, opts);
|
||||||
if (PyErr_Occurred()) return false;
|
|
||||||
convert_from_opts_text_gamma_adjustment(py_opts, opts);
|
|
||||||
if (PyErr_Occurred()) return false;
|
|
||||||
convert_from_opts_text_contrast(py_opts, opts);
|
|
||||||
if (PyErr_Occurred()) return false;
|
if (PyErr_Occurred()) return false;
|
||||||
convert_from_opts_cursor_shape(py_opts, opts);
|
convert_from_opts_cursor_shape(py_opts, opts);
|
||||||
if (PyErr_Occurred()) return false;
|
if (PyErr_Occurred()) return false;
|
||||||
|
|||||||
@@ -175,6 +175,31 @@ url_prefixes(PyObject *up, Options *opts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
text_composition_strategy(PyObject *val, Options *opts) {
|
||||||
|
if (!PyUnicode_Check(val)) { PyErr_SetString(PyExc_TypeError, "text_rendering_strategy must be a string"); return; }
|
||||||
|
opts->text_old_gamma = false;
|
||||||
|
opts->text_gamma_adjustment = 1.0f; opts->text_contrast = 0.f;
|
||||||
|
if (PyUnicode_CompareWithASCIIString(val, "platform") == 0) {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
opts->text_gamma_adjustment = 1.7f; opts->text_contrast = 30.f;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (PyUnicode_CompareWithASCIIString(val, "legacy") == 0) {
|
||||||
|
opts->text_old_gamma = true;
|
||||||
|
} else {
|
||||||
|
DECREF_AFTER_FUNCTION PyObject *parts = PyUnicode_Split(val, NULL, 1);
|
||||||
|
if (PyList_GET_SIZE(parts) != 2) { PyErr_SetString(PyExc_ValueError, "text_rendering_strategy must be of the form number:number"); return; }
|
||||||
|
DECREF_AFTER_FUNCTION PyObject *ga = PyFloat_FromString(PyList_GET_ITEM(parts, 0));
|
||||||
|
if (PyErr_Occurred()) return;
|
||||||
|
opts->text_gamma_adjustment = MAX(0.01f, PyFloat_AsFloat(ga));
|
||||||
|
DECREF_AFTER_FUNCTION PyObject *contrast = PyFloat_FromString(PyList_GET_ITEM(parts, 1));
|
||||||
|
if (PyErr_Occurred()) return;
|
||||||
|
opts->text_contrast = MAX(0.0f, PyFloat_AsFloat(contrast));
|
||||||
|
opts->text_contrast = MIN(100.0f, opts->text_contrast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static char_type*
|
static char_type*
|
||||||
list_of_chars(PyObject *chars) {
|
list_of_chars(PyObject *chars) {
|
||||||
if (!PyUnicode_Check(chars)) { PyErr_SetString(PyExc_TypeError, "list_of_chars must be a string"); return NULL; }
|
if (!PyUnicode_Check(chars)) { PyErr_SetString(PyExc_TypeError, "list_of_chars must be a string"); return NULL; }
|
||||||
|
|||||||
8
kitty/options/types.py
generated
8
kitty/options/types.py
generated
@@ -443,9 +443,7 @@ option_names = ( # {{{
|
|||||||
'tab_title_max_length',
|
'tab_title_max_length',
|
||||||
'tab_title_template',
|
'tab_title_template',
|
||||||
'term',
|
'term',
|
||||||
'text_contrast',
|
'text_composition_strategy',
|
||||||
'text_gamma_adjustment',
|
|
||||||
'text_old_gamma',
|
|
||||||
'touch_scroll_multiplier',
|
'touch_scroll_multiplier',
|
||||||
'undercurl_style',
|
'undercurl_style',
|
||||||
'update_check_interval',
|
'update_check_interval',
|
||||||
@@ -597,9 +595,7 @@ class Options:
|
|||||||
tab_title_max_length: int = 0
|
tab_title_max_length: int = 0
|
||||||
tab_title_template: str = '{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.tab}{title}'
|
tab_title_template: str = '{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.tab}{title}'
|
||||||
term: str = 'xterm-kitty'
|
term: str = 'xterm-kitty'
|
||||||
text_contrast: float = 0
|
text_composition_strategy: str = 'platform'
|
||||||
text_gamma_adjustment: float = 1.0
|
|
||||||
text_old_gamma: bool = False
|
|
||||||
touch_scroll_multiplier: float = 1.0
|
touch_scroll_multiplier: float = 1.0
|
||||||
undercurl_style: choices_for_undercurl_style = 'thin-sparse'
|
undercurl_style: choices_for_undercurl_style = 'thin-sparse'
|
||||||
update_check_interval: float = 24.0
|
update_check_interval: float = 24.0
|
||||||
|
|||||||
Reference in New Issue
Block a user