diff --git a/.github/workflows/linux-ci.yml b/.github/workflows/linux-ci.yml index edda7bc81..b373ac65c 100644 --- a/.github/workflows/linux-ci.yml +++ b/.github/workflows/linux-ci.yml @@ -60,7 +60,8 @@ jobs: libuv1-dev \ libjpeg-dev \ libpng-dev \ - libglfw3-dev + libglfw3-dev \ + libwebp-dev - name: Build MapLibre Native Core run: | @@ -185,7 +186,9 @@ jobs: libuv1-dev \ libjpeg-dev \ libpng-dev \ + libwebp-dev \ libglfw3-dev \ + libsqlite3-dev \ xserver-xorg-video-dummy \ xinit diff --git a/.github/workflows/node-ci.yml b/.github/workflows/node-ci.yml index d018098bf..30c921624 100644 --- a/.github/workflows/node-ci.yml +++ b/.github/workflows/node-ci.yml @@ -132,7 +132,8 @@ jobs: libc++-9-dev \ libc++abi-9-dev \ libjpeg-dev \ - libpng-dev + libpng-dev \ + libwebp-dev /usr/sbin/update-ccache-symlinks - name: Setup node diff --git a/.github/workflows/node-release.yml b/.github/workflows/node-release.yml index 54cf6a8bb..c227e1c1b 100644 --- a/.github/workflows/node-release.yml +++ b/.github/workflows/node-release.yml @@ -128,7 +128,8 @@ jobs: libc++-9-dev \ libc++abi-9-dev \ libjpeg-dev \ - libpng-dev + libpng-dev \ + libwebp-dev /usr/sbin/update-ccache-symlinks - name: Setup node diff --git a/CHANGELOG.md b/CHANGELOG.md index 738686f82..99b43b89e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### ✨ New features - *...Add new stuff here...* +- [core] Add WebP image decoding support to default platform (Linux, Windows) - [core] All CMake properties are now prefixed `MLN_*` [1054](https://github.com/maplibre/maplibre-native/pull/1054). - [windows] Added windows build support for core applications and node [#707](https://github.com/maplibre/maplibre-native/pull/707) - [core] Add `ClientOptions` to configure client information [#365](https://github.com/maplibre/maplibre-native/pull/365). diff --git a/platform/default/BUILD.bazel b/platform/default/BUILD.bazel index 8d6a24f90..4826e6541 100644 --- a/platform/default/BUILD.bazel +++ b/platform/default/BUILD.bazel @@ -70,6 +70,7 @@ cc_library( "src/mbgl/util/string_stdlib.cpp", "src/mbgl/util/thread.cpp", "src/mbgl/util/timer.cpp", + "src/mbgl/util/webp_reader.cpp", ], "//:ios": [], }), diff --git a/platform/default/src/mbgl/util/image.cpp b/platform/default/src/mbgl/util/image.cpp index 7d36dbd54..1ff505d6f 100644 --- a/platform/default/src/mbgl/util/image.cpp +++ b/platform/default/src/mbgl/util/image.cpp @@ -6,14 +6,29 @@ namespace mbgl { PremultipliedImage decodePNG(const uint8_t*, size_t); PremultipliedImage decodeJPEG(const uint8_t*, size_t); +PremultipliedImage decodeWEBP(const uint8_t*, size_t); PremultipliedImage decodeImage(const std::string& string) { const auto* data = reinterpret_cast(string.data()); const size_t size = string.size(); + const auto readUInt = [](const uint8_t* imageData, ptrdiff_t offset) -> uint32_t { + const auto ptr = imageData + offset; + return (static_cast(ptr[0]) << 24) | (static_cast(ptr[1]) << 16) | + (static_cast(ptr[2]) << 8) | static_cast(ptr[3]); + }; + + if (size >= 16) { + uint32_t magic1 = readUInt(data, 0x0); + uint32_t magic2 = readUInt(data, 0x8); + // RIFF WEBP + if (magic1 == 0x52494646 && magic2 == 0x57454250) { + return decodeWEBP(data, size); + } + } + if (size >= 4) { - uint32_t magic = (static_cast(data[0]) << 24) | (static_cast(data[1]) << 16) | - (static_cast(data[2]) << 8) | static_cast(data[3]); + uint32_t magic = readUInt(data, 0x0); if (magic == 0x89504E47U) { return decodePNG(data, size); } diff --git a/platform/default/src/mbgl/util/webp_reader.cpp b/platform/default/src/mbgl/util/webp_reader.cpp new file mode 100644 index 000000000..7faf6641d --- /dev/null +++ b/platform/default/src/mbgl/util/webp_reader.cpp @@ -0,0 +1,26 @@ +#include +#include +#include + +#include +#include + +namespace mbgl { + +PremultipliedImage decodeWEBP(const uint8_t* data, size_t size) { + int32_t width, height; + if (!WebPGetInfo(data, size, &width, &height)) { + Log::Warning(Event::Image, "Failed to decode WebP image header!"); + return {}; + } + + auto img = UnassociatedImage({static_cast(width), static_cast(height)}); + if (!WebPDecodeRGBAInto(data, size, img.data.get(), img.bytes(), static_cast(img.stride()))) { + Log::Warning(Event::Image, "Failed to decode WebP image contents!"); + return {}; + } + + return util::premultiply(std::move(img)); +} + +} // namespace mbgl diff --git a/platform/linux/BUILD.bazel b/platform/linux/BUILD.bazel index dfbc21b1f..f7ffb87cf 100644 --- a/platform/linux/BUILD.bazel +++ b/platform/linux/BUILD.bazel @@ -23,6 +23,7 @@ cc_library( "-lcurl", "-lpng", "-ljpeg", + "-lwebp", ] + ICU_FLAGS, visibility = ["//visibility:public"], deps = [ diff --git a/platform/linux/README.md b/platform/linux/README.md index 9f42948a3..7e1d8ad96 100644 --- a/platform/linux/README.md +++ b/platform/linux/README.md @@ -7,7 +7,7 @@ This guide explains how to get started building and running MapLibre Native on L The following system libraries need to be installed. ```bash -apt install libcurl4-openssl-dev libglfw3-dev libuv1-dev libpng-dev libicu-dev libjpeg62-turbo +apt install libcurl4-openssl-dev libglfw3-dev libuv1-dev libpng-dev libicu-dev libjpeg62-turbo libwebp-dev ``` Optional: `libsqlite3-dev` (also available as vendored dependency). diff --git a/platform/linux/linux.cmake b/platform/linux/linux.cmake index 69e32b90e..68e55d588 100644 --- a/platform/linux/linux.cmake +++ b/platform/linux/linux.cmake @@ -12,6 +12,7 @@ if (MLN_WITH_X11) endif () find_package(Threads REQUIRED) +pkg_search_module(WEBP libwebp REQUIRED) pkg_search_module(LIBUV libuv REQUIRED) target_sources( @@ -45,6 +46,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/filesystem.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/image.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/jpeg_reader.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/webp_reader.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/logging_stderr.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/monotonic_timer.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/png_reader.cpp @@ -100,6 +102,7 @@ target_include_directories( ${JPEG_INCLUDE_DIRS} ${LIBUV_INCLUDE_DIRS} ${X11_INCLUDE_DIRS} + ${WEBP_INCLUDE_DIRS} ) include(${PROJECT_SOURCE_DIR}/vendor/nunicode.cmake) @@ -127,6 +130,7 @@ target_link_libraries( ${LIBUV_LIBRARIES} ${X11_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + ${WEBP_LIBRARIES} $<$>:ICU::i18n> $<$>:ICU::uc> $<$:mbgl-vendor-icu> diff --git a/platform/windows/Get-VendorPackages.ps1 b/platform/windows/Get-VendorPackages.ps1 index c37a64d1d..fe18fc034 100644 --- a/platform/windows/Get-VendorPackages.ps1 +++ b/platform/windows/Get-VendorPackages.ps1 @@ -30,7 +30,7 @@ if(-not (Test-Path "$vcpkg_temp_dir\vcpkg.exe")) & "$vcpkg_temp_dir\bootstrap-vcpkg.bat" } -& "$vcpkg_temp_dir\vcpkg.exe" --disable-metrics --overlay-triplets=$([System.IO.Path]::Combine($PWD.Path, 'vendor', 'vcpkg-custom-triplets')) --triplet=$($Triplet) --clean-after-build install curl dlfcn-win32 glfw3 icu libuv libjpeg-turbo libpng $($renderer_packages) +& "$vcpkg_temp_dir\vcpkg.exe" --disable-metrics --overlay-triplets=$([System.IO.Path]::Combine($PWD.Path, 'vendor', 'vcpkg-custom-triplets')) --triplet=$($Triplet) --clean-after-build install curl dlfcn-win32 glfw3 icu libuv libjpeg-turbo libpng libwebp $($renderer_packages) subst $vcpkg_temp_dir /D diff --git a/platform/windows/windows.cmake b/platform/windows/windows.cmake index fcebee157..f9b2591e2 100644 --- a/platform/windows/windows.cmake +++ b/platform/windows/windows.cmake @@ -23,6 +23,7 @@ find_package(ICU OPTIONAL_COMPONENTS i18n uc) find_package(JPEG REQUIRED) find_package(libuv REQUIRED) find_package(PNG REQUIRED) +find_package(WebP REQUIRED) find_path(DLFCN_INCLUDE_DIRS dlfcn.h) find_path(LIBUV_INCLUDE_DIRS uv.h) @@ -57,6 +58,7 @@ target_sources( ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/filesystem.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/image.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/jpeg_reader.cpp + ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/webp_reader.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/logging_stderr.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/monotonic_timer.cpp ${PROJECT_SOURCE_DIR}/platform/default/src/mbgl/util/png_reader.cpp @@ -147,6 +149,7 @@ target_include_directories( ${DLFCN_INCLUDE_DIRS} ${JPEG_INCLUDE_DIRS} ${LIBUV_INCLUDE_DIRS} + ${WEBP_INCLUDE_DIRS} ) include(${PROJECT_SOURCE_DIR}/vendor/nunicode.cmake) @@ -172,6 +175,7 @@ target_link_libraries( ${CURL_LIBRARIES} ${JPEG_LIBRARIES} ${LIBUV_LIBRARIES} + ${WEBP_LIBRARIES} dlfcn-win32::dl $<$>:ICU::data> $<$>:ICU::i18n> diff --git a/test/fixtures/image/tile.webp b/test/fixtures/image/tile.webp new file mode 100644 index 000000000..a85c33286 Binary files /dev/null and b/test/fixtures/image/tile.webp differ diff --git a/test/util/image.test.cpp b/test/util/image.test.cpp index a520f94fa..b0f89bba7 100644 --- a/test/util/image.test.cpp +++ b/test/util/image.test.cpp @@ -78,6 +78,12 @@ TEST(Image, JPEGTile) { EXPECT_EQ(256u, image.size.height); } +TEST(Image, WebPTile) { + PremultipliedImage image = decodeImage(util::read_file("test/fixtures/image/tile.webp")); + EXPECT_EQ(256u, image.size.width); + EXPECT_EQ(256u, image.size.height); +} + TEST(Image, Resize) { AlphaImage image({0, 0});