IMG_webp.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 15 Feb 2013 14:47:06 -0800
changeset 347 ad5034cad524
parent 343 5bf0f0d6a74e
child 355 2742fe586c4d
permissions -rw-r--r--
Updated copyright year
     1 /*
     2   SDL_image:  An example image loading library for use with SDL
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     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.
     8 
     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:
    12 
    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.
    20 */
    21 
    22 /* This is a WEBP image file loading framework */
    23 
    24 #include <stdlib.h>
    25 #include <stdio.h>
    26 
    27 #include "SDL_image.h"
    28 
    29 #ifdef LOAD_WEBP
    30 
    31 /*=============================================================================
    32         File: SDL_webp.c
    33      Purpose: A WEBP loader for the SDL library      
    34     Revision: 
    35   Created by: Michael Bonfils (Murlock) (26 November 2011)
    36               murlock42@gmail.com
    37 
    38 =============================================================================*/
    39 
    40 #include "SDL_endian.h"
    41 
    42 #ifdef macintosh
    43 #define MACOS
    44 #endif
    45 #include <webp/decode.h>
    46 
    47 static struct {
    48 	int loaded;
    49 	void *handle;
    50 	int/*VP8StatuCode*/ (*webp_get_features_internal) (const uint8_t *data, uint32_t data_size, WebPBitstreamFeatures* const features, int decoder_abi_version);
    51 	uint8_t*	(*webp_decode_rgb_into) (const uint8_t* data, uint32_t data_size, uint8_t* output_buffer, int output_buffer_size, int output_stride);
    52 	uint8_t*	(*webp_decode_rgba_into) (const uint8_t* data, uint32_t data_size, uint8_t* output_buffer, int output_buffer_size, int output_stride);
    53 } lib;
    54 
    55 #ifdef LOAD_WEBP_DYNAMIC
    56 int IMG_InitWEBP()
    57 {
    58 	if ( lib.loaded == 0 ) {
    59 		lib.handle = SDL_LoadObject(LOAD_WEBP_DYNAMIC);
    60 		if ( lib.handle == NULL ) {
    61 			return -1;
    62 		}
    63 		lib.webp_get_features_internal = 
    64 			( int (*) (const uint8_t *, uint32_t, WebPBitstreamFeatures* const, int) )
    65 			SDL_LoadFunction(lib.handle, "WebPGetFeaturesInternal" );
    66 		if ( lib.webp_get_features_internal == NULL ) {
    67 			SDL_UnloadObject(lib.handle);
    68 			return -1;
    69 		}
    70 
    71 		lib.webp_decode_rgb_into = 
    72 			( uint8_t* (*) (const uint8_t*, uint32_t, uint8_t*, int, int ) )
    73 			SDL_LoadFunction(lib.handle, "WebPDecodeRGBInto" );
    74 		if ( lib.webp_decode_rgb_into == NULL ) {
    75 			SDL_UnloadObject(lib.handle);
    76 			return -1;
    77 		}
    78 
    79 		lib.webp_decode_rgba_into = 
    80 			( uint8_t* (*) (const uint8_t*, uint32_t, uint8_t*, int, int ) )
    81 			SDL_LoadFunction(lib.handle, "WebPDecodeRGBInto" );
    82 		if ( lib.webp_decode_rgba_into == NULL ) {
    83 			SDL_UnloadObject(lib.handle);
    84 			return -1;
    85 		}
    86 	}
    87 	++lib.loaded;
    88 
    89 	return 0;
    90 }
    91 void IMG_QuitWEBP()
    92 {
    93 	if ( lib.loaded == 0 ) {
    94 		return;
    95 	}
    96 	if ( lib.loaded == 1 ) {
    97 		SDL_UnloadObject(lib.handle);
    98 	}
    99 	--lib.loaded;
   100 }
   101 #else
   102 int IMG_InitWEBP()
   103 {
   104 	if ( lib.loaded == 0 ) {
   105 		lib.webp_get_features_internal = WebPGetFeaturesInternal;
   106 		lib.webp_decode_rgb_into = WebPDecodeRGBInto;
   107 		lib.webp_decode_rgba_into = WebPDecodeRGBAInto;
   108 	}
   109 	++lib.loaded;
   110 
   111 	return 0;
   112 }
   113 void IMG_QuitWEBP()
   114 {
   115 	if ( lib.loaded == 0 ) {
   116 		return;
   117 	}
   118 	if ( lib.loaded == 1 ) {
   119 	}
   120 	--lib.loaded;
   121 }
   122 #endif /* LOAD_WEBP_DYNAMIC */
   123 
   124 static int webp_getinfo( SDL_RWops *src, int *datasize ) {
   125 	Sint64 start;
   126 	int is_WEBP;
   127 	int data;
   128 	Uint8 magic[20];
   129 
   130 	if ( !src )
   131 		return 0;
   132 	start = SDL_RWtell(src);
   133 	is_WEBP = 0;
   134 	if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
   135 		if ( magic[ 0] == 'R' &&
   136                      magic[ 1] == 'I' &&
   137                      magic[ 2] == 'F' &&
   138                      magic[ 3] == 'F' &&
   139 										 magic[ 8] == 'W' &&
   140 										 magic[ 9] == 'E' &&
   141 										 magic[10] == 'B' &&
   142 										 magic[11] == 'P' &&
   143 										 magic[12] == 'V' &&
   144 										 magic[13] == 'P' &&
   145 										 magic[14] == '8' &&
   146 										 magic[15] == ' '  ) {
   147 			is_WEBP = 1;
   148 			data = magic[16] | magic[17]<<8 | magic[18]<<16 | magic[19]<<24;
   149 			if ( datasize )
   150 				*datasize = data;
   151 		}
   152 	}
   153 	SDL_RWseek(src, start, RW_SEEK_SET);
   154 	return(is_WEBP);
   155 }
   156 
   157 /* See if an image is contained in a data source */
   158 int IMG_isWEBP(SDL_RWops *src)
   159 {
   160 	return webp_getinfo( src, NULL );
   161 }
   162 
   163 SDL_Surface *IMG_LoadWEBP_RW(SDL_RWops *src)
   164 {
   165 	Sint64 start;
   166 	const char *error = NULL;
   167 	SDL_Surface *volatile surface = NULL;
   168 	Uint32 Rmask;
   169 	Uint32 Gmask;
   170 	Uint32 Bmask;
   171 	Uint32 Amask;
   172 	WebPBitstreamFeatures features;
   173 	int raw_data_size;
   174 	uint8_t *raw_data = NULL;
   175 	int r;
   176 	uint8_t *ret;
   177 
   178 	if ( !src ) {
   179 		/* The error message has been set in SDL_RWFromFile */
   180 		return NULL;
   181 	}
   182 
   183 	start = SDL_RWtell(src);
   184 
   185 	if ( !IMG_Init(IMG_INIT_WEBP) ) {
   186 		goto error;
   187 	}
   188 
   189 
   190 	raw_data_size = -1;
   191 	if ( !webp_getinfo( src, &raw_data_size ) ) {
   192 		error = "Invalid WEBP";
   193 		goto error;
   194 	}
   195 
   196 	// skip header
   197 	SDL_RWseek(src, start+20, RW_SEEK_SET );
   198 
   199 	raw_data = (uint8_t*) SDL_malloc( raw_data_size );
   200 	if ( raw_data == NULL ) {
   201 		error = "Failed to allocate enought buffer for WEBP";
   202 		goto error;
   203 	}
   204 
   205 	r = SDL_RWread(src, raw_data, 1, raw_data_size );
   206 	if ( r != raw_data_size ) {
   207 		error = "Failed to read WEBP";
   208 		goto error;
   209 	}
   210 	
   211 #if 0
   212 	// extract size of picture, not interesting since we don't know about alpha channel
   213 	int width = -1, height = -1;
   214 	if ( !WebPGetInfo( raw_data, raw_data_size, &width, &height ) ) {
   215 		printf("WebPGetInfo has failed\n" );
   216 		return NULL;
   217 	}
   218 #endif
   219 
   220 	if ( lib.webp_get_features_internal( raw_data, raw_data_size, &features, WEBP_DECODER_ABI_VERSION ) != VP8_STATUS_OK ) {
   221 		error = "WebPGetFeatures has failed";
   222 		goto error;
   223 	}
   224 
   225 	/* Check if it's ok !*/
   226 	Rmask = 0x000000FF;
   227 	Gmask = 0x0000FF00;
   228 	Bmask = 0x00FF0000;
   229 	Amask = features.has_alpha?0xFF000001:0;
   230 
   231 	surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
   232             features.width, features.height,
   233 			features.has_alpha?32:24, Rmask,Gmask,Bmask,Amask);
   234 
   235 	if ( surface == NULL ) {
   236 		error = "Failed to allocate SDL_Surface";
   237 		goto error;
   238 	}
   239 
   240 	if ( features.has_alpha ) {
   241 		ret = lib.webp_decode_rgba_into( raw_data, raw_data_size, (uint8_t *)surface->pixels, surface->pitch * surface->h,  surface->pitch );
   242 	} else {
   243 		ret = lib.webp_decode_rgb_into( raw_data, raw_data_size, (uint8_t *)surface->pixels, surface->pitch * surface->h,  surface->pitch );
   244 	}
   245 
   246 	if ( !ret ) {
   247 		error = "Failed to decode WEBP";
   248 		goto error;
   249 	}
   250 
   251 	return surface;
   252 
   253 
   254 error:
   255 
   256 	if ( surface ) {
   257 		SDL_FreeSurface( surface );
   258 	}
   259 
   260 	if ( raw_data ) {
   261 		SDL_free( raw_data );
   262 	}
   263 
   264 	if ( error ) {
   265 		IMG_SetError( error );
   266 	}
   267 
   268 	SDL_RWseek(src, start, RW_SEEK_SET);
   269 	return(NULL);
   270 }
   271 
   272 #else
   273 
   274 int IMG_InitWEBP()
   275 {
   276 	IMG_SetError("WEBP images are not supported");
   277 	return(-1);
   278 }
   279 
   280 void IMG_QuitWEBP()
   281 {
   282 }
   283 
   284 /* See if an image is contained in a data source */
   285 int IMG_isWEBP(SDL_RWops *src)
   286 {
   287 	return(0);
   288 }
   289 
   290 /* Load a WEBP type image from an SDL datasource */
   291 SDL_Surface *IMG_LoadWEBP_RW(SDL_RWops *src)
   292 {
   293 	return(NULL);
   294 }
   295 
   296 #endif /* LOAD_WEBP */