mirror of
https://github.com/bkaradzic/bimg.git
synced 2026-06-08 02:43:48 +00:00
5520 lines
157 KiB
C
5520 lines
157 KiB
C
/**
|
|
* @file simplewebp.h
|
|
* @author Google Inc., Miku AuahDark
|
|
* @brief A simple WebP decoder.
|
|
* @version 20251007
|
|
* See license at the bottom of the file.
|
|
*/
|
|
|
|
#ifndef _SIMPLE_WEBP_H_
|
|
#define _SIMPLE_WEBP_H_
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#if defined(__cplusplus) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901)
|
|
#include <stdint.h>
|
|
|
|
typedef uint8_t simplewebp_u8;
|
|
typedef int8_t simplewebp_i8;
|
|
typedef uint16_t simplewebp_u16;
|
|
typedef int16_t simplewebp_i16;
|
|
typedef uint32_t simplewebp_u32;
|
|
typedef int32_t simplewebp_i32;
|
|
|
|
#ifdef __cplusplus
|
|
typedef bool simplewebp_bool;
|
|
#else
|
|
#include <stdbool.h>
|
|
typedef _Bool simplewebp_bool;
|
|
#endif
|
|
|
|
#else /* Yeah this must be good enough */
|
|
typedef char simplewebp_bool;
|
|
typedef unsigned char simplewebp_u8;
|
|
typedef signed char simplewebp_i8;
|
|
typedef unsigned short simplewebp_u16;
|
|
typedef short simplewebp_i16;
|
|
typedef unsigned int simplewebp_u32;
|
|
typedef int simplewebp_i32;
|
|
#endif
|
|
|
|
#define SIMPLEWEBP_VERSION 20251007
|
|
|
|
/**
|
|
* @brief SimpleWebP "input stream".
|
|
*
|
|
* For user-defined "input stream", populate the struct accordingly.
|
|
* This struct can be allocated on stack, and is assumed so.
|
|
*/
|
|
typedef struct simplewebp_input
|
|
{
|
|
/**
|
|
* @brief Function-specific userdata.
|
|
*/
|
|
void *userdata;
|
|
|
|
/**
|
|
* @brief Function to close **and** deallocate `userdata`.
|
|
* @param userdata Function-specific userdata.
|
|
*/
|
|
void (*close)(void *userdata);
|
|
|
|
/**
|
|
* @brief Function to read from "input stream"
|
|
* @param size Amount of bytes to read.
|
|
* @param dest Output buffer.
|
|
* @param userdata Function-specific userdata.
|
|
* @return Amount of bytes read.
|
|
*/
|
|
size_t (*read)(size_t size, void *dest, void *userdata);
|
|
|
|
/**
|
|
* @brief Function to seek "input stream". Stream must support seeking!
|
|
* @param pos New position of the stream, based on the beginning of the file.
|
|
* @param userdata Function-specific userdata.
|
|
* @return Non-zero on success, zero on failure.
|
|
*/
|
|
simplewebp_bool (*seek)(size_t pos, void *userdata);
|
|
|
|
/**
|
|
* @brief Function to get current "input stream" position. Stream must support this!
|
|
* @return Stream position relative to the beginning.
|
|
*/
|
|
size_t (*tell)(void *userdata);
|
|
} simplewebp_input;
|
|
|
|
/**
|
|
* @brief SimpleWebP allocator structure.
|
|
*
|
|
* SimpleWebP functions that needs an allocation need to pass this structure.
|
|
* This struct can be allocated on stack.
|
|
*/
|
|
typedef struct simplewebp_allocator
|
|
{
|
|
/**
|
|
* @brief Allocate block of memory.
|
|
* @param userdata Allocator-specific data.
|
|
* @param size Amount of bytes to allocate.
|
|
* @return Pointer to tbe memory block, or `NULL` on failure.
|
|
*/
|
|
void *(*alloc)(void *userdata, size_t size);
|
|
|
|
/**
|
|
* @brief Free allocated memory.
|
|
* @param userdata Allocator-specific data.
|
|
* @param mem Valid pointer to the memory allocated by `alloc` function.
|
|
* @note Passing `NULL` is undefined behavior, although most implementation treat it as no-op.
|
|
*/
|
|
void (*free)(void *userdata, void *mem);
|
|
|
|
/**
|
|
* @brief Allocator-specific data.
|
|
*
|
|
* If your allocator is stateless, simply pass `NULL`.
|
|
*/
|
|
void *userdata;
|
|
} simplewebp_allocator;
|
|
|
|
/**
|
|
* @brief SimpleWebP opaque handle.
|
|
*/
|
|
typedef struct simplewebp simplewebp;
|
|
|
|
typedef enum simplewebp_error
|
|
{
|
|
/** No error */
|
|
SIMPLEWEBP_NO_ERROR = 0,
|
|
/** Failed to allocate memory */
|
|
SIMPLEWEBP_ALLOC_ERROR,
|
|
/** Input read error (such as EOF) */
|
|
SIMPLEWEBP_IO_ERROR,
|
|
/** Not a WebP image */
|
|
SIMPLEWEBP_NOT_WEBP_ERROR,
|
|
/** WebP image corrupt */
|
|
SIMPLEWEBP_CORRUPT_ERROR,
|
|
/** WebP image unsupported */
|
|
SIMPLEWEBP_UNSUPPORTED_ERROR,
|
|
/** WebP image is lossless */
|
|
SIMPLEWEBP_IS_LOSSLESS_ERROR
|
|
} simplewebp_error;
|
|
|
|
/**
|
|
* @brief Get runtime SimpleWebP version.
|
|
* In most cases, this should be equivalent to `SIMPLEWEBP_VERSION`
|
|
*
|
|
* @return SimpleWebP numeric version.
|
|
*/
|
|
size_t simplewebp_version(void);
|
|
/**
|
|
* @brief Get error message associated by SimpleWebP error code.
|
|
*
|
|
* @param error Error code.
|
|
* @return Error message as null-terminated string.
|
|
*/
|
|
const char *simplewebp_get_error_text(simplewebp_error error);
|
|
|
|
/**
|
|
* @brief Initialize `simplewebp_input` structure to load from memory.
|
|
*
|
|
* @param data Pointer to the WebP-encoded image in memory.
|
|
* @param size Size of `data` in bytes.
|
|
* @param out Destination structure.
|
|
* @param allocator Allocator structure, or `NULL` to use C default.
|
|
* @return Error codes.
|
|
*/
|
|
simplewebp_error simplewebp_input_from_memory(void *data, size_t size, simplewebp_input *out, const simplewebp_allocator *allocator);
|
|
/**
|
|
* @brief Close `simplewebp_input`, freeing the `userdata` and setting its `userdata` to `NULL`.
|
|
* @param input Pointer to the `simplewebp_input` structure.
|
|
* @note Application should not use the same `simplewebp_input` unless re-initialized again.
|
|
*/
|
|
void simplewebp_close_input(simplewebp_input *input);
|
|
|
|
/**
|
|
* @brief Load a WebP image.
|
|
*
|
|
* @param input Pointer to the `simplewebp_input` structure. This function will take the ownership of the `simplewebp_input`.
|
|
* @param allocator Allocator structure, or `NULL` to use C default.
|
|
* @param out Pointer to the `simplewebp` opaque handle.
|
|
* @return Error codes.
|
|
*/
|
|
simplewebp_error simplewebp_load(simplewebp_input *input, const simplewebp_allocator *allocator, simplewebp **out);
|
|
|
|
/**
|
|
* @brief Load a WebP image from memory.
|
|
*
|
|
* @param data Pointer to the WebP-encoded image in memory.
|
|
* @param size Size of `data` in bytes.
|
|
* @param allocator Allocator structure, or `NULL` to use C default.
|
|
* @param out Pointer to the `simplewebp` opaque handle.
|
|
* @return Error codes.
|
|
*/
|
|
simplewebp_error simplewebp_load_from_memory(void *data, size_t size, const simplewebp_allocator *allocator, simplewebp **out);
|
|
|
|
/**
|
|
* @brief Frees and unload associated memory and closes the "input stream".
|
|
* @param simplewebp `simplewebp` opaque handle.
|
|
*/
|
|
void simplewebp_unload(simplewebp *simplewebp);
|
|
|
|
/**
|
|
* @brief Get WebP image dimensions.
|
|
* @param simplewebp `simplewebp` opaque handle.
|
|
* @param width Where to store the image width.
|
|
* @param height Where to store the image height.
|
|
*/
|
|
void simplewebp_get_dimensions(simplewebp *simplewebp, size_t *width, size_t *height);
|
|
|
|
/**
|
|
* @brief Check if the WebP image is lossless or lossy.
|
|
* @param simplewebp `simplewebp` opaque handle.
|
|
* @return 1 if lossless, 0 if lossy.
|
|
*/
|
|
simplewebp_bool simplewebp_is_lossless(simplewebp *simplewebp);
|
|
|
|
/**
|
|
* @brief Decode WebP image to raw RGBA8 pixels data.
|
|
* @param simplewebp `simplewebp` opaque handle.
|
|
* @param buffer Block of memory with size of `width * height * 4` bytes. This is where the RGBA is stored.
|
|
* @param settings Ignored. Set this to `NULL`.
|
|
* @return Error codes.
|
|
*/
|
|
simplewebp_error simplewebp_decode(simplewebp *simplewebp, void *buffer, void *settings);
|
|
|
|
/**
|
|
* @brief Decode WebP image to raw planar YUVA420 pixels data. Can only be used on lossy WebP image.
|
|
* @param simplewebp `simplewebp` opaque handle.
|
|
* @param y_buffer Block of memory with size of `width * height` bytes.
|
|
* @param u_buffer Block of memory with size of `((width + 1) / 2) * ((height + 1) / 2)` bytes.
|
|
* @param v_buffer Block of memory with size of `((width + 1) / 2) * ((height + 1) / 2)` bytes.
|
|
* @param a_buffer Block of memory with size of `width * height` bytes.
|
|
* @param settings Ignored. Set this to `NULL`.
|
|
* @return simplewebp_error Error codes.
|
|
*/
|
|
simplewebp_error simplewebp_decode_yuva(simplewebp *simplewebp, void *y_buffer, void *u_buffer, void *v_buffer, void *a_buffer, void *settings);
|
|
|
|
#ifndef SIMPLEWEBP_DISABLE_STDIO
|
|
#include <stdio.h>
|
|
|
|
/**
|
|
* @brief Initialize `simplewebp_input` structure to load from `FILE*`.
|
|
*
|
|
* @param file C stdio `FILE*`.
|
|
* @param out Destination structure.
|
|
* @return Error codes.
|
|
*/
|
|
simplewebp_error simplewebp_input_from_file(FILE *file, simplewebp_input *out);
|
|
|
|
/**
|
|
* @brief Initialize `simplewebp_input` structure to load from file path using `fopen`.
|
|
*
|
|
* @param filename Path to file.
|
|
* @param out Destination structure.
|
|
* @return Error codes.
|
|
*/
|
|
simplewebp_error simplewebp_input_from_filename(const char *filename, simplewebp_input *out);
|
|
|
|
/**
|
|
* @brief Load a WebP image from `FILE*`.
|
|
*
|
|
* @param file C stdio `FILE*`.
|
|
* @param allocator Allocator structure, or `NULL` to use C default.
|
|
* @param out Pointer to the `simplewebp` opaque handle.
|
|
* @return Error codes.
|
|
*/
|
|
simplewebp_error simplewebp_load_from_file(FILE *file, const simplewebp_allocator *allocator, simplewebp **out);
|
|
|
|
/**
|
|
* @brief Load a WebP image from file path using `fopen`.
|
|
*
|
|
* @param filename Path to file.
|
|
* @param allocator Allocator structure, or `NULL` to use C default.
|
|
* @param out Pointer to the `simplewebp` opaque handle.
|
|
* @return Error codes.
|
|
*/
|
|
simplewebp_error simplewebp_load_from_filename(const char *filename, const simplewebp_allocator *allocator, simplewebp **out);
|
|
#endif /* SIMPLEWEBP_DISABLE_STDIO */
|
|
|
|
|
|
#ifdef __cplusplus
|
|
} /* extern "C" */
|
|
#endif
|
|
|
|
#endif /* _SIMPLE_WEBP_H_ */
|
|
|
|
#ifdef SIMPLEWEBP_IMPLEMENTATION
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
struct swebp__picture_header
|
|
{
|
|
simplewebp_u16 width, height;
|
|
simplewebp_u8 xscale, yscale, colorspace, clamp_type;
|
|
};
|
|
|
|
struct swebp__finfo
|
|
{
|
|
simplewebp_u8 limit, ilevel, inner, hev_thresh;
|
|
};
|
|
|
|
struct swebp__topsmp
|
|
{
|
|
simplewebp_u8 y[16], u[8], v[8];
|
|
};
|
|
|
|
struct swebp__mblock
|
|
{
|
|
simplewebp_u8 nz, nz_dc;
|
|
};
|
|
|
|
struct swebp__mblockdata
|
|
{
|
|
simplewebp_i16 coeffs[384];
|
|
simplewebp_u32 nonzero_y, nonzero_uv;
|
|
simplewebp_u8 imodes[16], is_i4x4, uvmode, dither, skip, segment;
|
|
};
|
|
|
|
typedef simplewebp_u8 swebp__probarray[11];
|
|
|
|
struct swebp__bandprobas
|
|
{
|
|
swebp__probarray probas[3];
|
|
};
|
|
|
|
struct swebp__proba
|
|
{
|
|
simplewebp_u8 segments[3];
|
|
struct swebp__bandprobas bands[4][8];
|
|
const struct swebp__bandprobas *bands_ptr[4][17];
|
|
};
|
|
|
|
struct swebp__frame_header
|
|
{
|
|
simplewebp_u8 key_frame, profile, show;
|
|
simplewebp_u32 partition_length;
|
|
};
|
|
|
|
struct swebp__filter_header
|
|
{
|
|
simplewebp_u8 simple, level, sharpness, use_lf_delta;
|
|
simplewebp_i32 ref_lf_delta[4], mode_lf_delta[4];
|
|
};
|
|
|
|
struct swebp__segment_header
|
|
{
|
|
simplewebp_u8 use_segment, update_map, absolute_delta;
|
|
simplewebp_i8 quantizer[4], filter_strength[4];
|
|
};
|
|
|
|
/* Bit reader and boolean decoder */
|
|
struct swebp__bdec
|
|
{
|
|
const simplewebp_u8 *buf, *buf_end, *buf_max;
|
|
simplewebp_u32 value;
|
|
simplewebp_u8 range, eof;
|
|
simplewebp_i8 bits;
|
|
};
|
|
|
|
typedef simplewebp_i32 swebp__quant_t[2];
|
|
struct swebp__quantmat
|
|
{
|
|
swebp__quant_t y1_mat, y2_mat, uv_mat;
|
|
simplewebp_i32 uv_quant, dither;
|
|
};
|
|
|
|
struct swebp__alpha
|
|
{
|
|
simplewebp_u8 filter_method;
|
|
simplewebp_bool is_lossless_compressed;
|
|
};
|
|
|
|
struct swebp__vp8
|
|
{
|
|
simplewebp_u8 ready;
|
|
|
|
struct swebp__bdec br;
|
|
struct swebp__frame_header frame_header;
|
|
struct swebp__picture_header picture_header;
|
|
struct swebp__filter_header filter_header;
|
|
struct swebp__segment_header segment_header;
|
|
|
|
simplewebp_i32 mb_w, mb_h;
|
|
simplewebp_i32 tl_mb_x, tl_mb_y;
|
|
simplewebp_i32 br_mb_x, br_mb_y;
|
|
|
|
simplewebp_u32 nparts_minus_1;
|
|
struct swebp__bdec parts[8];
|
|
|
|
struct swebp__quantmat dqm[4];
|
|
|
|
struct swebp__proba proba;
|
|
simplewebp_u8 use_skip_proba, skip_proba;
|
|
|
|
simplewebp_u8 *intra_t, intra_l[4];
|
|
|
|
struct swebp__topsmp *yuv_t;
|
|
|
|
struct swebp__mblock *mb_info;
|
|
struct swebp__finfo *f_info;
|
|
simplewebp_u8 *yuv_b;
|
|
|
|
|
|
simplewebp_u8 *cache_y, *cache_u, *cache_v;
|
|
simplewebp_i32 cache_y_stride, cache_uv_stride;
|
|
|
|
|
|
simplewebp_u8* mem;
|
|
size_t mem_size;
|
|
|
|
simplewebp_i32 mb_x, mb_y;
|
|
struct swebp__mblockdata *mb_data;
|
|
|
|
simplewebp_i8 filter_type;
|
|
struct swebp__finfo fstrengths[4][2];
|
|
|
|
simplewebp_u8 *alpha_plane;
|
|
};
|
|
|
|
struct swebp__vp8l_bdec
|
|
{
|
|
simplewebp_u8 *buf;
|
|
size_t len, bit_pos;
|
|
simplewebp_u8 eos;
|
|
};
|
|
|
|
struct swebp__vp8l_decoder
|
|
{
|
|
simplewebp_u32 width, height;
|
|
simplewebp_bool has_alpha;
|
|
};
|
|
|
|
union swebp__decoder_list
|
|
{
|
|
struct swebp__vp8 vp8;
|
|
struct swebp__vp8l_decoder vp8l;
|
|
};
|
|
|
|
struct swebp__yuvdst
|
|
{
|
|
simplewebp_u8 *y, *u, *v, *a;
|
|
};
|
|
|
|
struct swebp__pixel
|
|
{
|
|
simplewebp_u8 r, g, b, a;
|
|
};
|
|
|
|
struct swebp__chroma
|
|
{
|
|
simplewebp_u8 u, v;
|
|
};
|
|
|
|
struct simplewebp
|
|
{
|
|
simplewebp_input input, riff_input, vp8_input, vp8l_input, alph_input;
|
|
simplewebp_allocator allocator;
|
|
struct swebp__alpha alpha_decoder;
|
|
|
|
simplewebp_u8 webp_type; /* Simple lossy (0), Lossless (1) */
|
|
union swebp__decoder_list decoder;
|
|
};
|
|
|
|
struct simplewebp_memoryinput_data
|
|
{
|
|
simplewebp_allocator allocator;
|
|
void *data;
|
|
size_t size, pos;
|
|
};
|
|
|
|
static void *swebp__malloc(void *_unused, size_t size)
|
|
{
|
|
return malloc(size);
|
|
}
|
|
|
|
static void swebp__free(void *_unused, void *mem)
|
|
{
|
|
free(mem);
|
|
}
|
|
|
|
static void *swebp__alloc(simplewebp *simplewebp, size_t size)
|
|
{
|
|
return simplewebp->allocator.alloc(simplewebp->allocator.userdata, size);
|
|
}
|
|
|
|
static void swebp__dealloc(simplewebp *simplewebp, void *ptr)
|
|
{
|
|
if (ptr)
|
|
simplewebp->allocator.free(simplewebp->allocator.userdata, ptr);
|
|
}
|
|
|
|
static simplewebp_allocator swebp__default_allocator = {swebp__malloc, swebp__free, NULL};
|
|
|
|
size_t simplewebp_version(void)
|
|
{
|
|
return SIMPLEWEBP_VERSION;
|
|
}
|
|
|
|
const char *simplewebp_get_error_text(simplewebp_error error)
|
|
{
|
|
switch (error)
|
|
{
|
|
case SIMPLEWEBP_NO_ERROR:
|
|
return "No error";
|
|
case SIMPLEWEBP_ALLOC_ERROR:
|
|
return "Failed to allocate memory";
|
|
case SIMPLEWEBP_IO_ERROR:
|
|
return "Input read error (such as EOF)";
|
|
case SIMPLEWEBP_NOT_WEBP_ERROR:
|
|
return "Not a WebP image";
|
|
case SIMPLEWEBP_CORRUPT_ERROR:
|
|
return "WebP image corrupt";
|
|
case SIMPLEWEBP_UNSUPPORTED_ERROR:
|
|
return "WebP image unsupported";
|
|
case SIMPLEWEBP_IS_LOSSLESS_ERROR:
|
|
return "WebP image is lossless";
|
|
default:
|
|
return "Unknown error";
|
|
}
|
|
}
|
|
|
|
static size_t swebp__memoryinput_read(size_t size, void *dest, void *userdata)
|
|
{
|
|
struct simplewebp_memoryinput_data *input_data;
|
|
size_t nextpos, readed;
|
|
|
|
input_data = (struct simplewebp_memoryinput_data *) userdata;
|
|
nextpos = input_data->pos + size;
|
|
|
|
if (nextpos >= input_data->size)
|
|
{
|
|
readed = input_data->size - input_data->pos;
|
|
nextpos = input_data->size;
|
|
}
|
|
else
|
|
readed = size;
|
|
|
|
if (readed > 0)
|
|
{
|
|
memcpy(dest, ((char *) input_data->data) + input_data->pos, readed);
|
|
input_data->pos = nextpos;
|
|
}
|
|
|
|
return readed;
|
|
}
|
|
|
|
static simplewebp_bool swebp__memoryinput_seek(size_t pos, void *userdata)
|
|
{
|
|
struct simplewebp_memoryinput_data *input_data = (struct simplewebp_memoryinput_data *) userdata;
|
|
|
|
if (pos >= input_data->size)
|
|
input_data->pos = input_data->size;
|
|
else
|
|
input_data->pos = pos;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void swebp__memoryinput_close(void *userdata)
|
|
{
|
|
struct simplewebp_memoryinput_data *input_data = (struct simplewebp_memoryinput_data *) userdata;
|
|
input_data->allocator.free(input_data->allocator.userdata, input_data);
|
|
}
|
|
|
|
static size_t swebp__memoryinput_tell(void *userdata)
|
|
{
|
|
struct simplewebp_memoryinput_data *input_data = (struct simplewebp_memoryinput_data *) userdata;
|
|
return input_data->pos;
|
|
}
|
|
|
|
simplewebp_error simplewebp_input_from_memory(void *data, size_t size, simplewebp_input *out, const simplewebp_allocator *allocator)
|
|
{
|
|
struct simplewebp_memoryinput_data *input_data;
|
|
|
|
if (allocator == NULL)
|
|
allocator = &swebp__default_allocator;
|
|
|
|
input_data = (struct simplewebp_memoryinput_data *) allocator->alloc(
|
|
allocator->userdata,
|
|
sizeof(struct simplewebp_memoryinput_data)
|
|
);
|
|
if (input_data == NULL)
|
|
return SIMPLEWEBP_ALLOC_ERROR;
|
|
|
|
input_data->allocator = *allocator;
|
|
input_data->data = data;
|
|
input_data->size = size;
|
|
input_data->pos = 0;
|
|
out->userdata = input_data;
|
|
out->read = swebp__memoryinput_read;
|
|
out->seek = swebp__memoryinput_seek;
|
|
out->tell = swebp__memoryinput_tell;
|
|
out->close = swebp__memoryinput_close;
|
|
return SIMPLEWEBP_NO_ERROR;
|
|
}
|
|
|
|
struct simplewebp_input_proxy
|
|
{
|
|
simplewebp_input input;
|
|
simplewebp_allocator allocator;
|
|
|
|
size_t start, length;
|
|
};
|
|
|
|
static simplewebp_bool swebp__seek(size_t pos, simplewebp_input *input)
|
|
{
|
|
return input->seek(pos, input->userdata);
|
|
}
|
|
|
|
static size_t swebp__read(size_t size, void *dest, simplewebp_input *input)
|
|
{
|
|
return input->read(size, dest, input->userdata);
|
|
}
|
|
|
|
static simplewebp_bool swebp__read2(size_t size, void *dest, simplewebp_input *input)
|
|
{
|
|
return swebp__read(size, dest, input) == size;
|
|
}
|
|
|
|
static size_t swebp__tell(simplewebp_input *input)
|
|
{
|
|
return input->tell(input->userdata);
|
|
}
|
|
|
|
static size_t swebp__proxy_tell(void *userdata)
|
|
{
|
|
struct simplewebp_input_proxy *proxy;
|
|
size_t pos;
|
|
|
|
proxy = (struct simplewebp_input_proxy *) userdata;
|
|
pos = swebp__tell(&proxy->input);
|
|
|
|
if (pos < proxy->start)
|
|
{
|
|
swebp__seek(proxy->start, &proxy->input);
|
|
pos = proxy->start;
|
|
}
|
|
|
|
return pos - proxy->start;
|
|
}
|
|
|
|
static size_t swebp__proxy_read(size_t size, void *dest, void *userdata)
|
|
{
|
|
struct simplewebp_input_proxy *proxy;
|
|
size_t pos, nextpos, readed;
|
|
|
|
proxy = (struct simplewebp_input_proxy *) userdata;
|
|
pos = swebp__proxy_tell(userdata);
|
|
|
|
nextpos = pos + size;
|
|
|
|
if (nextpos >= proxy->length)
|
|
{
|
|
readed = size - (proxy->length - nextpos);
|
|
nextpos = proxy->length;
|
|
}
|
|
else
|
|
readed = size;
|
|
|
|
if (readed > 0)
|
|
readed = swebp__read(readed, dest, &proxy->input);
|
|
|
|
return readed;
|
|
}
|
|
|
|
static simplewebp_bool swebp__proxy_seek(size_t pos, void *userdata)
|
|
{
|
|
struct simplewebp_input_proxy *proxy = (struct simplewebp_input_proxy *) userdata;
|
|
|
|
if (pos > proxy->length)
|
|
pos = proxy->length;
|
|
|
|
return swebp__seek(pos + proxy->start, &proxy->input);
|
|
}
|
|
|
|
static void swebp__proxy_close(void *userdata)
|
|
{
|
|
struct simplewebp_input_proxy *proxy = (struct simplewebp_input_proxy *) userdata;
|
|
proxy->allocator.free(proxy->allocator.userdata, proxy);
|
|
}
|
|
|
|
static size_t swebp__proxy_size(void *userdata)
|
|
{
|
|
struct simplewebp_input_proxy *proxy = (struct simplewebp_input_proxy *) userdata;
|
|
return proxy->length;
|
|
}
|
|
|
|
static simplewebp_error swebp__proxy_create(
|
|
const simplewebp_allocator *allocator,
|
|
simplewebp_input *input,
|
|
simplewebp_input *out,
|
|
size_t start,
|
|
size_t length
|
|
)
|
|
{
|
|
struct simplewebp_input_proxy *proxy = (struct simplewebp_input_proxy *) allocator->alloc(
|
|
allocator->userdata,
|
|
sizeof(struct simplewebp_input_proxy)
|
|
);
|
|
if (proxy == NULL)
|
|
return SIMPLEWEBP_ALLOC_ERROR;
|
|
|
|
proxy->input = *input;
|
|
proxy->allocator = *allocator;
|
|
proxy->start = start;
|
|
proxy->length = length;
|
|
out->userdata = proxy;
|
|
out->read = swebp__proxy_read;
|
|
out->seek = swebp__proxy_seek;
|
|
out->tell = swebp__proxy_tell;
|
|
out->close = swebp__proxy_close;
|
|
return SIMPLEWEBP_NO_ERROR;
|
|
}
|
|
|
|
void simplewebp_close_input(simplewebp_input *input)
|
|
{
|
|
input->close(input->userdata);
|
|
input->userdata = NULL;
|
|
}
|
|
|
|
static simplewebp_u32 swebp__to_uint32(const simplewebp_u8 *buf)
|
|
{
|
|
return buf[0] | (((simplewebp_u32) buf[1]) << 8) | (((simplewebp_u32) buf[2]) << 16) | (((simplewebp_u32) buf[3]) << 24);
|
|
}
|
|
|
|
static simplewebp_error swebp__get_input_chunk_4cc(const simplewebp_allocator *allocator, simplewebp_input *input, simplewebp_input *outproxy, void *fourcc, size_t *chunk_size)
|
|
{
|
|
simplewebp_u8 size[4];
|
|
|
|
if (!swebp__read2(4, fourcc, input))
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
if (!swebp__read2(4, size, input))
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
|
|
*chunk_size = swebp__to_uint32(size);
|
|
return swebp__proxy_create(allocator, input, outproxy, swebp__tell(input), *chunk_size);
|
|
}
|
|
|
|
static simplewebp_u16 swebp__to_uint16(const simplewebp_u8 *buf)
|
|
{
|
|
return buf[0] | (((simplewebp_u16) buf[1]) << 8);
|
|
}
|
|
|
|
static simplewebp_error swebp__load_lossy(simplewebp_input *vp8_input, simplewebp *result)
|
|
{
|
|
simplewebp_u8 temp[8], profile;
|
|
simplewebp_u32 frametag, partition_size;
|
|
simplewebp_u16 width, height;
|
|
|
|
if (!swebp__seek(0, vp8_input))
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
|
|
if (!swebp__read2(3, temp, vp8_input))
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
|
|
frametag = temp[0] | (((simplewebp_u32) temp[1]) << 8) | (((simplewebp_u32) temp[2]) << 16);
|
|
if (frametag & 1)
|
|
/* Intraframe in SimpleWebP? Nope */
|
|
return SIMPLEWEBP_UNSUPPORTED_ERROR;
|
|
|
|
profile = (frametag >> 1) & 7;
|
|
if (profile > 3)
|
|
/* Unsupported profile */
|
|
return SIMPLEWEBP_UNSUPPORTED_ERROR;
|
|
|
|
partition_size = frametag >> 5;
|
|
if (partition_size >= swebp__proxy_size(vp8_input->userdata))
|
|
/* Inconsistent data */
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
|
|
if (!swebp__read2(7, temp, vp8_input))
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
|
|
if (memcmp(temp, "\x9D\x01\x2A", 3) != 0)
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
|
|
width = swebp__to_uint16(temp + 3);
|
|
height = swebp__to_uint16(temp + 5);
|
|
|
|
result->webp_type = 0;
|
|
memset(&result->decoder.vp8, 0, sizeof(struct swebp__vp8));
|
|
result->decoder.vp8.picture_header.width = width & 0x3FFF;
|
|
result->decoder.vp8.picture_header.height = height & 0x3FFF;
|
|
result->decoder.vp8.picture_header.xscale = (simplewebp_u8) (width >> 14);
|
|
result->decoder.vp8.picture_header.yscale = (simplewebp_u8) (height >> 14);
|
|
result->decoder.vp8.frame_header.partition_length = partition_size;
|
|
|
|
return SIMPLEWEBP_NO_ERROR;
|
|
}
|
|
|
|
static void swebp__vp8l_bitread_init(struct swebp__vp8l_bdec *bdec, simplewebp_u8 *buf, size_t size)
|
|
{
|
|
bdec->buf = buf;
|
|
bdec->len = size;
|
|
bdec->bit_pos = 0;
|
|
bdec->eos = 0;
|
|
}
|
|
|
|
static simplewebp_u32 swebp__vp8l_bitread_read(struct swebp__vp8l_bdec *bdec, int count)
|
|
{
|
|
int i;
|
|
simplewebp_u32 value = 0;
|
|
|
|
for (i = 0; i < count; i++, bdec->bit_pos++)
|
|
{
|
|
simplewebp_u8 b;
|
|
size_t bytepos = bdec->bit_pos >> 3;
|
|
|
|
if (bytepos >= bdec->len)
|
|
{
|
|
bdec->eos = 1;
|
|
break;
|
|
}
|
|
|
|
b = bdec->buf[bytepos];
|
|
value |= ((b >> (bdec->bit_pos & 7)) & 1) << i;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
static simplewebp_error swebp__load_lossless(simplewebp_input *vp8l_input, simplewebp *result)
|
|
{
|
|
simplewebp_u8 temp[5];
|
|
struct swebp__vp8l_bdec br;
|
|
|
|
if (!swebp__seek(0, vp8l_input))
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
|
|
if (!swebp__read2(5, temp, vp8l_input))
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
|
|
if (temp[0] != 0x2F)
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
|
|
swebp__vp8l_bitread_init(&br, temp + 1, 4);
|
|
|
|
memset(&result->decoder.vp8l, 0, sizeof(struct swebp__vp8l_decoder));
|
|
result->decoder.vp8l.width = swebp__vp8l_bitread_read(&br, 14) + 1;
|
|
result->decoder.vp8l.height = swebp__vp8l_bitread_read(&br, 14) + 1;
|
|
result->decoder.vp8l.has_alpha = swebp__vp8l_bitread_read(&br, 1);
|
|
if (swebp__vp8l_bitread_read(&br, 3) != 0)
|
|
return SIMPLEWEBP_UNSUPPORTED_ERROR;
|
|
|
|
result->webp_type = 1;
|
|
return SIMPLEWEBP_NO_ERROR;
|
|
}
|
|
|
|
static simplewebp_u32 swebp__to_uint24(const simplewebp_u8 *buf)
|
|
{
|
|
return buf[0] | (((simplewebp_u32) buf[1]) << 8) | (((simplewebp_u32) buf[2]) << 16);
|
|
}
|
|
|
|
static simplewebp_error swebp__alpha_init(struct swebp__alpha *alpha, simplewebp_input *input)
|
|
{
|
|
simplewebp_u8 flags;
|
|
|
|
if (!swebp__seek(0, input))
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
|
|
if (!swebp__read2(1, &flags, input))
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
|
|
alpha->filter_method = (flags >> 2) & 3;
|
|
alpha->is_lossless_compressed = (flags & 3) > 0;
|
|
|
|
return SIMPLEWEBP_NO_ERROR;
|
|
}
|
|
|
|
static simplewebp_i32 swebp__clip(simplewebp_i32 v, simplewebp_i32 m)
|
|
{
|
|
return (v < 0) ? 0 : ((v > m) ? m : v);
|
|
}
|
|
|
|
static void swebp__alpha_apply_filters(simplewebp_u8 *ptr, size_t width, size_t height, simplewebp_u8 filter_type)
|
|
{
|
|
size_t y, x;
|
|
|
|
if (filter_type == 0)
|
|
/* No filters to be applied */
|
|
return;
|
|
|
|
for (y = 0; y < height; y++)
|
|
{
|
|
for (x = (y == 0); x < width; x++)
|
|
{
|
|
size_t i = y * width + x;
|
|
simplewebp_u8 predictor = 0;
|
|
|
|
switch (filter_type)
|
|
{
|
|
case 0:
|
|
default:
|
|
/* Should not happen */
|
|
predictor = 0;
|
|
case 1:
|
|
predictor = x == 0 ? ptr[i - width] : ptr[i - 1];
|
|
break;
|
|
case 2:
|
|
predictor = y == 0 ? ptr[i - 1] : ptr[i - width];
|
|
break;
|
|
case 3:
|
|
{
|
|
simplewebp_i16 a, b, c;
|
|
simplewebp_i16 val;
|
|
|
|
a = x == 0 ? ptr[i - width] : ptr[i - 1];
|
|
b = y == 0 ? ptr[i - 1] : ptr[i - width];
|
|
if (x > 0)
|
|
{
|
|
if (y > 0)
|
|
c = ptr[i - width - 1];
|
|
else
|
|
c = ptr[i - 1];
|
|
}
|
|
else
|
|
{
|
|
if (y > 0)
|
|
c = ptr[i - width];
|
|
else
|
|
c = ptr[0];
|
|
}
|
|
val = a + b - c;
|
|
predictor = (simplewebp_u8) swebp__clip(val, 255);
|
|
break;
|
|
}
|
|
}
|
|
|
|
ptr[i] += predictor;
|
|
}
|
|
}
|
|
}
|
|
|
|
static simplewebp_error swebp__alpha_decode_simple(simplewebp *simplewebp, simplewebp_u8 *dst)
|
|
{
|
|
size_t width, height;
|
|
simplewebp_input *input = &simplewebp->alph_input;
|
|
|
|
if (!swebp__seek(1, input))
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
|
|
simplewebp_get_dimensions(simplewebp, &width, &height);
|
|
if (!swebp__read2(width * height, dst, input))
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
|
|
return SIMPLEWEBP_NO_ERROR;
|
|
}
|
|
|
|
static simplewebp_error swebp__decode_lossless_bitstream(
|
|
simplewebp *simplewebp,
|
|
simplewebp_input *input,
|
|
size_t bitstreamsize,
|
|
struct swebp__pixel *rgba,
|
|
simplewebp_bool skipheader
|
|
);
|
|
|
|
static simplewebp_error swebp__alpha_decode_lossless(simplewebp *simplewebp, simplewebp_u8 *dst)
|
|
{
|
|
size_t vp8lsize, width, height, i;
|
|
struct swebp__pixel *rgba;
|
|
simplewebp_error err;
|
|
|
|
simplewebp_get_dimensions(simplewebp, &width, &height);
|
|
|
|
vp8lsize = swebp__proxy_size(simplewebp->alph_input.userdata) - 1;
|
|
if (!swebp__proxy_seek(1, simplewebp->alph_input.userdata))
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
|
|
rgba = (struct swebp__pixel*) swebp__alloc(simplewebp, sizeof(struct swebp__pixel) * width * height);
|
|
if (!rgba)
|
|
return SIMPLEWEBP_ALLOC_ERROR;
|
|
|
|
err = swebp__decode_lossless_bitstream(
|
|
simplewebp,
|
|
&simplewebp->alph_input,
|
|
vp8lsize,
|
|
rgba,
|
|
1
|
|
);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
{
|
|
swebp__dealloc(simplewebp, rgba);
|
|
return err;
|
|
}
|
|
|
|
/* Pull green channel */
|
|
for (i = 0; i < width * height; i++)
|
|
dst[i] = rgba[i].g;
|
|
|
|
swebp__dealloc(simplewebp, rgba);
|
|
return SIMPLEWEBP_NO_ERROR;
|
|
}
|
|
|
|
static simplewebp_error swebp__alpha_decode(simplewebp *simplewebp, simplewebp_u8 *dst)
|
|
{
|
|
size_t width, height;
|
|
simplewebp_error err = SIMPLEWEBP_NO_ERROR;
|
|
|
|
simplewebp_get_dimensions(simplewebp, &width, &height);
|
|
|
|
if (simplewebp->alph_input.userdata)
|
|
{
|
|
if (simplewebp->alpha_decoder.is_lossless_compressed)
|
|
err = swebp__alpha_decode_lossless(simplewebp, dst);
|
|
else
|
|
err = swebp__alpha_decode_simple(simplewebp, dst);
|
|
|
|
if (err == SIMPLEWEBP_NO_ERROR)
|
|
swebp__alpha_apply_filters(dst, width, height, simplewebp->alpha_decoder.filter_method);
|
|
}
|
|
else
|
|
memset(dst, 255, width * height);
|
|
|
|
return err;
|
|
}
|
|
|
|
static simplewebp_bool swebp__has_decoder(simplewebp *simplewebp)
|
|
{
|
|
return simplewebp->vp8_input.userdata != NULL || simplewebp->vp8l_input.userdata != NULL;
|
|
}
|
|
|
|
simplewebp_error simplewebp_load(simplewebp_input *input, const simplewebp_allocator *allocator, simplewebp **out)
|
|
{
|
|
simplewebp_u8 temp[4];
|
|
simplewebp_error err;
|
|
simplewebp_input riff_input;
|
|
simplewebp *result;
|
|
size_t chunk_size;
|
|
|
|
if (allocator == NULL)
|
|
allocator = &swebp__default_allocator;
|
|
|
|
*out = NULL;
|
|
|
|
/* Read "RIFF" */
|
|
err = swebp__get_input_chunk_4cc(allocator, input, &riff_input, temp, &chunk_size);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
return err;
|
|
if (memcmp(temp, "RIFF", 4) != 0)
|
|
{
|
|
simplewebp_close_input(&riff_input);
|
|
return SIMPLEWEBP_NOT_WEBP_ERROR;
|
|
}
|
|
|
|
/* Read "WEBP" */
|
|
if (!swebp__read2(4, temp, &riff_input) || memcmp(temp, "WEBP", 4) != 0)
|
|
{
|
|
simplewebp_close_input(&riff_input);
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
}
|
|
|
|
/* Allocate simplewebp structure */
|
|
result = (simplewebp *) allocator->alloc(allocator->userdata, sizeof(simplewebp));
|
|
if (result == NULL)
|
|
return SIMPLEWEBP_ALLOC_ERROR;
|
|
memset(result, 0, sizeof(simplewebp));
|
|
|
|
result->allocator = *allocator;
|
|
result->riff_input = riff_input;
|
|
|
|
while (1)
|
|
{
|
|
simplewebp_input chunk_input_proxy;
|
|
size_t current_position;
|
|
|
|
err = swebp__get_input_chunk_4cc(allocator, &result->riff_input, &chunk_input_proxy, temp, &chunk_size);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
{
|
|
if (swebp__has_decoder(result))
|
|
/* Loaded successfully */
|
|
err = SIMPLEWEBP_NO_ERROR;
|
|
|
|
break;
|
|
}
|
|
|
|
current_position = swebp__tell(&result->riff_input);
|
|
|
|
if (memcmp(temp, "VP8 ", 4) == 0)
|
|
{
|
|
if (swebp__has_decoder(result))
|
|
{
|
|
err = SIMPLEWEBP_UNSUPPORTED_ERROR;
|
|
break;
|
|
}
|
|
|
|
err = swebp__load_lossy(&chunk_input_proxy, result);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
{
|
|
simplewebp_close_input(&chunk_input_proxy);
|
|
break;
|
|
}
|
|
|
|
result->vp8_input = chunk_input_proxy;
|
|
}
|
|
else if (memcmp(temp, "VP8L", 4) == 0)
|
|
{
|
|
if (swebp__has_decoder(result) || result->alph_input.userdata != NULL)
|
|
{
|
|
/* Alpha channel is present or existing VP8(L) decoder present. */
|
|
simplewebp_close_input(&chunk_input_proxy);
|
|
err = SIMPLEWEBP_UNSUPPORTED_ERROR;
|
|
break;
|
|
}
|
|
|
|
err = swebp__load_lossless(&chunk_input_proxy, result);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
{
|
|
simplewebp_close_input(&chunk_input_proxy);
|
|
break;
|
|
}
|
|
|
|
result->vp8l_input = chunk_input_proxy;
|
|
}
|
|
else if (memcmp(temp, "ALPH", 4) == 0)
|
|
{
|
|
if (result->vp8l_input.userdata != NULL)
|
|
{
|
|
/* Alpha channel already present in VP8L */
|
|
simplewebp_close_input(&chunk_input_proxy);
|
|
err = SIMPLEWEBP_UNSUPPORTED_ERROR;
|
|
break;
|
|
}
|
|
|
|
err = swebp__alpha_init(&result->alpha_decoder, &chunk_input_proxy);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
{
|
|
simplewebp_close_input(&chunk_input_proxy);
|
|
break;
|
|
}
|
|
|
|
result->alph_input = chunk_input_proxy;
|
|
}
|
|
else
|
|
/* Input unused. */
|
|
simplewebp_close_input(&chunk_input_proxy);
|
|
|
|
if (!swebp__seek(current_position + (chunk_size + 1) & (~((size_t) 1)), &result->riff_input))
|
|
{
|
|
err = SIMPLEWEBP_IO_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Success case */
|
|
if (err == SIMPLEWEBP_NO_ERROR)
|
|
{
|
|
result->input = *input;
|
|
*out = result;
|
|
}
|
|
/* Failure case */
|
|
else
|
|
{
|
|
simplewebp_unload(result);
|
|
*out = NULL;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
simplewebp_error simplewebp_load_from_memory(void *data, size_t size, const simplewebp_allocator *allocator, simplewebp **out)
|
|
{
|
|
simplewebp_input input;
|
|
simplewebp_error err;
|
|
|
|
err = simplewebp_input_from_memory(data, size, &input, allocator);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
return err;
|
|
|
|
err = simplewebp_load(&input, allocator, out);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
simplewebp_close_input(&input);
|
|
|
|
return err;
|
|
}
|
|
|
|
static void swebp__close_input(simplewebp_input *inp)
|
|
{
|
|
if (inp->userdata)
|
|
simplewebp_close_input(inp);
|
|
}
|
|
|
|
void simplewebp_unload(simplewebp *simplewebp)
|
|
{
|
|
swebp__close_input(&simplewebp->alph_input);
|
|
swebp__close_input(&simplewebp->vp8_input);
|
|
swebp__close_input(&simplewebp->vp8l_input);
|
|
swebp__close_input(&simplewebp->riff_input);
|
|
swebp__close_input(&simplewebp->input);
|
|
|
|
if (simplewebp->webp_type)
|
|
{
|
|
/* TODO: Clear lossless data*/
|
|
}
|
|
else
|
|
{
|
|
|
|
}
|
|
|
|
swebp__dealloc(simplewebp, simplewebp);
|
|
}
|
|
|
|
void simplewebp_get_dimensions(simplewebp *simplewebp, size_t *width, size_t *height)
|
|
{
|
|
switch (simplewebp->webp_type)
|
|
{
|
|
case 0:
|
|
*width = simplewebp->decoder.vp8.picture_header.width;
|
|
*height = simplewebp->decoder.vp8.picture_header.height;
|
|
break;
|
|
case 1:
|
|
*width = simplewebp->decoder.vp8l.width;
|
|
*height = simplewebp->decoder.vp8l.height;
|
|
break;
|
|
default:
|
|
*width = 0;
|
|
*height = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
simplewebp_bool simplewebp_is_lossless(simplewebp *simplewebp)
|
|
{
|
|
return simplewebp->webp_type == 1;
|
|
}
|
|
|
|
static void swebp__bitread_setbuf(struct swebp__bdec *br, simplewebp_u8 *buf, size_t size)
|
|
{
|
|
br->buf = buf;
|
|
br->buf_end = buf + size;
|
|
br->buf_max = (size >= sizeof(simplewebp_u32))
|
|
? (buf + size - sizeof(simplewebp_u32) + 1)
|
|
: buf;
|
|
}
|
|
|
|
static void swebp__bitread_load(struct swebp__bdec *br)
|
|
{
|
|
simplewebp_u32 bits;
|
|
|
|
if (br->buf < br->buf_max)
|
|
{
|
|
/* Read 24 bits at a time in big endian order */
|
|
bits = br->buf[2] | (br->buf[1] << 8) | (br->buf[0] << 16);
|
|
br->buf += 3; /* 24 / 8 */
|
|
br->value = bits | (br->value << 24);
|
|
br->bits += 24;
|
|
}
|
|
else
|
|
{
|
|
/* Only read 8 bits at a time */
|
|
if (br->buf < br->buf_end)
|
|
{
|
|
br->bits += 8;
|
|
br->value = (*br->buf++) | (br->value << 8);
|
|
}
|
|
else if (!br->eof)
|
|
{
|
|
br->value <<= 8;
|
|
br->bits += 8;
|
|
br->eof = 1;
|
|
}
|
|
else
|
|
br->bits = 0;
|
|
}
|
|
}
|
|
|
|
static void swebp__bitread_init(struct swebp__bdec *br, simplewebp_u8 *buf, size_t size)
|
|
{
|
|
br->range = 254;
|
|
br->value = 0;
|
|
br->bits = -8;
|
|
br->eof = 0;
|
|
swebp__bitread_setbuf(br, buf, size);
|
|
swebp__bitread_load(br);
|
|
}
|
|
|
|
/* https://stackoverflow.com/a/11398748 */
|
|
const simplewebp_u32 swebp__blog2_tab32[32] = {
|
|
0, 9, 1, 10, 13, 21, 2, 29,
|
|
11, 14, 16, 18, 22, 25, 3, 30,
|
|
8, 12, 20, 28, 15, 17, 24, 7,
|
|
19, 27, 23, 6, 26, 5, 4, 31
|
|
};
|
|
|
|
static simplewebp_u32 swebp__bitslog2floor(simplewebp_u32 value)
|
|
{
|
|
value |= value >> 1;
|
|
value |= value >> 2;
|
|
value |= value >> 4;
|
|
value |= value >> 8;
|
|
value |= value >> 16;
|
|
return swebp__blog2_tab32[(value * 0x07C4ACDDU) >> 27];
|
|
}
|
|
|
|
static simplewebp_u32 swebp__bitread_getbit(struct swebp__bdec *br, simplewebp_u32 prob)
|
|
{
|
|
simplewebp_u32 bit;
|
|
simplewebp_u8 range, split, value, shift;
|
|
simplewebp_i8 pos;
|
|
|
|
range = br->range;
|
|
|
|
if (br->bits < 0)
|
|
swebp__bitread_load(br);
|
|
|
|
pos = br->bits;
|
|
split = (simplewebp_u8) ((((simplewebp_u32) range) * prob) >> 8);
|
|
value = (simplewebp_u8) (br->value >> pos);
|
|
bit = value > split;
|
|
|
|
if (bit)
|
|
{
|
|
range -= split;
|
|
br->value -= (((simplewebp_u32) split) + 1) << pos;
|
|
}
|
|
else
|
|
range = split + 1;
|
|
|
|
shift = 7 ^ swebp__bitslog2floor(range);
|
|
range <<= shift;
|
|
br->bits -= shift;
|
|
br->range = range - 1;
|
|
return bit;
|
|
}
|
|
|
|
static simplewebp_u32 swebp__bitread_getval(struct swebp__bdec *br, simplewebp_u8 bits)
|
|
{
|
|
simplewebp_u32 value = 0;
|
|
|
|
while (bits--)
|
|
value |= swebp__bitread_getbit(br, 0x80) << bits;
|
|
|
|
return value;
|
|
}
|
|
|
|
static simplewebp_i32 swebp__bitread_getvalsigned(struct swebp__bdec *br, simplewebp_u8 bits)
|
|
{
|
|
simplewebp_i32 value = swebp__bitread_getval(br, bits);
|
|
return swebp__bitread_getval(br, 1) ? -value : value;
|
|
}
|
|
|
|
static simplewebp_i32 swebp__bitread_getsigned(struct swebp__bdec *br, simplewebp_i32 v)
|
|
{
|
|
simplewebp_i8 pos;
|
|
simplewebp_u32 split, value;
|
|
simplewebp_i32 mask;
|
|
|
|
if (br->bits < 0)
|
|
swebp__bitread_load(br);
|
|
|
|
pos = br->bits;
|
|
split = br->range >> 1;
|
|
value = br->value >> pos;
|
|
mask = ((simplewebp_i32) (split - value)) >> 31;
|
|
br->bits -= 1;
|
|
br->range += (simplewebp_u8) mask;
|
|
br->range |= 1;
|
|
br->value -= (simplewebp_u32) ((split + 1) & (simplewebp_u32) mask) << pos;
|
|
return (v ^ mask) - mask;
|
|
}
|
|
|
|
/* RFC 6386 section 14.1 */
|
|
static const simplewebp_u8 swebp__dctab[128] = {
|
|
4, 5, 6, 7, 8, 9, 10, 10,
|
|
11, 12, 13, 14, 15, 16, 17, 17,
|
|
18, 19, 20, 20, 21, 21, 22, 22,
|
|
23, 23, 24, 25, 25, 26, 27, 28,
|
|
29, 30, 31, 32, 33, 34, 35, 36,
|
|
37, 37, 38, 39, 40, 41, 42, 43,
|
|
44, 45, 46, 46, 47, 48, 49, 50,
|
|
51, 52, 53, 54, 55, 56, 57, 58,
|
|
59, 60, 61, 62, 63, 64, 65, 66,
|
|
67, 68, 69, 70, 71, 72, 73, 74,
|
|
75, 76, 76, 77, 78, 79, 80, 81,
|
|
82, 83, 84, 85, 86, 87, 88, 89,
|
|
91, 93, 95, 96, 98, 100, 101, 102,
|
|
104, 106, 108, 110, 112, 114, 116, 118,
|
|
122, 124, 126, 128, 130, 132, 134, 136,
|
|
138, 140, 143, 145, 148, 151, 154, 157
|
|
};
|
|
|
|
static const simplewebp_u16 swebp__actab[128] = {
|
|
4, 5, 6, 7, 8, 9, 10, 11,
|
|
12, 13, 14, 15, 16, 17, 18, 19,
|
|
20, 21, 22, 23, 24, 25, 26, 27,
|
|
28, 29, 30, 31, 32, 33, 34, 35,
|
|
36, 37, 38, 39, 40, 41, 42, 43,
|
|
44, 45, 46, 47, 48, 49, 50, 51,
|
|
52, 53, 54, 55, 56, 57, 58, 60,
|
|
62, 64, 66, 68, 70, 72, 74, 76,
|
|
78, 80, 82, 84, 86, 88, 90, 92,
|
|
94, 96, 98, 100, 102, 104, 106, 108,
|
|
110, 112, 114, 116, 119, 122, 125, 128,
|
|
131, 134, 137, 140, 143, 146, 149, 152,
|
|
155, 158, 161, 164, 167, 170, 173, 177,
|
|
181, 185, 189, 193, 197, 201, 205, 209,
|
|
213, 217, 221, 225, 229, 234, 239, 245,
|
|
249, 254, 259, 264, 269, 274, 279, 284
|
|
};
|
|
|
|
/* RFC 6386 section 13 */
|
|
static const simplewebp_u8 swebp__coeff_update_proba[4][8][3][11] = {
|
|
{ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255 },
|
|
{ 250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255 },
|
|
{ 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
}
|
|
},
|
|
{ { { 217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255 },
|
|
{ 234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255 }
|
|
},
|
|
{ { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
}
|
|
},
|
|
{ { { 186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
}
|
|
},
|
|
{ { { 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
},
|
|
{ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
|
|
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
|
|
}
|
|
}
|
|
};
|
|
|
|
/* RFC 6386 section 13.5 */
|
|
static const simplewebp_u8 swebp__coeff_proba0[4][8][3][11] = {
|
|
{ { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
|
|
{ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
|
|
{ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
|
|
},
|
|
{ { 253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128 },
|
|
{ 189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128 },
|
|
{ 106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128 }
|
|
},
|
|
{ { 1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128 },
|
|
{ 181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128 },
|
|
{ 78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128 },
|
|
},
|
|
{ { 1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128 },
|
|
{ 184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128 },
|
|
{ 77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128 },
|
|
},
|
|
{ { 1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128 },
|
|
{ 170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128 },
|
|
{ 37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128 }
|
|
},
|
|
{ { 1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128 },
|
|
{ 207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128 },
|
|
{ 102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128 }
|
|
},
|
|
{ { 1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128 },
|
|
{ 177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128 },
|
|
{ 80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128 }
|
|
},
|
|
{ { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
|
|
{ 246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
|
|
{ 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
|
|
}
|
|
},
|
|
{ { { 198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62 },
|
|
{ 131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1 },
|
|
{ 68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128 }
|
|
},
|
|
{ { 1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128 },
|
|
{ 184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128 },
|
|
{ 81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128 }
|
|
},
|
|
{ { 1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128 },
|
|
{ 99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128 },
|
|
{ 23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128 }
|
|
},
|
|
{ { 1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128 },
|
|
{ 109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128 },
|
|
{ 44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128 }
|
|
},
|
|
{ { 1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128 },
|
|
{ 94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128 },
|
|
{ 22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128 }
|
|
},
|
|
{ { 1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128 },
|
|
{ 124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128 },
|
|
{ 35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128 }
|
|
},
|
|
{ { 1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128 },
|
|
{ 121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128 },
|
|
{ 45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128 }
|
|
},
|
|
{ { 1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128 },
|
|
{ 203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128 },
|
|
{ 137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128 }
|
|
}
|
|
},
|
|
{ { { 253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128 },
|
|
{ 175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128 },
|
|
{ 73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128 }
|
|
},
|
|
{ { 1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128 },
|
|
{ 239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128 },
|
|
{ 155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128 }
|
|
},
|
|
{ { 1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128 },
|
|
{ 201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128 },
|
|
{ 69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128 }
|
|
},
|
|
{ { 1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128 },
|
|
{ 223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128 },
|
|
{ 141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128 }
|
|
},
|
|
{ { 1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128 },
|
|
{ 190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128 },
|
|
{ 149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
|
|
},
|
|
{ { 1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
|
|
{ 247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
|
|
{ 240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
|
|
},
|
|
{ { 1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128 },
|
|
{ 213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128 },
|
|
{ 55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
|
|
},
|
|
{ { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
|
|
{ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
|
|
{ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
|
|
}
|
|
},
|
|
{ { { 202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255 },
|
|
{ 126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128 },
|
|
{ 61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128 }
|
|
},
|
|
{ { 1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128 },
|
|
{ 166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128 },
|
|
{ 39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128 }
|
|
},
|
|
{ { 1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128 },
|
|
{ 124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128 },
|
|
{ 24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128 }
|
|
},
|
|
{ { 1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128 },
|
|
{ 149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128 },
|
|
{ 28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128 }
|
|
},
|
|
{ { 1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128 },
|
|
{ 123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128 },
|
|
{ 20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128 }
|
|
},
|
|
{ { 1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128 },
|
|
{ 168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128 },
|
|
{ 47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128 }
|
|
},
|
|
{ { 1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128 },
|
|
{ 141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128 },
|
|
{ 42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128 }
|
|
},
|
|
{ { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
|
|
{ 244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
|
|
{ 238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
|
|
}
|
|
}
|
|
};
|
|
|
|
static const simplewebp_u8 swebp__fextrarows[3] = {0, 2, 8};
|
|
|
|
static simplewebp_u8 *swebp__align32(simplewebp_u8 *ptr)
|
|
{
|
|
size_t uptr = (size_t) ptr;
|
|
return (simplewebp_u8 *) ((uptr + 31) & (~(size_t)31));
|
|
}
|
|
|
|
/* Clip tables */
|
|
|
|
static const simplewebp_u8 swebp__abs0[255 + 255 + 1] = {
|
|
0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4,
|
|
0xf3, 0xf2, 0xf1, 0xf0, 0xef, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe8,
|
|
0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0, 0xdf, 0xde, 0xdd, 0xdc,
|
|
0xdb, 0xda, 0xd9, 0xd8, 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0,
|
|
0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc8, 0xc7, 0xc6, 0xc5, 0xc4,
|
|
0xc3, 0xc2, 0xc1, 0xc0, 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
|
|
0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0, 0xaf, 0xae, 0xad, 0xac,
|
|
0xab, 0xaa, 0xa9, 0xa8, 0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0,
|
|
0x9f, 0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94,
|
|
0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88,
|
|
0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x7f, 0x7e, 0x7d, 0x7c,
|
|
0x7b, 0x7a, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
|
|
0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64,
|
|
0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58,
|
|
0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x4e, 0x4d, 0x4c,
|
|
0x4b, 0x4a, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40,
|
|
0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34,
|
|
0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
|
|
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c,
|
|
0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
|
|
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04,
|
|
0x03, 0x02, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
|
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
|
|
0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
|
|
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
|
|
0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
|
|
0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44,
|
|
0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
|
|
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c,
|
|
0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
|
|
0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
|
|
0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80,
|
|
0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c,
|
|
0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
|
|
0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
|
|
0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0,
|
|
0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc,
|
|
0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
|
|
0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4,
|
|
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0,
|
|
0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec,
|
|
0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
|
|
0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
|
};
|
|
static const simplewebp_u8 *const swebp__kabs0 = &swebp__abs0[255];
|
|
|
|
static const simplewebp_u8 swebp__sclip1[1020 + 1020 + 1] = {
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
|
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93,
|
|
0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
|
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab,
|
|
0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
|
|
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3,
|
|
0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
|
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
|
|
0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
|
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3,
|
|
0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
|
0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
|
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
|
|
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
|
|
0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
|
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
|
|
0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
|
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
|
|
0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
|
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
|
|
0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
|
|
};
|
|
static const simplewebp_i8 *const swebp__ksclip1 = (const simplewebp_i8 *) &swebp__sclip1[1020];
|
|
|
|
static const simplewebp_u8 swebp__sclip2[112 + 112 + 1] = {
|
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
|
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
|
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
|
|
0xfc, 0xfd, 0xfe, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
|
|
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
|
|
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
|
|
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
|
|
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
|
|
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
|
|
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
|
|
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
|
|
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f
|
|
};
|
|
static const simplewebp_i8 *const swebp__ksclip2 = (const simplewebp_i8 *) &swebp__sclip2[112];
|
|
|
|
static const simplewebp_u8 swebp__clip1[255 + 511 + 1] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
|
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
|
|
0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
|
|
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
|
|
0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
|
|
0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44,
|
|
0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
|
|
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c,
|
|
0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
|
|
0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
|
|
0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80,
|
|
0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c,
|
|
0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
|
|
0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
|
|
0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0,
|
|
0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc,
|
|
0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
|
|
0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4,
|
|
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0,
|
|
0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec,
|
|
0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
|
|
0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
|
};
|
|
static const simplewebp_u8 *const swebp__kclip1 = &swebp__clip1[255];
|
|
|
|
/* RFC 6386 section 14.4 */
|
|
|
|
static void swebp__transform_wht(const simplewebp_i16 *in, simplewebp_i16 *out)
|
|
{
|
|
simplewebp_i32 temp[16], i;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
simplewebp_i32 a0, a1, a2, a3;
|
|
|
|
a0 = in[i] + in[i + 12];
|
|
a1 = in[i + 4] + in[i + 8];
|
|
a2 = in[i + 4] - in[i + 8];
|
|
a3 = in[i] - in[i + 12];
|
|
temp[i] = a0 + a1;
|
|
temp[i + 4] = a3 + a2;
|
|
temp[i + 8] = a0 - a1;
|
|
temp[i + 12] = a3 - a2;
|
|
}
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
simplewebp_i32 dc, a0, a1, a2, a3;
|
|
|
|
dc = temp[i * 4] + 3;
|
|
a0 = dc + temp[i * 4 + 3];
|
|
a1 = temp[i * 4 + 1] + temp[i * 4 + 2];
|
|
a2 = temp[i * 4 + 1] - temp[i * 4 + 2];
|
|
a3 = dc - temp[i * 4 + 3];
|
|
out[i * 64] = (a0 + a1) >> 3;
|
|
out[i * 64 + 16] = (a3 + a2) >> 3;
|
|
out[i * 64 + 32] = (a0 - a1) >> 3;
|
|
out[i * 64 + 48] = (a3 - a2) >> 3;
|
|
}
|
|
}
|
|
|
|
static simplewebp_i32 swebp__mul1(simplewebp_i16 a)
|
|
{
|
|
return (((simplewebp_i32) a * 20091) >> 16) + a;
|
|
}
|
|
|
|
static simplewebp_i32 swebp__mul2(simplewebp_i16 a)
|
|
{
|
|
return ((simplewebp_i32) a * 35468) >> 16;
|
|
}
|
|
|
|
|
|
static simplewebp_u8 swebp__clip8b(simplewebp_i32 v) {
|
|
return (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255;
|
|
}
|
|
|
|
static void swebp__store(simplewebp_u8 *out, simplewebp_i32 x, simplewebp_i32 y, simplewebp_i32 v)
|
|
{
|
|
out[y * 32 + x] = swebp__clip8b(out[y * 32 + x] + (v >> 3));
|
|
}
|
|
|
|
static void swebp__transform_one(const simplewebp_i16 *in, simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 tmp[16], i;
|
|
|
|
/* Vertical pass */
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
simplewebp_i32 a, b, c, d;
|
|
|
|
a = in[i] + in[i + 8];
|
|
b = in[i] - in[i + 8];
|
|
c = swebp__mul2(in[i + 4]) - swebp__mul1(in[i + 12]);
|
|
d = swebp__mul1(in[i + 4]) + swebp__mul2(in[i + 12]);
|
|
tmp[i * 4] = a + d;
|
|
tmp[i * 4 + 1] = b + c;
|
|
tmp[i * 4 + 2] = b - c;
|
|
tmp[i * 4 + 3] = a - d;
|
|
}
|
|
/* Horizontal pass */
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
simplewebp_i32 dc, a, b, c, d;
|
|
|
|
dc = tmp[i] + 4;
|
|
a = dc + tmp[i + 8];
|
|
b = dc - tmp[i + 8];
|
|
c = swebp__mul2(tmp[i + 4]) - swebp__mul1(tmp[i + 12]);
|
|
d = swebp__mul1(tmp[i + 4]) + swebp__mul2(tmp[i + 12]);
|
|
swebp__store(out, 0, i, a + d);
|
|
swebp__store(out, 1, i, b + c);
|
|
swebp__store(out, 2, i, b - c);
|
|
swebp__store(out, 3, i, a - d);
|
|
}
|
|
}
|
|
|
|
static void swebp__transform(const simplewebp_i16 *in, simplewebp_u8 *out, simplewebp_u8 do_2)
|
|
{
|
|
swebp__transform_one(in, out);
|
|
if (do_2)
|
|
swebp__transform_one(in + 16, out + 4);
|
|
}
|
|
|
|
static void swebp__transform_dc(const simplewebp_i16 *in, simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 dc, x, y;
|
|
dc = in[0] + 4;
|
|
|
|
for (y = 0; y < 4; y++)
|
|
{
|
|
for (x = 0; x < 4; x++)
|
|
swebp__store(out, x, y, dc);
|
|
}
|
|
}
|
|
|
|
static void swebp__store2(simplewebp_u8 *out, simplewebp_i32 y, simplewebp_i32 dc, simplewebp_i32 d, simplewebp_i32 c)
|
|
{
|
|
swebp__store(out, 0, y, dc + d);
|
|
swebp__store(out, 1, y, dc + c);
|
|
swebp__store(out, 2, y, dc - c);
|
|
swebp__store(out, 3, y, dc - d);
|
|
}
|
|
|
|
static void swebp__transform_ac3(const simplewebp_i16 *in, simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 a, c4, d4, c1, d1;
|
|
|
|
a = in[0] + 4;
|
|
c4 = swebp__mul2(in[4]);
|
|
d4 = swebp__mul1(in[4]);
|
|
c1 = swebp__mul2(in[1]);
|
|
d1 = swebp__mul1(in[1]);
|
|
swebp__store2(out, 0, a + d4, d1, c1);
|
|
swebp__store2(out, 1, a + c4, d1, c1);
|
|
swebp__store2(out, 2, a - c4, d1, c1);
|
|
swebp__store2(out, 3, a - d4, d1, c1);
|
|
}
|
|
|
|
static void swebp__transform_uv(const simplewebp_i16 *in, simplewebp_u8 *out)
|
|
{
|
|
swebp__transform(in, out, 1);
|
|
swebp__transform(in + 32 /* 2*16 */, out + 128 /* 4*BPS */, 1);
|
|
}
|
|
|
|
static void swebp__transform_dcuv(const simplewebp_i16 *in, simplewebp_u8 *out)
|
|
{
|
|
if (in[0])
|
|
swebp__transform_dc(in, out);
|
|
if (in[16])
|
|
swebp__transform_dc(in + 16, out + 4);
|
|
if (in[32])
|
|
swebp__transform_dc(in + 32, out + 128);
|
|
if (in[48])
|
|
swebp__transform_dc(in + 48, out + 132);
|
|
}
|
|
|
|
static simplewebp_i32 swebp__needsfilter2(const simplewebp_u8 *p, simplewebp_i32 step, simplewebp_i32 t, simplewebp_i32 it)
|
|
{
|
|
simplewebp_i32 p3, p2, p1, p0, q0, q1, q2, q3;
|
|
p3 = p[-4 * step];
|
|
p2 = p[-3 * step];
|
|
p1 = p[-2 * step];
|
|
p0 = p[-step];
|
|
q0 = p[0];
|
|
q1 = p[step];
|
|
q2 = p[2 * step];
|
|
q3 = p[3 * step];
|
|
|
|
if ((4 * swebp__kabs0[p0 - q0] + swebp__kabs0[p1 - q1]) > t)
|
|
return 0;
|
|
|
|
return
|
|
swebp__kabs0[p3 - p2] <= it &&
|
|
swebp__kabs0[p2 - p1] <= it &&
|
|
swebp__kabs0[p1 - p0] <= it &&
|
|
swebp__kabs0[q3 - q2] <= it &&
|
|
swebp__kabs0[q2 - q1] <= it &&
|
|
swebp__kabs0[q1 - q0] <= it;
|
|
}
|
|
|
|
static simplewebp_i32 swebp__hev(const simplewebp_u8 *p, simplewebp_i32 step, simplewebp_i32 thresh)
|
|
{
|
|
simplewebp_i32 p1, p0, q0, q1;
|
|
|
|
p1 = p[-2 * step];
|
|
p0 = p[-step];
|
|
q0 = p[0];
|
|
q1 = p[step];
|
|
|
|
return (swebp__kabs0[p1 - p0] > thresh) || (swebp__kabs0[q1 - q0] > thresh);
|
|
}
|
|
|
|
static void swebp__do_filter2(simplewebp_u8 *p, simplewebp_i32 step)
|
|
{
|
|
simplewebp_i32 p1, p0, q0, q1, a, a1, a2;
|
|
|
|
p1 = p[-2 * step];
|
|
p0 = p[-step];
|
|
q0 = p[0];
|
|
q1 = p[step];
|
|
a = 3 * (q0 - p0) + swebp__ksclip1[p1 - q1];
|
|
a1 = swebp__ksclip2[(a + 4) >> 3];
|
|
a2 = swebp__ksclip2[(a + 3) >> 3];
|
|
p[-step] = swebp__kclip1[p0 + a2];
|
|
p[0] = swebp__kclip1[q0 - a1];
|
|
}
|
|
|
|
static void swebp__do_filter6(simplewebp_u8 *p, simplewebp_i32 step)
|
|
{
|
|
simplewebp_i32 p2, p1, p0, q0, q1, q2, a, a1, a2, a3;
|
|
|
|
p2 = p[-3 * step];
|
|
p1 = p[-2 * step];
|
|
p0 = p[-step];
|
|
q0 = p[0];
|
|
q1 = p[step];
|
|
q2 = p[2 * step];
|
|
a = swebp__ksclip1[3 * (q0 - p0) + swebp__ksclip1[p1 - q1]];
|
|
a1 = (27 * a + 63) >> 7;
|
|
a2 = (18 * a + 63) >> 7;
|
|
a3 = (9 * a + 63) >> 7;
|
|
|
|
p[-3 * step] = swebp__kclip1[p2 + a3];
|
|
p[-2 * step] = swebp__kclip1[p1 + a2];
|
|
p[-step] = swebp__kclip1[p0 + a1];
|
|
p[0] = swebp__kclip1[q0 - a1];
|
|
p[step] = swebp__kclip1[q1 - a2];
|
|
p[2 * step] = swebp__kclip1[q2 - a3];
|
|
}
|
|
|
|
static void swebp__filterloop26(simplewebp_u8 *p, simplewebp_i32 hstride, simplewebp_i32 vstride, simplewebp_i32 size, simplewebp_i32 thresh, simplewebp_i32 ithresh, simplewebp_i32 hev_thresh)
|
|
{
|
|
simplewebp_i32 thresh2 = 2 * thresh + 1;
|
|
|
|
while (size-- > 0)
|
|
{
|
|
if (swebp__needsfilter2(p, hstride, thresh2, ithresh))
|
|
{
|
|
if (swebp__hev(p, hstride, hev_thresh))
|
|
swebp__do_filter2(p, hstride);
|
|
else
|
|
swebp__do_filter6(p, hstride);
|
|
}
|
|
|
|
p += vstride;
|
|
}
|
|
}
|
|
|
|
static void swebp__vfilter16(simplewebp_u8 *p, simplewebp_i32 stride, simplewebp_i32 thresh, simplewebp_i32 ithresh, simplewebp_i32 hev_thresh)
|
|
{
|
|
swebp__filterloop26(p, stride, 1, 16, thresh, ithresh, hev_thresh);
|
|
}
|
|
|
|
static void swebp__do_filter4(simplewebp_u8 *p, simplewebp_i32 step)
|
|
{
|
|
simplewebp_i32 p1, p0, q0, q1, a, a1, a2, a3;
|
|
|
|
p1 = p[-2 * step];
|
|
p0 = p[-step];
|
|
q0 = p[0];
|
|
q1 = p[step];
|
|
a = 3 * (q0 - p0);
|
|
a1 = swebp__ksclip2[(a + 4) >> 3];
|
|
a2 = swebp__ksclip2[(a + 3) >> 3];
|
|
a3 = (a1 + 1) >> 1;
|
|
|
|
p[-2 * step] = swebp__kclip1[p1 + a3];
|
|
p[-step] = swebp__kclip1[p0 + a2];
|
|
p[0] = swebp__kclip1[q0 - a1];
|
|
p[step] = swebp__kclip1[q1 - a3];
|
|
}
|
|
|
|
static void swebp__filterloop24(simplewebp_u8 *p, simplewebp_i32 hstride, simplewebp_i32 vstride, simplewebp_i32 size, simplewebp_i32 thresh, simplewebp_i32 ithresh, simplewebp_i32 hev_thresh)
|
|
{
|
|
simplewebp_i32 thresh2 = 2 * thresh + 1;
|
|
|
|
while (size-- > 0)
|
|
{
|
|
if (swebp__needsfilter2(p, hstride, thresh2, ithresh))
|
|
{
|
|
if (swebp__hev(p, hstride, hev_thresh))
|
|
swebp__do_filter2(p, hstride);
|
|
else
|
|
swebp__do_filter4(p, hstride);
|
|
}
|
|
|
|
p += vstride;
|
|
}
|
|
}
|
|
|
|
static void swebp__vfilter16_i(simplewebp_u8 *p, simplewebp_i32 stride, simplewebp_i32 thresh, simplewebp_i32 ithresh, simplewebp_i32 hev_thresh)
|
|
{
|
|
simplewebp_i32 i;
|
|
|
|
for (i = 3; i > 0; i--)
|
|
{
|
|
p += 4 * stride;
|
|
swebp__filterloop24(p, stride, 1, 16, thresh, ithresh, hev_thresh);
|
|
}
|
|
}
|
|
|
|
static void swebp__hfilter16(simplewebp_u8 *p, simplewebp_i32 stride, simplewebp_i32 thresh, simplewebp_i32 ithresh, simplewebp_i32 hev_thresh)
|
|
{
|
|
swebp__filterloop26(p, 1, stride, 16, thresh, ithresh, hev_thresh);
|
|
}
|
|
|
|
static void swebp__vfilter8(simplewebp_u8 *u, simplewebp_u8 *v, simplewebp_i32 stride, simplewebp_i32 thresh, simplewebp_i32 ithresh, simplewebp_i32 hev_thresh)
|
|
{
|
|
swebp__filterloop26(u, stride, 1, 8, thresh, ithresh, hev_thresh);
|
|
swebp__filterloop26(v, stride, 1, 8, thresh, ithresh, hev_thresh);
|
|
}
|
|
|
|
static void swebp__vfilter8_i(simplewebp_u8 *u, simplewebp_u8 *v, simplewebp_i32 stride, simplewebp_i32 thresh, simplewebp_i32 ithresh, simplewebp_i32 hev_thresh)
|
|
{
|
|
swebp__filterloop24(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
|
|
swebp__filterloop24(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
|
|
}
|
|
|
|
static simplewebp_bool swebp__needsfilter(const simplewebp_u8 *p, simplewebp_i32 step, simplewebp_i32 t)
|
|
{
|
|
simplewebp_i32 p1, p0, q0, q1;
|
|
|
|
p1 = p[-2 * step];
|
|
p0 = p[-step];
|
|
q0 = p[0];
|
|
q1 = p[step];
|
|
return (4 * swebp__kabs0[p0 - q0] + swebp__kabs0[p1 - q1]) <= t;
|
|
}
|
|
|
|
static void swebp__simple_vfilter16(simplewebp_u8 *p, simplewebp_i32 stride, simplewebp_i32 thresh)
|
|
{
|
|
simplewebp_i32 i, thresh2;
|
|
|
|
thresh2 = 2 * thresh + 1;
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
if (swebp__needsfilter(p + i, stride, thresh2))
|
|
swebp__do_filter2(p + i, stride);
|
|
}
|
|
}
|
|
|
|
static void swebp__simple_hfilter16(simplewebp_u8 *p, simplewebp_i32 stride, simplewebp_i32 thresh)
|
|
{
|
|
simplewebp_i32 i, thresh2;
|
|
simplewebp_u8 *target;
|
|
|
|
thresh2 = 2 * thresh + 1;
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
target = p + i * stride;
|
|
|
|
if (swebp__needsfilter(target, 1, thresh2))
|
|
swebp__do_filter2(target, 1);
|
|
}
|
|
}
|
|
|
|
static void swebp__simple_vfilter16_i(simplewebp_u8 *p, simplewebp_i32 stride, simplewebp_i32 thresh)
|
|
{
|
|
simplewebp_i32 k;
|
|
|
|
for (k = 3; k > 0; k--)
|
|
{
|
|
p += 4 * stride;
|
|
swebp__simple_vfilter16(p, stride, thresh);
|
|
}
|
|
}
|
|
|
|
static void swebp__simple_hfilter16_i(simplewebp_u8 *p, simplewebp_i32 stride, simplewebp_i32 thresh)
|
|
{
|
|
simplewebp_i32 k;
|
|
|
|
for (k = 3; k > 0; k--)
|
|
{
|
|
p += 4;
|
|
swebp__simple_hfilter16(p, stride, thresh);
|
|
}
|
|
}
|
|
|
|
static void swebp__hfilter16_i(simplewebp_u8 *p, simplewebp_i32 stride, simplewebp_i32 thresh, simplewebp_i32 ithresh, simplewebp_i32 hev_thresh)
|
|
{
|
|
simplewebp_i32 k;
|
|
|
|
for (k = 3; k > 0; k--)
|
|
{
|
|
p += 4;
|
|
swebp__filterloop24(p, 1, stride, 16, thresh, ithresh, hev_thresh);
|
|
}
|
|
}
|
|
|
|
static void swebp__hfilter8(simplewebp_u8 *u, simplewebp_u8 *v, simplewebp_i32 stride, simplewebp_i32 thresh, simplewebp_i32 ithresh, simplewebp_i32 hev_thresh)
|
|
{
|
|
swebp__filterloop26(u, 1, stride, 8, thresh, ithresh, hev_thresh);
|
|
swebp__filterloop26(v, 1, stride, 8, thresh, ithresh, hev_thresh);
|
|
}
|
|
|
|
static void swebp__hfilter8_i(simplewebp_u8 *u, simplewebp_u8 *v, simplewebp_i32 stride, simplewebp_i32 thresh, simplewebp_i32 ithresh, simplewebp_i32 hev_thresh)
|
|
{
|
|
swebp__filterloop24(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
|
|
swebp__filterloop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
|
|
}
|
|
|
|
/* DC */
|
|
static void swebp__predluma4_0(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_u32 dc;
|
|
simplewebp_i32 i;
|
|
|
|
dc = 4;
|
|
for (i = 0; i < 4; i++)
|
|
dc += out[i - 32] + out[-1 + i * 32];
|
|
dc >>= 3;
|
|
for (i = 0; i < 4; i++)
|
|
memset(out + i * 32, dc, 4);
|
|
}
|
|
|
|
static void swebp__truemotion(simplewebp_u8 *out, simplewebp_i32 size)
|
|
{
|
|
const simplewebp_u8 *top, *clip0, *clip;
|
|
simplewebp_i32 x, y;
|
|
|
|
top = out - 32;
|
|
clip0 = swebp__kclip1 - top[-1];
|
|
|
|
for (y = 0; y < size; y++)
|
|
{
|
|
clip = clip0 + out[-1];
|
|
|
|
for (x = 0; x < size; x++)
|
|
out[x] = clip[top[x]];
|
|
|
|
out += 32;
|
|
}
|
|
}
|
|
|
|
/* TM4 */
|
|
static void swebp__predluma4_1(simplewebp_u8 *out)
|
|
{
|
|
swebp__truemotion(out, 4);
|
|
}
|
|
|
|
static simplewebp_u8 swebp__avg3(simplewebp_u32 a, simplewebp_u32 b, simplewebp_u32 c)
|
|
{
|
|
return (simplewebp_u8) ((a + 2 * b + c + 2) >> 2);
|
|
}
|
|
|
|
/* Vertical */
|
|
static void swebp__predluma4_2(simplewebp_u8 *out)
|
|
{
|
|
const simplewebp_u8 *top;
|
|
simplewebp_u8 vals[4], i;
|
|
|
|
top = out - 32;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
vals[i] = swebp__avg3(top[i - 1], top[i], top[i + 1]);
|
|
for (i = 0; i < 4; i++)
|
|
memcpy(out + i * 32, vals, sizeof(vals));
|
|
}
|
|
|
|
static void swebp__from_uint32(simplewebp_u8 *out, simplewebp_u32 value)
|
|
{
|
|
/* Little endian */
|
|
out[0] = (simplewebp_u8) value;
|
|
out[1] = (simplewebp_u8) (value >> 8);
|
|
out[2] = (simplewebp_u8) (value >> 16);
|
|
out[3] = (simplewebp_u8) (value >> 24);
|
|
}
|
|
|
|
/* Horizontal*/
|
|
static void swebp__predluma4_3(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 vals[5], i;
|
|
for (i = -1; i < 4; i++)
|
|
vals[i + 1] = out[-1 + i * 32];
|
|
|
|
swebp__from_uint32(out, 0x01010101U * swebp__avg3(vals[0], vals[1], vals[2]));
|
|
swebp__from_uint32(out + 32, 0x01010101U * swebp__avg3(vals[1], vals[2], vals[3]));
|
|
swebp__from_uint32(out + 64, 0x01010101U * swebp__avg3(vals[2], vals[3], vals[4]));
|
|
swebp__from_uint32(out + 96, 0x01010101U * swebp__avg3(vals[3], vals[4], vals[4]));
|
|
}
|
|
|
|
/* Right Down */
|
|
static void swebp__predluma4_4(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_u32 i, j, k, l, x, a, b, c, d;
|
|
|
|
i = out[-1];
|
|
j = out[-1 + 1 * 32];
|
|
k = out[-1 + 2 * 32];
|
|
l = out[-1 + 3 * 32];
|
|
x = out[-1 - 32];
|
|
a = out[0 - 32];
|
|
b = out[1 - 32];
|
|
c = out[2 - 32];
|
|
d = out[3 - 32];
|
|
|
|
out[3 * 32 + 0] = swebp__avg3(j, k, l);
|
|
out[3 * 32 + 1] = out[2 * 32 + 0] = swebp__avg3(i, j, k);
|
|
out[3 * 32 + 2] = out[2 * 32 + 1] = out[1 * 32 + 0] = swebp__avg3(x, i, j);
|
|
out[3 * 32 + 3] = out[2 * 32 + 2] = out[1 * 32 + 1] = out[0 * 32 + 0] = swebp__avg3(a, x, i);
|
|
out[2 * 32 + 3] = out[1 * 32 + 2] = out[0 * 32 + 1] = swebp__avg3(b, a, x);
|
|
out[1 * 32 + 3] = out[0 * 32 + 2] = swebp__avg3(c, b, a);
|
|
out[0 * 32 + 3] = swebp__avg3(d, c, b);
|
|
}
|
|
|
|
static simplewebp_u8 swebp__avg2(simplewebp_u32 a, simplewebp_u32 b)
|
|
{
|
|
return (simplewebp_u8) ((a + b + 1) >> 1);
|
|
}
|
|
|
|
/* Vertical-Right */
|
|
static void swebp__predluma4_5(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_u32 i, j, k, x, a, b, c, d;
|
|
|
|
i = out[-1];
|
|
j = out[-1 + 1 * 32];
|
|
k = out[-1 + 2 * 32];
|
|
x = out[-1 - 32];
|
|
a = out[0 - 32];
|
|
b = out[1 - 32];
|
|
c = out[2 - 32];
|
|
d = out[3 - 32];
|
|
|
|
out[0 * 32 + 0] = out[2 * 32 + 1] = swebp__avg2(x, a);
|
|
out[0 * 32 + 1] = out[2 * 32 + 2] = swebp__avg2(a, b);
|
|
out[0 * 32 + 2] = out[2 * 32 + 3] = swebp__avg2(b, c);
|
|
out[0 * 32 + 3] = swebp__avg2(c, d);
|
|
out[3 * 32 + 0] = swebp__avg3(k, j, i);
|
|
out[2 * 32 + 0] = swebp__avg3(j, i, x);
|
|
out[1 * 32 + 0] = out[3 * 32 + 1] = swebp__avg3(i, x, a);
|
|
out[1 * 32 + 1] = out[3 * 32 + 2] = swebp__avg3(x, a, b);
|
|
out[1 * 32 + 2] = out[3 * 32 + 3] = swebp__avg3(a, b, c);
|
|
out[1 * 32 + 3] = swebp__avg3(b, c, d);
|
|
}
|
|
|
|
/* Left Down */
|
|
static void swebp__predluma4_6(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 a, b, c, d, e, f, g, h;
|
|
|
|
a = out[-32];
|
|
b = out[-31];
|
|
c = out[-30];
|
|
d = out[-29];
|
|
e = out[-28];
|
|
f = out[-27];
|
|
g = out[-26];
|
|
h = out[-25];
|
|
|
|
out[0 * 32 + 0] = swebp__avg3(a, b, c);
|
|
out[0 * 32 + 1] = out[1 * 32 + 0] = swebp__avg3(b, c, d);
|
|
out[0 * 32 + 2] = out[1 * 32 + 1] = out[2 * 32 + 0] = swebp__avg3(c, d, e);
|
|
out[0 * 32 + 3] = out[1 * 32 + 2] = out[2 * 32 + 1] = out[3 * 32 + 0] = swebp__avg3(d, e, f);
|
|
out[1 * 32 + 3] = out[2 * 32 + 2] = out[3 * 32 + 1] = swebp__avg3(e, f, g);
|
|
out[2 * 32 + 3] = out[3 * 32 + 2] = swebp__avg3(f, g, h);
|
|
out[3 * 32 + 3] = swebp__avg3(g, h, h);
|
|
}
|
|
|
|
/* Vertical-Left */
|
|
static void swebp__predluma4_7(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 a, b, c, d, e, f, g, h;
|
|
|
|
a = out[-32];
|
|
b = out[-31];
|
|
c = out[-30];
|
|
d = out[-29];
|
|
e = out[-28];
|
|
f = out[-27];
|
|
g = out[-26];
|
|
h = out[-25];
|
|
|
|
out[0 * 32 + 0] = swebp__avg2(a, b);
|
|
out[0 * 32 + 1] = out[2 * 32 + 0] = swebp__avg2(b, c);
|
|
out[0 * 32 + 2] = out[2 * 32 + 1] = swebp__avg2(c, d);
|
|
out[0 * 32 + 3] = out[2 * 32 + 2] = swebp__avg2(d, e);
|
|
out[1 * 32 + 0] = swebp__avg3(a, b, c);
|
|
out[1 * 32 + 1] = out[3 * 32 + 0] = swebp__avg3(b, c, d);
|
|
out[1 * 32 + 2] = out[3 * 32 + 1] = swebp__avg3(c, d, e);
|
|
out[1 * 32 + 3] = out[3 * 32 + 2] = swebp__avg3(d, e, f);
|
|
out[2 * 32 + 3] = swebp__avg3(e, f, g);
|
|
out[3 * 32 + 3] = swebp__avg3(f, g, h);
|
|
}
|
|
|
|
/* Horizontal-Down */
|
|
static void swebp__predluma4_8(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_u32 i, j, k, l, x, a, b, c;
|
|
|
|
i = out[-1];
|
|
j = out[-1 + 1 * 32];
|
|
k = out[-1 + 2 * 32];
|
|
l = out[-1 + 3 * 32];
|
|
x = out[-1 - 32];
|
|
a = out[0 - 32];
|
|
b = out[1 - 32];
|
|
c = out[2 - 32];
|
|
|
|
out[0 * 32 + 0] = out[1 * 32 + 2] = swebp__avg2(i, x);
|
|
out[1 * 32 + 0] = out[2 * 32 + 2] = swebp__avg2(j, i);
|
|
out[2 * 32 + 0] = out[3 * 32 + 2] = swebp__avg2(k, j);
|
|
out[3 * 32 + 0] = swebp__avg2(l, k);
|
|
out[0 * 32 + 3] = swebp__avg3(a, b, c);
|
|
out[0 * 32 + 2] = swebp__avg3(x, a, b);
|
|
out[0 * 32 + 1] = out[1 * 32 + 3] = swebp__avg3(i, x, a);
|
|
out[1 * 32 + 1] = out[2 * 32 + 3] = swebp__avg3(j, i, x);
|
|
out[2 * 32 + 1] = out[3 * 32 + 3] = swebp__avg3(k, j, i);
|
|
out[3 * 32 + 1] = swebp__avg3(l, k, j);
|
|
}
|
|
|
|
/* Horizontal-Up */
|
|
static void swebp__predluma4_9(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_u32 i, j, k, l;
|
|
|
|
i = out[-1];
|
|
j = out[-1 + 1 * 32];
|
|
k = out[-1 + 2 * 32];
|
|
l = out[-1 + 3 * 32];
|
|
|
|
out[0 * 32 + 0] = swebp__avg2(i, j);
|
|
out[0 * 32 + 2] = out[1 * 32 + 0] = swebp__avg2(j, k);
|
|
out[1 * 32 + 2] = out[2 * 32 + 0] = swebp__avg2(k, l);
|
|
out[0 * 32 + 1] = swebp__avg3(i, j, k);
|
|
out[0 * 32 + 3] = out[1 * 32 + 1] = swebp__avg3(j, k, l);
|
|
out[1 * 32 + 3] = out[2 * 32 + 1] = swebp__avg3(k, l, l);
|
|
out[2 * 32 + 3] = out[2 * 32 + 2] =
|
|
out[3 * 32 + 0] = out[3 * 32 + 1] =
|
|
out[3 * 32 + 2] = out[3 * 32 + 3] = l;
|
|
}
|
|
|
|
static void swebp__predluma4(simplewebp_u8 num, simplewebp_u8 *out)
|
|
{
|
|
switch (num)
|
|
{
|
|
case 0:
|
|
swebp__predluma4_0(out);
|
|
break;
|
|
case 1:
|
|
swebp__predluma4_1(out);
|
|
break;
|
|
case 2:
|
|
swebp__predluma4_2(out);
|
|
break;
|
|
case 3:
|
|
swebp__predluma4_3(out);
|
|
break;
|
|
case 4:
|
|
swebp__predluma4_4(out);
|
|
break;
|
|
case 5:
|
|
swebp__predluma4_5(out);
|
|
break;
|
|
case 6:
|
|
swebp__predluma4_6(out);
|
|
break;
|
|
case 7:
|
|
swebp__predluma4_7(out);
|
|
break;
|
|
case 8:
|
|
swebp__predluma4_8(out);
|
|
break;
|
|
case 9:
|
|
swebp__predluma4_9(out);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void swebp__put16(simplewebp_i32 v, simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 j;
|
|
for (j = 0; j < 16; j++)
|
|
memset(out + j * 32, v, 16);
|
|
}
|
|
|
|
/* DC */
|
|
static void swebp__predluma16_0(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 dc, j;
|
|
|
|
dc = 16;
|
|
for (j = 0; j < 16; j++)
|
|
dc += out[-1 + j * 32] + out[j - 32];
|
|
|
|
swebp__put16(dc >> 5, out);
|
|
}
|
|
|
|
/* TM */
|
|
static void swebp__predluma16_1(simplewebp_u8 *out)
|
|
{
|
|
swebp__truemotion(out, 16);
|
|
}
|
|
|
|
/* Vertical */
|
|
static void swebp__predluma16_2(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 j;
|
|
for (j = 0; j < 16; j++)
|
|
memcpy(out + j * 32, out - 32, 16);
|
|
}
|
|
|
|
/* Horizontal */
|
|
static void swebp__predluma16_3(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 j;
|
|
for (j = 16; j > 0; j--)
|
|
{
|
|
memset(out, out[-1], 16);
|
|
out += 32;
|
|
}
|
|
}
|
|
|
|
/* DC w/o Top */
|
|
static void swebp__predluma16_4(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 dc, j;
|
|
|
|
dc = 8;
|
|
for (j = 0; j < 16; j++)
|
|
dc += out[-1 + j * 32];
|
|
|
|
swebp__put16(dc >> 4, out);
|
|
}
|
|
|
|
/* DC w/o Left */
|
|
static void swebp__predluma16_5(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 dc, j;
|
|
|
|
dc = 8;
|
|
for (j = 0; j < 16; j++)
|
|
dc += out[j - 32];
|
|
|
|
swebp__put16(dc >> 4, out);
|
|
}
|
|
|
|
/* DC w/o Top Left */
|
|
static void swebp__predluma16_6(simplewebp_u8 *out)
|
|
{
|
|
swebp__put16(128, out);
|
|
}
|
|
|
|
static void swebp__predluma16(simplewebp_u8 num, simplewebp_u8 *out)
|
|
{
|
|
switch (num)
|
|
{
|
|
case 0:
|
|
swebp__predluma16_0(out);
|
|
break;
|
|
case 1:
|
|
swebp__predluma16_1(out);
|
|
break;
|
|
case 2:
|
|
swebp__predluma16_2(out);
|
|
break;
|
|
case 3:
|
|
swebp__predluma16_3(out);
|
|
break;
|
|
case 4:
|
|
swebp__predluma16_4(out);
|
|
break;
|
|
case 5:
|
|
swebp__predluma16_5(out);
|
|
break;
|
|
case 6:
|
|
swebp__predluma16_6(out);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void swebp__put8x8uv(simplewebp_i32 value, simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 j;
|
|
for (j = 0; j < 8; j++)
|
|
memset(out + j * 32, value, 8);
|
|
}
|
|
|
|
/* DC */
|
|
static void swebp__predchroma8_0(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 dc0, i;
|
|
|
|
dc0 = 8;
|
|
for (i = 0; i < 8; i++)
|
|
dc0 += out[i - 32] + out[-1 + i * 32];
|
|
|
|
swebp__put8x8uv(dc0 >> 4, out);
|
|
}
|
|
|
|
/* TM */
|
|
static void swebp__predchroma8_1(simplewebp_u8 *out)
|
|
{
|
|
swebp__truemotion(out, 8);
|
|
}
|
|
|
|
/* Vertical */
|
|
static void swebp__predchroma8_2(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 j;
|
|
for (j = 0; j < 8; j++)
|
|
memcpy(out + j * 32, out - 32, 8);
|
|
}
|
|
|
|
/* Horizontal */
|
|
static void swebp__predchroma8_3(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 j;
|
|
for (j = 0; j < 8; j++)
|
|
memset(out + j * 32, out[j * 32 - 1], 8);
|
|
}
|
|
|
|
/* DC w/o Top */
|
|
static void swebp__predchroma8_4(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 dc0, i;
|
|
|
|
dc0 = 4;
|
|
for (i = 0; i < 8; i++)
|
|
dc0 += out[-1 + i * 32];
|
|
|
|
swebp__put8x8uv(dc0 >> 3, out);
|
|
}
|
|
|
|
/* DC w/o Left */
|
|
static void swebp__predchroma8_5(simplewebp_u8 *out)
|
|
{
|
|
simplewebp_i32 dc0, i;
|
|
|
|
dc0 = 4;
|
|
for (i = 0; i < 8; i++)
|
|
dc0 += out[i - 32];
|
|
|
|
swebp__put8x8uv(dc0 >> 3, out);
|
|
}
|
|
|
|
/* DC w/o Top Left */
|
|
static void swebp__predchroma8_6(simplewebp_u8 *out)
|
|
{
|
|
swebp__put8x8uv(128, out);
|
|
}
|
|
|
|
static void swebp__predchroma8(simplewebp_u8 num, simplewebp_u8 *out)
|
|
{
|
|
switch (num)
|
|
{
|
|
case 0:
|
|
swebp__predchroma8_0(out);
|
|
break;
|
|
case 1:
|
|
swebp__predchroma8_1(out);
|
|
break;
|
|
case 2:
|
|
swebp__predchroma8_2(out);
|
|
break;
|
|
case 3:
|
|
swebp__predchroma8_3(out);
|
|
break;
|
|
case 4:
|
|
swebp__predchroma8_4(out);
|
|
break;
|
|
case 5:
|
|
swebp__predchroma8_5(out);
|
|
break;
|
|
case 6:
|
|
swebp__predchroma8_6(out);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* RFC 6386 section 11.5 */
|
|
static const simplewebp_u8 swebp__modes_proba[10][10][9] = {
|
|
{ { 231, 120, 48, 89, 115, 113, 120, 152, 112 },
|
|
{ 152, 179, 64, 126, 170, 118, 46, 70, 95 },
|
|
{ 175, 69, 143, 80, 85, 82, 72, 155, 103 },
|
|
{ 56, 58, 10, 171, 218, 189, 17, 13, 152 },
|
|
{ 114, 26, 17, 163, 44, 195, 21, 10, 173 },
|
|
{ 121, 24, 80, 195, 26, 62, 44, 64, 85 },
|
|
{ 144, 71, 10, 38, 171, 213, 144, 34, 26 },
|
|
{ 170, 46, 55, 19, 136, 160, 33, 206, 71 },
|
|
{ 63, 20, 8, 114, 114, 208, 12, 9, 226 },
|
|
{ 81, 40, 11, 96, 182, 84, 29, 16, 36 } },
|
|
{ { 134, 183, 89, 137, 98, 101, 106, 165, 148 },
|
|
{ 72, 187, 100, 130, 157, 111, 32, 75, 80 },
|
|
{ 66, 102, 167, 99, 74, 62, 40, 234, 128 },
|
|
{ 41, 53, 9, 178, 241, 141, 26, 8, 107 },
|
|
{ 74, 43, 26, 146, 73, 166, 49, 23, 157 },
|
|
{ 65, 38, 105, 160, 51, 52, 31, 115, 128 },
|
|
{ 104, 79, 12, 27, 217, 255, 87, 17, 7 },
|
|
{ 87, 68, 71, 44, 114, 51, 15, 186, 23 },
|
|
{ 47, 41, 14, 110, 182, 183, 21, 17, 194 },
|
|
{ 66, 45, 25, 102, 197, 189, 23, 18, 22 } },
|
|
{ { 88, 88, 147, 150, 42, 46, 45, 196, 205 },
|
|
{ 43, 97, 183, 117, 85, 38, 35, 179, 61 },
|
|
{ 39, 53, 200, 87, 26, 21, 43, 232, 171 },
|
|
{ 56, 34, 51, 104, 114, 102, 29, 93, 77 },
|
|
{ 39, 28, 85, 171, 58, 165, 90, 98, 64 },
|
|
{ 34, 22, 116, 206, 23, 34, 43, 166, 73 },
|
|
{ 107, 54, 32, 26, 51, 1, 81, 43, 31 },
|
|
{ 68, 25, 106, 22, 64, 171, 36, 225, 114 },
|
|
{ 34, 19, 21, 102, 132, 188, 16, 76, 124 },
|
|
{ 62, 18, 78, 95, 85, 57, 50, 48, 51 } },
|
|
{ { 193, 101, 35, 159, 215, 111, 89, 46, 111 },
|
|
{ 60, 148, 31, 172, 219, 228, 21, 18, 111 },
|
|
{ 112, 113, 77, 85, 179, 255, 38, 120, 114 },
|
|
{ 40, 42, 1, 196, 245, 209, 10, 25, 109 },
|
|
{ 88, 43, 29, 140, 166, 213, 37, 43, 154 },
|
|
{ 61, 63, 30, 155, 67, 45, 68, 1, 209 },
|
|
{ 100, 80, 8, 43, 154, 1, 51, 26, 71 },
|
|
{ 142, 78, 78, 16, 255, 128, 34, 197, 171 },
|
|
{ 41, 40, 5, 102, 211, 183, 4, 1, 221 },
|
|
{ 51, 50, 17, 168, 209, 192, 23, 25, 82 } },
|
|
{ { 138, 31, 36, 171, 27, 166, 38, 44, 229 },
|
|
{ 67, 87, 58, 169, 82, 115, 26, 59, 179 },
|
|
{ 63, 59, 90, 180, 59, 166, 93, 73, 154 },
|
|
{ 40, 40, 21, 116, 143, 209, 34, 39, 175 },
|
|
{ 47, 15, 16, 183, 34, 223, 49, 45, 183 },
|
|
{ 46, 17, 33, 183, 6, 98, 15, 32, 183 },
|
|
{ 57, 46, 22, 24, 128, 1, 54, 17, 37 },
|
|
{ 65, 32, 73, 115, 28, 128, 23, 128, 205 },
|
|
{ 40, 3, 9, 115, 51, 192, 18, 6, 223 },
|
|
{ 87, 37, 9, 115, 59, 77, 64, 21, 47 } },
|
|
{ { 104, 55, 44, 218, 9, 54, 53, 130, 226 },
|
|
{ 64, 90, 70, 205, 40, 41, 23, 26, 57 },
|
|
{ 54, 57, 112, 184, 5, 41, 38, 166, 213 },
|
|
{ 30, 34, 26, 133, 152, 116, 10, 32, 134 },
|
|
{ 39, 19, 53, 221, 26, 114, 32, 73, 255 },
|
|
{ 31, 9, 65, 234, 2, 15, 1, 118, 73 },
|
|
{ 75, 32, 12, 51, 192, 255, 160, 43, 51 },
|
|
{ 88, 31, 35, 67, 102, 85, 55, 186, 85 },
|
|
{ 56, 21, 23, 111, 59, 205, 45, 37, 192 },
|
|
{ 55, 38, 70, 124, 73, 102, 1, 34, 98 } },
|
|
{ { 125, 98, 42, 88, 104, 85, 117, 175, 82 },
|
|
{ 95, 84, 53, 89, 128, 100, 113, 101, 45 },
|
|
{ 75, 79, 123, 47, 51, 128, 81, 171, 1 },
|
|
{ 57, 17, 5, 71, 102, 57, 53, 41, 49 },
|
|
{ 38, 33, 13, 121, 57, 73, 26, 1, 85 },
|
|
{ 41, 10, 67, 138, 77, 110, 90, 47, 114 },
|
|
{ 115, 21, 2, 10, 102, 255, 166, 23, 6 },
|
|
{ 101, 29, 16, 10, 85, 128, 101, 196, 26 },
|
|
{ 57, 18, 10, 102, 102, 213, 34, 20, 43 },
|
|
{ 117, 20, 15, 36, 163, 128, 68, 1, 26 } },
|
|
{ { 102, 61, 71, 37, 34, 53, 31, 243, 192 },
|
|
{ 69, 60, 71, 38, 73, 119, 28, 222, 37 },
|
|
{ 68, 45, 128, 34, 1, 47, 11, 245, 171 },
|
|
{ 62, 17, 19, 70, 146, 85, 55, 62, 70 },
|
|
{ 37, 43, 37, 154, 100, 163, 85, 160, 1 },
|
|
{ 63, 9, 92, 136, 28, 64, 32, 201, 85 },
|
|
{ 75, 15, 9, 9, 64, 255, 184, 119, 16 },
|
|
{ 86, 6, 28, 5, 64, 255, 25, 248, 1 },
|
|
{ 56, 8, 17, 132, 137, 255, 55, 116, 128 },
|
|
{ 58, 15, 20, 82, 135, 57, 26, 121, 40 } },
|
|
{ { 164, 50, 31, 137, 154, 133, 25, 35, 218 },
|
|
{ 51, 103, 44, 131, 131, 123, 31, 6, 158 },
|
|
{ 86, 40, 64, 135, 148, 224, 45, 183, 128 },
|
|
{ 22, 26, 17, 131, 240, 154, 14, 1, 209 },
|
|
{ 45, 16, 21, 91, 64, 222, 7, 1, 197 },
|
|
{ 56, 21, 39, 155, 60, 138, 23, 102, 213 },
|
|
{ 83, 12, 13, 54, 192, 255, 68, 47, 28 },
|
|
{ 85, 26, 85, 85, 128, 128, 32, 146, 171 },
|
|
{ 18, 11, 7, 63, 144, 171, 4, 4, 246 },
|
|
{ 35, 27, 10, 146, 174, 171, 12, 26, 128 } },
|
|
{ { 190, 80, 35, 99, 180, 80, 126, 54, 45 },
|
|
{ 85, 126, 47, 87, 176, 51, 41, 20, 32 },
|
|
{ 101, 75, 128, 139, 118, 146, 116, 128, 85 },
|
|
{ 56, 41, 15, 176, 236, 85, 37, 9, 62 },
|
|
{ 71, 30, 17, 119, 118, 255, 17, 18, 138 },
|
|
{ 101, 38, 60, 138, 55, 70, 43, 26, 142 },
|
|
{ 146, 36, 19, 30, 171, 255, 97, 27, 20 },
|
|
{ 138, 45, 61, 62, 219, 1, 81, 188, 64 },
|
|
{ 32, 41, 20, 117, 151, 142, 20, 21, 163 },
|
|
{ 112, 19, 12, 61, 195, 128, 48, 4, 24 } }
|
|
};
|
|
|
|
static const simplewebp_u8 swebp__bands[17] = {
|
|
0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 0
|
|
};
|
|
|
|
static simplewebp_error swebp__load_vp8_header(struct swebp__vp8 *vp8d, simplewebp_u8 *buf, size_t bufsize)
|
|
{
|
|
struct swebp__segment_header *segmnt_hdr;
|
|
struct swebp__filter_header *filt_hdr;
|
|
struct swebp__bdec br;
|
|
|
|
/* Populate picture headers */
|
|
vp8d->mb_w = (vp8d->picture_header.width + 15) >> 4;
|
|
vp8d->mb_h = (vp8d->picture_header.height + 15) >> 4;
|
|
|
|
/* Reset proba */
|
|
memset(vp8d->proba.segments, 255, sizeof(vp8d->proba.segments));
|
|
/* Reset segment header */
|
|
vp8d->segment_header.use_segment = 0;
|
|
vp8d->segment_header.update_map = 0;
|
|
vp8d->segment_header.absolute_delta = 1;
|
|
memset(&vp8d->segment_header.quantizer, 0, sizeof(vp8d->segment_header.quantizer));
|
|
memset(&vp8d->segment_header.filter_strength, 0, sizeof(vp8d->segment_header.filter_strength));
|
|
|
|
/* Initialize bitreader */
|
|
swebp__bitread_init(&br, buf, vp8d->frame_header.partition_length);
|
|
buf += vp8d->frame_header.partition_length;
|
|
bufsize -= vp8d->frame_header.partition_length;
|
|
|
|
/* Read more picture headers. This is a keyframe */
|
|
vp8d->picture_header.colorspace = swebp__bitread_getval(&br, 1);
|
|
vp8d->picture_header.clamp_type = swebp__bitread_getval(&br, 1);
|
|
|
|
/* Parse segment header */
|
|
segmnt_hdr = &vp8d->segment_header;
|
|
segmnt_hdr->use_segment = swebp__bitread_getval(&br, 1);
|
|
if (segmnt_hdr->use_segment)
|
|
{
|
|
simplewebp_i32 s;
|
|
segmnt_hdr->update_map = swebp__bitread_getval(&br, 1);
|
|
|
|
if (swebp__bitread_getval(&br, 1) /* update data */)
|
|
{
|
|
segmnt_hdr->absolute_delta = swebp__bitread_getval(&br, 1);
|
|
for (s = 0; s < 4; s++)
|
|
segmnt_hdr->quantizer[s] = swebp__bitread_getval(&br, 1)
|
|
? swebp__bitread_getvalsigned(&br, 7)
|
|
: 0;
|
|
for (s = 0; s < 4; s++)
|
|
segmnt_hdr->filter_strength[s] = swebp__bitread_getval(&br, 1)
|
|
? swebp__bitread_getvalsigned(&br, 6)
|
|
: 0;
|
|
|
|
}
|
|
|
|
if (segmnt_hdr->update_map)
|
|
{
|
|
for (s = 0; s < 3; s++)
|
|
vp8d->proba.segments[s] = swebp__bitread_getval(&br, 1)
|
|
? swebp__bitread_getval(&br, 8)
|
|
: 255;
|
|
}
|
|
}
|
|
else
|
|
segmnt_hdr->update_map = 0;
|
|
|
|
if (br.eof)
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
|
|
/* Parse filters */
|
|
filt_hdr = &vp8d->filter_header;
|
|
filt_hdr->simple = swebp__bitread_getval(&br, 1);
|
|
filt_hdr->level = swebp__bitread_getval(&br, 6);
|
|
filt_hdr->sharpness = swebp__bitread_getval(&br, 3);
|
|
filt_hdr->use_lf_delta = swebp__bitread_getval(&br, 1);
|
|
|
|
if (filt_hdr->use_lf_delta)
|
|
{
|
|
if (swebp__bitread_getval(&br, 1) /* update lf-delta? */)
|
|
{
|
|
simplewebp_i32 i;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (swebp__bitread_getval(&br, 1))
|
|
filt_hdr->ref_lf_delta[i] = swebp__bitread_getvalsigned(&br, 6);
|
|
}
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (swebp__bitread_getval(&br, 1))
|
|
filt_hdr->mode_lf_delta[i] = swebp__bitread_getvalsigned(&br, 6);
|
|
}
|
|
}
|
|
}
|
|
|
|
vp8d->filter_type = filt_hdr->level == 0 ? 0 : (filt_hdr->simple ? 1 : 2);
|
|
|
|
if (br.eof)
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
|
|
/* Parse partitions */
|
|
{
|
|
simplewebp_u8 *sz, *buf_end, *part_start;
|
|
size_t size_left, last_part, p;
|
|
|
|
sz = buf;
|
|
buf_end = buf + bufsize;
|
|
size_left = bufsize;
|
|
|
|
last_part = vp8d->nparts_minus_1 = (1 << swebp__bitread_getval(&br, 2)) - 1;
|
|
if (3 * last_part > bufsize)
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
|
|
part_start = buf + last_part * 3;
|
|
size_left -= last_part * 3;
|
|
|
|
for (p = 0; p < last_part; p++)
|
|
{
|
|
size_t psize = swebp__to_uint24(sz);
|
|
if (psize > size_left)
|
|
psize = size_left;
|
|
|
|
swebp__bitread_init(vp8d->parts + p, part_start, psize);
|
|
part_start += psize;
|
|
size_left -= psize;
|
|
sz += 3;
|
|
}
|
|
|
|
swebp__bitread_init(vp8d->parts + last_part, part_start, size_left);
|
|
if (part_start >= buf_end)
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
}
|
|
|
|
/* Parse quantizer */
|
|
{
|
|
simplewebp_i32 base_q0, dqy1_dc, dqy2_dc, dqy2_ac, dquv_dc, dquv_ac, i;
|
|
base_q0 = swebp__bitread_getval(&br, 7);
|
|
dqy1_dc = swebp__bitread_getval(&br, 1)
|
|
? swebp__bitread_getvalsigned(&br, 4)
|
|
: 0;
|
|
dqy2_dc = swebp__bitread_getval(&br, 1)
|
|
? swebp__bitread_getvalsigned(&br, 4)
|
|
: 0;
|
|
dqy2_ac = swebp__bitread_getval(&br, 1)
|
|
? swebp__bitread_getvalsigned(&br, 4)
|
|
: 0;
|
|
dquv_dc = swebp__bitread_getval(&br, 1)
|
|
? swebp__bitread_getvalsigned(&br, 4)
|
|
: 0;
|
|
dquv_ac = swebp__bitread_getval(&br, 1)
|
|
? swebp__bitread_getvalsigned(&br, 4)
|
|
: 0;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
simplewebp_i32 q;
|
|
struct swebp__quantmat *m;
|
|
|
|
if (segmnt_hdr->use_segment)
|
|
q = segmnt_hdr->quantizer[i] + (!segmnt_hdr->absolute_delta) * base_q0;
|
|
else
|
|
{
|
|
if (i > 0)
|
|
{
|
|
vp8d->dqm[i] = vp8d->dqm[0];
|
|
continue;
|
|
}
|
|
else
|
|
q = base_q0;
|
|
}
|
|
|
|
m = vp8d->dqm + i;
|
|
m->y1_mat[0] = swebp__dctab[swebp__clip(q + dqy1_dc, 127)];
|
|
m->y1_mat[1] = swebp__actab[swebp__clip(q + 0, 127)];
|
|
|
|
m->y2_mat[0] = swebp__dctab[swebp__clip(q + dqy2_dc, 127)] * 2;
|
|
m->y2_mat[1] = (swebp__actab[swebp__clip(q + dqy2_ac, 127)] * 101581) >> 16;
|
|
if (m->y2_mat[1] < 8)
|
|
m->y2_mat[1] = 8;
|
|
|
|
m->uv_mat[0] = swebp__dctab[swebp__clip(q + dquv_dc, 117)];
|
|
m->uv_mat[1] = swebp__actab[swebp__clip(q + dquv_ac, 127)];
|
|
|
|
m->uv_quant = q + dquv_ac;
|
|
}
|
|
}
|
|
|
|
/* Ignore "update proba" */
|
|
swebp__bitread_getval(&br, 1);
|
|
|
|
/* Parse proba */
|
|
{
|
|
struct swebp__proba *proba;
|
|
simplewebp_i32 t, b, c, p, v;
|
|
|
|
proba = &vp8d->proba;
|
|
|
|
for (t = 0; t < 4; t++)
|
|
{
|
|
for (b = 0; b < 8; b++)
|
|
{
|
|
for (c = 0; c < 3; c++)
|
|
{
|
|
for (p = 0; p < 11; p++)
|
|
{
|
|
v = swebp__bitread_getbit(&br, swebp__coeff_update_proba[t][b][c][p])
|
|
? swebp__bitread_getval(&br, 8)
|
|
: swebp__coeff_proba0[t][b][c][p];
|
|
proba->bands[t][b].probas[c][p] = v;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (b = 0; b < 17; b++)
|
|
proba->bands_ptr[t][b] = &proba->bands[t][swebp__bands[b]];
|
|
}
|
|
|
|
vp8d->use_skip_proba = swebp__bitread_getval(&br, 1);
|
|
if (vp8d->use_skip_proba)
|
|
vp8d->skip_proba = swebp__bitread_getval(&br, 8);
|
|
}
|
|
|
|
if (br.eof)
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
|
|
vp8d->br = br;
|
|
vp8d->ready = 1;
|
|
return SIMPLEWEBP_NO_ERROR;
|
|
}
|
|
|
|
static void swebp__vp8_enter_critical(struct swebp__vp8 *vp8d)
|
|
{
|
|
vp8d->tl_mb_x = vp8d->tl_mb_y = 0;
|
|
vp8d->br_mb_x = vp8d->mb_w;
|
|
vp8d->br_mb_y = vp8d->mb_h;
|
|
|
|
if (vp8d->filter_type > 0)
|
|
{
|
|
simplewebp_i32 s;
|
|
struct swebp__filter_header *filt_hdr;
|
|
|
|
filt_hdr = &vp8d->filter_header;
|
|
|
|
for (s = 0; s < 4; s++)
|
|
{
|
|
simplewebp_i32 i4x4, base_level;
|
|
|
|
if (vp8d->segment_header.use_segment)
|
|
base_level = vp8d->segment_header.filter_strength[s]
|
|
+ filt_hdr->level * (!vp8d->segment_header.absolute_delta);
|
|
else
|
|
base_level = filt_hdr->level;
|
|
|
|
for (i4x4 = 0; i4x4 <= 1; i4x4++)
|
|
{
|
|
struct swebp__finfo *info;
|
|
simplewebp_i32 level;
|
|
|
|
info = &vp8d->fstrengths[s][i4x4];
|
|
level = base_level
|
|
+ filt_hdr->ref_lf_delta[0] * filt_hdr->use_lf_delta
|
|
+ filt_hdr->mode_lf_delta[0] * i4x4 * filt_hdr->use_lf_delta;
|
|
|
|
level = (level < 0) ? 0 : ((level > 63) ? 63 : level);
|
|
if (level > 0)
|
|
{
|
|
simplewebp_i32 ilevel = level;
|
|
|
|
if (filt_hdr->sharpness > 0)
|
|
{
|
|
ilevel >>= 1 + (filt_hdr->sharpness > 4);
|
|
|
|
if (ilevel > 9 - filt_hdr->sharpness)
|
|
ilevel = 9 - filt_hdr->sharpness;
|
|
}
|
|
|
|
if (ilevel < 1)
|
|
ilevel = 1;
|
|
|
|
info->ilevel = ilevel;
|
|
info->limit = 2 * level + ilevel;
|
|
info->hev_thresh = (level >= 40) + (level >= 15);
|
|
}
|
|
else
|
|
info->limit = 0;
|
|
|
|
info->inner = i4x4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void swebp__vp8_parse_intra_mode(struct swebp__vp8 *vp8d, simplewebp_i32 mb_x)
|
|
{
|
|
simplewebp_u8 *top, *left;
|
|
struct swebp__mblockdata *block;
|
|
struct swebp__bdec *br;
|
|
|
|
top = vp8d->intra_t + 4 * mb_x;
|
|
left = vp8d->intra_l;
|
|
block = vp8d->mb_data + mb_x;
|
|
br = &vp8d->br;
|
|
|
|
if (vp8d->segment_header.update_map)
|
|
block->segment = !swebp__bitread_getbit(br, vp8d->proba.segments[0])
|
|
? swebp__bitread_getbit(br, vp8d->proba.segments[1])
|
|
: swebp__bitread_getbit(br, vp8d->proba.segments[2]) + 2;
|
|
else
|
|
block->segment = 0;
|
|
|
|
if (vp8d->use_skip_proba)
|
|
block->skip = swebp__bitread_getbit(br, vp8d->skip_proba);
|
|
|
|
block->is_i4x4 = !swebp__bitread_getbit(br, 145);
|
|
if (!block->is_i4x4)
|
|
{
|
|
simplewebp_i32 ymode = swebp__bitread_getbit(br, 156)
|
|
? (swebp__bitread_getbit(br, 128) ? 1 : 3)
|
|
: (swebp__bitread_getbit(br, 163) ? 2 : 0);
|
|
|
|
block->imodes[0] = ymode;
|
|
memset(top, ymode, 4);
|
|
memset(left, ymode, 4);
|
|
}
|
|
else
|
|
{
|
|
simplewebp_u8 *modes;
|
|
simplewebp_i32 y;
|
|
|
|
modes = block->imodes;
|
|
for (y = 0; y < 4; y++)
|
|
{
|
|
simplewebp_i32 ymode, x;
|
|
|
|
ymode = left[y];
|
|
for (x = 0; x < 4; x++)
|
|
{
|
|
const simplewebp_u8 *const prob = swebp__modes_proba[top[x]][ymode];
|
|
ymode = !swebp__bitread_getbit(br, prob[0]) ? 0 :
|
|
!swebp__bitread_getbit(br, prob[1]) ? 1 :
|
|
!swebp__bitread_getbit(br, prob[2]) ? 2 :
|
|
!swebp__bitread_getbit(br, prob[3]) ?
|
|
(!swebp__bitread_getbit(br, prob[4]) ? 3 :
|
|
(!swebp__bitread_getbit(br, prob[5]) ? 4
|
|
: 5)) :
|
|
(!swebp__bitread_getbit(br, prob[6]) ? 6 :
|
|
(!swebp__bitread_getbit(br, prob[7]) ? 7 :
|
|
(!swebp__bitread_getbit(br, prob[8]) ? 8
|
|
: 9))
|
|
);
|
|
top[x] = ymode;
|
|
}
|
|
|
|
memcpy(modes, top, 4);
|
|
modes += 4;
|
|
left[y] = ymode;
|
|
}
|
|
}
|
|
|
|
block->uvmode = !swebp__bitread_getbit(br, 142) ? 0 : (
|
|
!swebp__bitread_getbit(br, 114) ? 2 : (
|
|
swebp__bitread_getbit(br, 183) ? 1 : 3
|
|
));
|
|
}
|
|
|
|
static simplewebp_i32 swebp__vp8_parse_intra_row(struct swebp__vp8 *vp8d)
|
|
{
|
|
simplewebp_i32 mb_x;
|
|
|
|
for (mb_x = 0; mb_x < vp8d->mb_w; mb_x++)
|
|
swebp__vp8_parse_intra_mode(vp8d, mb_x);
|
|
|
|
return !vp8d->br.eof;
|
|
}
|
|
|
|
static void swebp__vp8_init_scanline(struct swebp__vp8 *vp8d)
|
|
{
|
|
struct swebp__mblock *const left = vp8d->mb_info - 1;
|
|
left->nz = 0;
|
|
left->nz_dc = 0;
|
|
memset(vp8d->intra_l, 0, sizeof(vp8d->intra_l));
|
|
vp8d->mb_x = 0;
|
|
}
|
|
|
|
static simplewebp_u8 *swebp__vp8_alloc_memory(struct swebp__vp8 *vp8d, simplewebp_allocator *allocator)
|
|
{
|
|
simplewebp_i32 mb_w;
|
|
size_t intra_pred_mode_size, top_size, mb_info_size, f_info_size;
|
|
size_t yuv_size, mb_data_size, cache_height, cache_size, alpha_size, needed;
|
|
simplewebp_u8 *orig_mem, *mem;
|
|
|
|
mb_w = vp8d->mb_w;
|
|
intra_pred_mode_size = 4 * mb_w;
|
|
top_size = sizeof(struct swebp__topsmp) * mb_w;
|
|
mb_info_size = (mb_w + 1) * sizeof(struct swebp__mblock);
|
|
f_info_size = vp8d->filter_type > 0 ? (mb_w * sizeof(struct swebp__finfo)) : 0;
|
|
yuv_size = (32 * 17 + 32 * 9) * sizeof(*vp8d->yuv_b);
|
|
mb_data_size = mb_w * sizeof(*vp8d->mb_data);
|
|
cache_height = (16 + swebp__fextrarows[vp8d->filter_type]) * 3 / 2;
|
|
cache_size = top_size * cache_height;
|
|
alpha_size = vp8d->picture_header.width * vp8d->picture_header.width;
|
|
|
|
needed = intra_pred_mode_size
|
|
+ top_size
|
|
+ mb_info_size
|
|
+ f_info_size
|
|
+ yuv_size
|
|
+ mb_data_size
|
|
+ cache_size
|
|
+ alpha_size + 31;
|
|
|
|
mem = orig_mem = (simplewebp_u8 *) allocator->alloc(allocator->userdata, needed);
|
|
|
|
if (mem)
|
|
{
|
|
vp8d->mem = mem;
|
|
vp8d->mem_size = needed;
|
|
|
|
vp8d->intra_t = mem;
|
|
mem += intra_pred_mode_size;
|
|
|
|
vp8d->yuv_t = (struct swebp__topsmp *) mem;
|
|
mem += top_size;
|
|
|
|
vp8d->mb_info = ((struct swebp__mblock *) mem) + 1;
|
|
mem += mb_info_size;
|
|
|
|
vp8d->f_info = f_info_size ? (struct swebp__finfo *) mem : NULL;
|
|
mem += f_info_size;
|
|
|
|
mem = swebp__align32(mem);
|
|
vp8d->yuv_b = mem;
|
|
mem += yuv_size;
|
|
|
|
vp8d->mb_data = (struct swebp__mblockdata *) mem;
|
|
mem += mb_data_size;
|
|
|
|
vp8d->cache_y_stride = 16 * mb_w;
|
|
vp8d->cache_uv_stride = 8 * mb_w;
|
|
{
|
|
simplewebp_i32 extra_rows, extra_y, extra_uv;
|
|
|
|
extra_rows = swebp__fextrarows[vp8d->filter_type];
|
|
extra_y = extra_rows * vp8d->cache_y_stride;
|
|
extra_uv = (extra_rows / 2) * vp8d->cache_uv_stride;
|
|
vp8d->cache_y = mem + extra_y;
|
|
vp8d->cache_u = vp8d->cache_y + 16 * vp8d->cache_y_stride + extra_uv;
|
|
vp8d->cache_v = vp8d->cache_u + 8 * vp8d->cache_uv_stride + extra_uv;
|
|
}
|
|
mem += cache_size;
|
|
|
|
vp8d->alpha_plane = alpha_size ? mem : NULL;
|
|
mem += alpha_size;
|
|
|
|
memset(vp8d->mb_info - 1, 0, mb_info_size);
|
|
swebp__vp8_init_scanline(vp8d);
|
|
memset(vp8d->intra_t, 0, intra_pred_mode_size);
|
|
}
|
|
|
|
return orig_mem;
|
|
}
|
|
|
|
static const simplewebp_u8 swebp__cat3[] = { 173, 148, 140, 0 };
|
|
static const simplewebp_u8 swebp__cat4[] = { 176, 155, 140, 135, 0 };
|
|
static const simplewebp_u8 swebp__cat5[] = { 180, 157, 141, 134, 130, 0 };
|
|
static const simplewebp_u8 swebp__cat6[] = { 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129, 0 };
|
|
static const simplewebp_u8* const swebp__cat3456[] = {
|
|
swebp__cat3,
|
|
swebp__cat4,
|
|
swebp__cat5,
|
|
swebp__cat6
|
|
};
|
|
static const simplewebp_u8 swebp__zigzag[16] = {
|
|
0, 1, 4, 8,
|
|
5, 2, 3, 6,
|
|
9, 12, 13, 10,
|
|
7, 11, 14, 15
|
|
};
|
|
|
|
static simplewebp_i32 swebp__get_large_value(struct swebp__bdec *br, const simplewebp_u8 *p)
|
|
{
|
|
simplewebp_i32 v;
|
|
|
|
if (!swebp__bitread_getbit(br, p[3]))
|
|
{
|
|
if (!swebp__bitread_getbit(br, p[4]))
|
|
v = 2;
|
|
else
|
|
v = 3 + swebp__bitread_getbit(br, p[5]);
|
|
}
|
|
else
|
|
{
|
|
if (!swebp__bitread_getbit(br, p[6]))
|
|
{
|
|
if (!swebp__bitread_getbit(br, p[7]))
|
|
v = 5 + swebp__bitread_getbit(br, 159);
|
|
else
|
|
{
|
|
v = 7 + 2 * swebp__bitread_getbit(br, 165);
|
|
v += swebp__bitread_getbit(br, 145);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const simplewebp_u8 *tab;
|
|
simplewebp_i32 bit1, bit0, cat;
|
|
|
|
bit1 = swebp__bitread_getbit(br, p[8]);
|
|
bit0 = swebp__bitread_getbit(br, p[9 + bit1]);
|
|
cat = 2 * bit1 + bit0;
|
|
v = 0;
|
|
|
|
for (tab = swebp__cat3456[cat]; *tab; ++tab)
|
|
v += v + swebp__bitread_getbit(br, *tab);
|
|
|
|
v += 3 + (8 << cat);
|
|
}
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
static simplewebp_i32 swebp__get_coeffs(
|
|
struct swebp__bdec *br,
|
|
const struct swebp__bandprobas *prob[],
|
|
simplewebp_i32 ctx,
|
|
const swebp__quant_t dq,
|
|
simplewebp_i32 n,
|
|
simplewebp_i16 *out
|
|
)
|
|
{
|
|
const simplewebp_u8 *p = prob[n]->probas[ctx];
|
|
|
|
for (; n < 16; n++)
|
|
{
|
|
if (!swebp__bitread_getbit(br, p[0]))
|
|
return n;
|
|
|
|
while (!swebp__bitread_getbit(br, p[1]))
|
|
{
|
|
p = prob[++n]->probas[0];
|
|
if (n == 16)
|
|
return 1;
|
|
}
|
|
|
|
{
|
|
const swebp__probarray *p_ctx;
|
|
simplewebp_i32 v;
|
|
|
|
p_ctx = &prob[n + 1]->probas[0];
|
|
|
|
if (!swebp__bitread_getbit(br, p[2]))
|
|
{
|
|
v = 1;
|
|
p = p_ctx[1];
|
|
}
|
|
else
|
|
{
|
|
v = swebp__get_large_value(br, p);
|
|
p = p_ctx[2];
|
|
}
|
|
|
|
out[swebp__zigzag[n]] = swebp__bitread_getsigned(br, v) * dq[n > 0];
|
|
}
|
|
}
|
|
|
|
return 16;
|
|
}
|
|
|
|
static simplewebp_u32 swebp__nz_code_bits(simplewebp_u32 nz_coeffs, simplewebp_i32 nz, simplewebp_i8 dc_nz)
|
|
{
|
|
nz_coeffs <<= 2;
|
|
nz_coeffs |= (nz > 3) ? 3 : (nz > 1) ? 2 : dc_nz;
|
|
return nz_coeffs;
|
|
}
|
|
|
|
static simplewebp_i32 swebp__vp8_decode_macroblock(struct swebp__vp8 *vp8d, struct swebp__bdec *token_br)
|
|
{
|
|
struct swebp__mblock *left, *mb;
|
|
struct swebp__mblockdata *block;
|
|
simplewebp_u8 skip;
|
|
|
|
left = vp8d->mb_info - 1;
|
|
mb = vp8d->mb_info + vp8d->mb_x;
|
|
block = vp8d->mb_data + vp8d->mb_x;
|
|
skip = vp8d->use_skip_proba ? block->skip : 0;
|
|
|
|
if (!skip)
|
|
{
|
|
/* Parse residuals */
|
|
const struct swebp__bandprobas * (*bands)[17], **ac_proba;
|
|
struct swebp__quantmat *q;
|
|
simplewebp_i16 *dst;
|
|
struct swebp__mblock *left_mb;
|
|
simplewebp_u8 tnz, lnz;
|
|
simplewebp_u32 non0_y, non0_uv, out_t_nz, out_l_nz;
|
|
simplewebp_i32 x, y, ch, first;
|
|
|
|
bands = vp8d->proba.bands_ptr;
|
|
q = &vp8d->dqm[block->segment];
|
|
dst = block->coeffs;
|
|
left_mb = vp8d->mb_info - 1;
|
|
non0_y = non0_uv = 0;
|
|
|
|
memset(dst, 0, 384 * sizeof(simplewebp_i16));
|
|
if (!block->is_i4x4)
|
|
{
|
|
simplewebp_i16 dc[16];
|
|
simplewebp_i32 ctx, nz;
|
|
|
|
memset(dc, 0, sizeof(dc));
|
|
ctx = mb->nz_dc + left_mb->nz_dc;
|
|
nz = swebp__get_coeffs(token_br, bands[1], ctx, q->y2_mat, 0, dc);
|
|
|
|
mb->nz_dc = left_mb->nz_dc = nz > 0;
|
|
if (nz > 1)
|
|
swebp__transform_wht(dc, dst);
|
|
else
|
|
{
|
|
simplewebp_i32 i, dc0;
|
|
dc0 = (dc[0] + 3) >> 3;
|
|
for (i = 0; i < 16; i++)
|
|
dst[i * 16] = dc0;
|
|
}
|
|
|
|
first = 1;
|
|
ac_proba = bands[0];
|
|
}
|
|
else
|
|
{
|
|
first = 0;
|
|
ac_proba = bands[3];
|
|
}
|
|
|
|
tnz = mb->nz & 0xf;
|
|
lnz = left_mb->nz & 0xf;
|
|
|
|
for (y = 0; y < 4; y++)
|
|
{
|
|
simplewebp_i32 l;
|
|
simplewebp_u32 nz_coeffs;
|
|
|
|
l = lnz & 1;
|
|
nz_coeffs = 0;
|
|
|
|
for (x = 0; x < 4; x++)
|
|
{
|
|
simplewebp_i32 ctx, nz;
|
|
|
|
ctx = l + (tnz & 1);
|
|
nz = swebp__get_coeffs(token_br, ac_proba, ctx, q->y1_mat, first, dst);
|
|
l = nz > first;
|
|
tnz = (tnz >> 1) | (l << 7);
|
|
nz_coeffs = swebp__nz_code_bits(nz_coeffs, nz, dst[0] != 0);
|
|
dst += 16;
|
|
}
|
|
|
|
tnz >>= 4;
|
|
lnz = (lnz >> 1) | (l << 7);
|
|
non0_y = (non0_y << 8) | nz_coeffs;
|
|
}
|
|
|
|
out_t_nz = tnz;
|
|
out_l_nz = lnz >> 4;
|
|
|
|
for (ch = 0; ch < 4; ch += 2)
|
|
{
|
|
simplewebp_u32 nz_coeffs = 0;
|
|
|
|
tnz = mb->nz >> (4 + ch);
|
|
lnz = left_mb->nz >> (4 + ch);
|
|
|
|
for (y = 0; y < 2; y++)
|
|
{
|
|
simplewebp_i32 l = lnz & 1;
|
|
|
|
for (x = 0; x < 2; x++)
|
|
{
|
|
simplewebp_i32 ctx, nz;
|
|
|
|
ctx = l + (tnz & 1);
|
|
nz = swebp__get_coeffs(token_br, bands[2], ctx, q->uv_mat, 0, dst);
|
|
l = nz > 0;
|
|
tnz = (tnz >> 1) | (l << 3);
|
|
nz_coeffs = swebp__nz_code_bits(nz_coeffs, nz, dst[0] != 0);
|
|
dst += 16;
|
|
}
|
|
|
|
tnz >>= 2;
|
|
lnz = (lnz >> 1) | (l << 5);
|
|
}
|
|
|
|
non0_uv |= nz_coeffs << (4 * ch);
|
|
out_t_nz |= tnz << (4 + ch);
|
|
out_l_nz |= (lnz & 0xf0) << ch;
|
|
}
|
|
|
|
mb->nz = out_t_nz;
|
|
left_mb->nz = out_l_nz;
|
|
|
|
block->nonzero_y = non0_y;
|
|
block->nonzero_uv = non0_uv;
|
|
block->dither = (non0_uv & 0xaaaa) ? 0 : q->dither;
|
|
|
|
skip = !(non0_y | non0_uv);
|
|
}
|
|
else
|
|
{
|
|
left->nz = mb->nz = 0;
|
|
if (!block->is_i4x4)
|
|
left->nz_dc = mb->nz_dc = 0;
|
|
|
|
block->nonzero_y = block->nonzero_uv = block->dither = 0;
|
|
}
|
|
|
|
if (vp8d->filter_type > 0)
|
|
{
|
|
struct swebp__finfo *const finfo = vp8d->f_info + vp8d->mb_x;
|
|
*finfo = vp8d->fstrengths[block->segment][block->is_i4x4];
|
|
finfo->inner |= !skip;
|
|
}
|
|
|
|
return !token_br->eof;
|
|
}
|
|
|
|
static void swebp__do_transform(simplewebp_u32 bits, const simplewebp_i16 *src, simplewebp_u8 *dst)
|
|
{
|
|
switch (bits >> 30)
|
|
{
|
|
case 3:
|
|
swebp__transform(src, dst, 0);
|
|
break;
|
|
case 2:
|
|
swebp__transform_ac3(src, dst);
|
|
break;
|
|
case 1:
|
|
swebp__transform_dc(src, dst);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static simplewebp_i32 swebp__check_mode(simplewebp_i32 mb_x, simplewebp_i32 mb_y, simplewebp_i32 mode)
|
|
{
|
|
if (mode == 0) {
|
|
if (mb_x == 0)
|
|
return (mb_y == 0) ? 6 : 5;
|
|
else
|
|
return (mb_y == 0) ? 4 : 0;
|
|
}
|
|
|
|
return mode;
|
|
}
|
|
|
|
static void swebp__do_transform_uv(simplewebp_u32 bits, const simplewebp_i16 *src, simplewebp_u8 *dst)
|
|
{
|
|
if (bits & 0xff)
|
|
{
|
|
if (bits & 0xaa)
|
|
swebp__transform_uv(src, dst);
|
|
else
|
|
swebp__transform_dcuv(src, dst);
|
|
}
|
|
}
|
|
|
|
static simplewebp_i32 swebp__multhi(simplewebp_i32 v, simplewebp_i32 coeff)
|
|
{
|
|
return (v * coeff) >> 8;
|
|
}
|
|
|
|
static simplewebp_u8 swebp__yuv2rgb_clip8(simplewebp_i32 v)
|
|
{
|
|
return ((v & ~16383) == 0) ? ((simplewebp_u8) (v >> 6)) : (v < 0) ? 0 : 255;
|
|
}
|
|
|
|
static void swebp__yuv2rgb_plain(simplewebp_u8 y, simplewebp_u8 u, simplewebp_u8 v, struct swebp__pixel *rgb)
|
|
{
|
|
simplewebp_i32 yhi = swebp__multhi(y, 19077);
|
|
|
|
rgb->r = swebp__yuv2rgb_clip8(yhi + swebp__multhi(v, 26149) - 14234);
|
|
rgb->g = swebp__yuv2rgb_clip8(yhi - swebp__multhi(u, 6419) - swebp__multhi(v, 13320) + 8708);
|
|
rgb->b = swebp__yuv2rgb_clip8(yhi + swebp__multhi(u, 33050) - 17685);
|
|
}
|
|
|
|
/* r = top-left, g = top-right, b = bottom-left, a = bottom-right */
|
|
static struct swebp__pixel swebp__do_upsample_center(
|
|
const simplewebp_u8 *vtop,
|
|
const simplewebp_u8 *vmid,
|
|
const simplewebp_u8 *vbot,
|
|
size_t xm1,
|
|
size_t x,
|
|
size_t xp1
|
|
)
|
|
{
|
|
/*
|
|
Consider these layout:
|
|
0 1 2 3 4 5
|
|
y y y y y y 0
|
|
t1 t2 t3
|
|
y y y y y y 1
|
|
|
|
y y y y y y 2
|
|
u1 u2 u3
|
|
y y y y y y 3
|
|
|
|
y y y y y y 4
|
|
v1 v2 v3
|
|
y y y y y y 5
|
|
|
|
t, u, v are the chroma (CbCr/UV).
|
|
|
|
We want to place all of them in y, but note that t, u, and v are centered.
|
|
So (note this is XY order, not YX)
|
|
y22 = 9 * u2 + 3 * u1 + 3 * t2 + t1
|
|
y32 = 9 * u2 + 3 * u3 + 3 * t2 + t3
|
|
y23 = 9 * u2 + 3 * u1 + 3 * v2 + v1
|
|
y33 = 9 * u2 + 3 * u3 + 3 * v2 + v3
|
|
|
|
Now let's generalize it: assume x, y span from 0 to chroma dimensions:
|
|
y[x * 2 +0, y * 2 +0] = 9 * uv[x, y] + 3 * uv[x-1, y] + 3 * uv[x, y-1] + uv[x-1, y-1]
|
|
y[x * 2 +1, y * 2 +0] = 9 * uv[x, y] + 3 * uv[x+1, y] + 3 * uv[x, y-1] + uv[x+1, y-1]
|
|
y[x * 2 +0, y * 2 +1] = 9 * uv[x, y] + 3 * uv[x-1, y] + 3 * uv[x, y+1] + uv[x-1, y+1]
|
|
y[x * 2 +1, y * 2 +1] = 9 * uv[x, y] + 3 * uv[x+1, y] + 3 * uv[x, y+1] + uv[x+1, y+1]
|
|
|
|
For rounding, add + 8 to each, then divide the result by 16, so: (formula_above + 8) / 16
|
|
*/
|
|
|
|
struct swebp__pixel out;
|
|
|
|
out.r = (simplewebp_u8) ((9u * vmid[x] + 3u * vmid[xm1] + 3u * vtop[x] + vtop[xm1] + 8u) / 16u);
|
|
out.g = (simplewebp_u8) ((9u * vmid[x] + 3u * vmid[xp1] + 3u * vtop[x] + vtop[xp1] + 8u) / 16u);
|
|
out.b = (simplewebp_u8) ((9u * vmid[x] + 3u * vmid[xm1] + 3u * vbot[x] + vbot[xm1] + 8u) / 16u);
|
|
out.a = (simplewebp_u8) ((9u * vmid[x] + 3u * vmid[xp1] + 3u * vbot[x] + vbot[xp1] + 8u) / 16u);
|
|
return out;
|
|
}
|
|
|
|
/* This is bilinear interpolation with center chroma. */
|
|
/* See https://stackoverflow.com/a/43784809 */
|
|
static void swebp__upsample_chroma(
|
|
const simplewebp_u8 *u,
|
|
const simplewebp_u8 *v,
|
|
struct swebp__chroma *dst,
|
|
size_t w,
|
|
size_t h
|
|
)
|
|
{
|
|
size_t y, fw;
|
|
fw = w * 2;
|
|
|
|
for (y = 0; y < h; y++)
|
|
{
|
|
size_t prev_y, next_y, x;
|
|
const simplewebp_u8 *uline;
|
|
const simplewebp_u8 *vline;
|
|
const simplewebp_u8 *ulineprev;
|
|
const simplewebp_u8 *vlineprev;
|
|
const simplewebp_u8 *ulinenext;
|
|
const simplewebp_u8 *vlinenext;
|
|
|
|
prev_y = y == 0 ? 0 : (y - 1);
|
|
next_y = y == (h - 1) ? y : (y + 1);
|
|
ulineprev = u + prev_y * w;
|
|
vlineprev = v + prev_y * w;
|
|
ulinenext = u + next_y * w;
|
|
vlinenext = v + next_y * w;
|
|
uline = u + y * w;
|
|
vline = v + y * w;
|
|
|
|
for (x = 0; x < w; x++)
|
|
{
|
|
size_t prev_x, next_x, i00, i10, i01, i11;
|
|
struct swebp__pixel uvalue, vvalue;
|
|
|
|
prev_x = x == 0 ? x : (x - 1);
|
|
next_x = x == (w - 1) ? x : (x + 1);
|
|
uvalue = swebp__do_upsample_center(ulineprev, uline, ulinenext, prev_x, x, next_x);
|
|
vvalue = swebp__do_upsample_center(vlineprev, vline, vlinenext, prev_x, x, next_x);
|
|
i00 = (y * 2) * fw + (x * 2);
|
|
i10 = (y * 2) * fw + (x * 2 + 1);
|
|
i01 = (y * 2 + 1) * fw + (x * 2);
|
|
i11 = (y * 2 + 1) * fw + (x * 2 + 1);
|
|
|
|
dst[i00].u = uvalue.r;
|
|
dst[i00].v = vvalue.r;
|
|
dst[i10].u = uvalue.g;
|
|
dst[i10].v = vvalue.g;
|
|
dst[i01].u = uvalue.b;
|
|
dst[i01].v = vvalue.b;
|
|
dst[i11].u = uvalue.a;
|
|
dst[i11].v = vvalue.a;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void swebp__yuva2rgba(
|
|
const simplewebp_u8 *yp,
|
|
const struct swebp__chroma *uv,
|
|
const simplewebp_u8 *a,
|
|
size_t w,
|
|
size_t h,
|
|
struct swebp__pixel *rgba
|
|
)
|
|
{
|
|
size_t y, x, uvw;
|
|
|
|
uvw = ((w + 1) / 2) * 2;
|
|
|
|
for (y = 0; y < h; y++)
|
|
{
|
|
for (x = 0; x < w; x++)
|
|
{
|
|
swebp__yuv2rgb_plain(yp[y * w + x], uv[y * uvw + x].u, uv[y * uvw + x].v, &rgba[y * w + x]);
|
|
rgba[y * w + x].a = a[y * w + x];
|
|
}
|
|
}
|
|
}
|
|
|
|
static simplewebp_error swebp__vp8_process_row(struct swebp__vp8 *vp8d, struct swebp__yuvdst *destination)
|
|
{
|
|
simplewebp_i32 filter_row;
|
|
|
|
filter_row = vp8d->filter_type > 0 && vp8d->mb_y >= vp8d->tl_mb_y && vp8d->mb_y <= vp8d->br_mb_y;
|
|
|
|
/* Reconstruct row */
|
|
{
|
|
simplewebp_i32 j, mb_x, mb_y;
|
|
simplewebp_u8 *y_dst, *u_dst, *v_dst;
|
|
|
|
mb_y = vp8d->mb_y;
|
|
y_dst = vp8d->yuv_b + 40;
|
|
u_dst = vp8d->yuv_b + 584;
|
|
v_dst = vp8d->yuv_b + 600;
|
|
|
|
for (j = 0; j < 16; j++)
|
|
y_dst[j * 32 - 1] = 129;
|
|
for (j = 0; j < 8; j++)
|
|
{
|
|
u_dst[j * 32 - 1] = 129;
|
|
v_dst[j * 32 - 1] = 129;
|
|
}
|
|
|
|
if (mb_y > 0)
|
|
y_dst[-33] = u_dst[-33] = v_dst[-33] = 129;
|
|
else
|
|
{
|
|
memset(y_dst - 33, 127, 21);
|
|
memset(u_dst - 33, 127, 9);
|
|
memset(v_dst - 33, 127, 9);
|
|
}
|
|
|
|
for (mb_x = 0; mb_x < vp8d->mb_w; mb_x++)
|
|
{
|
|
struct swebp__mblockdata *const block = vp8d->mb_data + mb_x;
|
|
|
|
if (mb_x > 0)
|
|
{
|
|
for (j = -1; j < 16; j++)
|
|
memcpy(y_dst + j * 32 - 4, y_dst + j * 32 + 12, 4);
|
|
for (j = -1; j < 8; j++)
|
|
{
|
|
memcpy(u_dst + j * 32 - 4, u_dst + j * 32 + 4, 4);
|
|
memcpy(v_dst + j * 32 - 4, v_dst + j * 32 + 4, 4);
|
|
}
|
|
}
|
|
|
|
{
|
|
struct swebp__topsmp *top_yuv;
|
|
const simplewebp_i16 *coeffs;
|
|
simplewebp_u32 bits;
|
|
simplewebp_i32 n;
|
|
|
|
top_yuv = vp8d->yuv_t + mb_x;
|
|
coeffs = block->coeffs;
|
|
bits = block->nonzero_y;
|
|
|
|
if (mb_y > 0)
|
|
{
|
|
memcpy(y_dst - 32, top_yuv[0].y, 16);
|
|
memcpy(u_dst - 32, top_yuv[0].u, 8);
|
|
memcpy(v_dst - 32, top_yuv[0].v, 8);
|
|
}
|
|
|
|
if (block->is_i4x4)
|
|
{
|
|
simplewebp_u32 *const top_right = (simplewebp_u32 *) (y_dst - 32 + 16);
|
|
|
|
if (mb_y > 0)
|
|
{
|
|
if (mb_x >= vp8d->mb_w - 1)
|
|
memset(top_right, top_yuv[0].y[15], 4);
|
|
else
|
|
memcpy(top_right, top_yuv[1].y, 4);
|
|
}
|
|
|
|
top_right[32] = top_right[64] = top_right[96] = top_right[0];
|
|
|
|
for (n = 0; n < 16; n++, bits <<= 2)
|
|
{
|
|
/* kScan[n] = (n & 3) * 4 + (n >> 2) * 128 */
|
|
simplewebp_u8 *const dst = y_dst + ((n & 3) * 4 + (n >> 2) * 128);
|
|
swebp__predluma4(block->imodes[n], dst);
|
|
swebp__do_transform(bits, coeffs + n * 16, dst);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const simplewebp_i32 pred_func = swebp__check_mode(mb_x, mb_y, block->imodes[0]);
|
|
swebp__predluma16(pred_func, y_dst);
|
|
|
|
if (bits)
|
|
{
|
|
for (n = 0; n < 16; n++, bits <<= 2)
|
|
{
|
|
simplewebp_u8 *const dst = y_dst + ((n & 3) * 4 + (n >> 2) * 128);
|
|
swebp__do_transform(bits, coeffs + n * 16, dst);
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
/* Chroma */
|
|
simplewebp_u32 bits_uv;
|
|
simplewebp_i32 pred_func;
|
|
|
|
bits_uv = block->nonzero_uv;
|
|
pred_func = swebp__check_mode(mb_x, mb_y, block->uvmode);
|
|
|
|
swebp__predchroma8(pred_func, u_dst);
|
|
swebp__predchroma8(pred_func, v_dst);
|
|
swebp__do_transform_uv(bits_uv >> 0, coeffs + 16 * 16, u_dst);
|
|
swebp__do_transform_uv(bits_uv >> 8, coeffs + 20 * 16, v_dst);
|
|
}
|
|
|
|
if (mb_y < vp8d->mb_h - 1)
|
|
{
|
|
memcpy(top_yuv[0].y, y_dst + 15 * 32, 16);
|
|
memcpy(top_yuv[0].u, u_dst + 7 * 32, 8);
|
|
memcpy(top_yuv[0].v, v_dst + 7 * 32, 8);
|
|
}
|
|
}
|
|
|
|
/* Transfer reconstructed samples */
|
|
{
|
|
simplewebp_u8 *y_out, *u_out, *v_out;
|
|
|
|
y_out = vp8d->cache_y + mb_x * 16;
|
|
u_out = vp8d->cache_u + mb_x * 8;
|
|
v_out = vp8d->cache_v + mb_x * 8;
|
|
|
|
for (j = 0; j < 16; j++)
|
|
memcpy(y_out + j * vp8d->cache_y_stride, y_dst + j * 32, 16);
|
|
for (j = 0; j < 8; j++)
|
|
{
|
|
memcpy(u_out + j * vp8d->cache_uv_stride, u_dst + j * 32, 8);
|
|
memcpy(v_out + j * vp8d->cache_uv_stride, v_dst + j * 32, 8);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Finish row */
|
|
{
|
|
simplewebp_i32 extra_y_rows, ysize, uvsize, mb_y;
|
|
simplewebp_u8 *ydst, *udst, *vdst, is_first_row, is_last_row;
|
|
|
|
extra_y_rows = swebp__fextrarows[vp8d->filter_type];
|
|
ysize = extra_y_rows * vp8d->cache_y_stride;
|
|
uvsize = (extra_y_rows / 2) * vp8d->cache_uv_stride;
|
|
ydst = vp8d->cache_y - ysize;
|
|
udst = vp8d->cache_u - uvsize;
|
|
vdst = vp8d->cache_v - uvsize;
|
|
mb_y = vp8d->mb_y;
|
|
is_first_row = mb_y == 0;
|
|
is_last_row = mb_y >= vp8d->br_mb_y - 1;
|
|
|
|
if (filter_row)
|
|
{
|
|
/* Filter row */
|
|
simplewebp_i32 mb_x;
|
|
|
|
for (mb_x = vp8d->tl_mb_x; mb_x < vp8d->br_mb_x; mb_x++)
|
|
{
|
|
simplewebp_i32 y_bps, ilevel, limit;
|
|
struct swebp__finfo *f_info;
|
|
simplewebp_u8 *y_dst;
|
|
|
|
f_info = vp8d->f_info + mb_x;
|
|
limit = f_info->limit;
|
|
|
|
if (limit > 0)
|
|
{
|
|
ilevel = f_info->ilevel;
|
|
y_bps = vp8d->cache_y_stride;
|
|
y_dst = vp8d->cache_y + mb_x * 16;
|
|
|
|
if (vp8d->filter_type == 1)
|
|
{
|
|
/* Simple filter */
|
|
if (mb_x > 0)
|
|
swebp__simple_hfilter16(y_dst, y_bps, limit + 4);
|
|
if (f_info->inner)
|
|
swebp__simple_hfilter16_i(y_dst, y_bps, limit);
|
|
if (mb_y > 0)
|
|
swebp__simple_vfilter16(y_dst, y_bps, limit + 4);
|
|
if (f_info->inner)
|
|
swebp__simple_vfilter16_i(y_dst, y_bps, limit);
|
|
}
|
|
else
|
|
{
|
|
/* Complex filter */
|
|
simplewebp_i32 uv_bps, hev_thresh;
|
|
simplewebp_u8 *u_dst, *v_dst;
|
|
|
|
uv_bps = vp8d->cache_uv_stride;
|
|
hev_thresh = f_info->hev_thresh;
|
|
u_dst = vp8d->cache_u + mb_x * 8;
|
|
v_dst = vp8d->cache_v + mb_x * 8;
|
|
|
|
if (mb_x > 0)
|
|
{
|
|
swebp__hfilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh);
|
|
swebp__hfilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh);
|
|
}
|
|
if (f_info->inner)
|
|
{
|
|
swebp__hfilter16_i(y_dst, y_bps, limit, ilevel, hev_thresh);
|
|
swebp__hfilter8_i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh);
|
|
}
|
|
if (mb_y > 0)
|
|
{
|
|
swebp__vfilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh);
|
|
swebp__vfilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh);
|
|
}
|
|
if (f_info->inner)
|
|
{
|
|
swebp__vfilter16_i(y_dst, y_bps, limit, ilevel, hev_thresh);
|
|
swebp__vfilter8_i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
/* Write YUV */
|
|
simplewebp_u8 *y_out, *u_out, *v_out;
|
|
simplewebp_i32 y_start, y_end;
|
|
|
|
y_start = mb_y * 16;
|
|
y_end = (mb_y + 1) * 16;
|
|
if (!is_first_row)
|
|
{
|
|
y_start -= extra_y_rows;
|
|
y_out = ydst;
|
|
u_out = udst;
|
|
v_out = vdst;
|
|
}
|
|
else
|
|
{
|
|
y_out = vp8d->cache_y;
|
|
u_out = vp8d->cache_u;
|
|
v_out = vp8d->cache_v;
|
|
}
|
|
|
|
if (!is_last_row)
|
|
y_end -= extra_y_rows;
|
|
if (y_end > vp8d->picture_header.height)
|
|
y_end = vp8d->picture_header.height;
|
|
|
|
{
|
|
/* Copy YUV buffer */
|
|
simplewebp_i32 row, iwidth, iwidth2, uv_start, uv_end;
|
|
|
|
iwidth = vp8d->picture_header.width;
|
|
iwidth2 = (iwidth + 1) / 2;
|
|
uv_start = y_start / 2;
|
|
uv_end = (y_end + 1) / 2;
|
|
|
|
/* Copy Y and A buffer */
|
|
for (row = y_start; row < y_end; row++)
|
|
memcpy(destination->y + row * iwidth, y_out + (row - y_start) * vp8d->cache_y_stride, iwidth);
|
|
|
|
/* Copy U and V buffer */
|
|
for (row = uv_start; row < uv_end; row++)
|
|
{
|
|
memcpy(destination->u + row * iwidth2, u_out + (row - uv_start) * vp8d->cache_uv_stride, iwidth2);
|
|
memcpy(destination->v + row * iwidth2, v_out + (row - uv_start) * vp8d->cache_uv_stride, iwidth2);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Rotate top samples */
|
|
if (!is_last_row)
|
|
{
|
|
memcpy(vp8d->cache_y - ysize, ydst + 16 * vp8d->cache_y_stride, ysize);
|
|
memcpy(vp8d->cache_u - uvsize, udst + 8 * vp8d->cache_uv_stride, uvsize);
|
|
memcpy(vp8d->cache_v - uvsize, vdst + 8 * vp8d->cache_uv_stride, uvsize);
|
|
}
|
|
}
|
|
|
|
return SIMPLEWEBP_NO_ERROR;
|
|
}
|
|
|
|
static simplewebp_error swebp__vp8_parse_frame(struct swebp__vp8 *vp8d, struct swebp__yuvdst *destination)
|
|
{
|
|
simplewebp_error err;
|
|
|
|
for (vp8d->mb_y = 0; vp8d->mb_y < vp8d->br_mb_y; vp8d->mb_y++)
|
|
{
|
|
struct swebp__bdec *token_br = &vp8d->parts[vp8d->mb_y & vp8d->nparts_minus_1];
|
|
|
|
if (!swebp__vp8_parse_intra_row(vp8d))
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
|
|
for (vp8d->mb_x = 0; vp8d->mb_x < vp8d->mb_w; vp8d->mb_x++)
|
|
{
|
|
if (!swebp__vp8_decode_macroblock(vp8d, token_br))
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
}
|
|
|
|
/* Prepare for next scanline and reconstruct it */
|
|
swebp__vp8_init_scanline(vp8d);
|
|
err = swebp__vp8_process_row(vp8d, destination);
|
|
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
return err;
|
|
}
|
|
|
|
return SIMPLEWEBP_NO_ERROR;
|
|
}
|
|
|
|
static simplewebp_error swebp__decode_lossy(simplewebp *simplewebp, struct swebp__yuvdst *destination, void *settings)
|
|
{
|
|
simplewebp_input input;
|
|
size_t vp8size;
|
|
simplewebp_u8 *vp8buffer, *decoder_mem;
|
|
struct swebp__vp8 *vp8d;
|
|
simplewebp_error err;
|
|
|
|
vp8d = &simplewebp->decoder.vp8;
|
|
input = simplewebp->vp8_input;
|
|
|
|
if (!swebp__seek(0, &input))
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
|
|
vp8size = swebp__proxy_size(input.userdata);
|
|
/* Sanity check */
|
|
if (vp8d->frame_header.partition_length > vp8size)
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
|
|
/* Read all VP8 chunk */
|
|
vp8buffer = (simplewebp_u8 *) swebp__alloc(simplewebp, vp8size);
|
|
if (vp8buffer == NULL)
|
|
return SIMPLEWEBP_ALLOC_ERROR;
|
|
|
|
if (!swebp__read2(vp8size, vp8buffer, &input))
|
|
{
|
|
swebp__dealloc(simplewebp, vp8buffer);
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
}
|
|
|
|
/* Let's skip already-read stuff at swebp__load_lossy */
|
|
if (!swebp__seek(10, &input))
|
|
{
|
|
swebp__dealloc(simplewebp, vp8buffer);
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
}
|
|
|
|
err = swebp__load_vp8_header(&simplewebp->decoder.vp8, vp8buffer + 10, vp8size - 10);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
{
|
|
swebp__dealloc(simplewebp, vp8buffer);
|
|
return err;
|
|
}
|
|
|
|
/* Enter critical */
|
|
swebp__vp8_enter_critical(&simplewebp->decoder.vp8);
|
|
decoder_mem = swebp__vp8_alloc_memory(vp8d, &simplewebp->allocator);
|
|
|
|
if (decoder_mem == NULL)
|
|
{
|
|
swebp__dealloc(simplewebp, vp8buffer);
|
|
return SIMPLEWEBP_ALLOC_ERROR;
|
|
}
|
|
|
|
err = swebp__vp8_parse_frame(vp8d, destination);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
{
|
|
swebp__dealloc(simplewebp, decoder_mem);
|
|
swebp__dealloc(simplewebp, vp8buffer);
|
|
return err;
|
|
}
|
|
|
|
/* Exit critical and cleanup */
|
|
swebp__dealloc(simplewebp, decoder_mem);
|
|
swebp__dealloc(simplewebp, vp8buffer);
|
|
vp8d->mem = NULL;
|
|
vp8d->mem_size = 0;
|
|
memset(&vp8d->br, 0, sizeof(struct swebp__bdec));
|
|
vp8d->ready = 0;
|
|
|
|
return swebp__alpha_decode(simplewebp, destination->a);
|
|
}
|
|
|
|
struct swebp__vp8l_code_node
|
|
{
|
|
simplewebp_u16 child[2];
|
|
};
|
|
|
|
struct swebp__vp8l_code
|
|
{
|
|
simplewebp_u16 size;
|
|
/* Constructing root: symbol[0] | (symbol[1] << 8) */
|
|
simplewebp_u8 symbol[2];
|
|
struct swebp__vp8l_code_node *tree;
|
|
};
|
|
|
|
struct swebp__vp8l_group
|
|
{
|
|
struct swebp__vp8l_code code[5];
|
|
};
|
|
|
|
const simplewebp_u16 swebp__vp8l_literals_count = 256;
|
|
const simplewebp_u16 swebp__vp8l_distances_count = 40;
|
|
const simplewebp_u16 swebp__vp8l_litlen_count = 256 + 24;
|
|
const size_t swebp__vp8l_offset_count = 120;
|
|
|
|
static const simplewebp_u8 swebp__vp8l_lencode_order[19] = {
|
|
17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
|
};
|
|
|
|
static const simplewebp_i8 swebp__vp8l_offsets[120][2] = {
|
|
{ 0, 1}, { 1, 0 }, { 1, 1}, {-1, 1}, { 0, 2}, { 2, 0},
|
|
{ 1, 2}, {-1, 2 }, { 2, 1}, {-2, 1}, { 2, 2}, {-2, 2},
|
|
{ 0, 3}, { 3, 0 }, { 1, 3}, {-1, 3}, { 3, 1}, {-3, 1},
|
|
{ 2, 3}, {-2, 3 }, { 3, 2}, {-3, 2}, { 0, 4}, { 4, 0},
|
|
{ 1, 4}, {-1, 4 }, { 4, 1}, {-4, 1}, { 3, 3}, {-3, 3},
|
|
{ 2, 4}, {-2, 4 }, { 4, 2}, {-4, 2}, { 0, 5}, { 3, 4},
|
|
{-3, 4}, { 4, 3 }, {-4, 3}, { 5, 0}, { 1, 5}, {-1, 5},
|
|
{ 5, 1}, {-5, 1 }, { 2, 5}, {-2, 5}, { 5, 2}, {-5, 2},
|
|
{ 4, 4}, {-4, 4 }, { 3, 5}, {-3, 5}, { 5, 3}, {-5, 3},
|
|
{ 0, 6}, { 6, 0 }, { 1, 6}, {-1, 6}, { 6, 1}, {-6, 1},
|
|
{ 2, 6}, {-2, 6 }, { 6, 2}, {-6, 2}, { 4, 5}, {-4, 5},
|
|
{ 5, 4}, {-5, 4 }, { 3, 6}, {-3, 6}, { 6, 3}, {-6, 3},
|
|
{ 0, 7}, { 7, 0 }, { 1, 7}, {-1, 7}, { 5, 5}, {-5, 5},
|
|
{ 7, 1}, {-7, 1 }, { 4, 6}, {-4, 6}, { 6, 4}, {-6, 4},
|
|
{ 2, 7}, {-2, 7 }, { 7, 2}, {-7, 2}, { 3, 7}, {-3, 7},
|
|
{ 7, 3}, {-7, 3 }, { 5, 6}, {-5, 6}, { 6, 5}, {-6, 5},
|
|
{ 8, 0}, { 4, 7 }, {-4, 7}, { 7, 4}, {-7, 4}, { 8, 1},
|
|
{ 8, 2}, { 6, 6 }, {-6, 6}, { 8, 3}, { 5, 7}, {-5, 7},
|
|
{ 7, 5}, {-7, 5 }, { 8, 4}, { 6, 7}, {-6, 7}, { 7, 6},
|
|
{-7, 6}, { 8, 5 }, { 7, 7}, {-7, 7}, { 8, 6}, { 8, 7},
|
|
};
|
|
|
|
static void swebp__vp8l_insert_code(
|
|
struct swebp__vp8l_code_node *tree,
|
|
simplewebp_u16 *root,
|
|
simplewebp_u16 size,
|
|
simplewebp_u16 symbol,
|
|
simplewebp_u16 word,
|
|
simplewebp_u16 *used,
|
|
simplewebp_u8 length
|
|
)
|
|
{
|
|
while (length)
|
|
{
|
|
simplewebp_u16 index;
|
|
struct swebp__vp8l_code_node *node;
|
|
|
|
index = *root;
|
|
if (index < size)
|
|
{
|
|
*root = (*used)++;
|
|
node = tree + (*root - size);
|
|
}
|
|
else
|
|
node = tree + (index - size);
|
|
|
|
root = &node->child[(word >> --length) & 1];
|
|
}
|
|
|
|
*root = symbol;
|
|
}
|
|
|
|
static simplewebp_error swebp__vp8l_canonical_code(
|
|
simplewebp *simplewebp,
|
|
simplewebp_u8 *lengths,
|
|
simplewebp_u16 size,
|
|
struct swebp__vp8l_code *code,
|
|
struct swebp__vp8l_code_node *treemem
|
|
)
|
|
{
|
|
simplewebp_u16 base[16], real_size, current_base, root, used;
|
|
struct swebp__vp8l_code_node *tree;
|
|
size_t i;
|
|
|
|
memset(base, 0, sizeof(base));
|
|
real_size = 0;
|
|
current_base = 0;
|
|
root = 0;
|
|
used = size;
|
|
tree = NULL;
|
|
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
simplewebp_u8 length = lengths[i];
|
|
if (length > 0)
|
|
{
|
|
base[length - 1]++;
|
|
real_size++;
|
|
}
|
|
}
|
|
real_size--;
|
|
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
simplewebp_u16 c = base[i];
|
|
base[i] = current_base;
|
|
current_base = (current_base + c) << 1;
|
|
}
|
|
|
|
if (treemem)
|
|
tree = treemem;
|
|
else
|
|
{
|
|
tree = (struct swebp__vp8l_code_node*) swebp__alloc(
|
|
simplewebp,
|
|
sizeof(struct swebp__vp8l_code_node) * real_size
|
|
);
|
|
if (!tree)
|
|
return SIMPLEWEBP_ALLOC_ERROR;
|
|
}
|
|
|
|
for (i = 0; i < real_size; i++)
|
|
{
|
|
tree[i].child[0] = 0;
|
|
tree[i].child[1] = 0;
|
|
}
|
|
|
|
for (i = 0; i < size; i++)
|
|
{
|
|
simplewebp_u8 l = lengths[i];
|
|
if (l > 0)
|
|
swebp__vp8l_insert_code(tree, &root, size, (simplewebp_u16) i, base[l - 1]++, &used, l);
|
|
}
|
|
|
|
code->size = size;
|
|
code->tree = tree;
|
|
code->symbol[0] = root & 0xFF;
|
|
code->symbol[1] = (root >> 8) & 0xFF;
|
|
|
|
return SIMPLEWEBP_NO_ERROR;
|
|
}
|
|
|
|
static simplewebp_u16 swebp__vp8l_read_code(struct swebp__vp8l_bdec *br, struct swebp__vp8l_code *code)
|
|
{
|
|
if (code->tree)
|
|
{
|
|
simplewebp_u16 index = code->symbol[0] | (((simplewebp_u16) code->symbol[1]) << 8);
|
|
|
|
while (index >= code->size)
|
|
index = code->tree[index - code->size].child[swebp__vp8l_bitread_read(br, 1)];
|
|
|
|
return index;
|
|
}
|
|
else
|
|
return code->symbol[code->size < 2 ? 0 : swebp__vp8l_bitread_read(br, 1)];
|
|
}
|
|
|
|
static simplewebp_error swebp__vp8l_decode_code_complex(
|
|
simplewebp *simplewebp,
|
|
struct swebp__vp8l_bdec *br,
|
|
struct swebp__vp8l_code *code,
|
|
simplewebp_u16 size
|
|
)
|
|
{
|
|
size_t i;
|
|
simplewebp_u8 lencode_lengths[19], lencode_read;
|
|
simplewebp_u8 lengths[256 + 24 + 2048];
|
|
simplewebp_u16 limit, count, p;
|
|
simplewebp_error err;
|
|
struct swebp__vp8l_code_node lencode_treemem[18];
|
|
struct swebp__vp8l_code lc;
|
|
|
|
lencode_read = (simplewebp_u8) swebp__vp8l_bitread_read(br, 4) + 4;
|
|
for (i = 0; i < 19; i++)
|
|
lencode_lengths[swebp__vp8l_lencode_order[i]] = i < lencode_read ? swebp__vp8l_bitread_read(br, 3) : 0;
|
|
|
|
if (swebp__vp8l_bitread_read(br, 1))
|
|
limit = swebp__vp8l_bitread_read(br, swebp__vp8l_bitread_read(br, 3) * 2 + 2) + 2;
|
|
else
|
|
limit = size;
|
|
|
|
if (br->eos)
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
|
|
err = swebp__vp8l_canonical_code(simplewebp, lencode_lengths, 19, &lc, lencode_treemem);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
return err;
|
|
|
|
count = 0;
|
|
p = 8;
|
|
|
|
for (i = 0; count < size && i < limit; i++)
|
|
{
|
|
simplewebp_u16 s, c;
|
|
|
|
s = swebp__vp8l_read_code(br, &lc);
|
|
c = 0;
|
|
|
|
if (br->eos)
|
|
{
|
|
swebp__dealloc(simplewebp, lc.tree);
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
}
|
|
|
|
switch (s)
|
|
{
|
|
default:
|
|
case 0:
|
|
lengths[count++] = (simplewebp_u8) s;
|
|
continue;
|
|
/* fall through */
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
case 13:
|
|
case 14:
|
|
case 15:
|
|
lengths[count++] = (simplewebp_u8) (p = s);
|
|
continue;
|
|
case 16:
|
|
s = 3 + swebp__vp8l_bitread_read(br, 2);
|
|
c = p;
|
|
break;
|
|
case 17:
|
|
s = 3 + swebp__vp8l_bitread_read(br, 3);
|
|
c = 0;
|
|
break;
|
|
case 18:
|
|
s = 11 + swebp__vp8l_bitread_read(br, 7);
|
|
c = 0;
|
|
break;
|
|
}
|
|
|
|
if (br->eos)
|
|
{
|
|
swebp__dealloc(simplewebp, lc.tree);
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
}
|
|
|
|
while (s--)
|
|
lengths[count++] = (simplewebp_u8) c;
|
|
}
|
|
|
|
err = swebp__vp8l_canonical_code(simplewebp, lengths, count, code, NULL);
|
|
return err;
|
|
}
|
|
|
|
static simplewebp_error swebp__vp8l_decode_code(
|
|
simplewebp *simplewebp,
|
|
struct swebp__vp8l_bdec *br,
|
|
struct swebp__vp8l_code *code,
|
|
simplewebp_u16 size
|
|
)
|
|
{
|
|
if (swebp__vp8l_bitread_read(br, 1))
|
|
{
|
|
simplewebp_bool two_symbols = (simplewebp_bool) swebp__vp8l_bitread_read(br, 1);
|
|
code->tree = NULL;
|
|
code->size = two_symbols + 1;
|
|
code->symbol[0] = swebp__vp8l_bitread_read(br, 1 + swebp__vp8l_bitread_read(br, 1) * 7);
|
|
code->symbol[1] = two_symbols ? swebp__vp8l_bitread_read(br, 8) : 0;
|
|
return br->eos ? SIMPLEWEBP_IO_ERROR : SIMPLEWEBP_NO_ERROR;
|
|
}
|
|
else
|
|
return swebp__vp8l_decode_code_complex(simplewebp, br, code, size);
|
|
}
|
|
|
|
static simplewebp_error swebp__vp8l_decode_group(
|
|
simplewebp *simplewebp,
|
|
struct swebp__vp8l_bdec *br,
|
|
struct swebp__vp8l_group *group,
|
|
simplewebp_u8 bits
|
|
)
|
|
{
|
|
size_t i;
|
|
simplewebp_u16 sizes[5];
|
|
sizes[0] = swebp__vp8l_litlen_count + (bits ? 1 << bits : 0);
|
|
sizes[1] = sizes[2] = sizes[3] = swebp__vp8l_literals_count;
|
|
sizes[4] = swebp__vp8l_distances_count;
|
|
|
|
for (i = 0; i < 5; i++)
|
|
{
|
|
simplewebp_error err;
|
|
struct swebp__vp8l_code *code;
|
|
|
|
code = group->code + i;
|
|
err = swebp__vp8l_decode_code(simplewebp, br, code, sizes[i]);
|
|
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
{
|
|
/* Free all tree pointers */
|
|
for (; i != (size_t) -1; i--)
|
|
{
|
|
code = group->code + i;
|
|
swebp__dealloc(simplewebp, code->tree);
|
|
code->tree = NULL;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
}
|
|
|
|
return SIMPLEWEBP_NO_ERROR;
|
|
}
|
|
|
|
static size_t swebp__hash_color(simplewebp_u8 bits, struct swebp__pixel c)
|
|
{
|
|
size_t value = (c.a << 24) | (c.r << 16) | (c.g << 8) | c.b;
|
|
return ((0x1e35a7bd * value) & 0xFFFFFFFF) >> (32 - bits);
|
|
}
|
|
|
|
static void swebp__vp8l_put_cache(simplewebp_u8 bits, struct swebp__pixel *ccache, struct swebp__pixel color)
|
|
{
|
|
if (bits)
|
|
ccache[swebp__hash_color(bits, color)] = color;
|
|
}
|
|
|
|
static size_t swebp__vp8l_lendst(struct swebp__vp8l_bdec *br, simplewebp_u16 c)
|
|
{
|
|
size_t extra;
|
|
|
|
if (c < 4)
|
|
return c;
|
|
|
|
extra = (c - 2) >> 1;
|
|
return ((2 + (c & 1)) << extra) + swebp__vp8l_bitread_read(br, (int) extra);
|
|
}
|
|
|
|
static simplewebp_error swebp__decode_vp8l_image(
|
|
simplewebp *simplewebp,
|
|
struct swebp__vp8l_bdec *br,
|
|
simplewebp_bool is_main,
|
|
size_t width,
|
|
size_t height,
|
|
struct swebp__pixel **dest
|
|
)
|
|
{
|
|
simplewebp_u8 ccache_bits, entropy_bits;
|
|
struct swebp__pixel *color_cache, *entropy, *image;
|
|
struct swebp__vp8l_group *groups;
|
|
size_t group_count, entropy_stride, i;
|
|
simplewebp_error err;
|
|
|
|
color_cache = NULL;
|
|
group_count = 1;
|
|
entropy_bits = 0;
|
|
entropy_stride = 0;
|
|
entropy = NULL;
|
|
err = SIMPLEWEBP_NO_ERROR;
|
|
|
|
if (*dest == NULL)
|
|
{
|
|
*dest = (struct swebp__pixel *) swebp__alloc(simplewebp, width * height * 4);
|
|
if (*dest == NULL)
|
|
return SIMPLEWEBP_ALLOC_ERROR;
|
|
}
|
|
image = *dest;
|
|
|
|
ccache_bits = swebp__vp8l_bitread_read(br, 1) ? swebp__vp8l_bitread_read(br, 4) : 0;
|
|
if (br->eos)
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
if (ccache_bits)
|
|
{
|
|
color_cache = (struct swebp__pixel*) swebp__alloc(simplewebp, (1 << ccache_bits) * 4);
|
|
if (!color_cache)
|
|
return SIMPLEWEBP_ALLOC_ERROR;
|
|
}
|
|
|
|
if (is_main)
|
|
{
|
|
if (swebp__vp8l_bitread_read(br, 1))
|
|
{
|
|
size_t block_mask, ew, eh, group;
|
|
struct swebp__pixel *ep;
|
|
|
|
entropy_bits = swebp__vp8l_bitread_read(br, 3) + 2;
|
|
block_mask = (1 << entropy_bits) - 1;
|
|
ew = (width + block_mask) >> entropy_bits;
|
|
eh = (height + block_mask) >> entropy_bits;
|
|
ep = NULL;
|
|
entropy_stride = ew;
|
|
|
|
err = swebp__decode_vp8l_image(simplewebp, br, 0, ew, eh, &ep);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
{
|
|
swebp__dealloc(simplewebp, ep);
|
|
swebp__dealloc(simplewebp, color_cache);
|
|
return err;
|
|
}
|
|
|
|
entropy = ep;
|
|
|
|
for (i = 0; i < ew * eh; i++)
|
|
{
|
|
group = (ep[i].r << 8) | ep[i].g;
|
|
if (group_count <= group)
|
|
group_count = group + 1;
|
|
}
|
|
}
|
|
|
|
if (br->eos)
|
|
{
|
|
swebp__dealloc(simplewebp, entropy);
|
|
swebp__dealloc(simplewebp, color_cache);
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
}
|
|
}
|
|
|
|
groups = (struct swebp__vp8l_group*) swebp__alloc(simplewebp, sizeof(struct swebp__vp8l_group) * group_count);
|
|
if (!groups)
|
|
{
|
|
swebp__dealloc(simplewebp, entropy);
|
|
swebp__dealloc(simplewebp, color_cache);
|
|
return SIMPLEWEBP_ALLOC_ERROR;
|
|
}
|
|
memset(groups, 0, sizeof(struct swebp__vp8l_group) * group_count);
|
|
|
|
for (i = 0; i < group_count; i++)
|
|
{
|
|
err = swebp__vp8l_decode_group(simplewebp, br, groups + i, ccache_bits);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
break;
|
|
}
|
|
|
|
if (err == SIMPLEWEBP_NO_ERROR)
|
|
{
|
|
/* Main image decoding routines. */
|
|
for (i = 0; i < width * height;)
|
|
{
|
|
struct swebp__pixel *pixel;
|
|
struct swebp__vp8l_group *g = groups;
|
|
simplewebp_u16 codeword;
|
|
size_t j;
|
|
|
|
pixel = image + i;
|
|
|
|
if (entropy)
|
|
{
|
|
size_t ex, ey;
|
|
struct swebp__pixel *ep;
|
|
|
|
ex = (i % width) >> entropy_bits;
|
|
ey = (i / width) >> entropy_bits;
|
|
ep = entropy + entropy_stride * ey + ex;
|
|
g += (ep->r << 8) | ep->g;
|
|
}
|
|
|
|
codeword = swebp__vp8l_read_code(br, &g->code[0]);
|
|
|
|
if (codeword < swebp__vp8l_literals_count)
|
|
{
|
|
struct swebp__pixel color = {0};
|
|
color.r = (simplewebp_u8) swebp__vp8l_read_code(br, &g->code[1]);
|
|
color.g = (simplewebp_u8) codeword;
|
|
color.b = (simplewebp_u8) swebp__vp8l_read_code(br, &g->code[2]);
|
|
color.a = (simplewebp_u8) swebp__vp8l_read_code(br, &g->code[3]);
|
|
*pixel = color;
|
|
i++;
|
|
|
|
swebp__vp8l_put_cache(ccache_bits, color_cache, color);
|
|
}
|
|
else if (codeword < swebp__vp8l_litlen_count)
|
|
{
|
|
size_t length, distance;
|
|
ptrdiff_t offset;
|
|
simplewebp_u16 distcode;
|
|
|
|
length = swebp__vp8l_lendst(br, codeword - swebp__vp8l_literals_count);
|
|
distcode = swebp__vp8l_read_code(br, &g->code[4]);
|
|
distance = swebp__vp8l_lendst(br, distcode);
|
|
|
|
if (distance < swebp__vp8l_offset_count)
|
|
offset = swebp__vp8l_offsets[distance][0] + swebp__vp8l_offsets[distance][1] * width;
|
|
else
|
|
offset = distance - swebp__vp8l_offset_count + 1;
|
|
offset = offset < 1 ? 1 : offset;
|
|
|
|
for (j = 0; j <= length; j++)
|
|
{
|
|
*pixel = pixel[-offset];
|
|
swebp__vp8l_put_cache(ccache_bits, color_cache, *pixel);
|
|
i++;
|
|
pixel++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pixel = color_cache[codeword - swebp__vp8l_litlen_count];
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Loop free memory */
|
|
for (i = 0; i < group_count; i++)
|
|
{
|
|
size_t j;
|
|
/* And the tree */
|
|
for (j = 0; j < 5; j++)
|
|
swebp__dealloc(simplewebp, groups[i].code[j].tree);
|
|
}
|
|
swebp__dealloc(simplewebp, entropy);
|
|
swebp__dealloc(simplewebp, color_cache);
|
|
swebp__dealloc(simplewebp, groups);
|
|
|
|
return err;
|
|
}
|
|
|
|
static simplewebp_error swebp__decode_vp8l_transform_data(
|
|
simplewebp *simplewebp,
|
|
struct swebp__vp8l_bdec *br,
|
|
size_t width,
|
|
size_t height,
|
|
simplewebp_u8 *bits_out,
|
|
struct swebp__pixel **dest
|
|
)
|
|
{
|
|
int bits;
|
|
size_t block_mask, data_w, data_h;
|
|
|
|
bits = swebp__vp8l_bitread_read(br, 3) + 2;
|
|
block_mask = (1 << bits) - 1;
|
|
data_w = (width + block_mask) >> bits;
|
|
data_h = (height + block_mask) >> bits;
|
|
*bits_out = (simplewebp_u8) bits;
|
|
|
|
return swebp__decode_vp8l_image(simplewebp, br, 0, data_w, data_h, dest);
|
|
}
|
|
|
|
static void swebp__batch_free(simplewebp *simplewebp, void **ptr, size_t count)
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
if (ptr[i])
|
|
swebp__dealloc(simplewebp, ptr[i]);
|
|
}
|
|
}
|
|
|
|
static simplewebp_u8 swebp__vp8l_index_reduction(simplewebp_u32 color_count)
|
|
{
|
|
if (color_count > 16)
|
|
return 0;
|
|
else if (color_count > 4)
|
|
return 1;
|
|
else if (color_count > 2)
|
|
return 2;
|
|
else
|
|
return 3;
|
|
}
|
|
|
|
static simplewebp_error swebp__decode_color_index_transform(
|
|
simplewebp *simplewebp,
|
|
struct swebp__vp8l_bdec *br,
|
|
size_t width,
|
|
size_t height,
|
|
simplewebp_u8 *index_size_out,
|
|
struct swebp__pixel **dest
|
|
)
|
|
{
|
|
simplewebp_u32 color_count, i;
|
|
simplewebp_error err;
|
|
struct swebp__pixel *pixel_data;
|
|
|
|
color_count = swebp__vp8l_bitread_read(br, 8);
|
|
*index_size_out = (simplewebp_u8) color_count++;
|
|
if (br->eos)
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
|
|
err = swebp__decode_vp8l_image(simplewebp, br, 0, color_count, 1, dest);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
return err;
|
|
|
|
pixel_data = *dest;
|
|
/* Reverse subtraction coding */
|
|
for (i = 1; i < color_count; i++)
|
|
{
|
|
struct swebp__pixel *prev = &pixel_data[i - 1];
|
|
pixel_data[i].r += prev->r;
|
|
pixel_data[i].g += prev->g;
|
|
pixel_data[i].b += prev->b;
|
|
pixel_data[i].a += prev->a;
|
|
}
|
|
|
|
return SIMPLEWEBP_NO_ERROR;
|
|
}
|
|
|
|
static struct swebp__pixel swebp__average2(struct swebp__pixel a, struct swebp__pixel b)
|
|
{
|
|
struct swebp__pixel result;
|
|
result.r = ((simplewebp_u16) a.r + (simplewebp_u16) b.r) / 2;
|
|
result.g = ((simplewebp_u16) a.g + (simplewebp_u16) b.g) / 2;
|
|
result.b = ((simplewebp_u16) a.b + (simplewebp_u16) b.b) / 2;
|
|
result.a = ((simplewebp_u16) a.a + (simplewebp_u16) b.a) / 2;
|
|
return result;
|
|
}
|
|
|
|
static struct swebp__pixel swebp__select(struct swebp__pixel l, struct swebp__pixel t, struct swebp__pixel tl)
|
|
{
|
|
int red = (int) l.r + (int) t.r - (int) tl.r;
|
|
int green = (int) l.g + (int) t.g - (int) tl.g;
|
|
int blue = (int) l.b + (int) t.b - (int) tl.b;
|
|
int alpha = (int) l.a + (int) t.a - (int) tl.a;
|
|
int pl = abs(alpha - l.a) + abs(red - l.r) + abs(green - l.g) + abs(blue - l.b);
|
|
int pt = abs(alpha - t.a) + abs(red - t.r) + abs(green - t.g) + abs(blue - t.b);
|
|
|
|
return pl < pt ? l : t;
|
|
}
|
|
|
|
static struct swebp__pixel swebp__clamp_add_subtract_full(
|
|
struct swebp__pixel a,
|
|
struct swebp__pixel b,
|
|
struct swebp__pixel c
|
|
)
|
|
{
|
|
struct swebp__pixel result;
|
|
result.r = swebp__clip((int) a.r + (int) b.r - (int) c.r, 255);
|
|
result.g = swebp__clip((int) a.g + (int) b.g - (int) c.g, 255);
|
|
result.b = swebp__clip((int) a.b + (int) b.b - (int) c.b, 255);
|
|
result.a = swebp__clip((int) a.a + (int) b.a - (int) c.a, 255);
|
|
return result;
|
|
}
|
|
|
|
static struct swebp__pixel swebp__clamp_add_subtract_half(struct swebp__pixel a, struct swebp__pixel b)
|
|
{
|
|
struct swebp__pixel result;
|
|
result.r = swebp__clip((int) a.r + ((int) a.r - (int) b.r) / 2, 255);
|
|
result.g = swebp__clip((int) a.g + ((int) a.g - (int) b.g) / 2, 255);
|
|
result.b = swebp__clip((int) a.b + ((int) a.b - (int) b.b) / 2, 255);
|
|
result.a = swebp__clip((int) a.a + ((int) a.a - (int) b.a) / 2, 255);
|
|
return result;
|
|
}
|
|
|
|
static struct swebp__pixel swebp__apply_predictor(
|
|
simplewebp_u8 type,
|
|
struct swebp__pixel *l,
|
|
struct swebp__pixel *tl,
|
|
struct swebp__pixel *t,
|
|
struct swebp__pixel *tr
|
|
)
|
|
{
|
|
const struct swebp__pixel black = {0, 0, 0, 255};
|
|
|
|
switch (type)
|
|
{
|
|
case 0:
|
|
default:
|
|
return black;
|
|
case 1:
|
|
return *l;
|
|
case 2:
|
|
return *t;
|
|
case 3:
|
|
return *tr;
|
|
case 4:
|
|
return *tl;
|
|
case 5:
|
|
return swebp__average2(swebp__average2(*l, *tr), *t);
|
|
case 6:
|
|
return swebp__average2(*l, *tl);
|
|
case 7:
|
|
return swebp__average2(*l, *t);
|
|
case 8:
|
|
return swebp__average2(*tl, *t);
|
|
case 9:
|
|
return swebp__average2(*tr, *t);
|
|
case 10:
|
|
return swebp__average2(swebp__average2(*l, *tl), swebp__average2(*tr, *t));
|
|
case 11:
|
|
return swebp__select(*l, *t, *tl);
|
|
case 12:
|
|
return swebp__clamp_add_subtract_full(*l, *t, *tl);
|
|
case 13:
|
|
return swebp__clamp_add_subtract_half(swebp__average2(*l, *t), *tl);
|
|
}
|
|
}
|
|
|
|
static size_t swebp__subsample_size(size_t size, size_t sampling_bits)
|
|
{
|
|
return (size + (((size_t) 1) << sampling_bits) - 1) >> sampling_bits;
|
|
}
|
|
|
|
static void swebp__apply_predictor_transform(
|
|
struct swebp__pixel *rgba,
|
|
size_t width,
|
|
size_t height,
|
|
simplewebp_u8 bits,
|
|
struct swebp__pixel *predictor_data
|
|
)
|
|
{
|
|
size_t x, y;
|
|
size_t tiles_per_row = swebp__subsample_size(width, bits);
|
|
|
|
for (y = 0; y < height; y++)
|
|
{
|
|
for (x = 0; x < width; x++)
|
|
{
|
|
struct swebp__pixel result;
|
|
simplewebp_u8 type = 0;
|
|
|
|
if (x > 0)
|
|
{
|
|
if (y > 0)
|
|
{
|
|
size_t tile_x = x >> bits;
|
|
size_t tile_y = y >> bits;
|
|
size_t tile_index = tile_y * tiles_per_row + tile_x;
|
|
type = predictor_data[tile_index].g;
|
|
}
|
|
else
|
|
type = 1;
|
|
}
|
|
else
|
|
type = y > 0 ? 2 : 0;
|
|
|
|
result = swebp__apply_predictor(type, rgba - 1, rgba - (width + 1), rgba - width, rgba - (width - 1));
|
|
rgba->r += result.r;
|
|
rgba->g += result.g;
|
|
rgba->b += result.b;
|
|
rgba->a += result.a;
|
|
rgba++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static simplewebp_u8 swebp__color_delta(int c1, int c2) {
|
|
int sc1 = c1 >= 128 ? -256 + c1 : c1;
|
|
int sc2 = c2 >= 128 ? -256 + c2 : c2;
|
|
return (simplewebp_u8) ((sc1 * sc2) >> 5);
|
|
}
|
|
|
|
static void swebp__apply_color_transform(
|
|
struct swebp__pixel *rgba,
|
|
size_t width,
|
|
size_t height,
|
|
simplewebp_u8 bits,
|
|
struct swebp__pixel *color_data
|
|
)
|
|
{
|
|
size_t x, y;
|
|
size_t tiles_per_row = swebp__subsample_size(width, bits);
|
|
|
|
for (y = 0; y < height; y++)
|
|
{
|
|
struct swebp__pixel *line = color_data + (y >> bits) * tiles_per_row;
|
|
|
|
for (x = 0; x < width; x++)
|
|
{
|
|
struct swebp__pixel *ref = &line[x >> bits];
|
|
rgba->r += swebp__color_delta(ref->b, rgba->g);
|
|
rgba->b += swebp__color_delta(ref->g, rgba->g);
|
|
rgba->b += swebp__color_delta(ref->r, rgba->r);
|
|
rgba++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void swebp__apply_green_sub_transform(
|
|
struct swebp__pixel *rgba,
|
|
size_t width,
|
|
size_t height
|
|
)
|
|
{
|
|
size_t x, y;
|
|
|
|
for (y = 0; y < height; y++)
|
|
{
|
|
for (x = 0; x < width; x++)
|
|
{
|
|
struct swebp__pixel *col = &rgba[y * width + x];
|
|
col->r += col->g;
|
|
col->b += col->g;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void swebp__apply_index_transform(
|
|
struct swebp__pixel *rgba,
|
|
size_t width,
|
|
size_t height,
|
|
simplewebp_u8 size,
|
|
struct swebp__pixel *index_data
|
|
)
|
|
{
|
|
size_t x, y;
|
|
simplewebp_u32 color_count;
|
|
simplewebp_u8 bits, mask, mod, rb;
|
|
size_t stride;
|
|
const struct swebp__pixel transparent_black = {0};
|
|
|
|
color_count = ((simplewebp_u32) size) + 1;
|
|
bits = swebp__vp8l_index_reduction(color_count);
|
|
stride = swebp__subsample_size(width, bits);
|
|
mask = (1 << (8 >> bits)) - 1;
|
|
mod = (1 << bits) - 1;
|
|
rb = 3 - bits;
|
|
|
|
for (y = height - 1; y != (size_t) -1; y--)
|
|
{
|
|
for (x = width - 1; x != (size_t) -1; x--)
|
|
{
|
|
const struct swebp__pixel *l = rgba + stride * y;
|
|
simplewebp_u8 i = (l[x >> bits].g >> ((x & mod) << rb)) & mask;
|
|
rgba[y * width + x] = i < color_count ? index_data[i] : transparent_black;
|
|
}
|
|
}
|
|
}
|
|
|
|
static simplewebp_error swebp__decode_lossless_bitstream_main(
|
|
simplewebp *simplewebp,
|
|
struct swebp__vp8l_bdec *br,
|
|
struct swebp__pixel *rgba,
|
|
simplewebp_bool skipheader
|
|
)
|
|
{
|
|
size_t actual_width, actual_height;
|
|
size_t full_width;
|
|
simplewebp_u32 width, height;
|
|
simplewebp_u8 filter_list;
|
|
struct swebp__pixel *filter_data[4];
|
|
simplewebp_u8 filter_bits[4];
|
|
simplewebp_bool filter_active[4];
|
|
int i;
|
|
simplewebp_error err;
|
|
|
|
simplewebp_get_dimensions(simplewebp, &actual_width, &actual_height);
|
|
|
|
if (!skipheader)
|
|
{
|
|
simplewebp_u32 version_num;
|
|
|
|
/* Validate header */
|
|
if (swebp__vp8l_bitread_read(br, 8) != 0x2F)
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
|
|
/* Validate dimensions */
|
|
full_width = width = swebp__vp8l_bitread_read(br, 14) + 1;
|
|
height = swebp__vp8l_bitread_read(br, 14) + 1;
|
|
if (width != actual_width || height != actual_height)
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
|
|
/* Skip alpha */
|
|
swebp__vp8l_bitread_read(br, 1);
|
|
version_num = swebp__vp8l_bitread_read(br, 3);
|
|
if (version_num != 0)
|
|
return SIMPLEWEBP_UNSUPPORTED_ERROR;
|
|
}
|
|
else
|
|
{
|
|
width = (simplewebp_u32) (full_width = actual_width);
|
|
height = (simplewebp_u32) actual_height;
|
|
}
|
|
|
|
/* Read transforms */
|
|
err = SIMPLEWEBP_NO_ERROR;
|
|
filter_list = 0;
|
|
memset(filter_active, 0, sizeof(simplewebp_bool) * 4);
|
|
memset(filter_bits, 0, sizeof(simplewebp_u8) * 4);
|
|
memset(filter_data, 0, sizeof(filter_data));
|
|
for (i = 0; i < sizeof(simplewebp_u8) * 4; i++)
|
|
{
|
|
simplewebp_u8 ttype, transform_bits;
|
|
struct swebp__pixel *filter_out = NULL;
|
|
|
|
if (swebp__vp8l_bitread_read(br, 1) == 0)
|
|
break;
|
|
|
|
ttype = swebp__vp8l_bitread_read(br, 2);
|
|
if (br->eos)
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
|
|
switch (ttype)
|
|
{
|
|
case 0:
|
|
/* Predictor transform */
|
|
case 1:
|
|
/* Color transform */
|
|
err = swebp__decode_vp8l_transform_data(simplewebp, br, width, height, &transform_bits, &filter_out);
|
|
break;
|
|
case 2:
|
|
/* Green subtraction transform */
|
|
err = SIMPLEWEBP_NO_ERROR;
|
|
transform_bits = 0;
|
|
filter_out = NULL;
|
|
break;
|
|
case 3:
|
|
/* Color index transform */
|
|
err = swebp__decode_color_index_transform(
|
|
simplewebp,
|
|
br,
|
|
width,
|
|
height,
|
|
&transform_bits,
|
|
&filter_out
|
|
);
|
|
width = (simplewebp_u32) swebp__subsample_size(width, swebp__vp8l_index_reduction(transform_bits + 1));
|
|
break;
|
|
default:
|
|
/* Unreachable */
|
|
err = SIMPLEWEBP_CORRUPT_ERROR;
|
|
break;
|
|
}
|
|
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
{
|
|
/* Error occured. Rollback. */
|
|
swebp__batch_free(simplewebp, (void **) filter_data, 4);
|
|
return err;
|
|
}
|
|
|
|
if (filter_active[ttype])
|
|
{
|
|
/* Multiple same filters defined, likely corrupt */
|
|
swebp__dealloc(simplewebp, filter_out);
|
|
swebp__batch_free(simplewebp, (void **) filter_data, 4);
|
|
return SIMPLEWEBP_CORRUPT_ERROR;
|
|
}
|
|
|
|
filter_list = (filter_list) << 2 | ttype;
|
|
filter_bits[i] = transform_bits;
|
|
filter_data[i] = filter_out;
|
|
filter_active[ttype] = 1;
|
|
}
|
|
|
|
/* Decode image */
|
|
err = swebp__decode_vp8l_image(simplewebp, br, 1, width, height, &rgba);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
{
|
|
swebp__batch_free(simplewebp, (void **) filter_data, sizeof(simplewebp_u8) * 4);
|
|
return err;
|
|
}
|
|
|
|
/* Apply transform */
|
|
i--;
|
|
for (; i >= 0; i--)
|
|
{
|
|
simplewebp_u8 ttype;
|
|
ttype = filter_list & 3;
|
|
|
|
switch (ttype)
|
|
{
|
|
case 0:
|
|
/* Predictor Transform */
|
|
swebp__apply_predictor_transform(rgba, width, height, filter_bits[i], filter_data[i]);
|
|
break;
|
|
case 1:
|
|
/* Color Transform */
|
|
swebp__apply_color_transform(rgba, width, height, filter_bits[i], filter_data[i]);
|
|
break;
|
|
case 2:
|
|
/* Green Transform */
|
|
swebp__apply_green_sub_transform(rgba, width, height);
|
|
break;
|
|
case 3:
|
|
/* Color Index Transform */
|
|
width = (simplewebp_u32) full_width;
|
|
swebp__apply_index_transform(rgba, width, height, filter_bits[i], filter_data[i]);
|
|
break;
|
|
}
|
|
|
|
filter_list >>= 2;
|
|
}
|
|
|
|
swebp__batch_free(simplewebp, (void **) filter_data, sizeof(simplewebp_u8) * 4);
|
|
return err;
|
|
}
|
|
|
|
/* Also used to decode alpha channel. */
|
|
static simplewebp_error swebp__decode_lossless_bitstream(
|
|
simplewebp *simplewebp,
|
|
simplewebp_input *input,
|
|
size_t bitstreamsize,
|
|
struct swebp__pixel *rgba,
|
|
simplewebp_bool skipheader
|
|
)
|
|
{
|
|
struct swebp__vp8l_bdec br;
|
|
simplewebp_error err;
|
|
simplewebp_u8 *bitstreambuffer = (simplewebp_u8 *) swebp__alloc(simplewebp, bitstreamsize);
|
|
|
|
if (!bitstreambuffer)
|
|
return SIMPLEWEBP_ALLOC_ERROR;
|
|
|
|
if (!swebp__read2(bitstreamsize, bitstreambuffer, input))
|
|
{
|
|
swebp__dealloc(simplewebp, bitstreambuffer);
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
}
|
|
|
|
swebp__vp8l_bitread_init(&br, bitstreambuffer, bitstreamsize);
|
|
err = swebp__decode_lossless_bitstream_main(simplewebp, &br, rgba, skipheader);
|
|
|
|
swebp__dealloc(simplewebp, bitstreambuffer);
|
|
return err;
|
|
}
|
|
|
|
static simplewebp_error swebp__decode_lossless(simplewebp *simplewebp, void *buffer)
|
|
{
|
|
size_t vp8lsize = swebp__proxy_size(simplewebp->vp8l_input.userdata);
|
|
if (!swebp__seek(0, &simplewebp->vp8l_input))
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
return swebp__decode_lossless_bitstream(
|
|
simplewebp,
|
|
&simplewebp->vp8l_input,
|
|
vp8lsize,
|
|
(struct swebp__pixel *) buffer,
|
|
0
|
|
);
|
|
}
|
|
|
|
simplewebp_error simplewebp_decode_yuva(simplewebp *simplewebp, void *y_buffer, void *u_buffer, void *v_buffer, void *a_buffer, void *settings)
|
|
{
|
|
if (simplewebp->webp_type == 0)
|
|
{
|
|
struct swebp__yuvdst destination;
|
|
destination.y = (simplewebp_u8*) y_buffer;
|
|
destination.u = (simplewebp_u8*) u_buffer;
|
|
destination.v = (simplewebp_u8*) v_buffer;
|
|
destination.a = (simplewebp_u8*) a_buffer;
|
|
return swebp__decode_lossy(simplewebp, &destination, settings);
|
|
}
|
|
|
|
return SIMPLEWEBP_IS_LOSSLESS_ERROR;
|
|
}
|
|
|
|
simplewebp_error simplewebp_decode(simplewebp *simplewebp, void *buffer, void *settings)
|
|
{
|
|
simplewebp_error err = SIMPLEWEBP_NO_ERROR;
|
|
|
|
if (simplewebp->webp_type == 0)
|
|
{
|
|
struct swebp__yuvdst dest;
|
|
struct swebp__chroma *upscaled;
|
|
simplewebp_u8 *mem, *orig_mem;
|
|
size_t needed, yw, yh, uvw, uvh;
|
|
|
|
/* Calculate allocation size. The allocated memory layout is [y, a, u, v] */
|
|
yw = simplewebp->decoder.vp8.picture_header.width;
|
|
yh = simplewebp->decoder.vp8.picture_header.height;
|
|
uvw = (yw + 1) / 2;
|
|
uvh = (yh + 1) / 2;
|
|
needed = ((yw * yh) + (uvw * uvh)) * 2;
|
|
/* For upsampling the UV */
|
|
needed += uvw * uvh * 4 * sizeof(struct swebp__chroma);
|
|
|
|
mem = orig_mem = (simplewebp_u8 *) swebp__alloc(simplewebp, needed);
|
|
if (mem == NULL)
|
|
return SIMPLEWEBP_ALLOC_ERROR;
|
|
|
|
dest.y = mem;
|
|
mem += yw * yh;
|
|
dest.a = mem;
|
|
mem += yw * yh;
|
|
dest.u = mem;
|
|
mem += uvw * uvh;
|
|
dest.v = mem;
|
|
mem += uvw * uvh;
|
|
upscaled = (struct swebp__chroma*) mem;
|
|
|
|
err = swebp__decode_lossy(simplewebp, &dest, settings);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
{
|
|
swebp__dealloc(simplewebp, orig_mem);
|
|
return err;
|
|
}
|
|
|
|
/* Upsample UV */
|
|
swebp__upsample_chroma(dest.u, dest.v, upscaled, uvw, uvh);
|
|
/* Convert YUVA to RGBA */
|
|
swebp__yuva2rgba(dest.y, upscaled, dest.a, yw, yh, (struct swebp__pixel*) buffer);
|
|
swebp__dealloc(simplewebp, orig_mem);
|
|
}
|
|
else
|
|
{
|
|
err = swebp__decode_lossless(simplewebp, buffer);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
return err;
|
|
|
|
if (!simplewebp->decoder.vp8l.has_alpha)
|
|
{
|
|
size_t i, w, h;
|
|
struct swebp__pixel *rgba;
|
|
|
|
w = simplewebp->decoder.vp8l.width;
|
|
h = simplewebp->decoder.vp8l.height;
|
|
|
|
/* libwebp sets the alpha to 255 if the has_alpha bit is not set. */
|
|
/* Interestingly, WebPShop as of 0.4.3 doesn't seem to respect that flag (it's always RGBA). */
|
|
rgba = (struct swebp__pixel*) buffer;
|
|
for (i = 0; i < w * h; i++)
|
|
rgba[i].a = 255;
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
#ifndef SIMPLEWEBP_DISABLE_STDIO
|
|
|
|
static size_t swebp__stdfile_read(size_t size, void *dest, void *userdata)
|
|
{
|
|
FILE *f = (FILE *) userdata;
|
|
return fread(dest, 1, size, f);
|
|
}
|
|
|
|
static simplewebp_bool swebp__stdfile_seek(size_t pos, void *userdata)
|
|
{
|
|
FILE *f = (FILE *) userdata;
|
|
return fseek(f, (long) pos, SEEK_SET) == 0;
|
|
}
|
|
|
|
static void swebp__stdfile_close(void *userdata)
|
|
{
|
|
FILE *f = (FILE *) userdata;
|
|
fclose(f);
|
|
}
|
|
|
|
static size_t swebp__stdfile_tell(void *userdata)
|
|
{
|
|
FILE *f = (FILE *) userdata;
|
|
return ftell(f);
|
|
}
|
|
|
|
simplewebp_error simplewebp_input_from_file(FILE *file, simplewebp_input *out)
|
|
{
|
|
out->userdata = file;
|
|
out->read = swebp__stdfile_read;
|
|
out->seek = swebp__stdfile_seek;
|
|
out->tell = swebp__stdfile_tell;
|
|
out->close = swebp__stdfile_close;
|
|
return SIMPLEWEBP_NO_ERROR;
|
|
}
|
|
|
|
simplewebp_error simplewebp_input_from_filename(const char *filename, simplewebp_input *out)
|
|
{
|
|
FILE *f = fopen(filename, "rb");
|
|
if (f == NULL)
|
|
return SIMPLEWEBP_IO_ERROR;
|
|
|
|
return simplewebp_input_from_file(f, out);
|
|
}
|
|
|
|
simplewebp_error simplewebp_load_from_file(FILE *file, const simplewebp_allocator *allocator, simplewebp **out)
|
|
{
|
|
simplewebp_input input;
|
|
simplewebp_error err;
|
|
|
|
err = simplewebp_input_from_file(file, &input);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
return err;
|
|
|
|
err = simplewebp_load(&input, allocator, out);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
simplewebp_close_input(&input);
|
|
|
|
return err;
|
|
}
|
|
|
|
simplewebp_error simplewebp_load_from_filename(const char *filename, const simplewebp_allocator *allocator, simplewebp **out)
|
|
{
|
|
simplewebp_input input;
|
|
simplewebp_error err;
|
|
|
|
err = simplewebp_input_from_filename(filename, &input);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
return err;
|
|
|
|
err = simplewebp_load(&input, allocator, out);
|
|
if (err != SIMPLEWEBP_NO_ERROR)
|
|
simplewebp_close_input(&input);
|
|
|
|
return err;
|
|
}
|
|
#endif /* SIMPLEWEBP_DISABLE_STDIO */
|
|
|
|
#ifdef __cplusplus
|
|
} /* extern "C" */
|
|
#endif
|
|
|
|
#endif /* SIMPLEWEBP_IMPLEMENTATION */
|
|
|
|
/**
|
|
* This software is available under BSD-3-Clause License
|
|
* Some parts of WebP Lossless code is taken from "whale" project by Matej Fencl
|
|
*
|
|
* Copyright (c) 2010 Google Inc., 2023 Miku AuahDark
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
|
* following conditions are met:
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
|
|
* disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
|
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
|
|
* products derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* Additional IP Rights Grant (Patents)
|
|
* ------------------------------------
|
|
*
|
|
* "These implementations" means the copyrightable works that implement the WebM codecs distributed by Google as part
|
|
* of the WebM Project.
|
|
*
|
|
* Google hereby grants to you a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as
|
|
* stated in this section) patent license to make, have made, use, offer to sell, sell, import, transfer, and
|
|
* otherwise run, modify and propagate the contents of these implementations of WebM, where such license applies only
|
|
* to those patent claims, both currently owned by Google and acquired in the future, licensable by Google that are
|
|
* necessarily infringed by these implementations of WebM. This grant does not include claims that would be infringed
|
|
* only as a consequence of further modification of these implementations. If you or your agent or exclusive licensee
|
|
* institute or order or agree to the institution of patent litigation or any other patent enforcement activity
|
|
* against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that any of these
|
|
* implementations of WebM or any code incorporated within any of these implementations of WebM constitute direct or
|
|
* contributory patent infringement, or inducement of patent infringement, then any patent rights granted to you under
|
|
* this License for these implementations of WebM shall terminate as of the date such litigation is filed.
|
|
*/
|