1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-24 15:26:15 +00:00

Add Image.load_exr_from_buffer and enable tinyexr by default

This commit is contained in:
metamuffin
2025-01-08 00:40:08 +01:00
parent b79fe2e020
commit 6145b0ca29
8 changed files with 52 additions and 4 deletions

View File

@@ -3925,6 +3925,7 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_bmp_from_buffer", "buffer"), &Image::load_bmp_from_buffer); ClassDB::bind_method(D_METHOD("load_bmp_from_buffer", "buffer"), &Image::load_bmp_from_buffer);
ClassDB::bind_method(D_METHOD("load_ktx_from_buffer", "buffer"), &Image::load_ktx_from_buffer); ClassDB::bind_method(D_METHOD("load_ktx_from_buffer", "buffer"), &Image::load_ktx_from_buffer);
ClassDB::bind_method(D_METHOD("load_dds_from_buffer", "buffer"), &Image::load_dds_from_buffer); ClassDB::bind_method(D_METHOD("load_dds_from_buffer", "buffer"), &Image::load_dds_from_buffer);
ClassDB::bind_method(D_METHOD("load_exr_from_buffer", "buffer"), &Image::load_exr_from_buffer);
ClassDB::bind_method(D_METHOD("load_svg_from_buffer", "buffer", "scale"), &Image::load_svg_from_buffer, DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("load_svg_from_buffer", "buffer", "scale"), &Image::load_svg_from_buffer, DEFVAL(1.0));
ClassDB::bind_method(D_METHOD("load_svg_from_string", "svg_str", "scale"), &Image::load_svg_from_string, DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("load_svg_from_string", "svg_str", "scale"), &Image::load_svg_from_string, DEFVAL(1.0));
@@ -4424,6 +4425,14 @@ Error Image::load_jpg_from_buffer(const Vector<uint8_t> &p_array) {
return _load_from_buffer(p_array, _jpg_mem_loader_func); return _load_from_buffer(p_array, _jpg_mem_loader_func);
} }
Error Image::load_exr_from_buffer(const Vector<uint8_t> &p_array) {
ERR_FAIL_NULL_V_MSG(
_exr_mem_loader_func,
ERR_UNAVAILABLE,
"The TinyEXR module isn't enabled. Recompile the Godot editor or export template binary with the `tinyexr_export_templates=yes` SCons option.");
return _load_from_buffer(p_array, _exr_mem_loader_func);
}
Error Image::load_webp_from_buffer(const Vector<uint8_t> &p_array) { Error Image::load_webp_from_buffer(const Vector<uint8_t> &p_array) {
return _load_from_buffer(p_array, _webp_mem_loader_func); return _load_from_buffer(p_array, _webp_mem_loader_func);
} }

View File

@@ -219,6 +219,7 @@ public:
static inline ScalableImageMemLoadFunc _svg_scalable_mem_loader_func = nullptr; static inline ScalableImageMemLoadFunc _svg_scalable_mem_loader_func = nullptr;
static inline ImageMemLoadFunc _ktx_mem_loader_func = nullptr; static inline ImageMemLoadFunc _ktx_mem_loader_func = nullptr;
static inline ImageMemLoadFunc _dds_mem_loader_func = nullptr; static inline ImageMemLoadFunc _dds_mem_loader_func = nullptr;
static inline ImageMemLoadFunc _exr_mem_loader_func = nullptr;
// External VRAM compression function pointers. // External VRAM compression function pointers.
@@ -429,6 +430,7 @@ public:
Error load_bmp_from_buffer(const Vector<uint8_t> &p_array); Error load_bmp_from_buffer(const Vector<uint8_t> &p_array);
Error load_ktx_from_buffer(const Vector<uint8_t> &p_array); Error load_ktx_from_buffer(const Vector<uint8_t> &p_array);
Error load_dds_from_buffer(const Vector<uint8_t> &p_array); Error load_dds_from_buffer(const Vector<uint8_t> &p_array);
Error load_exr_from_buffer(const Vector<uint8_t> &p_array);
Error load_svg_from_buffer(const Vector<uint8_t> &p_array, float scale = 1.0); Error load_svg_from_buffer(const Vector<uint8_t> &p_array, float scale = 1.0);
Error load_svg_from_string(const String &p_svg_str, float scale = 1.0); Error load_svg_from_string(const String &p_svg_str, float scale = 1.0);

View File

@@ -356,6 +356,13 @@
[b]Note:[/b] This method is only available in engine builds with the DDS module enabled. By default, the DDS module is enabled, but it can be disabled at build-time using the [code]module_dds_enabled=no[/code] SCons option. [b]Note:[/b] This method is only available in engine builds with the DDS module enabled. By default, the DDS module is enabled, but it can be disabled at build-time using the [code]module_dds_enabled=no[/code] SCons option.
</description> </description>
</method> </method>
<method name="load_exr_from_buffer">
<return type="int" enum="Error" />
<param index="0" name="buffer" type="PackedByteArray" />
<description>
Loads an image from the binary contents of an OpenEXR file.
</description>
</method>
<method name="load_from_file" qualifiers="static"> <method name="load_from_file" qualifiers="static">
<return type="Image" /> <return type="Image" />
<param index="0" name="path" type="String" /> <param index="0" name="path" type="String" />
@@ -489,7 +496,6 @@
<param index="1" name="grayscale" type="bool" default="false" /> <param index="1" name="grayscale" type="bool" default="false" />
<description> <description>
Saves the image as an EXR file to [param path]. If [param grayscale] is [code]true[/code] and the image has only one channel, it will be saved explicitly as monochrome rather than one red channel. This function will return [constant ERR_UNAVAILABLE] if Godot was compiled without the TinyEXR module. Saves the image as an EXR file to [param path]. If [param grayscale] is [code]true[/code] and the image has only one channel, it will be saved explicitly as monochrome rather than one red channel. This function will return [constant ERR_UNAVAILABLE] if Godot was compiled without the TinyEXR module.
[b]Note:[/b] The TinyEXR module is disabled in non-editor builds, which means [method save_exr] will return [constant ERR_UNAVAILABLE] when it is called from an exported project.
</description> </description>
</method> </method>
<method name="save_exr_to_buffer" qualifiers="const"> <method name="save_exr_to_buffer" qualifiers="const">
@@ -497,7 +503,6 @@
<param index="0" name="grayscale" type="bool" default="false" /> <param index="0" name="grayscale" type="bool" default="false" />
<description> <description>
Saves the image as an EXR file to a byte array. If [param grayscale] is [code]true[/code] and the image has only one channel, it will be saved explicitly as monochrome rather than one red channel. This function will return an empty byte array if Godot was compiled without the TinyEXR module. Saves the image as an EXR file to a byte array. If [param grayscale] is [code]true[/code] and the image has only one channel, it will be saved explicitly as monochrome rather than one red channel. This function will return an empty byte array if Godot was compiled without the TinyEXR module.
[b]Note:[/b] The TinyEXR module is disabled in non-editor builds, which means [method save_exr_to_buffer] will return an empty byte array when it is called from an exported project.
</description> </description>
</method> </method>
<method name="save_jpg" qualifiers="const"> <method name="save_jpg" qualifiers="const">

View File

@@ -1,5 +1,5 @@
def can_build(env, platform): def can_build(env, platform):
return env.editor_build return True
def configure(env): def configure(env):

View File

@@ -34,6 +34,8 @@
#include "thirdparty/tinyexr/tinyexr.h" #include "thirdparty/tinyexr/tinyexr.h"
#include "core/io/file_access_memory.h"
Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) { Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
Vector<uint8_t> src_image; Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length(); uint64_t src_image_len = f->get_length();
@@ -291,5 +293,19 @@ void ImageLoaderTinyEXR::get_recognized_extensions(List<String> *p_extensions) c
p_extensions->push_back("exr"); p_extensions->push_back("exr");
} }
ImageLoaderTinyEXR::ImageLoaderTinyEXR() { static Ref<Image> _tinyexr_mem_loader_func(const uint8_t *p_exr, int p_size) {
Ref<FileAccessMemory> memfile;
memfile.instantiate();
Error open_memfile_error = memfile->open_custom(p_exr, p_size);
ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for EXR image buffer.");
Ref<Image> img;
img.instantiate();
Error load_error = ImageLoaderTinyEXR().load_image(img, memfile, false, 1.0f);
ERR_FAIL_COND_V_MSG(load_error, Ref<Image>(), "Failed to load EXR image.");
return img;
}
ImageLoaderTinyEXR::ImageLoaderTinyEXR() {
Image::_exr_mem_loader_func = _tinyexr_mem_loader_func;
} }

View File

@@ -546,6 +546,8 @@ Ref<Image> DisplayServerWayland::clipboard_get_image() const {
err = image->load_tga_from_buffer(wayland_thread.selection_get_mime("image/x-targa")); err = image->load_tga_from_buffer(wayland_thread.selection_get_mime("image/x-targa"));
} else if (wayland_thread.selection_has_mime("image/ktx")) { } else if (wayland_thread.selection_has_mime("image/ktx")) {
err = image->load_ktx_from_buffer(wayland_thread.selection_get_mime("image/ktx")); err = image->load_ktx_from_buffer(wayland_thread.selection_get_mime("image/ktx"));
} else if (wayland_thread.selection_has_mime("image/x-exr")) {
err = image->load_exr_from_buffer(wayland_thread.selection_get_mime("image/x-exr"));
} }
ERR_FAIL_COND_V(err != OK, Ref<Image>()); ERR_FAIL_COND_V(err != OK, Ref<Image>());

View File

@@ -122,6 +122,20 @@ TEST_CASE("[Image] Saving and loading") {
"The BMP image should load successfully."); "The BMP image should load successfully.");
#endif // MODULE_BMP_ENABLED #endif // MODULE_BMP_ENABLED
#ifdef MODULE_EXR_ENABLED
// Load EXR
Ref<Image> image_exr;
image_exr.instantiate();
Ref<FileAccess> f_exr = FileAccess::open(TestUtils::get_data_path("images/icon.exr"), FileAccess::READ, &err);
REQUIRE(f_exr.is_valid());
PackedByteArray data_exr;
data_exr.resize(f_exr->get_length() + 1);
f_exr->get_buffer(data_exr.ptrw(), f_exr->get_length());
CHECK_MESSAGE(
image_exr->load_exr_from_buffer(data_exr) == OK,
"The EXR image should load successfully.");
#endif // MODULE_EXR_ENABLED
#ifdef MODULE_JPG_ENABLED #ifdef MODULE_JPG_ENABLED
// Load JPG // Load JPG
Ref<Image> image_jpg = memnew(Image()); Ref<Image> image_jpg = memnew(Image());

BIN
tests/data/images/icon.exr Normal file

Binary file not shown.