Skip to content

Commit 08fae7b

Browse files
jzernpalemieux
andauthored
Add webp support
Uses modified libwebp @ v1.5.0 to allow images larger than 16k pixels. Co-authored-by: Pierre-Anthony Lemieux <pal@palemieux.com>
1 parent 1a6a407 commit 08fae7b

File tree

8 files changed

+167
-3
lines changed

8 files changed

+167
-3
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@
2626
[submodule "ext/libavif"]
2727
path = ext/libavif
2828
url = https://github.com/AOMediaCodec/libavif.git
29+
[submodule "ext/libwebp"]
30+
path = ext/libwebp
31+
url = https://chromium.googlesource.com/webm/libwebp

CMakeLists.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ set(JPEGXL_ENABLE_MANPAGES FALSE CACHE INTERNAL "" FORCE)
5959
set(JPEGXL_ENABLE_AVX512 TRUE CACHE INTERNAL "" FORCE)
6060
add_subdirectory(ext/libjxl EXCLUDE_FROM_ALL)
6161

62+
# webp
63+
64+
add_subdirectory(ext/libwebp EXCLUDE_FROM_ALL)
65+
6266
# ffmpeg
6367

6468
# CONFIGURE_COMMAND ./configure --disable-avdevice --disable-avformat --disable-swresample --disable-swscale --disable-avfilter --disable-doc --disable-programs --prefix=${FFMPEG_INSTALL_DIR}
@@ -90,7 +94,7 @@ add_library(md5 ext/crypto-algorithms/md5.c)
9094

9195
file(GLOB LIBENCH_SRC_FILES src/main/cpp/*)
9296
add_executable(libench ${LIBENCH_SRC_FILES} ext/lodepng/lodepng.cpp)
93-
target_link_libraries(libench openjph md5 avif jxl libavcodec libavutil ${KDU_LIBRARY} ${CMAKE_DL_LIBS})
97+
target_link_libraries(libench openjph md5 avif jxl webp libavcodec libavutil ${KDU_LIBRARY} ${CMAKE_DL_LIBS})
9498

9599
# tests
96100

@@ -110,4 +114,6 @@ add_test(NAME "png" COMMAND libench png ${PROJECT_SOURCE_DIR}/src/test/resources
110114
add_test(NAME "ffv1" COMMAND libench ffv1 ${PROJECT_SOURCE_DIR}/src/test/resources/images/test1.png)
111115
add_test(NAME "ffv1-rgba" COMMAND libench ffv1 ${PROJECT_SOURCE_DIR}/src/test/resources/images/rgba.png)
112116
add_test(NAME "ffv1-yuv" COMMAND libench ffv1 ${PROJECT_SOURCE_DIR}/src/test/resources/images/loc.720x243.yuv422p10le.yuv)
117+
add_test(NAME "webp-rgb" COMMAND libench webp ${PROJECT_SOURCE_DIR}/src/test/resources/images/test1.png)
118+
add_test(NAME "webp-rgba" COMMAND libench webp ${PROJECT_SOURCE_DIR}/src/test/resources/images/rgba.png)
113119

ext/libwebp

Submodule libwebp added at 7f9f52e

src/main/cpp/main.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "ojph_codec.h"
77
#include "png_codec.h"
88
#include "qoi_codec.h"
9+
#include "webp_codec.h"
910
#include <chrono>
1011
#include <fstream>
1112
#include <iomanip>
@@ -185,6 +186,9 @@ int main(int argc, char* argv[]) {
185186
} else if (result["codec"].as<std::string>() == "ffv1") {
186187
encoder.reset(new libench::FFV1Encoder());
187188
decoder.reset(new libench::FFV1Decoder());
189+
} else if (result["codec"].as<std::string>() == "webp") {
190+
encoder.reset(new libench::WEBPEncoder());
191+
decoder.reset(new libench::WEBPDecoder());
188192
} else {
189193
throw std::runtime_error("Unknown encoder");
190194
}

src/main/cpp/webp_codec.cpp

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#include "webp_codec.h"
2+
#include "webp/decode.h"
3+
#include "webp/encode.h"
4+
#include <cstdint>
5+
#include <stdexcept>
6+
7+
/*
8+
* WEBPEncoder
9+
*/
10+
11+
libench::WEBPEncoder::WEBPEncoder() {
12+
WebPMemoryWriterInit(&this->writer_);
13+
};
14+
15+
libench::WEBPEncoder::~WEBPEncoder() {
16+
WebPMemoryWriterClear(&this->writer_);
17+
};
18+
19+
libench::CodestreamContext libench::WEBPEncoder::encodeRGB8(const ImageContext &image) {
20+
return this->encode8(image);
21+
}
22+
23+
libench::CodestreamContext libench::WEBPEncoder::encodeRGBA8(const ImageContext &image) {
24+
return this->encode8(image);
25+
}
26+
27+
libench::CodestreamContext libench::WEBPEncoder::encode8(const ImageContext &image) {
28+
WebPMemoryWriterClear(&this->writer_);
29+
30+
WebPConfig config;
31+
WebPPicture pic;
32+
const int level = 6; // 0 (faster) - 9 (slower)
33+
if (!WebPConfigInit(&config) || !WebPConfigLosslessPreset(&config, level) || !WebPPictureInit(&pic))
34+
throw std::runtime_error("WEBP encode failed");
35+
36+
const int num_comps = image.format.comps.num_comps;
37+
const int rgb_stride = image.width * num_comps;
38+
pic.width = image.width;
39+
pic.height = image.height;
40+
pic.use_argb = 1;
41+
int ret = num_comps == 3 ?
42+
WebPPictureImportRGB(&pic, image.planes8[0], rgb_stride) :
43+
WebPPictureImportRGBA(&pic, image.planes8[0], rgb_stride);
44+
if (!ret) {
45+
WebPPictureFree(&pic);
46+
throw std::runtime_error("WEBP encode failed");
47+
}
48+
49+
// Retain pixel values in fully transparent areas. The default will modify
50+
// the (invisible) pixels to improve compression.
51+
config.exact = 1;
52+
53+
pic.writer = WebPMemoryWrite;
54+
pic.custom_ptr = &this->writer_;
55+
56+
if (!WebPEncode(&config, &pic)) {
57+
WebPPictureFree(&pic);
58+
WebPMemoryWriterClear(&this->writer_);
59+
throw std::runtime_error("WEBP encode failed");
60+
}
61+
62+
CodestreamContext cs;
63+
cs.codestream = this->writer_.mem;
64+
cs.size = this->writer_.size;
65+
return cs;
66+
}
67+
68+
/*
69+
* WEBPDecoder
70+
*/
71+
72+
libench::WEBPDecoder::WEBPDecoder() {
73+
};
74+
75+
libench::WEBPDecoder::~WEBPDecoder() {
76+
WebPFree(this->image_.planes8[0]);
77+
};
78+
79+
libench::ImageContext libench::WEBPDecoder::decodeRGB8(const CodestreamContext& cs) {
80+
return this->decode8(cs, 3);
81+
}
82+
83+
libench::ImageContext libench::WEBPDecoder::decodeRGBA8(const CodestreamContext& cs) {
84+
return this->decode8(cs, 4);
85+
}
86+
87+
libench::ImageContext libench::WEBPDecoder::decode8(const CodestreamContext& cs, uint8_t num_comps) {
88+
WebPFree(this->image_.planes8[0]);
89+
90+
this->image_.format = num_comps == 3 ? libench::ImageFormat::RGB8 : libench::ImageFormat::RGBA8;
91+
92+
int width, height;
93+
this->image_.planes8[0] = num_comps == 3 ?
94+
WebPDecodeRGB(cs.codestream, cs.size, &width, &height) :
95+
WebPDecodeRGBA(cs.codestream, cs.size, &width, &height);
96+
97+
if (!this->image_.planes8[0])
98+
throw std::runtime_error("WEBP decode failed");
99+
100+
this->image_.width = static_cast<uint32_t>(width);
101+
this->image_.height = static_cast<uint32_t>(height);
102+
103+
return this->image_;
104+
}

src/main/cpp/webp_codec.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#ifndef LIBENCH_WEBP_H
2+
#define LIBENCH_WEBP_H
3+
4+
#include "codec.h"
5+
#include "webp/encode.h"
6+
7+
namespace libench {
8+
9+
class WEBPEncoder : public Encoder {
10+
public:
11+
WEBPEncoder();
12+
~WEBPEncoder() override;
13+
14+
CodestreamContext encodeRGB8(const ImageContext &image) override;
15+
16+
CodestreamContext encodeRGBA8(const ImageContext &image) override;
17+
18+
private:
19+
CodestreamContext encode8(const ImageContext &image);
20+
21+
WebPMemoryWriter writer_;
22+
};
23+
24+
class WEBPDecoder : public Decoder {
25+
public:
26+
WEBPDecoder();
27+
~WEBPDecoder() override;
28+
29+
ImageContext decodeRGB8(const CodestreamContext& cs) override;
30+
31+
ImageContext decodeRGBA8(const CodestreamContext& cs) override;
32+
33+
private:
34+
ImageContext decode8(const CodestreamContext& cs, uint8_t num_comps);
35+
36+
ImageContext image_;
37+
};
38+
39+
} // namespace libench
40+
41+
#endif

src/main/python/make_page.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ class CodecInfo:
4545
"qoi": CodecInfo(color="#dc582a", marker="o", formats=["RGBA8", "RGB8"]),
4646
"png": CodecInfo(color="#f2c75c", marker="o", formats=["RGBA8", "RGB8"]),
4747
"ffv1": CodecInfo(color="#94a596", marker="o", formats=["RGBA8", "RGB8", "YUV"]),
48-
"avif": CodecInfo(color="#5d3754", marker="o", formats=["RGBA8", "RGB8"])
48+
"avif": CodecInfo(color="#5d3754", marker="o", formats=["RGBA8", "RGB8"]),
49+
"webp": CodecInfo(color="#007a78", marker="o", formats=["RGBA8", "RGB8"])
4950
}
5051

5152
def make_analysis(df, msg: str, fig_name: str, build_dir_path: str):

src/main/resources/hbs/index.hbs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@
104104
<td><code>avif</code></td>
105105
<td>AVIF using <a href="https://github.com/AOMediaCodec/libavif">libavif</a></td>
106106
</tr>
107+
<tr>
108+
<td><code>webp</code></td>
109+
<td>WebP using <a href="https://chromium.googlesource.com/webm/libwebp">libwebp</a></td>
110+
</tr>
107111
</tbody>
108112
</table>
109113
</section>
@@ -146,4 +150,4 @@
146150
</footer>
147151
</body>
148152

149-
</html>
153+
</html>

0 commit comments

Comments
 (0)