All formats

libwebp

LanguageC (usable from C++)
LicenseBSD-3-Clause, with a separate patent grant
Repositorychromium.googlesource.com/webm/libwebp (mirror: github.com/webmproject/libwebp)
DocumentationAPI documentation, Container API
Depends onnothing (libjpeg, libpng, libtiff, giflib only for the command-line tools)
Read / writeyes / yes, lossy, lossless, alpha, animation, ICC / Exif / XMP

libwebp is the reference implementation of WebP, maintained by Google’s WebM project. Browsers, Android, ImageMagick, libvips, Pillow, GIMP and most other programs use it. It’s fast (SIMD for SSE2, SSE4.1, NEON, MSA) and supports every feature of the format.

The project builds several libraries:

Library Header Purpose
libwebp webp/decode.h, webp/encode.h decode and encode one still image
libsharpyuv sharpyuv/sharpyuv.h better RGB to YUV conversion, used by libwebp
libwebpdemux webp/demux.h read chunks, metadata and animation frames (WebPAnimDecoder)
libwebpmux webp/mux.h add or change chunks, build animations (WebPAnimEncoder)

Installation#

Shell
# Debian / Ubuntu
sudo apt install libwebp-dev
# Fedora
sudo dnf install libwebp-devel
# macOS
brew install webp
# Windows (vcpkg)
vcpkg install libwebp

With CMake (libwebp installs a CMake config):

cmake
find_package(WebP CONFIG REQUIRED)
target_link_libraries(myapp PRIVATE WebP::webp WebP::webpdemux)

Without CMake: pkg-config --cflags --libs libwebp libwebpdemux.

Basic usage: decode and encode#

The simple API decodes a whole file from memory into RGBA and encodes RGBA back to lossy WebP:

C
#include <stdio.h>
#include <stdlib.h>
#include <webp/decode.h>
#include <webp/encode.h>

static uint8_t *read_file(const char *path, size_t *size) {
    FILE *f = fopen(path, "rb");
    if (!f) return NULL;
    fseek(f, 0, SEEK_END);
    *size = (size_t)ftell(f);
    fseek(f, 0, SEEK_SET);
    uint8_t *data = malloc(*size);
    if (data && fread(data, 1, *size, f) != *size) { free(data); data = NULL; }
    fclose(f);
    return data;
}

int main(void) {
    size_t size;
    uint8_t *data = read_file("in.webp", &size);
    if (!data) return 1;

    int width, height;
    uint8_t *rgba = WebPDecodeRGBA(data, size, &width, &height);
    free(data);
    if (!rgba) { fprintf(stderr, "not a valid WebP file\n"); return 1; }
    printf("%d x %d\n", width, height);

    uint8_t *out = NULL;
    size_t out_size = WebPEncodeRGBA(rgba, width, height, width * 4 /*stride*/, 80.0f /*quality*/, &out);
    WebPFree(rgba);
    if (out_size == 0) { fprintf(stderr, "encode failed\n"); return 1; }

    FILE *f = fopen("out.webp", "wb");
    if (f) { fwrite(out, 1, out_size, f); fclose(f); }
    WebPFree(out);
    return 0;
}

Other decode functions return other layouts: WebPDecodeRGB, WebPDecodeBGRA, WebPDecodeARGB, WebPDecodeYUV. Free every buffer libwebp returns with WebPFree.

How to get WebP width, height and features without decoding#

WebPGetFeatures parses only the headers:

C
WebPBitstreamFeatures features;
if (WebPGetFeatures(data, size, &features) == VP8_STATUS_OK) {
    printf("%d x %d, alpha: %d, animated: %d, format: %s\n",
           features.width, features.height, features.has_alpha, features.has_animation,
           features.format == 1 ? "lossy" : features.format == 2 ? "lossless" : "mixed");
}

WebPGetInfo(data, size, &width, &height) is a shorter version that returns only the size. Both need just the first ~30 bytes of the file.

How to write a lossless WebP#

C
uint8_t *out = NULL;
size_t out_size = WebPEncodeLosslessRGBA(rgba, width, height, width * 4, &out);
// write out[0..out_size) to a file, then WebPFree(out)

How to set encoder options (method, sharp YUV, near-lossless)#

The advanced API exposes every cwebp option through WebPConfig:

C
#include <stdio.h>
#include <webp/encode.h>

// returns the encoded size, or 0 on error; the caller frees writer->mem with WebPMemoryWriterClear
size_t encode_advanced(const uint8_t *rgba, int width, int height, WebPMemoryWriter *writer) {
    WebPConfig config;
    if (!WebPConfigPreset(&config, WEBP_PRESET_PHOTO, 80.0f)) return 0;  // or _PICTURE, _DRAWING, _ICON, _TEXT
    config.method = 6;          // 0 = fast .. 6 = slowest, smallest
    config.use_sharp_yuv = 1;   // sharper color edges
    // lossless instead: WebPConfigLosslessPreset(&config, 9);
    if (!WebPValidateConfig(&config)) return 0;

    WebPPicture pic;
    if (!WebPPictureInit(&pic)) return 0;
    pic.width = width;
    pic.height = height;
    pic.use_argb = config.lossless;
    if (!WebPPictureImportRGBA(&pic, rgba, width * 4)) return 0;

    WebPMemoryWriterInit(writer);
    pic.writer = WebPMemoryWrite;
    pic.custom_ptr = writer;
    int ok = WebPEncode(&config, &pic);
    if (!ok) fprintf(stderr, "encode error %d\n", pic.error_code);
    WebPPictureFree(&pic);
    return ok ? writer->size : 0;
}

How to decode an animated WebP#

WebPAnimDecoder (in libwebpdemux) composes the frames on the canvas and returns full RGBA frames with timestamps:

C
#include <stdio.h>
#include <webp/demux.h>

int dump_frames(const uint8_t *data, size_t size) {
    WebPAnimDecoderOptions opts;
    if (!WebPAnimDecoderOptionsInit(&opts)) return 1;
    opts.color_mode = MODE_RGBA;
    opts.use_threads = 1;

    WebPData webp_data = { data, size };
    WebPAnimDecoder *dec = WebPAnimDecoderNew(&webp_data, &opts);
    if (!dec) return 1;

    WebPAnimInfo info;
    WebPAnimDecoderGetInfo(dec, &info);
    printf("canvas %u x %u, %u frames, loop %u\n",
           info.canvas_width, info.canvas_height, info.frame_count, info.loop_count);

    while (WebPAnimDecoderHasMoreFrames(dec)) {
        uint8_t *frame;  // canvas_width * canvas_height * 4 bytes, owned by the decoder
        int timestamp;   // end time of this frame in ms
        if (!WebPAnimDecoderGetNext(dec, &frame, &timestamp)) break;
        printf("frame ends at %d ms\n", timestamp);
    }
    WebPAnimDecoderDelete(dec);
    return 0;
}

To create animations use WebPAnimEncoderNew, WebPAnimEncoderAdd per frame and WebPAnimEncoderAssemble from webp/mux.h.

How to read ICC, Exif and XMP metadata#

C
#include <webp/demux.h>

WebPData webp_data = { data, size };
WebPDemuxer *demux = WebPDemux(&webp_data);
if (demux) {
    uint32_t flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS);
    WebPChunkIterator it;
    if ((flags & EXIF_FLAG) && WebPDemuxGetChunk(demux, "EXIF", 1, &it)) {
        printf("Exif: %zu bytes\n", it.chunk.size);  // it.chunk.bytes points to the data
        WebPDemuxReleaseChunkIterator(&it);
    }
    if ((flags & ICCP_FLAG) && WebPDemuxGetChunk(demux, "ICCP", 1, &it)) {
        printf("ICC profile: %zu bytes\n", it.chunk.size);
        WebPDemuxReleaseChunkIterator(&it);
    }
    WebPDemuxDelete(demux);
}

WebPEncode doesn’t write metadata. Add chunks to an encoded file with WebPMuxSetChunk from webp/mux.h (or the webpmux tool).

Tips#