From b59ed4b7d10a6c74215fc9d7ded2f355ba713f09 Mon Sep 17 00:00:00 2001 From: Vincent Wei Date: Tue, 19 Oct 2021 18:46:53 +0800 Subject: [PATCH] implement __mg_check_webp, __mg_init_webp and __mg_cleanup_webp --- src/mybmp/webp.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 2 deletions(-) diff --git a/src/mybmp/webp.c b/src/mybmp/webp.c index 6f916a2b..9bc15fa6 100644 --- a/src/mybmp/webp.c +++ b/src/mybmp/webp.c @@ -59,26 +59,139 @@ #ifdef _MGIMAGE_WEBP #include "gdi.h" +#include "constants.h" #include +#define RIFF_HEADER_SIZE 12 + +#define HEADER_CHUNK_SIZE 64 +#define READ_BUFF_SIZE 1024 + +struct webp_decode_info { + WebPDecoderConfig config; + size_t sz_data; + char buf[READ_BUFF_SIZE]; +}; + void* __mg_init_webp(MG_RWops *fp, MYBITMAP *mybmp, RGB *pal) { + int n; + size_t pitch; + struct webp_decode_info *info = NULL; + + if ((info = malloc(sizeof(struct webp_decode_info))) == NULL) { + _ERR_PRINTF ("__mg_init_webp: failed to allocate memory\n"); + return NULL; + } + + if (!WebPInitDecoderConfig(&info->config)) { + _ERR_PRINTF ("__mg_init_webp: WebPInitDecoderConfig failed\n"); + goto error; + } + + info->sz_data = 0; + do { + VP8StatusCode sc; + + if (info->sz_data + HEADER_CHUNK_SIZE > READ_BUFF_SIZE) { + _ERR_PRINTF ("__mg_init_webp: two small buffer\n"); + goto error; + } + + n = MGUI_RWread(fp, info->buf + info->sz_data, 1, HEADER_CHUNK_SIZE); + if (n > 0) { + info->sz_data += n; + } + else + goto error; + + sc = WebPGetFeatures(info->buf, info->sz_data, &info->config.input); + if (sc == VP8_STATUS_OK) { + break; + } + else if (sc == VP8_STATUS_NOT_ENOUGH_DATA) { + continue; + } + else { + _ERR_PRINTF ("__mg_init_webp: WebPGetFeatures failed: %d\n", sc); + goto error; + } + } while (1); + + if (info->config.input.has_animation) { + _ERR_PRINTF ("__mg_init_webp: animation not supported\n"); + goto error; + } + + mybmp->w = info->config.input.width; + mybmp->h = info->config.input.height; + mybmp->frames = 1; + if (info->config.input.has_alpha) { + info->config.output.colorspace = MODE_RGBA; + + mybmp->depth = 32; + mybmp->flags |= MYBMP_FLOW_DOWN | MYBMP_ALPHA | MYBMP_TYPE_RGBA; + mybmp->flags |= MYBMP_RGBSIZE_4; + + pitch = (size_t)info->config.input.width * 4; + } + else { + info->config.output.colorspace = MODE_RGB; + + mybmp->depth = 24; + mybmp->flags |= MYBMP_FLOW_DOWN | MYBMP_ALPHA | MYBMP_TYPE_RGBA; + mybmp->flags |= MYBMP_RGBSIZE_4; + + pitch = (size_t)info->config.input.width * 3; + } + + pitch = ROUND_TO_MULTIPLE(pitch, 8); + + // Have config.output point to an external buffer: + info->config.output.u.RGBA.rgba = (uint8_t*)malloc(pitch); + info->config.output.u.RGBA.stride = pitch; + info->config.output.u.RGBA.size = pitch; + info->config.output.is_external_memory = 1; + + if (info->config.output.u.RGBA.rgba == NULL) { + _ERR_PRINTF ("__mg_init_webp: failed to allocate memory\n"); + goto error; + } + + return info; + +error: + if (info) + free(info); return NULL; } void __mg_cleanup_webp(void *init_info) { + struct webp_decode_info *info = init_info; + + if (info) { + free(info->config.output.u.RGBA.rgba); + free(info); + } } -int __mg_load_webp (MG_RWops *fp, void *init_info, MYBITMAP *my_bmp, +int __mg_load_webp(MG_RWops *fp, void *init_info, MYBITMAP *my_bmp, CB_ONE_SCANLINE cb, void *context) { return ERR_BMP_OK; } -BOOL __mg_check_webp (MG_RWops* fp) +BOOL __mg_check_webp(MG_RWops* fp) { + unsigned char header[RIFF_HEADER_SIZE]; + + MGUI_RWread(fp, header, RIFF_HEADER_SIZE, 1); + if (!WebPGetInfo(header, RIFF_HEADER_SIZE, NULL, NULL)) { + } + + return WebPGetInfo(header, RIFF_HEADER_SIZE, NULL, NULL); } #endif /* _MGIMAGE_WEBP */