Merge pull request #78248 from felaugmar/load-svg-adjustable-scale
Added `Image::load_svg_from_(buffer|string)`
This commit is contained in:
commit
6960a1d0e8
15 changed files with 96 additions and 44 deletions
|
@ -3004,6 +3004,7 @@ ImageMemLoadFunc Image::_jpg_mem_loader_func = nullptr;
|
|||
ImageMemLoadFunc Image::_webp_mem_loader_func = nullptr;
|
||||
ImageMemLoadFunc Image::_tga_mem_loader_func = nullptr;
|
||||
ImageMemLoadFunc Image::_bmp_mem_loader_func = nullptr;
|
||||
ScalableImageMemLoadFunc Image::_svg_scalable_mem_loader_func = nullptr;
|
||||
|
||||
void (*Image::_image_compress_bc_func)(Image *, Image::UsedChannels) = nullptr;
|
||||
void (*Image::_image_compress_bptc_func)(Image *, Image::UsedChannels) = nullptr;
|
||||
|
@ -3476,6 +3477,9 @@ void Image::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("load_tga_from_buffer", "buffer"), &Image::load_tga_from_buffer);
|
||||
ClassDB::bind_method(D_METHOD("load_bmp_from_buffer", "buffer"), &Image::load_bmp_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_string", "svg_str", "scale"), &Image::load_svg_from_string, DEFVAL(1.0));
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "_set_data", "_get_data");
|
||||
|
||||
BIND_CONSTANT(MAX_WIDTH);
|
||||
|
@ -3825,6 +3829,28 @@ Error Image::load_bmp_from_buffer(const Vector<uint8_t> &p_array) {
|
|||
return _load_from_buffer(p_array, _bmp_mem_loader_func);
|
||||
}
|
||||
|
||||
Error Image::load_svg_from_buffer(const Vector<uint8_t> &p_array, float scale) {
|
||||
ERR_FAIL_NULL_V_MSG(
|
||||
_svg_scalable_mem_loader_func,
|
||||
ERR_UNAVAILABLE,
|
||||
"The SVG module isn't enabled. Recompile the Godot editor or export template binary with the `module_svg_enabled=yes` SCons option.");
|
||||
|
||||
int buffer_size = p_array.size();
|
||||
|
||||
ERR_FAIL_COND_V(buffer_size == 0, ERR_INVALID_PARAMETER);
|
||||
|
||||
Ref<Image> image = _svg_scalable_mem_loader_func(p_array.ptr(), buffer_size, scale);
|
||||
ERR_FAIL_COND_V(!image.is_valid(), ERR_PARSE_ERROR);
|
||||
|
||||
copy_internals_from(image);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error Image::load_svg_from_string(const String &p_svg_str, float scale) {
|
||||
return load_svg_from_buffer(p_svg_str.to_utf8_buffer(), scale);
|
||||
}
|
||||
|
||||
void Image::convert_rg_to_ra_rgba8() {
|
||||
ERR_FAIL_COND(format != FORMAT_RGBA8);
|
||||
ERR_FAIL_COND(!data.size());
|
||||
|
|
|
@ -48,6 +48,7 @@ typedef Vector<uint8_t> (*SavePNGBufferFunc)(const Ref<Image> &p_img);
|
|||
typedef Error (*SaveJPGFunc)(const String &p_path, const Ref<Image> &p_img, float p_quality);
|
||||
typedef Vector<uint8_t> (*SaveJPGBufferFunc)(const Ref<Image> &p_img, float p_quality);
|
||||
typedef Ref<Image> (*ImageMemLoadFunc)(const uint8_t *p_png, int p_size);
|
||||
typedef Ref<Image> (*ScalableImageMemLoadFunc)(const uint8_t *p_data, int p_size, float p_scale);
|
||||
typedef Error (*SaveWebPFunc)(const String &p_path, const Ref<Image> &p_img, const bool p_lossy, const float p_quality);
|
||||
typedef Vector<uint8_t> (*SaveWebPBufferFunc)(const Ref<Image> &p_img, const bool p_lossy, const float p_quality);
|
||||
|
||||
|
@ -148,6 +149,7 @@ public:
|
|||
static ImageMemLoadFunc _webp_mem_loader_func;
|
||||
static ImageMemLoadFunc _tga_mem_loader_func;
|
||||
static ImageMemLoadFunc _bmp_mem_loader_func;
|
||||
static ScalableImageMemLoadFunc _svg_scalable_mem_loader_func;
|
||||
|
||||
static void (*_image_compress_bc_func)(Image *, UsedChannels p_channels);
|
||||
static void (*_image_compress_bptc_func)(Image *, UsedChannels p_channels);
|
||||
|
@ -401,6 +403,9 @@ public:
|
|||
Error load_tga_from_buffer(const Vector<uint8_t> &p_array);
|
||||
Error load_bmp_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_string(const String &p_svg_str, float scale = 1.0);
|
||||
|
||||
void convert_rg_to_ra_rgba8();
|
||||
void convert_ra_rgba8_to_rg();
|
||||
void convert_rgba8_to_bgra8();
|
||||
|
|
|
@ -333,6 +333,25 @@
|
|||
Loads an image from the binary contents of a PNG file.
|
||||
</description>
|
||||
</method>
|
||||
<method name="load_svg_from_buffer">
|
||||
<return type="int" enum="Error" />
|
||||
<param index="0" name="buffer" type="PackedByteArray" />
|
||||
<param index="1" name="scale" type="float" default="1.0" />
|
||||
<description>
|
||||
Loads an image from the UTF-8 binary contents of an [b]uncompressed[/b] SVG file ([b].svg[/b]).
|
||||
[b]Note:[/b] Beware when using compressed SVG files (like [b].svgz[/b]), they need to be [code]decompressed[/code] before loading.
|
||||
[b]Note:[/b] This method is only available in engine builds with the SVG module enabled. By default, the SVG module is enabled, but it can be disabled at build-time using the [code]module_svg_enabled=no[/code] SCons option.
|
||||
</description>
|
||||
</method>
|
||||
<method name="load_svg_from_string">
|
||||
<return type="int" enum="Error" />
|
||||
<param index="0" name="svg_str" type="String" />
|
||||
<param index="1" name="scale" type="float" default="1.0" />
|
||||
<description>
|
||||
Loads an image from the string contents of a SVG file ([b].svg[/b]).
|
||||
[b]Note:[/b] This method is only available in engine builds with the SVG module enabled. By default, the SVG module is enabled, but it can be disabled at build-time using the [code]module_svg_enabled=no[/code] SCons option.
|
||||
</description>
|
||||
</method>
|
||||
<method name="load_tga_from_buffer">
|
||||
<return type="int" enum="Error" />
|
||||
<param index="0" name="buffer" type="PackedByteArray" />
|
||||
|
|
|
@ -244,8 +244,7 @@ static Ref<ImageTexture> editor_generate_icon(int p_index, float p_scale, float
|
|||
// Generating upsampled icons is slower, and the benefit is hardly visible
|
||||
// with integer editor scales.
|
||||
const bool upsample = !Math::is_equal_approx(Math::round(p_scale), p_scale);
|
||||
ImageLoaderSVG img_loader;
|
||||
Error err = img_loader.create_image_from_string(img, editor_icons_sources[p_index], p_scale, upsample, p_convert_colors);
|
||||
Error err = ImageLoaderSVG::create_image_from_string(img, editor_icons_sources[p_index], p_scale, upsample, p_convert_colors);
|
||||
ERR_FAIL_COND_V_MSG(err != OK, Ref<ImageTexture>(), "Failed generating icon, unsupported or invalid SVG data in editor theme.");
|
||||
if (p_saturation != 1.0) {
|
||||
img->adjust_bcs(1.0, 1.0, p_saturation);
|
||||
|
|
|
@ -43,11 +43,6 @@
|
|||
#include "editor/project_settings_editor.h"
|
||||
#include "scene/gui/menu_button.h"
|
||||
|
||||
#include "modules/modules_enabled.gen.h" // For svg.
|
||||
#ifdef MODULE_SVG_ENABLED
|
||||
#include "modules/svg/image_loader_svg.h"
|
||||
#endif
|
||||
|
||||
static inline void setup_http_request(HTTPRequest *request) {
|
||||
request->set_use_threads(EDITOR_DEF("asset_library/use_threads", true));
|
||||
|
||||
|
@ -775,18 +770,9 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB
|
|||
image->copy_internals_from(Image::_webp_mem_loader_func(r, len));
|
||||
} else if ((memcmp(&r[0], &bmp_signature[0], 2) == 0) && Image::_bmp_mem_loader_func) {
|
||||
image->copy_internals_from(Image::_bmp_mem_loader_func(r, len));
|
||||
} else if (Image::_svg_scalable_mem_loader_func) {
|
||||
image->copy_internals_from(Image::_svg_scalable_mem_loader_func(r, len, 1.0));
|
||||
}
|
||||
#ifdef MODULE_SVG_ENABLED
|
||||
else {
|
||||
ImageLoaderSVG svg_loader;
|
||||
Ref<Image> img = Ref<Image>(memnew(Image));
|
||||
Error err = svg_loader.create_image_from_utf8_buffer(img, image_data, 1.0, false);
|
||||
|
||||
if (err == OK) {
|
||||
image->copy_internals_from(img);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!image->is_empty()) {
|
||||
|
|
|
@ -67,12 +67,22 @@ void ImageLoaderSVG::_replace_color_property(const HashMap<Color, Color> &p_colo
|
|||
}
|
||||
}
|
||||
|
||||
Error ImageLoaderSVG::create_image_from_utf8_buffer(Ref<Image> p_image, const PackedByteArray &p_buffer, float p_scale, bool p_upsample) {
|
||||
Ref<Image> ImageLoaderSVG::load_mem_svg(const uint8_t *p_svg, int p_size, float p_scale) {
|
||||
Ref<Image> img;
|
||||
img.instantiate();
|
||||
|
||||
Error err = create_image_from_utf8_buffer(img, p_svg, p_size, p_scale, false);
|
||||
ERR_FAIL_COND_V(err, Ref<Image>());
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
Error ImageLoaderSVG::create_image_from_utf8_buffer(Ref<Image> p_image, const uint8_t *p_buffer, int p_buffer_size, float p_scale, bool p_upsample) {
|
||||
ERR_FAIL_COND_V_MSG(Math::is_zero_approx(p_scale), ERR_INVALID_PARAMETER, "ImageLoaderSVG: Can't load SVG with a scale of 0.");
|
||||
|
||||
std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen();
|
||||
|
||||
tvg::Result result = picture->load((const char *)p_buffer.ptr(), p_buffer.size(), "svg", true);
|
||||
tvg::Result result = picture->load((const char *)p_buffer, p_buffer_size, "svg", true);
|
||||
if (result != tvg::Result::Success) {
|
||||
return ERR_INVALID_DATA;
|
||||
}
|
||||
|
@ -142,6 +152,10 @@ Error ImageLoaderSVG::create_image_from_utf8_buffer(Ref<Image> p_image, const Pa
|
|||
return OK;
|
||||
}
|
||||
|
||||
Error ImageLoaderSVG::create_image_from_utf8_buffer(Ref<Image> p_image, const PackedByteArray &p_buffer, float p_scale, bool p_upsample) {
|
||||
return create_image_from_utf8_buffer(p_image, p_buffer.ptr(), p_buffer.size(), p_scale, p_upsample);
|
||||
}
|
||||
|
||||
Error ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map) {
|
||||
if (p_color_map.size()) {
|
||||
_replace_color_property(p_color_map, "stop-color=\"", p_string);
|
||||
|
@ -179,3 +193,7 @@ Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileacces
|
|||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ImageLoaderSVG::ImageLoaderSVG() {
|
||||
Image::_svg_scalable_mem_loader_func = load_mem_svg;
|
||||
}
|
||||
|
|
|
@ -36,16 +36,22 @@
|
|||
class ImageLoaderSVG : public ImageFormatLoader {
|
||||
static HashMap<Color, Color> forced_color_map;
|
||||
|
||||
void _replace_color_property(const HashMap<Color, Color> &p_color_map, const String &p_prefix, String &r_string);
|
||||
static void _replace_color_property(const HashMap<Color, Color> &p_color_map, const String &p_prefix, String &r_string);
|
||||
|
||||
static Ref<Image> load_mem_svg(const uint8_t *p_svg, int p_size, float p_scale);
|
||||
|
||||
public:
|
||||
static void set_forced_color_map(const HashMap<Color, Color> &p_color_map);
|
||||
|
||||
Error create_image_from_utf8_buffer(Ref<Image> p_image, const PackedByteArray &p_buffer, float p_scale, bool p_upsample);
|
||||
Error create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map);
|
||||
static Error create_image_from_utf8_buffer(Ref<Image> p_image, const uint8_t *p_buffer, int p_buffer_size, float p_scale, bool p_upsample);
|
||||
static Error create_image_from_utf8_buffer(Ref<Image> p_image, const PackedByteArray &p_buffer, float p_scale, bool p_upsample);
|
||||
|
||||
static Error create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map);
|
||||
|
||||
virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) override;
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
|
||||
|
||||
ImageLoaderSVG();
|
||||
};
|
||||
|
||||
#endif // IMAGE_LOADER_SVG_H
|
||||
|
|
|
@ -3299,11 +3299,10 @@ EditorExportPlatformAndroid::EditorExportPlatformAndroid() {
|
|||
Ref<Image> img = memnew(Image);
|
||||
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
|
||||
|
||||
ImageLoaderSVG img_loader;
|
||||
img_loader.create_image_from_string(img, _android_logo_svg, EDSCALE, upsample, false);
|
||||
ImageLoaderSVG::create_image_from_string(img, _android_logo_svg, EDSCALE, upsample, false);
|
||||
logo = ImageTexture::create_from_image(img);
|
||||
|
||||
img_loader.create_image_from_string(img, _android_run_icon_svg, EDSCALE, upsample, false);
|
||||
ImageLoaderSVG::create_image_from_string(img, _android_run_icon_svg, EDSCALE, upsample, false);
|
||||
run_icon = ImageTexture::create_from_image(img);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1978,8 +1978,7 @@ EditorExportPlatformIOS::EditorExportPlatformIOS() {
|
|||
Ref<Image> img = memnew(Image);
|
||||
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
|
||||
|
||||
ImageLoaderSVG img_loader;
|
||||
img_loader.create_image_from_string(img, _ios_logo_svg, EDSCALE, upsample, false);
|
||||
ImageLoaderSVG::create_image_from_string(img, _ios_logo_svg, EDSCALE, upsample, false);
|
||||
logo = ImageTexture::create_from_image(img);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -521,11 +521,10 @@ EditorExportPlatformLinuxBSD::EditorExportPlatformLinuxBSD() {
|
|||
Ref<Image> img = memnew(Image);
|
||||
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
|
||||
|
||||
ImageLoaderSVG img_loader;
|
||||
img_loader.create_image_from_string(img, _linuxbsd_logo_svg, EDSCALE, upsample, false);
|
||||
ImageLoaderSVG::create_image_from_string(img, _linuxbsd_logo_svg, EDSCALE, upsample, false);
|
||||
set_logo(ImageTexture::create_from_image(img));
|
||||
|
||||
img_loader.create_image_from_string(img, _linuxbsd_run_icon_svg, EDSCALE, upsample, false);
|
||||
ImageLoaderSVG::create_image_from_string(img, _linuxbsd_run_icon_svg, EDSCALE, upsample, false);
|
||||
run_icon = ImageTexture::create_from_image(img);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -2442,11 +2442,10 @@ EditorExportPlatformMacOS::EditorExportPlatformMacOS() {
|
|||
Ref<Image> img = memnew(Image);
|
||||
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
|
||||
|
||||
ImageLoaderSVG img_loader;
|
||||
img_loader.create_image_from_string(img, _macos_logo_svg, EDSCALE, upsample, false);
|
||||
ImageLoaderSVG::create_image_from_string(img, _macos_logo_svg, EDSCALE, upsample, false);
|
||||
logo = ImageTexture::create_from_image(img);
|
||||
|
||||
img_loader.create_image_from_string(img, _macos_run_icon_svg, EDSCALE, upsample, false);
|
||||
ImageLoaderSVG::create_image_from_string(img, _macos_run_icon_svg, EDSCALE, upsample, false);
|
||||
run_icon = ImageTexture::create_from_image(img);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -515,8 +515,7 @@ EditorExportPlatformUWP::EditorExportPlatformUWP() {
|
|||
Ref<Image> img = memnew(Image);
|
||||
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
|
||||
|
||||
ImageLoaderSVG img_loader;
|
||||
img_loader.create_image_from_string(img, _uwp_logo_svg, EDSCALE, upsample, false);
|
||||
ImageLoaderSVG::create_image_from_string(img, _uwp_logo_svg, EDSCALE, upsample, false);
|
||||
|
||||
logo = ImageTexture::create_from_image(img);
|
||||
#endif
|
||||
|
|
|
@ -674,11 +674,10 @@ EditorExportPlatformWeb::EditorExportPlatformWeb() {
|
|||
Ref<Image> img = memnew(Image);
|
||||
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
|
||||
|
||||
ImageLoaderSVG img_loader;
|
||||
img_loader.create_image_from_string(img, _web_logo_svg, EDSCALE, upsample, false);
|
||||
ImageLoaderSVG::create_image_from_string(img, _web_logo_svg, EDSCALE, upsample, false);
|
||||
logo = ImageTexture::create_from_image(img);
|
||||
|
||||
img_loader.create_image_from_string(img, _web_run_icon_svg, EDSCALE, upsample, false);
|
||||
ImageLoaderSVG::create_image_from_string(img, _web_run_icon_svg, EDSCALE, upsample, false);
|
||||
run_icon = ImageTexture::create_from_image(img);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1011,11 +1011,10 @@ EditorExportPlatformWindows::EditorExportPlatformWindows() {
|
|||
Ref<Image> img = memnew(Image);
|
||||
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
|
||||
|
||||
ImageLoaderSVG img_loader;
|
||||
img_loader.create_image_from_string(img, _windows_logo_svg, EDSCALE, upsample, false);
|
||||
ImageLoaderSVG::create_image_from_string(img, _windows_logo_svg, EDSCALE, upsample, false);
|
||||
set_logo(ImageTexture::create_from_image(img));
|
||||
|
||||
img_loader.create_image_from_string(img, _windows_run_icon_svg, EDSCALE, upsample, false);
|
||||
ImageLoaderSVG::create_image_from_string(img, _windows_run_icon_svg, EDSCALE, upsample, false);
|
||||
run_icon = ImageTexture::create_from_image(img);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -83,8 +83,8 @@ static Ref<ImageTexture> generate_icon(int p_index) {
|
|||
// Generating upsampled icons is slower, and the benefit is hardly visible
|
||||
// with integer scales.
|
||||
const bool upsample = !Math::is_equal_approx(Math::round(scale), scale);
|
||||
ImageLoaderSVG img_loader;
|
||||
Error err = img_loader.create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, HashMap<Color, Color>());
|
||||
|
||||
Error err = ImageLoaderSVG::create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, HashMap<Color, Color>());
|
||||
ERR_FAIL_COND_V_MSG(err != OK, Ref<ImageTexture>(), "Failed generating icon, unsupported or invalid SVG data in default theme.");
|
||||
#else
|
||||
// If the SVG module is disabled, we can't really display the UI well, but at least we won't crash.
|
||||
|
|
Loading…
Reference in a new issue