From 84756b68e68c8a25b820a8c3dda01ec7f0a59353 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 6 May 2022 11:08:10 +0200 Subject: Add documentation about Image/ImBuf to python/RNA API. Related to T95616, the relationship between Image ID and ImBuf 'cached' buffers can be fairly confusing when using the RNA API. Reviewed By: campbellbarton, jbakker Differential Revision: https://developer.blender.org/D14833 --- doc/python_api/examples/bpy.types.Image.py | 47 ++++++++++++++++++++++++++ source/blender/makesrna/intern/rna_image.c | 35 ++++++++++++------- source/blender/makesrna/intern/rna_image_api.c | 2 +- source/blender/python/generic/imbuf_py_api.c | 14 ++++++-- 4 files changed, 82 insertions(+), 16 deletions(-) create mode 100644 doc/python_api/examples/bpy.types.Image.py diff --git a/doc/python_api/examples/bpy.types.Image.py b/doc/python_api/examples/bpy.types.Image.py new file mode 100644 index 00000000000..715623f6f76 --- /dev/null +++ b/doc/python_api/examples/bpy.types.Image.py @@ -0,0 +1,47 @@ +""" +Image Data +++++++++++ + +The Image data-block is a shallow wrapper around image or video file(s) +(on disk, as packed data, or generated). + +All actual data like the pixel buffer, size, resolution etc. is +cached in an :class:`imbuf.types.ImBuf` image buffer (or several buffers +in some cases, like UDIM textures, multi-views, animations...). + +Several properties and functions of the Image data-block are then actually +using/modifying its image buffer, and not the Image data-block itself. + +.. warning:: + + One key limitation is that image buffers are not shared between different + Image data-blocks, and they are not duplicated when copying an image. + + So until a modified image buffer is saved on disk, duplicating its Image + data-block will not propagate the underlying buffer changes to the new Image. + + +This example script generates an Image data-block with a given size, +change its first pixel, rescale it, and duplicates the image. + +The duplicated image still has the same size and colors as the original image +at its creation, all editing in the original image's buffer is 'lost' in its copy. +""" + +import bpy + +image_src = bpy.data.images.new('src', 1024, 102) +print(image_src.size) +print(image_src.pixels[0:4]) + +image_src.scale(1024, 720) +image_src.pixels[0:4] = (0.5, 0.5, 0.5, 0.5) +image_src.update() +print(image_src.size) +print(image_src.pixels[0:4]) + +image_dest = image_src.copy() +image_dest.update() +print(image_dest.size) +print(image_dest.pixels[0:4]) + diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 3a93a44e0d1..bd3b03add95 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -1073,22 +1073,31 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Depth", "Image bit depth"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - prop = RNA_def_int_vector(srna, - "size", - 2, - NULL, - 0, - 0, - "Size", - "Width and height in pixels, zero when image data can't be loaded", - 0, - 0); + prop = RNA_def_int_vector( + srna, + "size", + 2, + NULL, + 0, + 0, + "Size", + "Width and height of the image buffer in pixels, zero when image data can't be loaded", + 0, + 0); RNA_def_property_subtype(prop, PROP_PIXEL); RNA_def_property_int_funcs(prop, "rna_Image_size_get", NULL, NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - prop = RNA_def_float_vector( - srna, "resolution", 2, NULL, 0, 0, "Resolution", "X/Y pixels per meter", 0, 0); + prop = RNA_def_float_vector(srna, + "resolution", + 2, + NULL, + 0, + 0, + "Resolution", + "X/Y pixels per meter, for the image buffer", + 0, + 0); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_float_funcs(prop, "rna_Image_resolution_get", "rna_Image_resolution_set", NULL); @@ -1105,7 +1114,7 @@ static void rna_def_image(BlenderRNA *brna) prop = RNA_def_property(srna, "pixels", PROP_FLOAT, PROP_NONE); RNA_def_property_flag(prop, PROP_DYNAMIC); RNA_def_property_multi_array(prop, 1, NULL); - RNA_def_property_ui_text(prop, "Pixels", "Image pixels in floating-point values"); + RNA_def_property_ui_text(prop, "Pixels", "Image buffer pixels in floating-point values"); RNA_def_property_dynamic_array_funcs(prop, "rna_Image_pixels_get_length"); RNA_def_property_float_funcs(prop, "rna_Image_pixels_get", "rna_Image_pixels_set", NULL); diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index 0b188b2b3db..897573f9fd9 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -316,7 +316,7 @@ void RNA_api_image(StructRNA *srna) RNA_def_function_flag(func, FUNC_USE_REPORTS); func = RNA_def_function(srna, "scale", "rna_Image_scale"); - RNA_def_function_ui_description(func, "Scale the image in pixels"); + RNA_def_function_ui_description(func, "Scale the buffer of the image, in pixels"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_int(func, "width", 1, 1, INT_MAX, "", "Width", 1, INT_MAX); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); diff --git a/source/blender/python/generic/imbuf_py_api.c b/source/blender/python/generic/imbuf_py_api.c index ef11d1ab32d..e6d90c46866 100644 --- a/source/blender/python/generic/imbuf_py_api.c +++ b/source/blender/python/generic/imbuf_py_api.c @@ -559,7 +559,11 @@ static PyMethodDef IMB_methods[] = { {NULL, NULL, 0, NULL}, }; -PyDoc_STRVAR(IMB_doc, "This module provides access to Blender's image manipulation API."); +PyDoc_STRVAR(IMB_doc, + "This module provides access to Blender's image manipulation API.\n" + "\n" + "It provides access to image buffers outside of Blender's\n" + ":class:`bpy.types.Image` data-block context.\n"); static struct PyModuleDef IMB_module_def = { PyModuleDef_HEAD_INIT, "imbuf", /* m_name */ @@ -596,7 +600,13 @@ PyObject *BPyInit_imbuf(void) * for docs and the ability to use with built-ins such as `isinstance`, `issubclass`. * \{ */ -PyDoc_STRVAR(IMB_types_doc, "This module provides access to image buffer types."); +PyDoc_STRVAR(IMB_types_doc, + "This module provides access to image buffer types.\n" + "\n" + ".. note::\n" + "\n" + " Image buffer is also the structure used by :class:`bpy.types.Image`\n" + " ID type to store and manipulate image data at runtime.\n"); static struct PyModuleDef IMB_types_module_def = { PyModuleDef_HEAD_INIT, -- cgit v1.2.3