blob: 3e47ef62492eccd32c41a8ec83d828754dd8e51a [file] [log] [blame] [view]
# WebP 2
WebP 2 is an experimental image codec based on WebP. WebP 2 will not be released
as an image format but is used as a playground for image compression
experiments.
This package contains the library that can be used in other programs to encode
or decode Webp 2 images, as well as command line tools.
See http://developers.google.com/speed/webp for the first version of WebP.
[TOC]
## What to expect?
The WebP 2 experimental codec is mostly pushing the features of WebP further in
terms of compression efficiency. The new features (like 10b HDR support) are
kept minimal. The axis of experimentation are:
* more efficient lossy compression (~30% better than WebP)
* better visual degradation at very low bitrate
* improved lossless compression
* improved transparency compression
* animation support
* ultra-light previews
* lightweight incremental decoding
* small container overhead, tailored specifically for image compression
* full 10bit architecture (HDR10)
* strong focus on software implementation, fully multi-threaded
The use cases remain mostly the same as WebP: transfer over the wire, faster
web, smaller apps, better user experience... \
WebP 2 is primarily tuned for the typical content available on the Web and
Mobile apps: medium-range dimensions, transparency, short animations,
thumbnails.
As of Nov. 2020, WebP 2 is only partially optimized and, roughly speaking 5x
slower than WebP for lossy compression. It still compresses 2x faster than AVIF,
but takes 3x more time to decompress. The goal is to reach decompression speed
parity.
Side-by-side codec comparisons can be found at:
- [2022-10-04](https://storage.googleapis.com/demos.webmproject.org/webp/cmp/2022_10_04/index.html#eaglefairy-hst-big*1:1&AVIF-AOM=s&WEBP2=s&subset1)
- [2021-12-15](https://storage.googleapis.com/demos.webmproject.org/webp/cmp/2021_12_15/index.html#ohashi0806shield*1:1&AVIF-AOM=t&WEBP2=t&subset1)
- [2021-08-10](https://storage.googleapis.com/demos.webmproject.org/webp/cmp/2021_08_10/index.html#crepuscular-rays-at-sunset-near-waterberg-plateau&AVIF-AOM=s&WEBP2=s&subset1)
## Building
### Prerequisites
A compiler (e.g., gcc 6+, clang 7+ or Microsoft Visual Studio 2017+ are
recommended) and CMake.
On a Debian-like system the following should install everything you need for a
minimal build:
```shell
$ sudo apt install build-essential cmake
```
### Compiling
```shell
$ mkdir build && cd build
$ cmake ..
$ make -j
```
Configuration options:
* `WP2_ENABLE_SIMD`: enable any SIMD optimization.
* `WP2_ENABLE_BITTRACE`: enable tracing.
For additional options see:
```shell
$ cmake .. -LH
```
### Compiling with Android NDK
The latest NDK for Android can be retrieved from the Android
[download page](https://developer.android.com/ndk/downloads).
Assuming the variable NDK_ROOT is positioned correctly to point to the NDK's
directory, the Android binaries can be built with:
```shell
$ mkdir build && cd build
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/android.cmake \
-DWP2_ANDROID_NDK_PATH=${NDK_ROOT}
$ make -j
```
Extra configuration option:
* `ANDROID_ABI`: one of armeabi-v7a,armeabi-v7a with
NEON,arm64-v8a,x86,x86_64... (default is arm64-v8a)
## Binaries
### cwp2
`cwp2` is a tool to encode images in webp2.
Usage:
```shell
$ cwp2 in_file [options] [-o out_file]
```
Example for a single image:
```shell
$ cwp2 -q 70 input.png -o output.wp2
```
Example for an animation, with list of frames and durations in ms:
```shell
$ cwp2 -q 70 -f frame1.png 10 frame2.png 20 frame3.png 5 -o output.wp2
```
Important options:
Flag | Default value | Description
------------------ | :-----------: | -----------
`-o <string>` | | output file path
`-q <float>` | 75 | image quality factor \[0=lossy : 100=lossless\]*
`-alpha_q <float>` | 100 | alpha quality factor \[0=lossy : 100=lossless\]*
`-effort <int>` | 5 | compression effort \[0=fast : 9=slower/better\]
`-f [<str> <int>]` | | create an animation (alternate image, duration)
\* The quality factor range corresponds to:
Quality factor | Meaning
:------------: | -------------------------------------------------------
0 | Lossy compression, smallest file size and worst quality
... | Lossy compression
95 | Lossy compression, biggest file size and best quality
96 | Near-lossless compression (maximum preprocessing)
... | Near-lossless compression
99 | Near-lossless compression (minimum preprocessing)
100 | Lossless compression
Use `cwp2 -h` to see a full list of available options.
### dwp2
`dwp2` is a tool to decode webp2 images.
Usage:
```shell
$ dwp2 in_file [options] [-o out_file]
```
Use `dwp2 -h` to see a full list of available options.
### vwp2
`vwp2` is a visual inspection and debugging tool. You need OpenGL and GLUT to
build it.
![Screenshot of vwp2](./doc/vwp2.webp)
To open any image (jpeg, png, etc.) then compress it in WebP 2 and view the
result:
```shell
$ vwp2 in_file...
```
`vwp2` takes most of the same flags as `cwp2`, e.g. `-q` for quality. Encoding
parameters can also be changed dynamically in the tool using key bindings.
Press `h` to a list of key bindings.
Use the top left menu or press `v` and `shift+v` to cycle between views.
Press `i` to show or hide info (note this hides the menu).
To view an already compressed file, use:
```shell
$ vwp2 -d path/to/image.wp2
```
### rd_curve
rd_curve is a command-line tool for compressing images at multiple quality
levels using different codecs (webp2, webp, jpeg, av1) to create rate-distortion
curves (rd curves). An rd curve is a plot of distortion (difference between
source and encoded image) vs bits per pixel, for different quality settings.
```shell
$ rd_curve [options] input_file
```
`rd_curve` takes most of the same flags as `cwp2`, e.g. `-q` for quality,
`-effort`, and so on.
By default, only the webp2 codec is used. Use `-webp`, `-jpeg` or `-av1` flags
to add other codecs.
By default, results are printed as plain text on standard output.
With the `-html` flag, rd_curve outputs an html file. It also saves compressed
images (turns on the `-save` option). Use the `-save_folder` option to set the
directory where images are saved.
```shell
$ rd_curve input.png -webp -jpeg -av1 -html -save_folder $(pwd) > myfile.html
```
### get_disto
`get_disto` computes the difference between two images (typically the compressed
file and the original file)
```shell
$ get_disto [options] compressed_file orig_file
```
`get_disto` outputs in order:
- compressed file size
- overall PSNR (or other metric, if specified through flags)
- PSNR (or other metric) for A, R, G and B channels, in order
- compressed file bits per pixel
## API
### Encoding API
Encoding functions are available in the header `src/wp2/encode.h`.
#### Encoding an image
```c++
#include "imageio/image_dec.h"
#include "src/wp2/base.h"
#include "src/wp2/encode.h"
WP2::ArgbBuffer input_buffer;
WP2Status status = WP2::ReadImage("path/to/image.png", &input_buffer);
if (status != WP2_STATUS_OK) { /* handle error */ }
WP2::EncoderConfig config;
config.quality = 70;
WP2::MemoryWriter writer;
status = WP2::Encode(input_buffer, &writer, config);
if (status != WP2_STATUS_OK) { /* handle error */ }
// do something with writer.mem_
```
#### Encoding an animation
```c++
#include "imageio/image_dec.h"
#include "src/wp2/base.h"
#include "src/wp2/encode.h"
WP2::ArgbBuffer frame1, frame2;
WP2Status status = WP2::ReadImage("path/to/frame1.png", &frame1);
if (status != WP2_STATUS_OK) { /* handle error */ }
status = WP2::ReadImage("path/to/frame2.png", &frame2);
if (status != WP2_STATUS_OK) { /* handle error */ }
WP2::AnimationEncoder encoder;
status = encoder.AddFrame(frame1, /*duration_ms=*/100);
if (status != WP2_STATUS_OK) { /* handle error */ }
status = encoder.AddFrame(frame2, /*duration_ms=*/50);
if (status != WP2_STATUS_OK) { /* handle error */ }
WP2::EncoderConfig config;
config.quality = 70;
WP2::MemoryWriter writer;
status = encoder.Encode(&writer, config, /*loop_count=*/1);
if (status != WP2_STATUS_OK) { /* handle error */ }
// do something with writer.mem_
```
### Decoding API
Decoding functions are available in the header `src/wp2/decode.h`.
#### Simple decoding
This is mainly just one function to call:
```c++
#include "src/wp2/base.h"
#include "src/wp2/decode.h"
const std::string data = ...
WP2::ArgbBuffer output_buffer;
WP2Status status = WP2::Decode(data, &output_buffer);
```
If the file is a WebP 2 animation, `output_buffer` will contain the first frame.
Please have a look at the file `src/wp2/decode.h` for further details.
#### Animation decoding
To decode all the frames of an animation, the more advanced `Decoder` API can be
used. See tests/test_decoder_api.cc for common use cases.
```c++
WP2::ArrayDecoder decoder(data, data_size);
uint32_t duration_ms;
while (decoder.ReadFrame(&duration_ms)) {
// A frame is ready. Use or copy its 'duration_ms' and 'decoder.GetPixels()'.
}
if (decoder.GetStatus() != WP2_STATUS_OK) { /* error */ }
```
#### Incremental decoding
If you want to start decoding before all the data is available, you can use the
`Decoder` API. Use an `WP2::ArrayDecoder` if the data is stored in an array that
progressively gets larger, with old bytes still available as new bytes come in.
Use a `WP2::StreamDecoder` if data is streamed, with old bytes no longer
available as new bytes come in. You can also subclass `WP2::CustomDecoder` to
fit your needs. See tests/test_decoder_api.cc for common use cases.
Below is an example with `WP2::StreamDecoder`.
```c++
WP2::StreamDecoder decoder;
while (/*additional data is available in some 'new_data[]' buffer*/) {
decoder.AppendInput(new_data, new_data_size);
while (decoder.ReadFrame()) {
// ReadFrame() returns true when an entire frame is available
// (a still image is considered as a single-frame animation).
// The canvas is stored in GetPixels() till the next call to ReadFrame().
// Use the whole GetPixels().
}
if (decoder.Failed()) break;
if (!decoder.GetDecodedArea().IsEmpty()) {
// Use the partially GetDecodedArea() of GetPixels().
}
}
if (decoder.GetStatus() != WP2_STATUS_OK) { /* error */ }
```
## Development
### Bugs
Please report all bugs to the issue tracker: https://bugs.chromium.org/p/webp2
### Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to submit patches.
One of the easiest ways to contribute is to report cases with compression
artifacts or surprising output size. These 'bad cases' are very useful to help
improve the compression library!
Please use the [tracker](https://bugs.chromium.org/p/webp2) to report such
issues, making sure to include:
* the version or revision used (using "`git rev-parse HEAD`" for instance)
* the version of the compiler used (if you compiled your own version)
* the problematic source image (will only be used for debugging and discarded
afterward!)
* the *exact* command line to use to reproduce the issue
* the output file, if applicable.
### Coding conventions and style
* Code must follow the
[Google C++ style guide](https://google.github.io/styleguide/cppguide.html)
unless local style differs.
* `const` is used for variables everywhere possible, including for pointers in
function declarations. Input parameters use const references.
```c++
void DoSomething(const Type1& const input, Type2* const out)
```
* Do not use C++ exceptions.
* Do not use std containers in the main library, e.g. no std::vector/set/map
(but they can be used in tests). For vectors, use WP2::Vector instead.
* Use uint32_t for sizes, width, height, loop indices, etc.
* Most functions should return a WP2Status
### File layout
* **CMakeLists.txt** and **cmake/\*** are used to build the project with
CMake.
* **doc/\*** contains the container and format specifications.
* **examples/\*** and **extras/\*** contain executables and tools.
* **cwp2.cc** and **dwp2.cc** are the main entry points to the library.
* **imageio/\*** contains image-reading and image-writing functions. Several
formats are handled such as PNG, WebP etc.
* **presubmit/\*** contains the continuous integration testing scripts (run by
[Jenkins](https://build.webmproject.org/jenkins/view/webp/job/libwebp2__test/)
when a patch of
[libwebp2](https://chromium.googlesource.com/codecs/libwebp2) is sent to
[Gerrit](https://chromium-review.googlesource.com/q/project:codecs%252Flibwebp2)).
* **swig/\*** contains the [SWIG](http://www.swig.org/) wrapper for Python and
**wp2_js/\*** contains the Javascript interface.
* **src/\*** contains the core library.
* **src/wp2/\*** contains the public API headers. Consult **encode.h** and
**decode.h** to interact with libwebp2.
* **src/enc/\*** contains the encoder-related sources.
* **src/enc/main_enc.cc** contains the encoder entry point.
* **src/dec/\*** contains the decoder-related sources.
* **src/dec/main_dec.cc** contains the still image decoding entry
functions.
* **src/dec/incr/decoder_stages.cc** contains the incremental and
animation **Decoder** class implementation.
* **src/common/\*** and **src/utils/\*** contain the files that are used
by both encode and decode functions.
* **src/common/header_enc_dec.h** is used to code image-wise
**BitstreamFeatures**.
* **src/common/global_params.h** contains the frame-wise
**GlobalParams**.
* **src/enc/tile_enc.h** and **src/dec/tile_dec.h** contain the
tile-wise coding functions.
* **src/dsp/\*** contains the low-level, platform-optimized algorithms.
* **tests/\*** contains the tests:
* **test_simple_enc_dec.cc** and **test_decoder_api.cc** are simple
examples to start with.
* **tests/include/\*** and **tests/tools/\*** contain the helper headers
and tools for testing.
* **tests/testdata/\*** contains some sample images used by the tests.
* **tests/bench/\*** contains the performance-measuring tools. Requires
[Google Benchmark](https://github.com/google/benchmark).
* **tests/fuzz/\*** contains the fuzzing tools. See
[OSS-Fuzz](https://github.com/google/oss-fuzz) for more information.
### Testing
#### Dependencies
The following dependencies are needed for some tests to pass:
```shell
$ sudo apt install libpng-dev libjpeg-dev libtiff-dev libgif-dev libwebp-dev
```
#### Google Test Integration
Most tests have a dependency on the GoogleTest library. To run them all, the
`WP2_ENABLE_TESTS` cmake variable must be turned on at cmake generation time (ON
by default), and the `GTEST_SOURCE_DIR` cmake variable must be set to the path
of the Google Test source directory (../googletest by default):
```shell
$ git clone https://github.com/google/googletest.git path/to/googletest
$ cmake path/to/wp2 -DWP2_ENABLE_TESTS=ON -DGTEST_SOURCE_DIR=path/to/googletest
```
Alternatively you may install the library instead. CMake should then be able to
find it automatically afterwards:
```shell
$ sudo apt install libgtest-dev
```
#### Running the tests
To run the tests you can use ctest after the build:
```shell
$ make
$ ctest
```
Or run them one by one from the `tests` source folder, so that the `testdata`
folder is accessible:
```shell
$ cd ../tests
$ ../build/tests/test_simple_encode
```
## Discussion
Email: webp-discuss@googlegroups.com
Web: https://groups.google.com/a/webmproject.org/g/webp-discuss