* by Sebastian Krzyszkowiak (dos@dosowisko.net).
*/
#include <webp/decode.h>
#include <webp/encode.h>
#include "allegro5/allegro.h"
#include "allegro5/allegro_image.h"
#include "allegro5/internal/aintern_image.h"
#include "iio.h"
ALLEGRO_DEBUG_CHANNEL("image")
* Loading routines
****************************************************************************/
static ALLEGRO_BITMAP *load_from_buffer(const uint8_t* data, size_t data_size,
int flags)
{
ALLEGRO_BITMAP *bmp;
ALLEGRO_LOCKED_REGION *lock;
bool premul = !(flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA);
WebPDecoderConfig config;
WebPInitDecoderConfig(&config);
if (WebPGetFeatures(data, data_size, &config.input) != VP8_STATUS_OK) {
ALLEGRO_ERROR("Could not read WebP stream info\n");
return NULL;
}
bmp = al_create_bitmap(config.input.width, config.input.height);
if (!bmp) {
ALLEGRO_ERROR("al_create_bitmap failed while loading WebP.\n");
return NULL;
}
lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE,
ALLEGRO_LOCK_WRITEONLY);
config.output.colorspace = premul ? MODE_rgbA : MODE_RGBA;
config.output.u.RGBA.rgba = (uint8_t*)lock->data;
config.output.u.RGBA.stride = lock->pitch;
config.output.u.RGBA.size = lock->pitch * config.input.height;
config.output.is_external_memory = 1;
if (WebPDecode(data, data_size, &config) != VP8_STATUS_OK) {
ALLEGRO_ERROR("Could not decode WebP stream\n");
al_destroy_bitmap(bmp);
return NULL;
}
al_unlock_bitmap(bmp);
return bmp;
}
ALLEGRO_BITMAP *_al_load_webp_f(ALLEGRO_FILE *fp, int flags)
{
ALLEGRO_ASSERT(fp);
ALLEGRO_BITMAP *bmp;
size_t data_size = al_fsize(fp);
uint8_t *data = al_malloc(data_size * sizeof(uint8_t));
if (al_fread(fp, data, data_size) != data_size) {
ALLEGRO_ERROR("Could not read WebP file\n");
free(data);
return NULL;
}
bmp = load_from_buffer(data, data_size, flags);
free(data);
return bmp;
}
ALLEGRO_BITMAP *_al_load_webp(const char *filename, int flags)
{
ALLEGRO_FILE *fp;
ALLEGRO_BITMAP *bmp;
ALLEGRO_ASSERT(filename);
fp = al_fopen(filename, "rb");
if (!fp) {
ALLEGRO_ERROR("Unable to open %s for reading.\n", filename);
return NULL;
}
bmp = _al_load_webp_f(fp, flags);
al_fclose(fp);
return bmp;
}
* Saving routines
****************************************************************************/
bool _al_save_webp_f(ALLEGRO_FILE *fp, ALLEGRO_BITMAP *bmp)
{
ALLEGRO_LOCKED_REGION *lock;
bool ret = false;
lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE,
ALLEGRO_LOCK_READONLY);
if (!lock) {
ALLEGRO_ERROR("Failed to lock bitmap.\n");
return false;
}
uint8_t *output = NULL;
size_t size;
const char* level = al_get_config_value(al_get_system_config(), "image", "webp_quality_level");
if (!level || strcmp(level, "lossless") == 0) {
size = WebPEncodeLosslessRGBA((const uint8_t*)lock->data,
al_get_bitmap_width(bmp), al_get_bitmap_height(bmp),
lock->pitch, &output);
} else {
size = WebPEncodeRGBA((const uint8_t*)lock->data,
al_get_bitmap_width(bmp), al_get_bitmap_height(bmp),
lock->pitch, level ? strtol(level, NULL, 10) : 75, &output);
}
if (al_fwrite(fp, output, size) == size) {
ret = true;
}
#if WEBP_DECODER_ABI_VERSION >= 0x0206
WebPFree(output);
#else
free(output);
#endif
al_unlock_bitmap(bmp);
return ret;
}
bool _al_save_webp(const char *filename, ALLEGRO_BITMAP *bmp)
{
ALLEGRO_FILE *fp;
bool retsave;
bool retclose;
ALLEGRO_ASSERT(filename);
ALLEGRO_ASSERT(bmp);
fp = al_fopen(filename, "wb");
if (!fp) {
ALLEGRO_ERROR("Unable to open file %s for writing\n", filename);
return false;
}
retsave = _al_save_webp_f(fp, bmp);
if (!retsave) {
ALLEGRO_ERROR("Unable to store WebP bitmap in file %s\n", filename);
}
retclose = al_fclose(fp);
if (!retclose) {
ALLEGRO_ERROR("Unable to close file %s\n", filename);
}
return retsave && retclose;
}