Skip to content

Commit efa1056

Browse files
committed
Merge pull request godotengine#101255 from metamuffin/load-exr-image
Add `Image.load_exr_from_buffer`
2 parents e873576 + 6145b0c commit efa1056

File tree

8 files changed

+51
-3
lines changed

8 files changed

+51
-3
lines changed

core/io/image.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3925,6 +3925,7 @@ void Image::_bind_methods() {
39253925
ClassDB::bind_method(D_METHOD("load_bmp_from_buffer", "buffer"), &Image::load_bmp_from_buffer);
39263926
ClassDB::bind_method(D_METHOD("load_ktx_from_buffer", "buffer"), &Image::load_ktx_from_buffer);
39273927
ClassDB::bind_method(D_METHOD("load_dds_from_buffer", "buffer"), &Image::load_dds_from_buffer);
3928+
ClassDB::bind_method(D_METHOD("load_exr_from_buffer", "buffer"), &Image::load_exr_from_buffer);
39283929

39293930
ClassDB::bind_method(D_METHOD("load_svg_from_buffer", "buffer", "scale"), &Image::load_svg_from_buffer, DEFVAL(1.0));
39303931
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) {
44244425
return _load_from_buffer(p_array, _jpg_mem_loader_func);
44254426
}
44264427

4428+
Error Image::load_exr_from_buffer(const Vector<uint8_t> &p_array) {
4429+
ERR_FAIL_NULL_V_MSG(
4430+
_exr_mem_loader_func,
4431+
ERR_UNAVAILABLE,
4432+
"The TinyEXR module isn't enabled. Recompile the Godot editor or export template binary with the `tinyexr_export_templates=yes` SCons option.");
4433+
return _load_from_buffer(p_array, _exr_mem_loader_func);
4434+
}
4435+
44274436
Error Image::load_webp_from_buffer(const Vector<uint8_t> &p_array) {
44284437
return _load_from_buffer(p_array, _webp_mem_loader_func);
44294438
}

core/io/image.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ class Image : public Resource {
219219
static inline ScalableImageMemLoadFunc _svg_scalable_mem_loader_func = nullptr;
220220
static inline ImageMemLoadFunc _ktx_mem_loader_func = nullptr;
221221
static inline ImageMemLoadFunc _dds_mem_loader_func = nullptr;
222+
static inline ImageMemLoadFunc _exr_mem_loader_func = nullptr;
222223

223224
// External VRAM compression function pointers.
224225

@@ -429,6 +430,7 @@ class Image : public Resource {
429430
Error load_bmp_from_buffer(const Vector<uint8_t> &p_array);
430431
Error load_ktx_from_buffer(const Vector<uint8_t> &p_array);
431432
Error load_dds_from_buffer(const Vector<uint8_t> &p_array);
433+
Error load_exr_from_buffer(const Vector<uint8_t> &p_array);
432434

433435
Error load_svg_from_buffer(const Vector<uint8_t> &p_array, float scale = 1.0);
434436
Error load_svg_from_string(const String &p_svg_str, float scale = 1.0);

doc/classes/Image.xml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,13 @@
356356
[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.
357357
</description>
358358
</method>
359+
<method name="load_exr_from_buffer">
360+
<return type="int" enum="Error" />
361+
<param index="0" name="buffer" type="PackedByteArray" />
362+
<description>
363+
Loads an image from the binary contents of an OpenEXR file.
364+
</description>
365+
</method>
359366
<method name="load_from_file" qualifiers="static">
360367
<return type="Image" />
361368
<param index="0" name="path" type="String" />
@@ -489,15 +496,13 @@
489496
<param index="1" name="grayscale" type="bool" default="false" />
490497
<description>
491498
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.
492-
[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.
493499
</description>
494500
</method>
495501
<method name="save_exr_to_buffer" qualifiers="const">
496502
<return type="PackedByteArray" />
497503
<param index="0" name="grayscale" type="bool" default="false" />
498504
<description>
499505
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.
500-
[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.
501506
</description>
502507
</method>
503508
<method name="save_jpg" qualifiers="const">

modules/tinyexr/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
def can_build(env, platform):
2-
return env.editor_build
2+
return True
33

44

55
def configure(env):

modules/tinyexr/image_loader_tinyexr.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434

3535
#include "thirdparty/tinyexr/tinyexr.h"
3636

37+
#include "core/io/file_access_memory.h"
38+
3739
Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
3840
Vector<uint8_t> src_image;
3941
uint64_t src_image_len = f->get_length();
@@ -291,5 +293,19 @@ void ImageLoaderTinyEXR::get_recognized_extensions(List<String> *p_extensions) c
291293
p_extensions->push_back("exr");
292294
}
293295

296+
static Ref<Image> _tinyexr_mem_loader_func(const uint8_t *p_exr, int p_size) {
297+
Ref<FileAccessMemory> memfile;
298+
memfile.instantiate();
299+
Error open_memfile_error = memfile->open_custom(p_exr, p_size);
300+
ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for EXR image buffer.");
301+
302+
Ref<Image> img;
303+
img.instantiate();
304+
Error load_error = ImageLoaderTinyEXR().load_image(img, memfile, false, 1.0f);
305+
ERR_FAIL_COND_V_MSG(load_error, Ref<Image>(), "Failed to load EXR image.");
306+
return img;
307+
}
308+
294309
ImageLoaderTinyEXR::ImageLoaderTinyEXR() {
310+
Image::_exr_mem_loader_func = _tinyexr_mem_loader_func;
295311
}

platform/linuxbsd/wayland/display_server_wayland.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,8 @@ Ref<Image> DisplayServerWayland::clipboard_get_image() const {
546546
err = image->load_tga_from_buffer(wayland_thread.selection_get_mime("image/x-targa"));
547547
} else if (wayland_thread.selection_has_mime("image/ktx")) {
548548
err = image->load_ktx_from_buffer(wayland_thread.selection_get_mime("image/ktx"));
549+
} else if (wayland_thread.selection_has_mime("image/x-exr")) {
550+
err = image->load_exr_from_buffer(wayland_thread.selection_get_mime("image/x-exr"));
549551
}
550552

551553
ERR_FAIL_COND_V(err != OK, Ref<Image>());

tests/core/io/test_image.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,20 @@ TEST_CASE("[Image] Saving and loading") {
122122
"The BMP image should load successfully.");
123123
#endif // MODULE_BMP_ENABLED
124124

125+
#ifdef MODULE_EXR_ENABLED
126+
// Load EXR
127+
Ref<Image> image_exr;
128+
image_exr.instantiate();
129+
Ref<FileAccess> f_exr = FileAccess::open(TestUtils::get_data_path("images/icon.exr"), FileAccess::READ, &err);
130+
REQUIRE(f_exr.is_valid());
131+
PackedByteArray data_exr;
132+
data_exr.resize(f_exr->get_length() + 1);
133+
f_exr->get_buffer(data_exr.ptrw(), f_exr->get_length());
134+
CHECK_MESSAGE(
135+
image_exr->load_exr_from_buffer(data_exr) == OK,
136+
"The EXR image should load successfully.");
137+
#endif // MODULE_EXR_ENABLED
138+
125139
#ifdef MODULE_JPG_ENABLED
126140
// Load JPG
127141
Ref<Image> image_jpg = memnew(Image());

tests/data/images/icon.exr

1 MB
Binary file not shown.

0 commit comments

Comments
 (0)