Documentación de la API de WebP

En esta sección, se describe la API para el codificador y el decodificador que se incluyen en la biblioteca WebP. Esta descripción de API pertenece a la versión 1.3.0.

Encabezados y bibliotecas

Cuando instales libwebp, se instalará un directorio llamado webp/ en la ubicación típica de tu plataforma. Por ejemplo, en las plataformas Unix, se copiarían los siguientes archivos de encabezado en /usr/local/include/webp/.

decode.h
encode.h
types.h

Las bibliotecas se encuentran en los directorios de bibliotecas habituales. Las bibliotecas estáticas y dinámicas se encuentran en /usr/local/lib/ en las plataformas Unix.

API de decodificación simple

Para comenzar a usar la API de decodificación, debes asegurarte de tener los archivos de biblioteca y encabezado instalados como se describió antes.

Incluye el encabezado de API de decodificación en tu código C/C++ de la siguiente manera:

#include "webp/decode.h"
int WebPGetInfo(const uint8_t* data, size_t data_size, int* width, int* height);

Esta función validará el encabezado de la imagen WebP y recuperará el ancho y la altura de la imagen. Los punteros *width y *height se pueden pasar NULL si se consideran irrelevantes.

Atributos de entrada

datos
Puntero a datos de imagen WebP
tamaño_datos
Este es el tamaño del bloque de memoria al que hace referencia data y que contiene los datos de imagen.

Resultado que se muestra

falso
Código de error que se muestra en (a) error(es) de formato.
true
El éxito se debe a *width y *height solo son válidos cuando la devolución se realiza de forma correcta.
ancho
Valor de número entero. El rango es de 1 a 16,383.
alto
Valor de número entero. El rango es de 1 a 16,383.
struct WebPBitstreamFeatures {
  int width;          // Width in pixels.
  int height;         // Height in pixels.
  int has_alpha;      // True if the bitstream contains an alpha channel.
  int has_animation;  // True if the bitstream is an animation.
  int format;         // 0 = undefined (/mixed), 1 = lossy, 2 = lossless
}

VP8StatusCode WebPGetFeatures(const uint8_t* data,
                              size_t data_size,
                              WebPBitstreamFeatures* features);

Esta función recuperará atributos del flujo de bits. La estructura *features se completa con la información que se recopila del flujo de bits:

Atributos de entrada

datos
Puntero a datos de imagen WebP
tamaño_datos
Este es el tamaño del bloque de memoria al que hace referencia data y que contiene los datos de imagen.

Resultado que se muestra

VP8_STATUS_OK
Cuando los elementos se recuperen correctamente.
VP8_STATUS_NOT_ENOUGH_DATA
Cuando se necesitan más datos para recuperar los atributos de los encabezados.

Valores de error VP8StatusCode adicionales en otros casos.

funciones
Puntero para la estructura WebPBitstreamFeatures.
uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size, int* width, int* height);
uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size, int* width, int* height);
uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size, int* width, int* height);
uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size, int* width, int* height);
uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size, int* width, int* height);

Estas funciones decodifican una imagen WebP a la que apunta data.

  • WebPDecodeRGBA muestra muestras de imágenes RGBA en orden [r0, g0, b0, a0, r1, g1, b1, a1, ...].
  • WebPDecodeARGB muestra muestras de imágenes ARGB en orden [a0, r0, g0, b0, a1, r1, g1, b1, ...].
  • WebPDecodeBGRA muestra muestras de imágenes de BGRA en orden [b0, g0, r0, a0, b1, g1, r1, a1, ...].
  • WebPDecodeRGB muestra muestras de imágenes RGB en orden [r0, g0, b0, r1, g1, b1, ...].
  • WebPDecodeBGR muestra muestras de imágenes BGR en orden [b0, g0, r0, b1, g1, r1, ...].

El código que llama a cualquiera de estas funciones debe borrar el búfer de datos (uint8_t*) que muestran estas funciones con WebPFree().

Atributos de entrada

datos
Puntero a datos de imagen WebP
tamaño_datos
Este es el tamaño del bloque de memoria al que hace referencia data y que contiene los datos de imagen
ancho
Valor de número entero. Actualmente, el rango está limitado de 1 a 16,383.
alto
Valor de número entero. El límite actualmente es de 1 a 16,383.

Resultado que se muestra

uint8_t*
Puntero para muestras de imágenes WebP decodificadas en orden lineal RGBA/ARGB/BGRA/RGB/BGR, respectivamente.
uint8_t* WebPDecodeRGBAInto(const uint8_t* data, size_t data_size,
                            uint8_t* output_buffer, int output_buffer_size, int output_stride);
uint8_t* WebPDecodeARGBInto(const uint8_t* data, size_t data_size,
                            uint8_t* output_buffer, int output_buffer_size, int output_stride);
uint8_t* WebPDecodeBGRAInto(const uint8_t* data, size_t data_size,
                            uint8_t* output_buffer, int output_buffer_size, int output_stride);
uint8_t* WebPDecodeRGBInto(const uint8_t* data, size_t data_size,
                           uint8_t* output_buffer, int output_buffer_size, int output_stride);
uint8_t* WebPDecodeBGRInto(const uint8_t* data, size_t data_size,
                           uint8_t* output_buffer, int output_buffer_size, int output_stride);

Estas funciones son variantes de las anteriores y decodifican la imagen directamente en un búfer output_buffer asignado previamente. El almacenamiento máximo disponible en este búfer se indica mediante output_buffer_size. Si este almacenamiento no es suficiente (o se produjo un error), se muestra NULL. De lo contrario, se muestra output_buffer para mayor comodidad.

El parámetro output_stride especifica la distancia (en bytes) entre las líneas de análisis. Por lo tanto, se espera que el output_buffer_size sea al menos output_stride * picture - height.

Atributos de entrada

datos
Puntero a datos de imagen WebP
tamaño_datos
Este es el tamaño del bloque de memoria al que hace referencia data y que contiene los datos de imagen
tamaño_de_búfer_de_salida
Valor de número entero. Tamaño del búfer asignado
segmento_salida
Valor de número entero. Especifica la distancia entre las líneas de análisis.

Resultado que se muestra

búfer_de_salida
Puntero para la imagen WebP decodificada.
uint8_t*
output_buffer si la función se realiza correctamente; de lo contrario, NULL.

API de decodificación avanzada

La decodificación de WebP admite una API avanzada que proporciona la capacidad de recortar y ajustar la escala en el momento, algo de gran utilidad en entornos con memoria limitada, como los teléfonos celulares. Básicamente, el uso de memoria se escalará con el tamaño de salida, no con el de la entrada cuando solo se necesita una vista previa rápida o una parte ampliada de una imagen demasiado grande. Algunas CPU también se pueden ahorrar.

La decodificación de WebP tiene dos variantes: decodificación de imágenes completa y decodificación incremental en búferes de entrada pequeños. De manera opcional, los usuarios pueden proporcionar un búfer de memoria externo para decodificar la imagen. En la siguiente muestra de código, se explican los pasos para usar la API de decodificación avanzada.

Primero, necesitamos inicializar un objeto de configuración:

#include "webp/decode.h"

WebPDecoderConfig config;
CHECK(WebPInitDecoderConfig(&config));

// One can adjust some additional decoding options:
config.options.no_fancy_upsampling = 1;
config.options.use_scaling = 1;
config.options.scaled_width = scaledWidth();
config.options.scaled_height = scaledHeight();
// etc.

Las opciones de decodificación se recopilan dentro de la estructura WebPDecoderConfig:

struct WebPDecoderOptions {
  int bypass_filtering;             // if true, skip the in-loop filtering
  int no_fancy_upsampling;          // if true, use faster pointwise upsampler
  int use_cropping;                 // if true, cropping is applied first 
  int crop_left, crop_top;          // top-left position for cropping.
                                    // Will be snapped to even values.
  int crop_width, crop_height;      // dimension of the cropping area
  int use_scaling;                  // if true, scaling is applied afterward
  int scaled_width, scaled_height;  // final resolution
  int use_threads;                  // if true, use multi-threaded decoding
  int dithering_strength;           // dithering strength (0=Off, 100=full)
  int flip;                         // if true, flip output vertically
  int alpha_dithering_strength;     // alpha dithering strength in [0..100]
};

De forma opcional, las funciones de flujo de bits se pueden leer en config.input, en caso de que sea necesario conocerlas con anticipación. Por ejemplo, es útil saber si la foto tiene transparencia. Ten en cuenta que esto también analizará el encabezado del flujo de bits y, por lo tanto, es una buena manera de saber si este se parece a un WebP válido.

CHECK(WebPGetFeatures(data, data_size, &config.input) == VP8_STATUS_OK);

Luego, debemos configurar el búfer de memoria de decodificación en caso de que queremos suministrarlo directamente en lugar de depender del decodificador para su asignación. Solo necesitamos suministrar el puntero a la memoria, así como el tamaño total del búfer y el intervalo de líneas (distancia en bytes entre las líneas de análisis).

// Specify the desired output colorspace:
config.output.colorspace = MODE_BGRA;
// Have config.output point to an external buffer:
config.output.u.RGBA.rgba = (uint8_t*)memory_buffer;
config.output.u.RGBA.stride = scanline_stride;
config.output.u.RGBA.size = total_size_of_the_memory_buffer;
config.output.is_external_memory = 1;

La imagen está lista para decodificarse. Hay dos variantes posibles para decodificar la imagen. Para decodificar la imagen, sigue estos pasos:

CHECK(WebPDecode(data, data_size, &config) == VP8_STATUS_OK);

Como alternativa, podemos usar el método incremental para decodificar la imagen de forma progresiva a medida que los bytes nuevos estén disponibles:

WebPIDecoder* idec = WebPINewDecoder(&config.output);
CHECK(idec != NULL);
while (additional_data_is_available) {
  // ... (get additional data in some new_data[] buffer)
  VP8StatusCode status = WebPIAppend(idec, new_data, new_data_size);
  if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) {
    break;
  }
  // The above call decodes the current available buffer.
  // Part of the image can now be refreshed by calling
  // WebPIDecGetRGB()/WebPIDecGetYUVA() etc.
}
WebPIDelete(idec);  // the object doesn't own the image memory, so it can
                    // now be deleted. config.output memory is preserved.

La imagen decodificada ahora está en config.output (o, en su lugar, en config.output.u.RGBA) en este caso, ya que el espacio de color de salida solicitado era MODE_BGRA. La imagen se puede guardar, mostrar o procesar de alguna otra manera. Luego, solo necesitamos recuperar la memoria asignada en el objeto de configuración. Es seguro llamar a esta función incluso si la memoria es externa y no se asignó mediante WebPDecode():

WebPFreeDecBuffer(&config.output);

Con esta API, la imagen también se puede decodificar a los formatos YUV y YUVA, mediante MODE_YUV y MODE_YUVA, respectivamente. Este formato también se denomina Y'CbCr.

API de codificación simple

Se proporcionan algunas funciones muy simples para los arreglos de codificación de las muestras RGBA en los diseños más comunes. Se declaran en el encabezado webp/encode.h de la siguiente manera:

size_t WebPEncodeRGB(const uint8_t* rgb, int width, int height, int stride, float quality_factor, uint8_t** output);
size_t WebPEncodeBGR(const uint8_t* bgr, int width, int height, int stride, float quality_factor, uint8_t** output);
size_t WebPEncodeRGBA(const uint8_t* rgba, int width, int height, int stride, float quality_factor, uint8_t** output);
size_t WebPEncodeBGRA(const uint8_t* bgra, int width, int height, int stride, float quality_factor, uint8_t** output);

El factor de calidad quality_factor varía de 0 a 100 y controla la pérdida y la calidad durante la compresión. El valor 0 corresponde a los tamaños de salida bajos y de calidad baja, mientras que 100 es el tamaño de salida más alto y de calidad más alta. Cuando el proceso finaliza correctamente, los bytes comprimidos se ubican en el puntero *output, y se muestra el tamaño en bytes (de lo contrario, se muestra 0, en caso de error). El emisor debe llamar a WebPFree() en el puntero *output para reclamar memoria.

El arreglo de entrada debe ser un arreglo empaquetado de bytes (uno para cada canal, como se espera por el nombre de la función). stride corresponde a la cantidad de bytes necesarios para pasar de una fila a la siguiente. Por ejemplo, el diseño de BGRA es el siguiente:

Existen funciones equivalentes para la codificación sin pérdidas, con firmas:

size_t WebPEncodeLosslessRGB(const uint8_t* rgb, int width, int height, int stride, uint8_t** output);
size_t WebPEncodeLosslessBGR(const uint8_t* bgr, int width, int height, int stride, uint8_t** output);
size_t WebPEncodeLosslessRGBA(const uint8_t* rgba, int width, int height, int stride, uint8_t** output);
size_t WebPEncodeLosslessBGRA(const uint8_t* bgra, int width, int height, int stride, uint8_t** output);

Ten en cuenta que estas funciones, como las versiones con pérdida, usan la configuración predeterminada de la biblioteca. Sin pérdida, esto significa que la configuración "exacta" está inhabilitada. Los valores RGB en las áreas transparentes se modificarán para mejorar la compresión. Para evitar esto, usa WebPEncode() y establece WebPConfig::exact en 1.

API de codificación avanzada

De forma interna, el codificador incluye numerosos parámetros de codificación avanzada. Pueden ser útiles para equilibrar mejor la compensación entre la eficiencia de la compresión y el tiempo de procesamiento. Estos parámetros se recopilan dentro de la estructura WebPConfig. Los campos más usados de esta estructura son los siguientes:

struct WebPConfig {
  int lossless;           // Lossless encoding (0=lossy(default), 1=lossless).
  float quality;          // between 0 and 100. For lossy, 0 gives the smallest
                          // size and 100 the largest. For lossless, this
                          // parameter is the amount of effort put into the
                          // compression: 0 is the fastest but gives larger
                          // files compared to the slowest, but best, 100.
  int method;             // quality/speed trade-off (0=fast, 6=slower-better)

  WebPImageHint image_hint;  // Hint for image type (lossless only for now).

  // Parameters related to lossy compression only:
  int target_size;        // if non-zero, set the desired target size in bytes.
                          // Takes precedence over the 'compression' parameter.
  float target_PSNR;      // if non-zero, specifies the minimal distortion to
                          // try to achieve. Takes precedence over target_size.
  int segments;           // maximum number of segments to use, in [1..4]
  int sns_strength;       // Spatial Noise Shaping. 0=off, 100=maximum.
  int filter_strength;    // range: [0 = off .. 100 = strongest]
  int filter_sharpness;   // range: [0 = off .. 7 = least sharp]
  int filter_type;        // filtering type: 0 = simple, 1 = strong (only used
                          // if filter_strength > 0 or autofilter > 0)
  int autofilter;         // Auto adjust filter's strength [0 = off, 1 = on]
  int alpha_compression;  // Algorithm for encoding the alpha plane (0 = none,
                          // 1 = compressed with WebP lossless). Default is 1.
  int alpha_filtering;    // Predictive filtering method for alpha plane.
                          //  0: none, 1: fast, 2: best. Default if 1.
  int alpha_quality;      // Between 0 (smallest size) and 100 (lossless).
                          // Default is 100.
  int pass;               // number of entropy-analysis passes (in [1..10]).

  int show_compressed;    // if true, export the compressed picture back.
                          // In-loop filtering is not applied.
  int preprocessing;      // preprocessing filter (0=none, 1=segment-smooth)
  int partitions;         // log2(number of token partitions) in [0..3]
                          // Default is set to 0 for easier progressive decoding.
  int partition_limit;    // quality degradation allowed to fit the 512k limit on
                          // prediction modes coding (0: no degradation,
                          // 100: maximum possible degradation).
  int use_sharp_yuv;      // if needed, use sharp (and slow) RGB->YUV conversion
};

Ten en cuenta que se puede acceder a la mayoría de estos parámetros para la experimentación con la herramienta de línea de comandos de cwebp.

Las muestras de entrada deben unirse a una estructura WebPPicture. Esta estructura puede almacenar muestras de entrada en formato RGBA o YUVA, según el valor de la marca use_argb.

La estructura se organiza de la siguiente manera:

struct WebPPicture {
  int use_argb;              // To select between ARGB and YUVA input.

  // YUV input, recommended for lossy compression.
  // Used if use_argb = 0.
  WebPEncCSP colorspace;     // colorspace: should be YUVA420 or YUV420 for now (=Y'CbCr).
  int width, height;         // dimensions (less or equal to WEBP_MAX_DIMENSION)
  uint8_t *y, *u, *v;        // pointers to luma/chroma planes.
  int y_stride, uv_stride;   // luma/chroma strides.
  uint8_t* a;                // pointer to the alpha plane
  int a_stride;              // stride of the alpha plane

  // Alternate ARGB input, recommended for lossless compression.
  // Used if use_argb = 1.
  uint32_t* argb;            // Pointer to argb (32 bit) plane.
  int argb_stride;           // This is stride in pixels units, not bytes.

  // Byte-emission hook, to store compressed bytes as they are ready.
  WebPWriterFunction writer;  // can be NULL
  void* custom_ptr;           // can be used by the writer.

  // Error code for the latest error encountered during encoding
  WebPEncodingError error_code;
};

Esta estructura también tiene una función para emitir los bytes comprimidos a medida que estén disponibles. A continuación, se muestra un ejemplo con un escritor en la memoria. Otros escritores pueden almacenar datos directamente en un archivo (consulta examples/cwebp.c para ver un ejemplo).

El flujo general para codificar mediante la API avanzada se ve de la siguiente manera:

Primero, debemos establecer una configuración de codificación que contenga los parámetros de compresión. Ten en cuenta que se puede usar la misma configuración para comprimir varias imágenes diferentes después.

#include "webp/encode.h"

WebPConfig config;
if (!WebPConfigPreset(&config, WEBP_PRESET_PHOTO, quality_factor)) return 0;   // version error

// Add additional tuning:
config.sns_strength = 90;
config.filter_sharpness = 6;
config.alpha_quality = 90;
config_error = WebPValidateConfig(&config);  // will verify parameter ranges (always a good habit)

Luego, se debe hacer referencia a las muestras de entrada en un WebPPicture por referencia o copia. A continuación, se muestra un ejemplo en el que se asigna el búfer para almacenar las muestras. Sin embargo, se puede configurar con facilidad una “vista” a un arreglo de muestra ya asignado. Consulta la función WebPPictureView().

// Setup the input data, allocating a picture of width x height dimension
WebPPicture pic;
if (!WebPPictureInit(&pic)) return 0;  // version error
pic.width = width;
pic.height = height;
if (!WebPPictureAlloc(&pic)) return 0;   // memory error

// At this point, 'pic' has been initialized as a container, and can receive the YUVA or RGBA samples.
// Alternatively, one could use ready-made import functions like WebPPictureImportRGBA(), which will take
// care of memory allocation. In any case, past this point, one will have to call WebPPictureFree(&pic)
// to reclaim allocated memory.

Para emitir los bytes comprimidos, se llama a un hook cada vez que hay nuevos bytes disponibles. Aquí hay un ejemplo simple con el escritor de memoria declarado en webp/encode.h. Es probable que se necesite esta inicialización para que cada imagen se comprima:

// Set up a byte-writing method (write-to-memory, in this case):
WebPMemoryWriter writer;
WebPMemoryWriterInit(&writer);
pic.writer = WebPMemoryWrite;
pic.custom_ptr = &writer;

Ya estamos listos para comprimir las muestras de entrada (y liberar su memoria posteriormente):

int ok = WebPEncode(&config, &pic);
WebPPictureFree(&pic);   // Always free the memory associated with the input.
if (!ok) {
  printf("Encoding error: %d\n", pic.error_code);
} else {
  printf("Output size: %d\n", writer.size);
}

Para un uso más avanzado de la API y la estructura, se recomienda consultar la documentación disponible en el encabezado webp/encode.h. Leer el código de ejemplo examples/cwebp.c puede ser útil para descubrir parámetros menos usados.