diff options
Diffstat (limited to 'modules/webp/image_loader_webp.cpp')
-rw-r--r-- | modules/webp/image_loader_webp.cpp | 81 |
1 files changed, 74 insertions, 7 deletions
diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp index b304c4824f..5bebad2b53 100644 --- a/modules/webp/image_loader_webp.cpp +++ b/modules/webp/image_loader_webp.cpp @@ -30,6 +30,7 @@ #include "image_loader_webp.h" +#include "core/config/project_settings.h" #include "core/io/marshalls.h" #include "core/os/os.h" #include "core/string/print_string.h" @@ -68,13 +69,78 @@ static Vector<uint8_t> _webp_lossy_pack(const Ref<Image> &p_image, float p_quali w[1] = 'E'; w[2] = 'B'; w[3] = 'P'; - copymem(&w[4], dst_buff, dst_size); - free(dst_buff); + memcpy(&w[4], dst_buff, dst_size); + WebPFree(dst_buff); return dst; } -static Ref<Image> _webp_lossy_unpack(const Vector<uint8_t> &p_buffer) { +static Vector<uint8_t> _webp_lossless_pack(const Ref<Image> &p_image) { + ERR_FAIL_COND_V(p_image.is_null() || p_image->is_empty(), Vector<uint8_t>()); + + int compression_level = ProjectSettings::get_singleton()->get("rendering/textures/lossless_compression/webp_compression_level"); + compression_level = CLAMP(compression_level, 0, 9); + + Ref<Image> img = p_image->duplicate(); + if (img->detect_alpha()) { + img->convert(Image::FORMAT_RGBA8); + } else { + img->convert(Image::FORMAT_RGB8); + } + + Size2 s(img->get_width(), img->get_height()); + Vector<uint8_t> data = img->get_data(); + const uint8_t *r = data.ptr(); + + // we need to use the more complex API in order to access the 'exact' flag... + + WebPConfig config; + WebPPicture pic; + if (!WebPConfigInit(&config) || !WebPConfigLosslessPreset(&config, compression_level) || !WebPPictureInit(&pic)) { + ERR_FAIL_V(Vector<uint8_t>()); + } + + WebPMemoryWriter wrt; + config.exact = 1; + pic.use_argb = 1; + pic.width = s.width; + pic.height = s.height; + pic.writer = WebPMemoryWrite; + pic.custom_ptr = &wrt; + WebPMemoryWriterInit(&wrt); + + bool success_import = false; + if (img->get_format() == Image::FORMAT_RGB8) { + success_import = WebPPictureImportRGB(&pic, r, 3 * s.width); + } else { + success_import = WebPPictureImportRGBA(&pic, r, 4 * s.width); + } + bool success_encode = false; + if (success_import) { + success_encode = WebPEncode(&config, &pic); + } + WebPPictureFree(&pic); + + if (!success_encode) { + WebPMemoryWriterClear(&wrt); + ERR_FAIL_V_MSG(Vector<uint8_t>(), "WebP packing failed."); + } + + // copy from wrt + Vector<uint8_t> dst; + dst.resize(4 + wrt.size); + uint8_t *w = dst.ptrw(); + w[0] = 'W'; + w[1] = 'E'; + w[2] = 'B'; + w[3] = 'P'; + memcpy(&w[4], wrt.mem, wrt.size); + WebPMemoryWriterClear(&wrt); + + return dst; +} + +static Ref<Image> _webp_unpack(const Vector<uint8_t> &p_buffer) { int size = p_buffer.size() - 4; ERR_FAIL_COND_V(size <= 0, Ref<Image>()); const uint8_t *r = p_buffer.ptr(); @@ -139,7 +205,7 @@ Error webp_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) { Ref<Image> img; - img.instance(); + img.instantiate(); Error err = webp_load_image_from_buffer(img.ptr(), p_png, p_size); ERR_FAIL_COND_V(err, Ref<Image>()); return img; @@ -147,7 +213,7 @@ static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) { Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; - int src_image_len = f->get_len(); + uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); src_image.resize(src_image_len); @@ -168,6 +234,7 @@ void ImageLoaderWEBP::get_recognized_extensions(List<String> *p_extensions) cons ImageLoaderWEBP::ImageLoaderWEBP() { Image::_webp_mem_loader_func = _webp_mem_loader_func; - Image::lossy_packer = _webp_lossy_pack; - Image::lossy_unpacker = _webp_lossy_unpack; + Image::webp_lossy_packer = _webp_lossy_pack; + Image::webp_lossless_packer = _webp_lossless_pack; + Image::webp_unpacker = _webp_unpack; } |