Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorBrecht Van Lommel <brecht@blender.org>2022-05-19 21:31:58 +0300
committerBrecht Van Lommel <brecht@blender.org>2022-05-23 16:34:50 +0300
commit469ee7ff1529a1b28ce0b300835ebc42d5c5362f (patch)
tree9be3874673f222ac3c3773fe726f0158287ac1e6 /source
parent2f2d13b8c664b90a7d3249d6ad71bac3d519026d (diff)
Python API: add mathutils.Color functions to convert color spaces
Between scene linear and sRGB, XYZ, linear Rec.709 and ACES2065-1. And add some clarifications about color spaces in the docs. Fixes T98267 Ref T68926 Differential Revision: https://developer.blender.org/D14989
Diffstat (limited to 'source')
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h8
-rw-r--r--source/blender/imbuf/intern/IMB_colormanagement_intern.h4
-rw-r--r--source/blender/imbuf/intern/colormanagement.c18
-rw-r--r--source/blender/imbuf/intern/colormanagement_inline.c24
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c10
-rw-r--r--source/blender/python/mathutils/CMakeLists.txt2
-rw-r--r--source/blender/python/mathutils/mathutils_Color.c169
7 files changed, 219 insertions, 16 deletions
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 1f0ed4cafbe..94036da9d22 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -72,8 +72,16 @@ BLI_INLINE float IMB_colormanagement_get_luminance(const float rgb[3]);
* Byte equivalent of #IMB_colormanagement_get_luminance().
*/
BLI_INLINE unsigned char IMB_colormanagement_get_luminance_byte(const unsigned char[3]);
+
+/**
+ * Conversion between scene linear and other color spaces.
+ */
BLI_INLINE void IMB_colormanagement_xyz_to_rgb(float rgb[3], const float xyz[3]);
BLI_INLINE void IMB_colormanagement_rgb_to_xyz(float xyz[3], const float rgb[3]);
+BLI_INLINE void IMB_colormanagement_rec709_to_rgb(float rgb[3], const float rec709[3]);
+BLI_INLINE void IMB_colormanagement_rgb_to_rec709(float rec709[3], const float rgb[3]);
+BLI_INLINE void IMB_colormanagement_aces_to_rgb(float rgb[3], const float aces[3]);
+BLI_INLINE void IMB_colormanagement_rgb_to_aces(float aces[3], const float rgb[3]);
const float *IMB_colormanagement_get_xyz_to_rgb(void);
/** \} */
diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
index c89b15480a2..fd70c633f83 100644
--- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h
+++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
@@ -20,6 +20,10 @@ struct OCIO_ConstCPUProcessorRcPtr;
extern float imbuf_luma_coefficients[3];
extern float imbuf_xyz_to_rgb[3][3];
extern float imbuf_rgb_to_xyz[3][3];
+extern float imbuf_xyz_to_aces[3][3];
+extern float imbuf_aces_to_xyz[3][3];
+extern float imbuf_xyz_to_rec709[3][3];
+extern float imbuf_rec709_to_xyz[3][3];
#define MAX_COLORSPACE_NAME 64
#define MAX_COLORSPACE_DESCRIPTION 512
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 95e2d36891a..f189614e61c 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -75,8 +75,10 @@ static int global_tot_looks = 0;
float imbuf_luma_coefficients[3] = {0.0f};
float imbuf_xyz_to_rgb[3][3] = {{0.0f}};
float imbuf_rgb_to_xyz[3][3] = {{0.0f}};
-static float imbuf_xyz_to_linear_srgb[3][3] = {{0.0f}};
-static float imbuf_linear_srgb_to_xyz[3][3] = {{0.0f}};
+float imbuf_xyz_to_rec709[3][3] = {{0.0f}};
+float imbuf_rec709_to_xyz[3][3] = {{0.0f}};
+float imbuf_xyz_to_aces[3][3] = {{0.0f}};
+float imbuf_aces_to_xyz[3][3] = {{0.0f}};
/* lock used by pre-cached processors getters, so processor wouldn't
* be created several times
@@ -573,10 +575,14 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
/* Load luminance coefficients. */
OCIO_configGetDefaultLumaCoefs(config, imbuf_luma_coefficients);
+
+ /* Load standard color spaces. */
OCIO_configGetXYZtoRGB(config, imbuf_xyz_to_rgb);
invert_m3_m3(imbuf_rgb_to_xyz, imbuf_xyz_to_rgb);
- copy_m3_m3(imbuf_xyz_to_linear_srgb, OCIO_XYZ_TO_LINEAR_SRGB);
- invert_m3_m3(imbuf_linear_srgb_to_xyz, imbuf_xyz_to_linear_srgb);
+ copy_m3_m3(imbuf_xyz_to_rec709, OCIO_XYZ_TO_REC709);
+ invert_m3_m3(imbuf_rec709_to_xyz, imbuf_xyz_to_rec709);
+ copy_m3_m3(imbuf_aces_to_xyz, OCIO_ACES_TO_XYZ);
+ invert_m3_m3(imbuf_xyz_to_aces, imbuf_aces_to_xyz);
}
static void colormanage_free_config(void)
@@ -2370,14 +2376,14 @@ void IMB_colormanagement_color_picking_to_scene_linear_v3(float pixel[3])
void IMB_colormanagement_scene_linear_to_srgb_v3(float pixel[3])
{
mul_m3_v3(imbuf_rgb_to_xyz, pixel);
- mul_m3_v3(imbuf_xyz_to_linear_srgb, pixel);
+ mul_m3_v3(imbuf_xyz_to_rec709, pixel);
linearrgb_to_srgb_v3_v3(pixel, pixel);
}
void IMB_colormanagement_srgb_to_scene_linear_v3(float pixel[3])
{
srgb_to_linearrgb_v3_v3(pixel, pixel);
- mul_m3_v3(imbuf_linear_srgb_to_xyz, pixel);
+ mul_m3_v3(imbuf_rec709_to_xyz, pixel);
mul_m3_v3(imbuf_xyz_to_rgb, pixel);
}
diff --git a/source/blender/imbuf/intern/colormanagement_inline.c b/source/blender/imbuf/intern/colormanagement_inline.c
index 411cf9af802..4c632da1520 100644
--- a/source/blender/imbuf/intern/colormanagement_inline.c
+++ b/source/blender/imbuf/intern/colormanagement_inline.c
@@ -37,4 +37,28 @@ void IMB_colormanagement_rgb_to_xyz(float xyz[3], const float rgb[3])
mul_v3_m3v3(xyz, imbuf_rgb_to_xyz, rgb);
}
+void IMB_colormanagement_rec709_to_rgb(float rgb[3], const float rec709[3])
+{
+ mul_v3_m3v3(rgb, imbuf_rec709_to_xyz, rec709);
+ mul_v3_m3v3(rgb, imbuf_xyz_to_rgb, rgb);
+}
+
+void IMB_colormanagement_rgb_to_rec709(float rec709[3], const float rgb[3])
+{
+ mul_v3_m3v3(rec709, imbuf_rgb_to_xyz, rgb);
+ mul_v3_m3v3(rec709, imbuf_xyz_to_rec709, rec709);
+}
+
+void IMB_colormanagement_aces_to_rgb(float rgb[3], const float aces[3])
+{
+ mul_v3_m3v3(rgb, imbuf_aces_to_xyz, aces);
+ mul_v3_m3v3(rgb, imbuf_xyz_to_rgb, rgb);
+}
+
+void IMB_colormanagement_rgb_to_aces(float aces[3], const float rgb[3])
+{
+ mul_v3_m3v3(aces, imbuf_rgb_to_xyz, rgb);
+ mul_v3_m3v3(aces, imbuf_xyz_to_aces, aces);
+}
+
#endif /* __IMB_COLORMANAGEMENT_INLINE_H__ */
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 38d473f04dd..ec0a182e338 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -2195,7 +2195,7 @@ static void rna_def_mloopcol(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_float_funcs(
prop, "rna_MeshLoopColor_color_get", "rna_MeshLoopColor_color_set", NULL);
- RNA_def_property_ui_text(prop, "Color", "");
+ RNA_def_property_ui_text(prop, "Color", "Color in sRGB color space");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
}
@@ -3210,7 +3210,9 @@ static void rna_def_mesh(BlenderRNA *brna)
NULL);
RNA_def_property_struct_type(prop, "MeshLoopColorLayer");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
- RNA_def_property_ui_text(prop, "Vertex Colors", "All vertex colors");
+ RNA_def_property_ui_text(prop,
+ "Vertex Colors",
+ "Legacy vertex color layers. Deprecated, use color attributes instead");
rna_def_loop_colors(brna, prop);
/* Sculpt Vertex colors */
@@ -3228,7 +3230,9 @@ static void rna_def_mesh(BlenderRNA *brna)
NULL);
RNA_def_property_struct_type(prop, "MeshVertColorLayer");
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
- RNA_def_property_ui_text(prop, "Sculpt Vertex Colors", "All vertex colors");
+ RNA_def_property_ui_text(prop,
+ "Sculpt Vertex Colors",
+ "Sculpt vertex color layers. Deprecated, use color attributes instead");
rna_def_vert_colors(brna, prop);
/* TODO: edge customdata layers (bmesh py api can access already). */
diff --git a/source/blender/python/mathutils/CMakeLists.txt b/source/blender/python/mathutils/CMakeLists.txt
index 1be9b568626..747d6c0e8f8 100644
--- a/source/blender/python/mathutils/CMakeLists.txt
+++ b/source/blender/python/mathutils/CMakeLists.txt
@@ -4,6 +4,7 @@ set(INC
.
../../blenkernel
../../blenlib
+ ../../imbuf
../../bmesh
../../depsgraph
../../makesdna
@@ -42,6 +43,7 @@ set(SRC
set(LIB
bf_blenlib
+ bf_imbuf
bf_python_ext
${PYTHON_LINKFLAGS}
diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c
index 8b126639f10..1495a465432 100644
--- a/source/blender/python/mathutils/mathutils_Color.c
+++ b/source/blender/python/mathutils/mathutils_Color.c
@@ -14,6 +14,8 @@
#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
+#include "IMB_colormanagement.h"
+
#ifndef MATH_STANDALONE
# include "BLI_dynstr.h"
#endif
@@ -76,6 +78,120 @@ static PyObject *Color_ToTupleExt(ColorObject *self, int ndigits)
return ret;
}
+PyDoc_STRVAR(Color_from_scene_linear_to_srgb_doc,
+ ".. function:: from_scene_linear_to_srgb()\n"
+ "\n"
+ " Convert from scene linear to sRGB color space.\n"
+ "\n"
+ " :return: A color in sRGB color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_scene_linear_to_srgb(ColorObject *self)
+{
+ float col[3] = {self->col[0], self->col[1], self->col[2]};
+ IMB_colormanagement_scene_linear_to_srgb_v3(col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
+
+PyDoc_STRVAR(Color_from_srgb_to_scene_linear_doc,
+ ".. function:: from_srgb_to_scene_linear()\n"
+ "\n"
+ " Convert from sRGB to scene linear color space.\n"
+ "\n"
+ " :return: A color in scene linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_srgb_to_scene_linear(ColorObject *self)
+{
+ float col[3] = {self->col[0], self->col[1], self->col[2]};
+ IMB_colormanagement_srgb_to_scene_linear_v3(col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
+
+PyDoc_STRVAR(Color_from_scene_linear_to_xyz_d65_doc,
+ ".. function:: from_scene_linear_to_xyz_d65()\n"
+ "\n"
+ " Convert from scene linear to CIE XYZ (Illuminant D65) color space.\n"
+ "\n"
+ " :return: A color in XYZ color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_scene_linear_to_xyz_d65(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_rgb_to_xyz(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
+
+PyDoc_STRVAR(Color_from_xyz_d65_to_scene_linear_doc,
+ ".. function:: from_xyz_d65_to_scene_linear()\n"
+ "\n"
+ " Convert from CIE XYZ (Illuminant D65) to scene linear color space.\n"
+ "\n"
+ " :return: A color in scene linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_xyz_d65_to_scene_linear(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_xyz_to_rgb(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
+
+PyDoc_STRVAR(Color_from_scene_linear_to_aces_doc,
+ ".. function:: from_scene_linear_to_aces()\n"
+ "\n"
+ " Convert from scene linear to ACES2065-1 linear color space.\n"
+ "\n"
+ " :return: A color in ACES2065-1 linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_scene_linear_to_aces(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_rgb_to_aces(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
+
+PyDoc_STRVAR(Color_from_aces_to_scene_linear_doc,
+ ".. function:: from_aces_to_scene_linear()\n"
+ "\n"
+ " Convert from ACES2065-1 linear to scene linear color space.\n"
+ "\n"
+ " :return: A color in scene linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_aces_to_scene_linear(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_aces_to_rgb(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
+
+PyDoc_STRVAR(Color_from_scene_linear_to_rec709_linear_doc,
+ ".. function:: from_scene_linear_to_rec709_linear()\n"
+ "\n"
+ " Convert from scene linear to Rec.709 linear color space.\n"
+ "\n"
+ " :return: A color in Rec.709 linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_scene_linear_to_rec709_linear(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_rgb_to_rec709(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
+
+PyDoc_STRVAR(Color_from_rec709_linear_to_scene_linear_doc,
+ ".. function:: from_rec709_linear_to_scene_linear()\n"
+ "\n"
+ " Convert from Rec.709 linear color space to scene linear color space.\n"
+ "\n"
+ " :return: A color in scene linear color space.\n"
+ " :rtype: :class:`Color`\n");
+static PyObject *Color_from_rec709_linear_to_scene_linear(ColorObject *self)
+{
+ float col[3];
+ IMB_colormanagement_rec709_to_rgb(col, self->col);
+ return Color_CreatePyObject(col, Py_TYPE(self));
+}
+
+/* ---------------------------- Colorspace conversion -------------- */
+
PyDoc_STRVAR(Color_copy_doc,
".. function:: copy()\n"
"\n"
@@ -869,17 +985,56 @@ static struct PyMethodDef Color_methods[] = {
/* base-math methods */
{"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc},
+
+ /* Colorspace methods. */
+ {"from_scene_linear_to_srgb",
+ (PyCFunction)Color_from_scene_linear_to_srgb,
+ METH_NOARGS,
+ Color_from_scene_linear_to_srgb_doc},
+ {"from_srgb_to_scene_linear",
+ (PyCFunction)Color_from_srgb_to_scene_linear,
+ METH_NOARGS,
+ Color_from_srgb_to_scene_linear_doc},
+ {"from_scene_linear_to_xyz_d65",
+ (PyCFunction)Color_from_scene_linear_to_xyz_d65,
+ METH_NOARGS,
+ Color_from_scene_linear_to_xyz_d65_doc},
+ {"from_xyz_d65_to_scene_linear",
+ (PyCFunction)Color_from_xyz_d65_to_scene_linear,
+ METH_NOARGS,
+ Color_from_xyz_d65_to_scene_linear_doc},
+ {"from_scene_linear_to_aces",
+ (PyCFunction)Color_from_scene_linear_to_aces,
+ METH_NOARGS,
+ Color_from_scene_linear_to_aces_doc},
+ {"from_aces_to_scene_linear",
+ (PyCFunction)Color_from_aces_to_scene_linear,
+ METH_NOARGS,
+ Color_from_aces_to_scene_linear_doc},
+ {"from_scene_linear_to_rec709_linear",
+ (PyCFunction)Color_from_scene_linear_to_rec709_linear,
+ METH_NOARGS,
+ Color_from_scene_linear_to_rec709_linear_doc},
+ {"from_rec709_linear_to_scene_linear",
+ (PyCFunction)Color_from_rec709_linear_to_scene_linear,
+ METH_NOARGS,
+ Color_from_rec709_linear_to_scene_linear_doc},
{NULL, NULL, 0, NULL},
};
/* ------------------PY_OBECT DEFINITION-------------------------- */
-PyDoc_STRVAR(color_doc,
- ".. class:: Color(rgb)\n"
- "\n"
- " This object gives access to Colors in Blender.\n"
- "\n"
- " :param rgb: (r, g, b) color values\n"
- " :type rgb: 3d vector\n");
+PyDoc_STRVAR(
+ color_doc,
+ ".. class:: Color(rgb)\n"
+ "\n"
+ " This object gives access to Colors in Blender.\n"
+ "\n"
+ " Most colors returned by Blender APIs are in scene linear color space, as defined by "
+ " the OpenColorIO configuration. The notable exception is user interface theming colors, "
+ " which are in sRGB color space.\n"
+ "\n"
+ " :param rgb: (r, g, b) color values\n"
+ " :type rgb: 3d vector\n");
PyTypeObject color_Type = {
PyVarObject_HEAD_INIT(NULL, 0) "Color", /* tp_name */
sizeof(ColorObject), /* tp_basicsize */