Browse Source

For in-engine processing allow saving openexr to a buffer.

K. S. Ernest (iFire) Lee 3 years ago
parent
commit
ce42ee790c

+ 9 - 0
core/io/image.cpp

@@ -85,6 +85,7 @@ SaveJPGFunc Image::save_jpg_func = nullptr;
 SaveEXRFunc Image::save_exr_func = nullptr;
 
 SavePNGBufferFunc Image::save_png_buffer_func = nullptr;
+SaveEXRBufferFunc Image::save_exr_buffer_func = nullptr;
 SaveJPGBufferFunc Image::save_jpg_buffer_func = nullptr;
 
 SaveWebPFunc Image::save_webp_func = nullptr;
@@ -2323,6 +2324,13 @@ Error Image::save_exr(const String &p_path, bool p_grayscale) const {
 	return save_exr_func(p_path, Ref<Image>((Image *)this), p_grayscale);
 }
 
+Vector<uint8_t> Image::save_exr_to_buffer() const {
+	if (save_exr_buffer_func == nullptr) {
+		return Vector<uint8_t>();
+	}
+	return save_exr_buffer_func(Ref<Image>((Image *)this), false);
+}
+
 Error Image::save_webp(const String &p_path, const bool p_lossy, const float p_quality) const {
 	if (save_webp_func == nullptr) {
 		return ERR_UNAVAILABLE;
@@ -3180,6 +3188,7 @@ void Image::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("save_jpg", "path", "quality"), &Image::save_jpg, DEFVAL(0.75));
 	ClassDB::bind_method(D_METHOD("save_jpg_to_buffer", "quality"), &Image::save_jpg_to_buffer, DEFVAL(0.75));
 	ClassDB::bind_method(D_METHOD("save_exr", "path", "grayscale"), &Image::save_exr, DEFVAL(false));
+	ClassDB::bind_method(D_METHOD("save_exr_to_buffer", "grayscale"), &Image::save_exr_to_buffer, DEFVAL(false));
 	ClassDB::bind_method(D_METHOD("save_webp", "path", "lossy", "quality"), &Image::save_webp, DEFVAL(false), DEFVAL(0.75f));
 	ClassDB::bind_method(D_METHOD("save_webp_to_buffer", "lossy", "quality"), &Image::save_webp_to_buffer, DEFVAL(false), DEFVAL(0.75f));
 

+ 3 - 0
core/io/image.h

@@ -52,6 +52,7 @@ typedef Error (*SaveWebPFunc)(const String &p_path, const Ref<Image> &p_img, con
 typedef Vector<uint8_t> (*SaveWebPBufferFunc)(const Ref<Image> &p_img, const bool p_lossy, const float p_quality);
 
 typedef Error (*SaveEXRFunc)(const String &p_path, const Ref<Image> &p_img, bool p_grayscale);
+typedef Vector<uint8_t> (*SaveEXRBufferFunc)(const Ref<Image> &p_img, bool p_grayscale);
 
 class Image : public Resource {
 	GDCLASS(Image, Resource);
@@ -61,6 +62,7 @@ public:
 	static SaveJPGFunc save_jpg_func;
 	static SaveEXRFunc save_exr_func;
 	static SavePNGBufferFunc save_png_buffer_func;
+	static SaveEXRBufferFunc save_exr_buffer_func;
 	static SaveJPGBufferFunc save_jpg_buffer_func;
 	static SaveWebPFunc save_webp_func;
 	static SaveWebPBufferFunc save_webp_buffer_func;
@@ -292,6 +294,7 @@ public:
 	Error save_jpg(const String &p_path, float p_quality = 0.75) const;
 	Vector<uint8_t> save_png_to_buffer() const;
 	Vector<uint8_t> save_jpg_to_buffer(float p_quality = 0.75) const;
+	Vector<uint8_t> save_exr_to_buffer() const;
 	Error save_exr(const String &p_path, bool p_grayscale) const;
 	Error save_webp(const String &p_path, const bool p_lossy = false, const float p_quality = 0.75f) const;
 	Vector<uint8_t> save_webp_to_buffer(const bool p_lossy = false, const float p_quality = 0.75f) const;

+ 22 - 11
modules/tinyexr/image_saver_tinyexr.cpp

@@ -141,13 +141,14 @@ static int get_channel_count(Image::Format p_format) {
 	}
 }
 
-Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale) {
+Vector<uint8_t> save_exr_buffer(const Ref<Image> &p_img, bool p_grayscale) {
 	Image::Format format = p_img->get_format();
 
 	if (!is_supported_format(format)) {
 		// Format not supported
 		print_error("Image format not supported for saving as EXR. Consider saving as PNG.");
-		return ERR_UNAVAILABLE;
+
+		return Vector<uint8_t>();
 	}
 
 	EXRHeader header;
@@ -175,15 +176,15 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale)
 	};
 
 	int channel_count = get_channel_count(format);
-	ERR_FAIL_COND_V(channel_count < 0, ERR_UNAVAILABLE);
-	ERR_FAIL_COND_V(p_grayscale && channel_count != 1, ERR_INVALID_PARAMETER);
+	ERR_FAIL_COND_V(channel_count < 0, Vector<uint8_t>());
+	ERR_FAIL_COND_V(p_grayscale && channel_count != 1, Vector<uint8_t>());
 
 	int target_pixel_type = get_target_pixel_type(format);
-	ERR_FAIL_COND_V(target_pixel_type < 0, ERR_UNAVAILABLE);
+	ERR_FAIL_COND_V(target_pixel_type < 0, Vector<uint8_t>());
 	int target_pixel_type_size = get_pixel_type_size(target_pixel_type);
-	ERR_FAIL_COND_V(target_pixel_type_size < 0, ERR_UNAVAILABLE);
+	ERR_FAIL_COND_V(target_pixel_type_size < 0, Vector<uint8_t>());
 	SrcPixelType src_pixel_type = get_source_pixel_type(format);
-	ERR_FAIL_COND_V(src_pixel_type == SRC_UNSUPPORTED, ERR_UNAVAILABLE);
+	ERR_FAIL_COND_V(src_pixel_type == SRC_UNSUPPORTED, Vector<uint8_t>());
 	const int pixel_count = p_img->get_width() * p_img->get_height();
 
 	const int *channel_mapping = channel_mappings[channel_count - 1];
@@ -270,15 +271,25 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale)
 	const char *err = nullptr;
 
 	size_t bytes = SaveEXRImageToMemory(&image, &header, &mem, &err);
+	if (err && *err != OK) {
+		return Vector<uint8_t>();
+	}
+	Vector<uint8_t> buffer;
+	buffer.resize(bytes);
+	memcpy(buffer.ptrw(), mem, bytes);
+	free(mem);
+	return buffer;
+}
 
-	if (bytes == 0) {
-		print_error(String("Saving EXR failed. Error: {0}").format(varray(err)));
+Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale) {
+	const Vector<uint8_t> buffer = save_exr_buffer(p_img, p_grayscale);
+	if (buffer.size() == 0) {
+		print_error(String("Saving EXR failed."));
 		return ERR_FILE_CANT_WRITE;
 	} else {
 		Ref<FileAccess> ref = FileAccess::open(p_path, FileAccess::WRITE);
 		ERR_FAIL_COND_V(ref.is_null(), ERR_FILE_CANT_WRITE);
-		ref->store_buffer(mem, bytes);
-		free(mem);
+		ref->store_buffer(buffer.ptr(), buffer.size());
 	}
 
 	return OK;

+ 1 - 0
modules/tinyexr/image_saver_tinyexr.h

@@ -34,5 +34,6 @@
 #include "core/os/os.h"
 
 Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale);
+Vector<uint8_t> save_exr_buffer(const Ref<Image> &p_img, bool p_grayscale);
 
 #endif // IMAGE_SAVER_TINYEXR_H

+ 1 - 0
modules/tinyexr/register_types.cpp

@@ -44,6 +44,7 @@ void initialize_tinyexr_module(ModuleInitializationLevel p_level) {
 	ImageLoader::add_image_format_loader(image_loader_tinyexr);
 
 	Image::save_exr_func = save_exr;
+	Image::save_exr_buffer_func = save_exr_buffer;
 }
 
 void uninitialize_tinyexr_module(ModuleInitializationLevel p_level) {