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:
Kovid Goyal 2023-02-08 13:46:04 +05:30
parent 8433f1d731
commit 4dfd4d4972
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 55 additions and 76 deletions

View File

@ -38,7 +38,7 @@ Detailed list of changes
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]

View File

@ -233,36 +233,30 @@ the curl will peak once per character, with dense twice.
'''
)
opt('text_old_gamma', 'no',
option_type='to_bool', ctype='bool',
long_text='''
Revert to using the old (pre 0.28) gamma correction algorithm when rendering text.
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_composition_strategy', 'platform', ctype='!text_composition_strategy', long_text='''
Control how kitty composites text glyphs onto the background color.
The default value of :code:`platform` tries for text rendering as
close to "native" for the platform kitty is running on as possible.
opt('text_gamma_adjustment', '1.0',
option_type='positive_float', ctype='float',
long_text='''
Adjust the thickness of darker text on lighter backgrounds. Increasing the value
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.
A value of :code:`legacy` uses the old (pre kitty 0.28) strategy for how glyphs
are composited. This will make dark text on light backgrounds look thicker and
light text on dark backgrounds thinner. It might also make some text appear like
the strokes are uneven.
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.
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,
a value of ~1.7 usually works well.
'''
)
backgrounds is affected very little.
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() # }}}

10
kitty/options/parse.py generated
View File

@ -1278,14 +1278,8 @@ class Parser:
def term(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['term'] = str(val)
def text_contrast(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['text_contrast'] = positive_float(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 text_composition_strategy(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['text_composition_strategy'] = str(val)
def touch_scroll_multiplier(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['touch_scroll_multiplier'] = float(val)

View File

@ -58,41 +58,15 @@ convert_from_opts_modify_font(PyObject *py_opts, Options *opts) {
}
static void
convert_from_python_text_old_gamma(PyObject *val, Options *opts) {
opts->text_old_gamma = PyObject_IsTrue(val);
convert_from_python_text_composition_strategy(PyObject *val, Options *opts) {
text_composition_strategy(val, opts);
}
static void
convert_from_opts_text_old_gamma(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "text_old_gamma");
convert_from_opts_text_composition_strategy(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "text_composition_strategy");
if (ret == NULL) return;
convert_from_python_text_old_gamma(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);
convert_from_python_text_composition_strategy(ret, opts);
Py_DECREF(ret);
}
@ -1081,11 +1055,7 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
if (PyErr_Occurred()) return false;
convert_from_opts_modify_font(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_text_old_gamma(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);
convert_from_opts_text_composition_strategy(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_cursor_shape(py_opts, opts);
if (PyErr_Occurred()) return false;

View File

@ -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*
list_of_chars(PyObject *chars) {
if (!PyUnicode_Check(chars)) { PyErr_SetString(PyExc_TypeError, "list_of_chars must be a string"); return NULL; }

View File

@ -443,9 +443,7 @@ option_names = ( # {{{
'tab_title_max_length',
'tab_title_template',
'term',
'text_contrast',
'text_gamma_adjustment',
'text_old_gamma',
'text_composition_strategy',
'touch_scroll_multiplier',
'undercurl_style',
'update_check_interval',
@ -597,9 +595,7 @@ class Options:
tab_title_max_length: int = 0
tab_title_template: str = '{fmt.fg.red}{bell_symbol}{activity_symbol}{fmt.fg.tab}{title}'
term: str = 'xterm-kitty'
text_contrast: float = 0
text_gamma_adjustment: float = 1.0
text_old_gamma: bool = False
text_composition_strategy: str = 'platform'
touch_scroll_multiplier: float = 1.0
undercurl_style: choices_for_undercurl_style = 'thin-sparse'
update_check_interval: float = 24.0