6/19/2011

Compressing Images into WebP format using libwebp

libwebp is a software implementation of WebP, a lossy compression picture format which is introduced by Google. It provides a set of lean APIs that are easy to encode and decode WebP images. libwebp comes with two demo program: cwebp and dwebp. It could use cwebp to transform JPEG/ PNG images into WebP format.  And dwebp takes decoding jobs in contrast.
cwebp is a good example to study encoder part of libwebp. Here is a handy class to do the same job.


/*
    Copyright (C) 2011, W.L. Chuang 

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see .
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "SimpleWebpEncoder.hh"


SimpleWebpEncoder::SimpleWebpEncoder(unsigned int width, unsigned int height) :
    width(width), height(height)
{
    WebPPictureInit(&picture);
    picture.width  = width;
    picture.height = height;

    WebPConfigInit(&config);
    WebPConfigPreset(&config, WEBP_PRESET_PHOTO, 80);
}

SimpleWebpEncoder::~SimpleWebpEncoder()
{
    WebPPictureFree(&picture);
}

struct _context
{
    unsigned char* buffer;
    unsigned int   bufferWrote;
    unsigned int   bufferRemained;
};

static int writeWebP(const uint8_t* data, size_t data_size,
                     const WebPPicture* const picture);

int SimpleWebpEncoder::compress(void* video, unsigned char* bitstream,
                                unsigned int max, unsigned int* used)
{
    struct _context context;

    if (!WebPPictureImportRGB(&picture, (unsigned char*)video, 3 * width)) {
        fprintf(stderr, "Failed to convert RGB to YCbCr\n");
        return -1;
    }

    context.buffer         = bitstream;
    context.bufferWrote    = 0;
    context.bufferRemained = max;

    picture.writer = writeWebP;
    picture.custom_ptr = (void*)&context;

    if (!WebPEncode(&config, &picture)) {
        fprintf(stderr, "Error! Cannot encode picture as WebP\n");
        return -1;
    }

    *used = context.bufferWrote;

    return 0;
}

static int writeWebP(const uint8_t* data, size_t data_size,
                     const WebPPicture* const picture)
{
    struct _context* context = (struct _context*)picture->custom_ptr;

    if (data_size > context->bufferRemained) {
        fprintf(stderr, "Error! Bytestream buffer overflow\n");
        return 0;
    }

    memcpy(&context->buffer[context->bufferWrote], data, data_size);
    context->bufferWrote += data_size;

    return 1;
}

No comments:

Post a Comment