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
diff options
context:
space:
mode:
authorColin Basnett <cmbasnett@gmail.com>2022-06-21 02:52:14 +0300
committerColin Basnett <cmbasnett@gmail.com>2022-06-21 03:13:48 +0300
commit0fff238150d076576053c25b646f653d6e3b0edb (patch)
treeacdd2eaa5cec9c1251186f69aa17a1c27dfef374
parent579784eff99a57e1b827ff71d921bd07db7649fb (diff)
Moved some things around, finally have a global hash table for registered image formats
-rw-r--r--source/blender/blentranslation/BLT_translation.h3
-rw-r--r--source/blender/makesdna/DNA_image_types.h3
-rw-r--r--source/blender/makesrna/intern/rna_image.c212
-rw-r--r--source/blender/makesrna/intern/rna_wm.c220
-rw-r--r--source/blender/python/intern/bpy_imageformat_wrap.c40
-rw-r--r--source/blender/python/intern/bpy_imageformat_wrap.h24
-rw-r--r--source/blender/windowmanager/WM_api.h22
-rw-r--r--source/blender/windowmanager/intern/wm_imageformat_type.c201
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c2
9 files changed, 512 insertions, 215 deletions
diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index 129eba3de2f..247be831aad 100644
--- a/source/blender/blentranslation/BLT_translation.h
+++ b/source/blender/blentranslation/BLT_translation.h
@@ -69,6 +69,9 @@ const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid
/* Default context for operator names/labels. */
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT "Operator"
+/* Default context for image format names/labels. */
+#define BLT_I18CONTEXT_IMAGEFORMAT_DEFAULT "Image Format"
+
/* Context for events/keymaps (necessary, since those often use one or two letters,
* easy to get collisions with other areas...). */
#define BLT_I18NCONTEXT_UI_EVENTS "UI_Events_KeyMaps"
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index e521dae219d..07b1928717a 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -276,9 +276,6 @@ enum {
typedef struct imfImageFormat {
struct imfImageFormat *next, *prev;
-
- const char *bl_extensions;
-
struct imfImageFormatType *type;
} imfImageFormat;
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 38706606997..abf3d5cfcde 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -53,45 +53,6 @@ static const EnumPropertyItem image_source_items[] = {
{0, NULL, 0, NULL, NULL},
};
-#ifdef WITH_PYTHON
-
-static bool rna_imageformat_is_a_bytes_cb(const struct bContext *C,
- struct imfImageFormatType *ift,
- const char *bytes)
-{
- extern FunctionRNA rna_ImageFormat_is_a_bytes_func;
-
- PointerRNA ptr;
- ParameterList list;
- FunctionRNA *func;
- void *ret;
- bool is_a_bytes;
-
- /* seems to be some sort of temporary rna pointer?? */
- RNA_pointer_create(NULL, ift->rna_ext.srna, NULL, &ptr);
- func = &rna_ImageFormat_is_a_bytes_func;
-
- /* set up arguments */
- RNA_parameter_list_create(&list, &ptr, func);
- RNA_parameter_set_lookup(&list, "data", bytes);
-
- /* call function */
- ift->rna_ext.call((struct bContext *)C, &ptr, func, &list);
-
- /* get return value */
- RNA_parameter_get_lookup(&list, "result", &ret);
- is_a_bytes = *(bool *)ret;
-
- return is_a_bytes;
-}
-
-static Image *rna_imageformat_load_cb(struct imfImageFormatType *ift, const char *bytes)
-{
- return NULL;
-}
-
-#endif /* WITH_PYTHON */
-
#ifdef RNA_RUNTIME
@@ -731,129 +692,6 @@ static void rna_UDIMTile_remove(Image *image, PointerRNA *ptr)
WM_main_add_notifier(NC_IMAGE | ND_DRAW, NULL);
}
-static StructRNA *rna_ImageFormat_register(Main *bmain,
- ReportList *reports,
- void *data,
- const char *identifier,
- StructValidateFunc validate,
- StructCallbackFunc call,
- StructFreeFunc free)
-{
- struct {
- char idname[MAX_NAME];
- char extensions[MAX_NAME];
- } temp_buffers;
-
- imfImageFormatType dummy_type = {NULL};
- imfImageFormat dummy = {NULL};
- PointerRNA mnp_ptr;
-
- /* TODO: how is the size determined? magic of rna defs? */
- int have_function[2];
-
- /* setup dummy gizmo & gizmo type to store static properties in */
- dummy.type = &dummy_type;
- dummy_type.idname = temp_buffers.idname;
- dummy_type.extensions = temp_buffers.extensions;
- RNA_pointer_create(NULL, &RNA_ImageFormat, &dummy, &mnp_ptr);
-
- /* Clear so we can detect if it's left unset. */
- temp_buffers.idname[0] = '\0';
- temp_buffers.extensions[0] = '\0';
-
- /* validate the python class */
- if (validate(&mnp_ptr, data, have_function) != 0) {
- return NULL;
- }
-
- /* make sure the id does not exceeed buffer length */
- if (strlen(identifier) >= sizeof(temp_buffers.idname)) {
- BKE_reportf(reports,
- RPT_ERROR,
- "Registering image format class: '%s' is too long, maximum length is %d",
- identifier,
- (int)sizeof(temp_buffers.idname));
- return NULL;
- }
-
- // TODO: check if we've added this gizmo before, remove it if so.
- {
- }
-
- if (!RNA_struct_available_or_report(reports, dummy_type.idname)) {
- return NULL;
- }
-
- if (!RNA_struct_bl_idname_ok_or_report(reports, dummy_type.idname, "_IF_")) {
- return NULL;
- }
-
- {
- /* allocate the idname */
- dummy_type.idname = BLI_strdup(temp_buffers.idname);
- }
-
- /* Create a new ImageFormat type. */
- dummy_type.rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummy_type.idname, &RNA_ImageFormat);
- dummy_type.rna_ext.data = data;
- dummy_type.rna_ext.call = call;
- dummy_type.rna_ext.free = free;
- RNA_def_struct_flag(dummy_type.rna_ext.srna, STRUCT_NO_IDPROPERTIES | STRUCT_RUNTIME);
-
- // function callbacks
- {
- int i = 0;
- dummy_type.is_a_bytes = (have_function[i++]) ? rna_imageformat_is_a_bytes_cb : NULL;
- dummy_type.load = (have_function[i++]) ? rna_imageformat_load_cb : NULL;
- BLI_assert(i == ARRAY_SIZE(have_function));
- }
-
- // TODO: actually register the type in a list somewhere! (wm, probably)
-
- /* update while blender is running */
- WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
-
- return dummy_type.rna_ext.srna;
-}
-
-static void rna_ImageFormat_unregister(Main *UNUSED(bmain), StructRNA *type)
-{
- imfImageFormatType *ift = RNA_struct_blender_type_get(type);
-
- if (!ift) {
- return;
- }
-
- //WM_gizmotype_remove_ptr(NULL, bmain, gzt);
-
- /* Free extension after removing instances so `__del__` doesn't crash, see: T85567. */
- RNA_struct_free_extension(type, &ift->rna_ext);
- RNA_struct_free(&BLENDER_RNA, type);
-
- /* Free gizmo group after the extension as it owns the identifier memory. */
- //WM_gizmotype_free_ptr(gzt);
-
- WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
-}
-
-static StructRNA *rna_ImageFormat_refine(PointerRNA *ptr)
-{
- imfImageFormat *imf = (imfImageFormat *)ptr->data;
- return (imf->type && imf->type->rna_ext.srna) ? imf->type->rna_ext.srna : &RNA_ImageFormat;
-}
-
-static void rna_ImageFormat_bl_extensions_set(PointerRNA *ptr, const char *value)
-{
- imfImageFormat *data = ptr->data;
- char *str = (char *)data->type->extensions;
- if (!str[0]) {
- BLI_strncpy(str, value, MAX_NAME); /* utf8 already ensured */
- }
- else {
- BLI_assert_msg(0, "setting the bl_idname on a non-builtin operator");
- }
-}
-
#else
static void rna_def_imageuser(BlenderRNA *brna)
@@ -1115,55 +953,6 @@ static void rna_def_udim_tiles(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
}
-static void rna_def_imageformat(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
- FunctionRNA *func;
-
- // TODO: are we just missing a text thingy?
- srna = RNA_def_struct(brna, "ImageFormat", NULL);
- RNA_def_struct_sdna(srna, "imfImageFormat");
- RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES);
- RNA_def_struct_register_funcs(srna, "rna_ImageFormat_register", "rna_ImageFormat_unregister", NULL);
- RNA_def_struct_refine_func(srna, "rna_ImageFormat_refine");
-
- /*
- TODO: ideally we want a list of these instead of a single string,
- but we'll have to deal with this for now
- */
- /* extensions (semicolon separated) */
- prop = RNA_def_property(srna, "bl_extensions", PROP_STRING, PROP_NONE);
- //RNA_def_property_string_sdna(prop, NULL, "type->extensions");
- RNA_def_property_string_maxlength(prop, MAX_NAME);
- RNA_def_property_flag(prop, PROP_NEVER_NULL | PROP_REGISTER);
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ImageFormat_bl_extensions_set");
-
- /* idname */
- prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
- RNA_def_property_string_sdna(prop, NULL, "type->idname");
- RNA_def_property_string_maxlength(prop, MAX_NAME);
- RNA_def_property_flag(prop, PROP_REGISTER);
-
- /* is_a_bytes */
- func = RNA_def_function(srna, "is_a_bytes", NULL);
- RNA_def_function_ui_description(func, "FILLMEIN");
- RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER);
- prop = RNA_def_property(func, "data", PROP_STRING, PROP_BYTESTRING);
- RNA_def_parameter_flags(prop, PROP_NEVER_NULL, PARM_REQUIRED);
- prop = RNA_def_boolean(func, "result", false, "", "");
- RNA_def_function_return(func, prop);
-
- /* load */
- func = RNA_def_function(srna, "load", NULL);
- RNA_def_function_ui_description(func, "FILLMEIN");
- RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER);
- prop = RNA_def_property(func, "data", PROP_STRING, PROP_BYTESTRING);
- RNA_def_parameter_flags(prop, PROP_NEVER_NULL, PARM_REQUIRED);
- prop = RNA_def_pointer(func, "result", "Image", "", ""); // TODO: this should return an imbuf!
- RNA_def_function_return(func, prop);
-}
-
static void rna_def_image(BlenderRNA *brna)
{
StructRNA *srna;
@@ -1466,7 +1255,6 @@ void RNA_def_image(BlenderRNA *brna)
{
rna_def_render_slot(brna);
rna_def_udim_tile(brna);
- rna_def_imageformat(brna);
rna_def_image(brna);
rna_def_imageuser(brna);
rna_def_image_packed_files(brna);
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 3ff9e6be3ce..a76524e934c 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -504,6 +504,45 @@ const EnumPropertyItem rna_enum_wm_report_items[] = {
{0, NULL, 0, NULL, NULL},
};
+#ifdef WITH_PYTHON
+
+static bool rna_imageformat_is_a_bytes_cb(const struct bContext *C,
+ struct imfImageFormatType *ift,
+ const char *bytes)
+{
+ extern FunctionRNA rna_ImageFormat_is_a_bytes_func;
+
+ PointerRNA ptr;
+ ParameterList list;
+ FunctionRNA *func;
+ void *ret;
+ bool is_a_bytes;
+
+ /* seems to be some sort of temporary rna pointer?? */
+ RNA_pointer_create(NULL, ift->rna_ext.srna, NULL, &ptr);
+ func = &rna_ImageFormat_is_a_bytes_func;
+
+ /* set up arguments */
+ RNA_parameter_list_create(&list, &ptr, func);
+ RNA_parameter_set_lookup(&list, "data", bytes);
+
+ /* call function */
+ ift->rna_ext.call((struct bContext *)C, &ptr, func, &list);
+
+ /* get return value */
+ RNA_parameter_get_lookup(&list, "result", &ret);
+ is_a_bytes = *(bool *)ret;
+
+ return is_a_bytes;
+}
+
+static Image *rna_imageformat_load_cb(struct imfImageFormatType *ift, const char *bytes)
+{
+ return NULL;
+}
+
+#endif /* WITH_PYTHON */
+
#ifdef RNA_RUNTIME
# include "BLI_string_utils.h"
@@ -1434,6 +1473,10 @@ static void rna_Operator_unregister(struct Main *bmain, StructRNA *type);
extern void BPY_RNA_operator_wrapper(wmOperatorType *ot, void *userdata);
extern void BPY_RNA_operator_macro_wrapper(wmOperatorType *ot, void *userdata);
+/* bpy_imageformat_wrap.c */
+
+extern void BPY_RNA_imageformat_wrapper(imfImageFormatType *ift, void *userdata);
+
static StructRNA *rna_Operator_register(Main *bmain,
ReportList *reports,
void *data,
@@ -1783,6 +1826,132 @@ static void rna_KeyMapItem_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
WM_keyconfig_update_tag(NULL, kmi);
}
+static void rna_ImageFormat_unregister(Main *UNUSED(bmain), StructRNA *type)
+{
+ imfImageFormatType *ift = RNA_struct_blender_type_get(type);
+
+ if (!ift) {
+ return;
+ }
+
+ // WM_gizmotype_remove_ptr(NULL, bmain, gzt);
+
+ /* Free extension after removing instances so `__del__` doesn't crash, see: T85567. */
+ RNA_struct_free_extension(type, &ift->rna_ext);
+ RNA_struct_free(&BLENDER_RNA, type);
+
+ /* Free image format type after the extension as it owns the identifier memory. */
+ wm_imageformattype_remove_ptr(ift);
+
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+}
+
+static StructRNA *rna_ImageFormat_register(Main *bmain,
+ ReportList *reports,
+ void *data,
+ const char *identifier,
+ StructValidateFunc validate,
+ StructCallbackFunc call,
+ StructFreeFunc free)
+{
+ struct {
+ char idname[MAX_NAME];
+ char extensions[MAX_NAME];
+ } temp_buffers;
+
+ imfImageFormatType dummy_type = {NULL};
+ imfImageFormat dummy = {NULL};
+ PointerRNA mnp_ptr;
+
+ /* TODO: how is the size determined? magic of rna defs? */
+ int have_function[2];
+
+ /* setup dummy gizmo & gizmo type to store static properties in */
+ dummy.type = &dummy_type;
+ dummy_type.idname = temp_buffers.idname;
+ dummy_type.extensions = temp_buffers.extensions;
+ RNA_pointer_create(NULL, &RNA_ImageFormat, &dummy, &mnp_ptr);
+
+ /* Clear so we can detect if it's left unset. */
+ temp_buffers.idname[0] = '\0';
+ temp_buffers.extensions[0] = '\0';
+
+ /* validate the python class */
+ if (validate(&mnp_ptr, data, have_function) != 0) {
+ return NULL;
+ }
+
+ /* make sure the id does not exceeed buffer length */
+ if (strlen(identifier) >= sizeof(temp_buffers.idname)) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "Registering image format class: '%s' is too long, maximum length is %d",
+ identifier,
+ (int)sizeof(temp_buffers.idname));
+ return NULL;
+ }
+
+ /* unregister image format type with same ID */
+ imfImageFormatType *ift = WM_imageformattype_find(dummy_type.idname, true);
+ if (ift && ift->rna_ext.srna) {
+ rna_ImageFormat_unregister(bmain, ift->rna_ext.srna);
+ }
+
+ if (!RNA_struct_available_or_report(reports, dummy_type.idname)) {
+ return NULL;
+ }
+
+ if (!RNA_struct_bl_idname_ok_or_report(reports, dummy_type.idname, "_IF_")) {
+ return NULL;
+ }
+
+ {
+ /* allocate the idname */
+ dummy_type.idname = BLI_strdup(temp_buffers.idname);
+ }
+
+ /* Create a new ImageFormat type. */
+ dummy_type.rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummy_type.idname, &RNA_ImageFormat);
+ dummy_type.rna_ext.data = data;
+ dummy_type.rna_ext.call = call;
+ dummy_type.rna_ext.free = free;
+ RNA_def_struct_flag(dummy_type.rna_ext.srna, STRUCT_NO_IDPROPERTIES | STRUCT_RUNTIME);
+
+ // function callbacks
+ {
+ int i = 0;
+ dummy_type.is_a_bytes = (have_function[i++]) ? rna_imageformat_is_a_bytes_cb : NULL;
+ dummy_type.load = (have_function[i++]) ? rna_imageformat_load_cb : NULL;
+ BLI_assert(i == ARRAY_SIZE(have_function));
+ }
+
+ // register the image format type
+ wm_imageformattype_append_ptr(BPY_RNA_imageformat_wrapper, (void *)&dummy_type);
+
+ /* update while blender is running */
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+
+ return dummy_type.rna_ext.srna;
+}
+
+static StructRNA *rna_ImageFormat_refine(PointerRNA *ptr)
+{
+ imfImageFormat *imf = (imfImageFormat *)ptr->data;
+ return (imf->type && imf->type->rna_ext.srna) ? imf->type->rna_ext.srna : &RNA_ImageFormat;
+}
+
+static void rna_ImageFormat_bl_extensions_set(PointerRNA *ptr, const char *value)
+{
+ imfImageFormat *data = ptr->data;
+ char *str = (char *)data->type->extensions;
+ if (!str[0]) {
+ BLI_strncpy(str, value, MAX_NAME); /* utf8 already ensured */
+ }
+ else {
+ BLI_assert_msg(0, "setting the bl_idname on a non-builtin operator");
+ }
+}
+
#else /* RNA_RUNTIME */
/**
@@ -2784,6 +2953,56 @@ static void rna_def_keyconfig(BlenderRNA *brna)
RNA_api_keymapitem(srna);
}
+static void rna_def_imageformat(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+ FunctionRNA *func;
+
+ // TODO: are we just missing a text thingy?
+ srna = RNA_def_struct(brna, "ImageFormat", NULL);
+ RNA_def_struct_sdna(srna, "imfImageFormat");
+ RNA_def_struct_flag(srna, STRUCT_NO_DATABLOCK_IDPROPERTIES);
+ RNA_def_struct_register_funcs(
+ srna, "rna_ImageFormat_register", "rna_ImageFormat_unregister", NULL);
+ RNA_def_struct_refine_func(srna, "rna_ImageFormat_refine");
+
+ /*
+ TODO: ideally we want a list of these instead of a single string,
+ but we'll have to deal with this for now
+ */
+ /* extensions (semicolon separated) */
+ prop = RNA_def_property(srna, "bl_extensions", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->extensions");
+ RNA_def_property_string_maxlength(prop, MAX_NAME);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL | PROP_REGISTER);
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ImageFormat_bl_extensions_set");
+
+ /* idname */
+ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "type->idname");
+ RNA_def_property_string_maxlength(prop, MAX_NAME);
+ RNA_def_property_flag(prop, PROP_REGISTER);
+
+ /* is_a_bytes */
+ func = RNA_def_function(srna, "is_a_bytes", NULL);
+ RNA_def_function_ui_description(func, "FILLMEIN");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER);
+ prop = RNA_def_property(func, "data", PROP_STRING, PROP_BYTESTRING);
+ RNA_def_parameter_flags(prop, PROP_NEVER_NULL, PARM_REQUIRED);
+ prop = RNA_def_boolean(func, "result", false, "", "");
+ RNA_def_function_return(func, prop);
+
+ /* load */
+ func = RNA_def_function(srna, "load", NULL);
+ RNA_def_function_ui_description(func, "FILLMEIN");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER);
+ prop = RNA_def_property(func, "data", PROP_STRING, PROP_BYTESTRING);
+ RNA_def_parameter_flags(prop, PROP_NEVER_NULL, PARM_REQUIRED);
+ prop = RNA_def_pointer(func, "result", "Image", "", ""); // TODO: this should return an imbuf!
+ RNA_def_function_return(func, prop);
+}
+
void RNA_def_wm(BlenderRNA *brna)
{
rna_def_operator(brna);
@@ -2801,6 +3020,7 @@ void RNA_def_wm(BlenderRNA *brna)
rna_def_windowmanager(brna);
rna_def_keyconfig_prefs(brna);
rna_def_keyconfig(brna);
+ rna_def_imageformat(brna);
}
#endif /* RNA_RUNTIME */
diff --git a/source/blender/python/intern/bpy_imageformat_wrap.c b/source/blender/python/intern/bpy_imageformat_wrap.c
new file mode 100644
index 00000000000..988292b01f7
--- /dev/null
+++ b/source/blender/python/intern/bpy_imageformat_wrap.c
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup pythonintern
+ *
+ * This file exposes functionality for defining to define operators that C can call into.
+ * The generic callback functions for python operators are defines in
+ * 'rna_wm.c', some calling into functions here to do python specific
+ * functionality.
+ */
+
+#include <Python.h>
+
+#include "BLI_utildefines.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_prototypes.h"
+
+#include "bpy_intern_string.h"
+#include "bpy_imageformat_wrap.h" /* own include */
+#include "bpy_rna.h"
+
+void BPY_RNA_imageformat_wrapper(imfImageFormatType *ift, void *userdata)
+{
+ /* take care not to overwrite anything set in
+ * WM_imageformattype_append_ptr before opfunc() is called */
+ StructRNA *srna = ift->srna;
+ *ift = *((imfImageFormatType *)userdata);
+ ift->srna = srna; /* restore */
+
+ /* Use i18n context from rna_ext.srna if possible (py image formats). */
+ if (ift->rna_ext.srna) {
+ RNA_def_struct_translation_context(ift->srna,
+ RNA_struct_translation_context(ift->rna_ext.srna));
+ }
+}
diff --git a/source/blender/python/intern/bpy_imageformat_wrap.h b/source/blender/python/intern/bpy_imageformat_wrap.h
new file mode 100644
index 00000000000..61ccc6613ba
--- /dev/null
+++ b/source/blender/python/intern/bpy_imageformat_wrap.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup pythonintern
+ */
+
+#pragma once
+
+struct imfImageFormatType;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* exposed to rna/wm api */
+/**
+ * Generic function used by all Python defined image formats
+ * it's passed as an argument to #WM_imageformattype_append_ptr in for image format registration.
+ */
+void BPY_RNA_imageformat_wrapper(struct imfImageFormatType *ift, void *userdata);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 60cded3b869..208704caf49 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -1792,6 +1792,28 @@ bool WM_xr_actionmap_binding_remove(XrActionMapItem *ami, XrActionMapBinding *am
XrActionMapBinding *WM_xr_actionmap_binding_find(XrActionMapItem *ami, const char *name);
#endif /* WITH_XR_OPENXR */
+/**
+ * Image Formats
+ */
+
+imfImageFormatType *WM_imageformattype_find(const char *idname, bool quiet);
+void wm_imageformattype_iter(struct GHashIterator *ghi);
+static imfImageFormatType *wm_imageformattype_append__begin(void);
+static void wm_imageformattype_append__end(imfImageFormatType *ift);
+void wm_imageformattype_append(void (*opfunc)(imfImageFormatType *));
+void wm_imageformattype_append_ptr(void (*opfunc)(imfImageFormatType *, void *), void *userdata);
+void wm_imageformattype_remove_ptr(imfImageFormatType *ift);
+bool wm_imageformattype_remove(const char *idname);
+void wm_imageformattype_init(void);
+static void imageformattype_ghash_free_cb(imfImageFormatType *ift);
+void wm_imageformattype_free(void);
+void wm_imageformattype_idname_visit_for_search(const struct bContext *C,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ const char *edit_text,
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/windowmanager/intern/wm_imageformat_type.c b/source/blender/windowmanager/intern/wm_imageformat_type.c
new file mode 100644
index 00000000000..5efdf67ed56
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_imageformat_type.c
@@ -0,0 +1,201 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup wm
+ *
+ * Operator Registry.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "CLG_log.h"
+
+#include "DNA_ID.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BLT_translation.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_idprop.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+#include "RNA_prototypes.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "wm.h"
+#include "wm_event_system.h"
+
+#define UNDOCUMENTED_IMAGEFORMAT_TIP N_("(undocumented image format)")
+
+/* -------------------------------------------------------------------- */
+/** \name Image Format Type Registry
+ * \{ */
+
+static GHash *global_imageformat_hash = NULL;
+// TODO: no idea what this is for
+/** Counter for operator-properties that should not be tagged with #OP_PROP_TAG_ADVANCED. */
+static int ot_prop_basic_count = -1;
+
+struct imfImageFormatType *WM_imageformattype_find(const char *idname, bool quiet)
+{
+ if (idname[0]) {
+ imfImageFormatType *ift;
+
+ /* needed to support python style names without the _OT_ syntax */
+ char idname_bl[OP_MAX_TYPENAME];
+ WM_operator_bl_idname(idname_bl, idname); // TODO: remove this or reimplement?? not sure if needed yet.
+
+ ift = BLI_ghash_lookup(global_imageformat_hash, idname_bl);
+ if (ift) {
+ return ift;
+ }
+
+ if (!quiet) {
+ CLOG_INFO(
+ WM_LOG_OPERATORS, 0, "search for unknown image format '%s', '%s'\n", idname_bl, idname);
+ }
+ }
+ else {
+ if (!quiet) {
+ CLOG_INFO(WM_LOG_OPERATORS, 0, "search for empty image format");
+ }
+ }
+
+ return NULL;
+}
+
+void wm_imageformattype_iter(GHashIterator *ghi)
+{
+ BLI_ghashIterator_init(ghi, global_imageformat_hash);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Image Format Type Append
+ * \{ */
+
+static imfImageFormatType *wm_imageformattype_append__begin(void)
+{
+ imfImageFormatType *ift = MEM_callocN(sizeof(imfImageFormatType), "imageformattype");
+
+ ift->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_ImageFormat); // TODO: wrong type?? use other function
+ /* Set the default i18n context now, so that opfunc can redefine it if needed! */
+ RNA_def_struct_translation_context(ift->srna, BLT_I18CONTEXT_IMAGEFORMAT_DEFAULT);
+ ift->translation_context = BLT_I18CONTEXT_IMAGEFORMAT_DEFAULT;
+
+ return ift;
+}
+
+static void wm_imageformattype_append__end(imfImageFormatType *ift)
+{
+ if (ift->name == NULL) {
+ CLOG_ERROR(WM_LOG_OPERATORS, "ImageFormat '%s' has no name property", ift->idname); // TODO: change error clgref
+ }
+ BLI_assert((ift->description == NULL) || (ift->description[0]));
+
+ /* XXX All ops should have a description but for now allow them not to. */
+ RNA_def_struct_ui_text(
+ ift->srna, ift->name, ift->description ? ift->description : UNDOCUMENTED_IMAGEFORMAT_TIP);
+ RNA_def_struct_identifier(&BLENDER_RNA, ift->srna, ift->idname);
+
+ BLI_ghash_insert(global_imageformat_hash, (void *)ift->idname, ift);
+}
+
+/* All ops in 1 list (for time being... needs evaluation later). */
+
+void wm_imageformattype_append(void (*opfunc)(imfImageFormatType *))
+{
+ imfImageFormatType *ift = wm_imageformattype_append__begin();
+ opfunc(ift);
+ wm_imageformattype_append__end(ift);
+}
+
+void wm_imageformattype_append_ptr(void (*opfunc)(imfImageFormatType *, void *), void *userdata)
+{
+ imfImageFormatType *ift = wm_imageformattype_append__begin();
+ opfunc(ift, userdata);
+ wm_imageformattype_append__end(ift);
+}
+
+/** \} */
+
+void wm_imageformattype_remove_ptr(imfImageFormatType *ift)
+{
+ BLI_assert(ift == WM_imageformattype_find(otiftidname, false));
+
+ RNA_struct_free(&BLENDER_RNA, ift->srna);
+
+ BLI_ghash_remove(global_imageformat_hash, ift->idname, NULL, NULL);
+
+ MEM_freeN(ift);
+}
+
+bool wm_imageformattype_remove(const char *idname)
+{
+ imfImageFormatType *ift = WM_imageformattype_find(idname, 0);
+
+ if (ift == NULL) {
+ return false;
+ }
+
+ wm_imageformattype_remove_ptr(ift);
+
+ return true;
+}
+
+void wm_imageformattype_init(void)
+{
+ /* reserve size is set based on blender default setup */
+ global_imageformat_hash = BLI_ghash_str_new_ex("wm_imageformattype_init gh", 64);
+}
+
+static void imageformattype_ghash_free_cb(imfImageFormatType *ift)
+{
+ if (ift->rna_ext.srna) {
+ /* python image format, allocs own string */
+ // TODO: delete more of these things that alloc their own strings
+ MEM_freeN((void *)ift->idname);
+ }
+
+ MEM_freeN(ift);
+}
+
+void wm_imageformattype_free(void)
+{
+ BLI_ghash_free(global_imageformat_hash, NULL, (GHashValFreeFP)imageformattype_ghash_free_cb);
+ global_imageformat_hash = NULL;
+}
+
+// TODO: probably remove
+void wm_imageformattype_idname_visit_for_search(const bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ const char *UNUSED(edit_text),
+ StringPropertySearchVisitFunc visit_fn,
+ void *visit_user_data)
+{
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, global_imageformat_hash) {
+ imfImageFormatType *ift = BLI_ghashIterator_getValue(&gh_iter);
+
+ char idname_py[OP_MAX_TYPENAME];
+ WM_operator_py_idname(idname_py, ift->idname);
+
+ StringPropertySearchVisitParams visit_params = {NULL};
+ visit_params.text = idname_py;
+ visit_params.info = ift->name;
+ visit_fn(visit_user_data, &visit_params);
+ }
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index f77aad24719..d56b14a4d4b 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -222,6 +222,8 @@ void WM_init(bContext *C, int argc, const char **argv)
wm_operatortype_init();
wm_operatortypes_register();
+ wm_imageformattype_init();
+
WM_paneltype_init(); /* Lookup table only. */
WM_menutype_init();
WM_uilisttype_init();