Merge branch 'blender-v4.4-release'
[blender.git] / source / blender / python / intern / bpy_utils_previews.cc
blob3e49104cb6c85eaf375f7720c1d26db8c2fe1fac
1 /* SPDX-FileCopyrightText: 2023 Blender Authors
3 * SPDX-License-Identifier: GPL-2.0-or-later */
5 /** \file
6 * \ingroup pythonintern
8 * This file defines a singleton py object accessed via 'bpy.utils.previews',
9 * which exposes low-level API for custom previews/icons.
10 * It is replaced in final API by an higher-level python wrapper, that handles previews by addon,
11 * and automatically release them on deletion.
14 #include <Python.h>
15 #include <structmember.h>
17 #include "RNA_access.hh"
18 #include "RNA_prototypes.hh"
20 #include "bpy_rna.hh"
21 #include "bpy_utils_previews.hh"
23 #include "../generic/py_capi_utils.hh"
25 #include "IMB_thumbs.hh"
27 #include "BKE_preview_image.hh"
29 #define STR_SOURCE_TYPES "'IMAGE', 'MOVIE', 'BLEND', 'FONT'"
31 PyDoc_STRVAR(
32 /* Wrap. */
33 bpy_utils_previews_new_doc,
34 ".. method:: new(name)\n"
35 "\n"
36 " Generate a new empty preview.\n"
37 "\n"
38 " :arg name: The name (unique id) identifying the preview.\n"
39 " :type name: str\n"
40 " :return: The Preview matching given name, or a new empty one.\n"
41 " :rtype: :class:`bpy.types.ImagePreview`\n"
42 /* This is only true when accessed via 'bpy.utils.previews.ImagePreviewCollection.load',
43 * however this is the public API, allow this minor difference to the internal version here. */
44 " :raises KeyError: if ``name`` already exists.");
45 static PyObject *bpy_utils_previews_new(PyObject * /*self*/, PyObject *args)
47 char *name;
48 PreviewImage *prv;
50 if (!PyArg_ParseTuple(args, "s:new", &name)) {
51 return nullptr;
54 prv = BKE_previewimg_cached_ensure(name);
55 PointerRNA ptr = RNA_pointer_create_discrete(nullptr, &RNA_ImagePreview, prv);
57 return pyrna_struct_CreatePyObject(&ptr);
60 PyDoc_STRVAR(
61 /* Wrap. */
62 bpy_utils_previews_load_doc,
63 ".. method:: load(name, filepath, filetype, force_reload=False)\n"
64 "\n"
65 " Generate a new preview from given file path.\n"
66 "\n"
67 " :arg name: The name (unique id) identifying the preview.\n"
68 " :type name: str\n"
69 " :arg filepath: The file path to generate the preview from.\n"
70 " :type filepath: str | bytes\n"
71 " :arg filetype: The type of file, needed to generate the preview in [" STR_SOURCE_TYPES
72 "].\n"
73 " :type filetype: str\n"
74 " :arg force_reload: If True, force running thumbnail manager even if preview already "
75 "exists in cache.\n"
76 " :type force_reload: bool\n"
77 " :return: The Preview matching given name, or a new empty one.\n"
78 " :rtype: :class:`bpy.types.ImagePreview`\n"
79 /* This is only true when accessed via 'bpy.utils.previews.ImagePreviewCollection.load',
80 * however this is the public API, allow this minor difference to the internal version here. */
81 " :raises KeyError: if ``name`` already exists.");
82 static PyObject *bpy_utils_previews_load(PyObject * /*self*/, PyObject *args)
84 char *name;
85 PyC_UnicodeAsBytesAndSize_Data filepath_data = {nullptr};
86 const PyC_StringEnumItems path_type_items[] = {
87 {THB_SOURCE_IMAGE, "IMAGE"},
88 {THB_SOURCE_MOVIE, "MOVIE"},
89 {THB_SOURCE_BLEND, "BLEND"},
90 {THB_SOURCE_FONT, "FONT"},
91 {THB_SOURCE_OBJECT_IO, "OBJECT_IO"},
92 {0, nullptr},
94 PyC_StringEnum path_type = {
95 path_type_items,
96 /* The default isn't used. */
99 int force_reload = false;
101 if (!PyArg_ParseTuple(args,
102 "s" /* `name` */
103 "O&" /* `filepath` */
104 "O&" /* `filetype` */
105 "|" /* Optional arguments. */
106 "p" /* `force_reload` */
107 ":load",
108 &name,
109 PyC_ParseUnicodeAsBytesAndSize,
110 &filepath_data,
111 PyC_ParseStringEnum,
112 &path_type,
113 &force_reload))
115 return nullptr;
118 PreviewImage *prv = BKE_previewimg_cached_thumbnail_read(
119 name, filepath_data.value, path_type.value_found, force_reload);
121 Py_XDECREF(filepath_data.value_coerce);
123 PointerRNA ptr = RNA_pointer_create_discrete(nullptr, &RNA_ImagePreview, prv);
124 return pyrna_struct_CreatePyObject(&ptr);
127 PyDoc_STRVAR(
128 /* Wrap. */
129 bpy_utils_previews_release_doc,
130 ".. method:: release(name)\n"
131 "\n"
132 " Release (free) a previously created preview.\n"
133 "\n"
134 "\n"
135 " :arg name: The name (unique id) identifying the preview.\n"
136 " :type name: str\n");
137 static PyObject *bpy_utils_previews_release(PyObject * /*self*/, PyObject *args)
139 char *name;
141 if (!PyArg_ParseTuple(args, "s:release", &name)) {
142 return nullptr;
145 BKE_previewimg_cached_release(name);
147 Py_RETURN_NONE;
150 static PyMethodDef bpy_utils_previews_methods[] = {
151 /* Can't use METH_KEYWORDS alone, see http://bugs.python.org/issue11587 */
152 {"new", (PyCFunction)bpy_utils_previews_new, METH_VARARGS, bpy_utils_previews_new_doc},
153 {"load", (PyCFunction)bpy_utils_previews_load, METH_VARARGS, bpy_utils_previews_load_doc},
154 {"release",
155 (PyCFunction)bpy_utils_previews_release,
156 METH_VARARGS,
157 bpy_utils_previews_release_doc},
158 {nullptr, nullptr, 0, nullptr},
161 PyDoc_STRVAR(
162 /* Wrap. */
163 bpy_utils_previews_doc,
164 "This object contains basic static methods to handle cached (non-ID) previews in Blender\n"
165 "(low-level API, not exposed to final users).");
166 static PyModuleDef bpy_utils_previews_module = {
167 /*m_base*/ PyModuleDef_HEAD_INIT,
168 /*m_name*/ "bpy._utils_previews",
169 /*m_doc*/ bpy_utils_previews_doc,
170 /*m_size*/ 0,
171 /*m_methods*/ bpy_utils_previews_methods,
172 /*m_slots*/ nullptr,
173 /*m_traverse*/ nullptr,
174 /*m_clear*/ nullptr,
175 /*m_free*/ nullptr,
178 PyObject *BPY_utils_previews_module()
180 PyObject *submodule;
182 submodule = PyModule_Create(&bpy_utils_previews_module);
184 return submodule;