2 SDL_image: An example image loading library for use with SDL
3 Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
22 /* This is a WEBP image file loading framework */
27 #include "SDL_image.h"
31 /*=============================================================================
33 Purpose: A WEBP loader for the SDL library
35 Created by: Michael Bonfils (Murlock) (26 November 2011)
38 =============================================================================*/
40 #include "SDL_endian.h"
45 #include <webp/decode.h>
50 VP8StatusCode (*webp_get_features_internal) (const uint8_t *data, size_t data_size, WebPBitstreamFeatures* features, int decoder_abi_version);
51 uint8_t* (*webp_decode_rgb_into) (const uint8_t* data, size_t data_size, uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
52 uint8_t* (*webp_decode_rgba_into) (const uint8_t* data, size_t data_size, uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
55 #ifdef LOAD_WEBP_DYNAMIC
58 if ( lib.loaded == 0 ) {
59 lib.handle = SDL_LoadObject(LOAD_WEBP_DYNAMIC);
60 if ( lib.handle == NULL ) {
64 lib.webp_get_features_internal =
65 ( VP8StatusCode (*) (const uint8_t *, size_t, WebPBitstreamFeatures*, int) )
66 SDL_LoadFunction(lib.handle, "WebPGetFeaturesInternal" );
67 if ( lib.webp_get_features_internal == NULL ) {
68 SDL_UnloadObject(lib.handle);
72 lib.webp_decode_rgb_into =
73 ( uint8_t* (*) (const uint8_t*, size_t, uint8_t*, size_t, int ) )
74 SDL_LoadFunction(lib.handle, "WebPDecodeRGBInto" );
75 if ( lib.webp_decode_rgb_into == NULL ) {
76 SDL_UnloadObject(lib.handle);
80 lib.webp_decode_rgba_into =
81 ( uint8_t* (*) (const uint8_t*, size_t, uint8_t*, size_t, int ) )
82 SDL_LoadFunction(lib.handle, "WebPDecodeRGBAInto" );
83 if ( lib.webp_decode_rgba_into == NULL ) {
84 SDL_UnloadObject(lib.handle);
94 if ( lib.loaded == 0 ) {
97 if ( lib.loaded == 1 ) {
98 SDL_UnloadObject(lib.handle);
105 if ( lib.loaded == 0 ) {
107 extern VP8StatusCode WebPGetFeaturesInternal(const uint8_t*, size_t, WebPBitstreamFeatures*, int) __attribute__((weak_import));
108 if ( WebPGetFeaturesInternal == NULL )
110 /* Missing weakly linked framework */
111 IMG_SetError("Missing webp.framework");
116 lib.webp_get_features_internal = WebPGetFeaturesInternal;
117 lib.webp_decode_rgb_into = WebPDecodeRGBInto;
118 lib.webp_decode_rgba_into = WebPDecodeRGBAInto;
126 if ( lib.loaded == 0 ) {
129 if ( lib.loaded == 1 ) {
133 #endif /* LOAD_WEBP_DYNAMIC */
135 static int webp_getinfo( SDL_RWops *src, int *datasize ) {
142 start = SDL_RWtell(src);
144 if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
145 if ( magic[ 0] == 'R' &&
156 #if WEBP_DECODER_ABI_VERSION < 0x0003 /* old versions don't support WEBPVP8X and WEBPVP8L */
159 (magic[15] == ' ' || magic[15] == 'X' || magic[15] == 'L')) {
163 *datasize = (int)SDL_RWseek(src, 0, SEEK_END);
167 SDL_RWseek(src, start, RW_SEEK_SET);
171 /* See if an image is contained in a data source */
172 int IMG_isWEBP(SDL_RWops *src)
174 return webp_getinfo( src, NULL );
177 SDL_Surface *IMG_LoadWEBP_RW(SDL_RWops *src)
180 const char *error = NULL;
181 SDL_Surface *volatile surface = NULL;
186 WebPBitstreamFeatures features;
188 uint8_t *raw_data = NULL;
193 /* The error message has been set in SDL_RWFromFile */
197 start = SDL_RWtell(src);
199 if ( !IMG_Init(IMG_INIT_WEBP) ) {
204 if ( !webp_getinfo( src, &raw_data_size ) ) {
205 error = "Invalid WEBP";
209 // seek to start of file
210 SDL_RWseek(src, 0, RW_SEEK_SET );
212 raw_data = (uint8_t*) SDL_malloc( raw_data_size );
213 if ( raw_data == NULL ) {
214 error = "Failed to allocate enought buffer for WEBP";
218 r = SDL_RWread(src, raw_data, 1, raw_data_size );
219 if ( r != raw_data_size ) {
220 error = "Failed to read WEBP";
225 // extract size of picture, not interesting since we don't know about alpha channel
226 int width = -1, height = -1;
227 if ( !WebPGetInfo( raw_data, raw_data_size, &width, &height ) ) {
228 printf("WebPGetInfo has failed\n" );
233 if ( lib.webp_get_features_internal( raw_data, raw_data_size, &features, WEBP_DECODER_ABI_VERSION ) != VP8_STATUS_OK ) {
234 error = "WebPGetFeatures has failed";
238 /* Check if it's ok !*/
239 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
243 Amask = (features.has_alpha) ? 0xFF000000 : 0;
245 s = (features.has_alpha) ? 0 : 8;
246 Rmask = 0xFF000000 >> s;
247 Gmask = 0x00FF0000 >> s;
248 Bmask = 0x0000FF00 >> s;
249 Amask = 0x000000FF >> s;
252 surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
253 features.width, features.height,
254 features.has_alpha?32:24, Rmask,Gmask,Bmask,Amask);
256 if ( surface == NULL ) {
257 error = "Failed to allocate SDL_Surface";
261 if ( features.has_alpha ) {
262 ret = lib.webp_decode_rgba_into( raw_data, raw_data_size, (uint8_t *)surface->pixels, surface->pitch * surface->h, surface->pitch );
264 ret = lib.webp_decode_rgb_into( raw_data, raw_data_size, (uint8_t *)surface->pixels, surface->pitch * surface->h, surface->pitch );
268 error = "Failed to decode WEBP";
278 SDL_FreeSurface( surface );
282 SDL_free( raw_data );
286 IMG_SetError( error );
289 SDL_RWseek(src, start, RW_SEEK_SET);
297 IMG_SetError("WEBP images are not supported");
305 /* See if an image is contained in a data source */
306 int IMG_isWEBP(SDL_RWops *src)
311 /* Load a WEBP type image from an SDL datasource */
312 SDL_Surface *IMG_LoadWEBP_RW(SDL_RWops *src)
317 #endif /* LOAD_WEBP */