Add support for displaying correct colors with PNG files that contain embedded ICC color profiles
This commit is contained in:
parent
6ca1b7c240
commit
5eefd41059
2
.github/workflows/ci.py
vendored
2
.github/workflows/ci.py
vendored
@ -36,7 +36,7 @@ def install_deps():
|
|||||||
run('sudo apt-get update')
|
run('sudo apt-get update')
|
||||||
run('sudo apt-get install -y libgl1-mesa-dev libxi-dev libxrandr-dev libxinerama-dev'
|
run('sudo apt-get install -y libgl1-mesa-dev libxi-dev libxrandr-dev libxinerama-dev'
|
||||||
' libxcursor-dev libxcb-xkb-dev libdbus-1-dev libxkbcommon-dev libharfbuzz-dev'
|
' libxcursor-dev libxcb-xkb-dev libdbus-1-dev libxkbcommon-dev libharfbuzz-dev'
|
||||||
' libpng-dev libfontconfig-dev libxkbcommon-x11-dev libcanberra-dev')
|
' libpng-dev liblcms2-dev libfontconfig-dev libxkbcommon-x11-dev libcanberra-dev')
|
||||||
if is_bundle:
|
if is_bundle:
|
||||||
install_bundle()
|
install_bundle()
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -26,7 +26,7 @@ kitty_constants = iv['kitty_constants']
|
|||||||
|
|
||||||
def binary_includes():
|
def binary_includes():
|
||||||
return tuple(map(get_dll_path, (
|
return tuple(map(get_dll_path, (
|
||||||
'expat', 'sqlite3', 'ffi', 'z', 'lzma', 'png16',
|
'expat', 'sqlite3', 'ffi', 'z', 'lzma', 'png16', 'lcms2',
|
||||||
|
|
||||||
# dont include freetype because fontconfig is closely coupled to it
|
# dont include freetype because fontconfig is closely coupled to it
|
||||||
# and also distros often patch freetype
|
# and also distros often patch freetype
|
||||||
|
|||||||
@ -262,6 +262,7 @@ class Freeze(object):
|
|||||||
'z.1',
|
'z.1',
|
||||||
'harfbuzz.0',
|
'harfbuzz.0',
|
||||||
'png16.16',
|
'png16.16',
|
||||||
|
'lcms2.2',
|
||||||
'crypto.1.0.0',
|
'crypto.1.0.0',
|
||||||
'ssl.1.0.0',
|
'ssl.1.0.0',
|
||||||
):
|
):
|
||||||
|
|||||||
@ -153,6 +153,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "lcms2",
|
||||||
|
"unix": {
|
||||||
|
"filename": "lcms2-2.11.tar.gz",
|
||||||
|
"hash": "sha256:478c9c3938d7a91b1171de4616f8b04308a8676d73eadc19505b7ace41327f28",
|
||||||
|
"urls": ["https://github.com/mm2/Little-CMS/archive/2.11/{filename}"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "graphite",
|
"name": "graphite",
|
||||||
"os": "linux",
|
"os": "linux",
|
||||||
|
|||||||
@ -18,6 +18,7 @@ Run-time dependencies:
|
|||||||
* harfbuzz >= 1.5.0
|
* harfbuzz >= 1.5.0
|
||||||
* zlib
|
* zlib
|
||||||
* libpng
|
* libpng
|
||||||
|
* liblcms2
|
||||||
* freetype (not needed on macOS)
|
* freetype (not needed on macOS)
|
||||||
* fontconfig (not needed on macOS)
|
* fontconfig (not needed on macOS)
|
||||||
* libcanberra (not needed on macOS)
|
* libcanberra (not needed on macOS)
|
||||||
|
|||||||
@ -4,6 +4,13 @@ Changelog
|
|||||||
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
|
|kitty| is a feature full, cross-platform, *fast*, GPU based terminal emulator.
|
||||||
To update |kitty|, :doc:`follow the instructions <binary>`.
|
To update |kitty|, :doc:`follow the instructions <binary>`.
|
||||||
|
|
||||||
|
0.18.4 [2020-08-11]
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
- Add support for displaying correct colors with non-sRGB PNG files (Adds a
|
||||||
|
dependency on liblcms2)
|
||||||
|
|
||||||
|
|
||||||
0.18.3 [2020-08-11]
|
0.18.3 [2020-08-11]
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
|||||||
@ -161,9 +161,10 @@ of transmitting paletted images.
|
|||||||
RGB and RGBA data
|
RGB and RGBA data
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
In these formats the pixel data is stored directly as 3 or 4 bytes per pixel, respectively.
|
In these formats the pixel data is stored directly as 3 or 4 bytes per pixel,
|
||||||
When specifying images in this format, the image dimensions **must** be sent in the control data.
|
respectively. The colors in the data **must** be in the *sRGB color space*. When
|
||||||
For example::
|
specifying images in this format, the image dimensions **must** be sent in the
|
||||||
|
control data. For example::
|
||||||
|
|
||||||
<ESC>_Gf=24,s=10,v=20;<payload><ESC>\
|
<ESC>_Gf=24,s=10,v=20;<payload><ESC>\
|
||||||
|
|
||||||
|
|||||||
@ -7,8 +7,10 @@
|
|||||||
|
|
||||||
#include "png-reader.h"
|
#include "png-reader.h"
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
|
#include <lcms2.h>
|
||||||
|
|
||||||
|
|
||||||
|
static cmsHPROFILE srgb_profile = NULL;
|
||||||
struct fake_file { const uint8_t *buf; size_t sz, cur; };
|
struct fake_file { const uint8_t *buf; size_t sz, cur; };
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -64,13 +66,30 @@ inflate_png_inner(png_read_data *d, const uint8_t *buf, size_t bufsz) {
|
|||||||
bit_depth = png_get_bit_depth(png, info);
|
bit_depth = png_get_bit_depth(png, info);
|
||||||
double image_gamma;
|
double image_gamma;
|
||||||
int intent;
|
int intent;
|
||||||
|
cmsHPROFILE input_profile = NULL;
|
||||||
|
cmsHTRANSFORM colorspace_transform = NULL;
|
||||||
if (png_get_sRGB(png, info, &intent)) {
|
if (png_get_sRGB(png, info, &intent)) {
|
||||||
// do nothing since we output sRGB
|
// do nothing since we output sRGB
|
||||||
} else if (png_get_gAMA(png, info, &image_gamma)) {
|
} else if (png_get_gAMA(png, info, &image_gamma)) {
|
||||||
if (image_gamma != 0 && fabs(image_gamma - 1.0/2.2) > 0.0001) png_set_gamma(png, 2.2, image_gamma);
|
if (image_gamma != 0 && fabs(image_gamma - 1.0/2.2) > 0.0001) png_set_gamma(png, 2.2, image_gamma);
|
||||||
} else {
|
} else {
|
||||||
// do nothing since we don't know what gamma the source image is in
|
// Look for an embedded color profile
|
||||||
// TODO: handle images with color profiles
|
png_charp name;
|
||||||
|
int compression_type;
|
||||||
|
png_bytep profdata;
|
||||||
|
png_uint_32 proflen;
|
||||||
|
if (png_get_iCCP(png, info, &name, &compression_type, &profdata, &proflen) & PNG_INFO_iCCP) {
|
||||||
|
input_profile = cmsOpenProfileFromMem(profdata, proflen);
|
||||||
|
if (input_profile) {
|
||||||
|
if (!srgb_profile) {
|
||||||
|
srgb_profile = cmsCreate_sRGBProfile();
|
||||||
|
if (!srgb_profile) ABRT(ENOMEM, "Out of memory allocating sRGB colorspace profile");
|
||||||
|
}
|
||||||
|
colorspace_transform = cmsCreateTransform(
|
||||||
|
input_profile, TYPE_RGBA_8, srgb_profile, TYPE_RGBA_8, INTENT_PERCEPTUAL, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we get RGBA data out of libpng
|
// Ensure we get RGBA data out of libpng
|
||||||
@ -93,9 +112,17 @@ inflate_png_inner(png_read_data *d, const uint8_t *buf, size_t bufsz) {
|
|||||||
if (d->decompressed == NULL) ABRT(ENOMEM, "Out of memory allocating decompression buffer for PNG");
|
if (d->decompressed == NULL) ABRT(ENOMEM, "Out of memory allocating decompression buffer for PNG");
|
||||||
d->row_pointers = malloc(d->height * sizeof(png_bytep));
|
d->row_pointers = malloc(d->height * sizeof(png_bytep));
|
||||||
if (d->row_pointers == NULL) ABRT(ENOMEM, "Out of memory allocating row_pointers buffer for PNG");
|
if (d->row_pointers == NULL) ABRT(ENOMEM, "Out of memory allocating row_pointers buffer for PNG");
|
||||||
for (int i = 0; i < d->height; i++) d->row_pointers[i] = d->decompressed + i * rowbytes;
|
for (int i = 0; i < d->height; i++) d->row_pointers[i] = d->decompressed + i * rowbytes * sizeof(png_byte);
|
||||||
png_read_image(png, d->row_pointers);
|
png_read_image(png, d->row_pointers);
|
||||||
|
|
||||||
|
if (colorspace_transform) {
|
||||||
|
for (int i = 0; i < d->height; i++) {
|
||||||
|
cmsDoTransform(colorspace_transform, d->row_pointers[i], d->row_pointers[i], d->width);
|
||||||
|
}
|
||||||
|
cmsDeleteTransform(colorspace_transform);
|
||||||
|
}
|
||||||
|
if (input_profile) cmsCloseProfile(input_profile);
|
||||||
|
|
||||||
d->ok = true;
|
d->ok = true;
|
||||||
err:
|
err:
|
||||||
if (png) png_destroy_read_struct(&png, info ? &info : NULL, NULL);
|
if (png) png_destroy_read_struct(&png, info ? &info : NULL, NULL);
|
||||||
@ -130,8 +157,20 @@ static PyMethodDef module_methods[] = {
|
|||||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
unload(void) {
|
||||||
|
if (srgb_profile) cmsCloseProfile(srgb_profile);
|
||||||
|
srgb_profile = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
init_png_reader(PyObject *module) {
|
init_png_reader(PyObject *module) {
|
||||||
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
||||||
|
if (Py_AtExit(unload) != 0) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Failed to register the PNG library at exit handler");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
4
setup.py
4
setup.py
@ -329,6 +329,7 @@ def kitty_env() -> Env:
|
|||||||
cppflags.append('-DSECONDARY_VERSION={}'.format(version[1]))
|
cppflags.append('-DSECONDARY_VERSION={}'.format(version[1]))
|
||||||
at_least_version('harfbuzz', 1, 5)
|
at_least_version('harfbuzz', 1, 5)
|
||||||
cflags.extend(pkg_config('libpng', '--cflags-only-I'))
|
cflags.extend(pkg_config('libpng', '--cflags-only-I'))
|
||||||
|
cflags.extend(pkg_config('lcms2', '--cflags-only-I'))
|
||||||
if is_macos:
|
if is_macos:
|
||||||
font_libs = ['-framework', 'CoreText', '-framework', 'CoreGraphics']
|
font_libs = ['-framework', 'CoreText', '-framework', 'CoreGraphics']
|
||||||
# Apple deprecated OpenGL in Mojave (10.14) silence the endless
|
# Apple deprecated OpenGL in Mojave (10.14) silence the endless
|
||||||
@ -342,7 +343,8 @@ def kitty_env() -> Env:
|
|||||||
pylib = get_python_flags(cflags)
|
pylib = get_python_flags(cflags)
|
||||||
gl_libs = ['-framework', 'OpenGL'] if is_macos else pkg_config('gl', '--libs')
|
gl_libs = ['-framework', 'OpenGL'] if is_macos else pkg_config('gl', '--libs')
|
||||||
libpng = pkg_config('libpng', '--libs')
|
libpng = pkg_config('libpng', '--libs')
|
||||||
ans.ldpaths += pylib + font_libs + gl_libs + libpng
|
lcms2 = pkg_config('lcms2', '--libs')
|
||||||
|
ans.ldpaths += pylib + font_libs + gl_libs + libpng + lcms2
|
||||||
if is_macos:
|
if is_macos:
|
||||||
ans.ldpaths.extend('-framework Cocoa'.split())
|
ans.ldpaths.extend('-framework Cocoa'.split())
|
||||||
elif not is_openbsd:
|
elif not is_openbsd:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user