diff --git a/.gitmodules b/.gitmodules index 0df9bf9e87..969a47316e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -82,3 +82,7 @@ path = project/lib/hashlink url = https://github.com/HaxeFoundation/hashlink shallow = true +[submodule "project/lib/webp"] + path = project/lib/webp + url = https://github.com/webmproject/libwebp + shallow = true diff --git a/NOTICE.md b/NOTICE.md index a806789ebd..ee2998e83d 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -46,6 +46,9 @@ This product bundles pixman 0.32.8, which is available under an This product bundles libpng 1.6.12, which is available under a "zlib" (BSD-style) license. For details, see [project/lib/png/](project/lib). +This product bundles libwebp 1.6.0, which is available under a +BSD-3-Clause license. For details, see [project/lib/webp/](project/lib). + This product bundles SDL 2.0.12, which is available under a "zlib" (BSD-style) license. For details, see [project/lib/sdl/](project/lib). @@ -58,6 +61,7 @@ This product bundles libvorbis 1.3.3, which is available under a This product bundles zlib 1.2.8, which is available under a "zlib" (BSD-style) license. For details, see [project/lib/zlib/](project/lib). + ------- Modifications and source-repository versions of Haxe core files are included in the diff --git a/project/Build.xml b/project/Build.xml index d6f0d7c857..6a5854ba30 100755 --- a/project/Build.xml +++ b/project/Build.xml @@ -26,6 +26,7 @@ + @@ -214,6 +215,13 @@ +
+ + + + +
+
@@ -364,6 +372,7 @@ + @@ -397,6 +406,7 @@ + diff --git a/project/include/graphics/format/WEBP.h b/project/include/graphics/format/WEBP.h new file mode 100644 index 0000000000..65c74cd4fb --- /dev/null +++ b/project/include/graphics/format/WEBP.h @@ -0,0 +1,19 @@ +#ifndef LIME_GRAPHICS_FORMAT_WEBP_H +#define LIME_GRAPHICS_FORMAT_WEBP_H + +#include +#include +#include + +namespace lime { + + class WEBP { + + public: + static bool Decode (Resource *resource, ImageBuffer *imageBuffer, bool decodeData = true); + static bool Encode (ImageBuffer *imageBuffer, Bytes *bytes, int quality); + }; + +} + +#endif diff --git a/project/lib/README.md b/project/lib/README.md index 022e17030e..2accca8be9 100644 --- a/project/lib/README.md +++ b/project/lib/README.md @@ -18,6 +18,7 @@ Lime includes code from several other C/C++ libraries, listed below. Lime prefer - [**OpenAL Soft**](https://openal-soft.org/) | [primary repo](https://github.com/kcat/openal-soft) - [**Pixman**](http://pixman.org/) | [primary repo](https://gitlab.freedesktop.org/pixman/pixman) | [GitHub mirror](https://github.com/freedesktop/pixman) - [**libpng**](http://www.libpng.org/pub/png/libpng.html) | [primary repo](https://sourceforge.net/p/libpng/code) | [GitHub mirror](https://github.com/glennrp/libpng)[^1] +- [**libwebp**](https://developers.google.com/speed/webp) | [primary repo](https://chromium.googlesource.com/webm/libwebp) | [GitHub mirror](https://github.com/webmproject/libwebp) - [**SDL**](https://www.libsdl.org/) | [primary repo](https://github.com/libsdl-org/SDL) - [**tiny file dialogs**](https://sourceforge.net/projects/tinyfiledialogs/) | [primary repo](https://sourceforge.net/p/tinyfiledialogs/code) | [unofficial GitHub mirror](https://github.com/openfl/libtinyfiledialogs)[^1] - [**Vorbis**](https://www.xiph.org/vorbis/) | [primary repo](https://github.com/xiph/vorbis) diff --git a/project/lib/webp b/project/lib/webp new file mode 160000 index 0000000000..4fa2191233 --- /dev/null +++ b/project/lib/webp @@ -0,0 +1 @@ +Subproject commit 4fa21912338357f89e4fd51cf2368325b59e9bd9 diff --git a/project/lib/webp-files.xml b/project/lib/webp-files.xml new file mode 100644 index 0000000000..228330de11 --- /dev/null +++ b/project/lib/webp-files.xml @@ -0,0 +1,148 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + +
+ + + +
+ + + + + + +
+ + +
+ + + + + + + + + + + + + +
+ +
+
diff --git a/project/src/ExternalInterface.cpp b/project/src/ExternalInterface.cpp index 39ccdcf3d5..f4969600da 100644 --- a/project/src/ExternalInterface.cpp +++ b/project/src/ExternalInterface.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -1882,6 +1883,17 @@ namespace lime { #endif break; + case 2: + + #ifdef LIME_WEBP + if (WEBP::Encode (&imageBuffer, &data, quality)) { + + return data.Value (bytes); + + } + #endif + break; + default: break; } @@ -1917,6 +1929,17 @@ namespace lime { #endif break; + case 2: + + #ifdef LIME_WEBP + if (WEBP::Encode (buffer, bytes, quality)) { + + return bytes; + + } + #endif + break; + default: break; } @@ -1936,6 +1959,14 @@ namespace lime { bytes.Set (data); resource = Resource (&bytes); + #ifdef LIME_WEBP + if (WEBP::Decode (&resource, &imageBuffer)) { + + return imageBuffer.Value (buffer); + + } + #endif + #ifdef LIME_PNG if (PNG::Decode (&resource, &imageBuffer)) { @@ -1961,6 +1992,14 @@ namespace lime { Resource resource = Resource (data); + #ifdef LIME_WEBP + if (WEBP::Decode (&resource, buffer)) { + + return buffer; + + } + #endif + #ifdef LIME_PNG if (PNG::Decode (&resource, buffer)) { @@ -1987,6 +2026,14 @@ namespace lime { Resource resource = Resource (val_string (data)); ImageBuffer imageBuffer = ImageBuffer (buffer); + #ifdef LIME_WEBP + if (WEBP::Decode (&resource, &imageBuffer)) { + + return imageBuffer.Value (buffer); + + } + #endif + #ifdef LIME_PNG if (PNG::Decode (&resource, &imageBuffer)) { @@ -2012,6 +2059,14 @@ namespace lime { Resource resource = Resource (data); + #ifdef LIME_WEBP + if (WEBP::Decode (&resource, buffer)) { + + return buffer; + + } + #endif + #ifdef LIME_PNG if (PNG::Decode (&resource, buffer)) { @@ -2033,6 +2088,77 @@ namespace lime { } + value lime_webp_decode_bytes (value data, bool decodeData, value buffer) { + + ImageBuffer imageBuffer (buffer); + + Bytes bytes (data); + Resource resource = Resource (&bytes); + + #ifdef LIME_WEBP + if (WEBP::Decode (&resource, &imageBuffer, decodeData)) { + + return imageBuffer.Value (buffer); + + } + #endif + + return alloc_null (); + + } + + + HL_PRIM ImageBuffer* HL_NAME(hl_webp_decode_bytes) (Bytes* data, bool decodeData, ImageBuffer* buffer) { + + Resource resource = Resource (data); + + #ifdef LIME_WEBP + if (WEBP::Decode (&resource, buffer, decodeData)) { + + return buffer; + + } + #endif + + return 0; + + } + + + value lime_webp_decode_file (HxString path, bool decodeData, value buffer) { + + ImageBuffer imageBuffer (buffer); + Resource resource = Resource (hxs_utf8 (path, nullptr)); + + #ifdef LIME_WEBP + if (WEBP::Decode (&resource, &imageBuffer, decodeData)) { + + return imageBuffer.Value (buffer); + + } + #endif + + return alloc_null (); + + } + + + HL_PRIM ImageBuffer* HL_NAME(hl_webp_decode_file) (hl_vstring* path, bool decodeData, ImageBuffer* buffer) { + + Resource resource = Resource (path); + + #ifdef LIME_WEBP + if (WEBP::Decode (&resource, buffer, decodeData)) { + + return buffer; + + } + #endif + + return 0; + + } + value lime_image_load (value data, value buffer) { if (val_is_string (data)) { @@ -4117,6 +4243,8 @@ namespace lime { DEFINE_PRIME2v (lime_orientation_event_manager_register); DEFINE_PRIME3 (lime_png_decode_bytes); DEFINE_PRIME3 (lime_png_decode_file); + DEFINE_PRIME3 (lime_webp_decode_bytes); + DEFINE_PRIME3 (lime_webp_decode_file); DEFINE_PRIME2v (lime_render_event_manager_register); DEFINE_PRIME2v (lime_sensor_event_manager_register); DEFINE_PRIME0 (lime_system_get_allow_screen_timeout); @@ -4311,6 +4439,8 @@ namespace lime { DEFINE_HL_PRIM (_VOID, hl_orientation_event_manager_register, _FUN (_VOID, _NO_ARG) _TORIENTATION_EVENT); DEFINE_HL_PRIM (_TIMAGEBUFFER, hl_png_decode_bytes, _TBYTES _BOOL _TIMAGEBUFFER); DEFINE_HL_PRIM (_TIMAGEBUFFER, hl_png_decode_file, _STRING _BOOL _TIMAGEBUFFER); + DEFINE_HL_PRIM (_TIMAGEBUFFER, hl_webp_decode_bytes, _TBYTES _BOOL _TIMAGEBUFFER); + DEFINE_HL_PRIM (_TIMAGEBUFFER, hl_webp_decode_file, _STRING _BOOL _TIMAGEBUFFER); DEFINE_HL_PRIM (_VOID, hl_render_event_manager_register, _FUN (_VOID, _NO_ARG) _TRENDER_EVENT); DEFINE_HL_PRIM (_VOID, hl_sensor_event_manager_register, _FUN (_VOID, _NO_ARG) _TSENSOR_EVENT); DEFINE_HL_PRIM (_BOOL, hl_system_get_allow_screen_timeout, _NO_ARG); diff --git a/project/src/graphics/format/WEBP.cpp b/project/src/graphics/format/WEBP.cpp new file mode 100644 index 0000000000..70fbfc1457 --- /dev/null +++ b/project/src/graphics/format/WEBP.cpp @@ -0,0 +1,153 @@ +#ifdef LIME_WEBP + +extern "C" { + #include + #include +} + +#include +#include +#include +#include +#include +#include +#include + +namespace lime { + + static inline int clampi (int value, int min, int max) { + return value < min ? min : (value > max ? max : value); + } + + static bool LoadResourceToMemory (Resource* resource, Bytes*& owned, const uint8_t*& src, size_t& len) { + + owned = nullptr; + src = nullptr; + len = 0; + + if (!resource) return false; + + if (resource->path) { + + FILE_HANDLE* file = lime::fopen (resource->path, "rb"); + if (!file) return false; + + unsigned char sig[12] = {0}; + int readOK = lime::fread (&sig[0], 12, 1, file); + lime::fclose (file); + + if (readOK != 1) return false; + + const bool isRIFF = (sig[0]=='R' && sig[1]=='I' && sig[2]=='F' && sig[3]=='F'); + const bool isWEBP = (sig[8]=='W' && sig[9]=='E' && sig[10]=='B' && sig[11]=='P'); + if (!isRIFF || !isWEBP) return false; + + Bytes* bytes = new Bytes (); + bytes->ReadFile (resource->path); + if (bytes->length <= 0) { delete bytes; return false; } + + owned = bytes; + src = reinterpret_cast(bytes->b); + len = static_cast(bytes->length); + return true; + + } else if (resource->data) { + + src = reinterpret_cast(resource->data->b); + len = static_cast(resource->data->length); + if (len == 0) return false; + + return true; + + } + + return false; + } + + + bool WEBP::Decode (Resource* resource, ImageBuffer* imageBuffer, bool decodeData) { + + if (!resource || !imageBuffer) return false; + + Bytes* owned = nullptr; + const uint8_t* src = nullptr; + size_t len = 0; + + if (!LoadResourceToMemory (resource, owned, src, len)) { + return false; + } + + int width = 0, height = 0; + if (!WebPGetInfo (src, len, &width, &height) || width <= 0 || height <= 0) { + if (owned) delete owned; + return false; + } + + if (!decodeData) { + imageBuffer->width = width; + imageBuffer->height = height; + if (owned) delete owned; + return true; + } + + imageBuffer->Resize (width, height, 32); + unsigned char* dst = imageBuffer->data && imageBuffer->data->buffer + ? imageBuffer->data->buffer->b : nullptr; + if (!dst) { + if (owned) delete owned; + return false; + } + + const int stride = imageBuffer->Stride (); + const size_t dstSize = static_cast(height) * static_cast(stride); + + uint8_t* ok = WebPDecodeRGBAInto (src, len, dst, dstSize, stride); + if (!ok) { + if (owned) delete owned; + return false; + } + + if (owned) delete owned; + return true; + } + + + + bool WEBP::Encode (ImageBuffer* imageBuffer, Bytes* bytes, int quality) { + + if (!imageBuffer || !bytes) return false; + + const int width = imageBuffer->width; + const int height = imageBuffer->height; + if (width <= 0 || height <= 0) return false; + + const int stride = imageBuffer->Stride (); + const uint8_t* src = imageBuffer->data && imageBuffer->data->buffer + ? reinterpret_cast(imageBuffer->data->buffer->b) : nullptr; + if (!src) return false; + + + uint8_t* out = nullptr; + const float clampedQuality = static_cast(clampi (quality, 0, 100)); + size_t out_size = WebPEncodeRGBA (src, width, height, stride, clampedQuality, &out); + + if (!out || out_size == 0) { + if (out) WebPFree (out); + return false; + } + + if (out_size > static_cast((std::numeric_limits::max)())) { + WebPFree (out); + return false; + } + + bytes->Resize (static_cast(out_size)); + std::memcpy (bytes->b, out, out_size); + WebPFree (out); + + return true; + } + +} // namespace lime + +#endif // LIME_WEBP