IMG_webp.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 31 Dec 2011 09:41:39 -0500
changeset 280 ec4ae96c100c
parent 278 2fd74c55f313
child 288 cbf4a9d168ff
permissions -rw-r--r--
Happy New Year!
     1 /*
     2   SDL_image:  An example image loading library for use with SDL
     3   Copyright (C) 1997-2012 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 	int start;
   126 	int is_WEBP;
   127 	Uint8 magic[20];
   128 
   129 	if ( !src )
   130 		return 0;
   131 	start = SDL_RWtell(src);
   132 	is_WEBP = 0;
   133 	if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
   134 		if ( magic[ 0] == 'R' &&
   135                      magic[ 1] == 'I' &&
   136                      magic[ 2] == 'F' &&
   137                      magic[ 3] == 'F' &&
   138 										 magic[ 8] == 'W' &&
   139 										 magic[ 9] == 'E' &&
   140 										 magic[10] == 'B' &&
   141 										 magic[11] == 'P' &&
   142 										 magic[12] == 'V' &&
   143 										 magic[13] == 'P' &&
   144 										 magic[14] == '8' &&
   145 										 magic[15] == ' '  ) {
   146 			is_WEBP = 1;
   147 			int data = magic[16] | magic[17]<<8 | magic[18]<<16 | magic[19]<<24;
   148 			if ( datasize )
   149 				*datasize = data;
   150 		}
   151 	}
   152 	SDL_RWseek(src, start, RW_SEEK_SET);
   153 	return(is_WEBP);
   154 }
   155 
   156 /* See if an image is contained in a data source */
   157 int IMG_isWEBP(SDL_RWops *src)
   158 {
   159 	return webp_getinfo( src, NULL );
   160 }
   161 
   162 SDL_Surface *IMG_LoadWEBP_RW(SDL_RWops *src)
   163 {
   164 	int start;
   165 	const char *error = NULL;
   166 	SDL_Surface *volatile surface = NULL;
   167 	Uint32 Rmask;
   168 	Uint32 Gmask;
   169 	Uint32 Bmask;
   170 	Uint32 Amask;
   171 
   172 	if ( !src ) {
   173 		/* The error message has been set in SDL_RWFromFile */
   174 		return NULL;
   175 	}
   176 
   177 	start = SDL_RWtell(src);
   178 
   179 	if ( !IMG_Init(IMG_INIT_WEBP) ) {
   180 		goto error;
   181 	}
   182 
   183 
   184 	int raw_data_size = -1;
   185 	if ( !webp_getinfo( src, &raw_data_size ) ) {
   186 		error = "Invalid WEBP";
   187 		goto error;
   188 	}
   189 
   190 	// skip header
   191 	SDL_RWseek(src, start+20, RW_SEEK_SET );
   192 
   193 	uint8_t *raw_data = (uint8_t*) malloc( raw_data_size );
   194 	if ( raw_data == NULL ) {
   195 		error = "Failed to allocate enought buffer for WEBP";
   196 		goto error;
   197 	}
   198 
   199 	int r = SDL_RWread(src, raw_data, 1, raw_data_size );
   200 	if ( r != raw_data_size ) {
   201 		error = "Failed to read WEBP";
   202 		goto error;
   203 	}
   204 	
   205 #if 0
   206 	// extract size of picture, not interesting since we don't know about alpha channel
   207 	int width = -1, height = -1;
   208 	if ( !WebPGetInfo( raw_data, raw_data_size, &width, &height ) ) {
   209 		printf("WebPGetInfo has failed\n" );
   210 		return NULL;
   211 	}
   212 #endif
   213 
   214 	WebPBitstreamFeatures features;
   215   if ( lib.webp_get_features_internal( raw_data, raw_data_size, &features, WEBP_DECODER_ABI_VERSION ) != VP8_STATUS_OK ) {
   216 		error = "WebPGetFeatures has failed";
   217 		return NULL;
   218 	}
   219 
   220 	/* Check if it's ok !*/
   221 	Rmask = 0x000000FF;
   222 	Gmask = 0x0000FF00;
   223 	Bmask = 0x00FF0000;
   224 	Amask = features.has_alpha?0xFF000001:0;
   225 
   226 	surface = SDL_AllocSurface(SDL_SWSURFACE, features.width, features.height,
   227 			features.has_alpha?32:24, Rmask,Gmask,Bmask,Amask);
   228 
   229 	if ( surface == NULL ) {
   230 		error = "Failed to allocate SDL_Surface";
   231 		goto error;
   232 	}
   233 
   234 
   235 	uint8_t *ret = NULL;
   236 	if ( features.has_alpha ) {
   237 		ret = lib.webp_decode_rgba_into( raw_data, raw_data_size, surface->pixels, surface->pitch * surface->h,  surface->pitch );
   238 	} else {
   239 		ret = lib.webp_decode_rgb_into( raw_data, raw_data_size, surface->pixels, surface->pitch * surface->h,  surface->pitch );
   240 	}
   241 
   242 	if ( !ret ) {
   243 		error = "Failed to decode WEBP";
   244 		goto error;
   245 	}
   246 
   247 	return surface;
   248 
   249 
   250 error:
   251 
   252 	if ( surface ) {
   253 		SDL_FreeSurface( surface );
   254 	}
   255 
   256 	if ( raw_data ) {
   257 		free( raw_data );
   258 	}
   259 
   260 	if ( error ) {
   261 		IMG_SetError( error );
   262 	}
   263 
   264 	SDL_RWseek(src, start, RW_SEEK_SET);
   265 	return(NULL);
   266 }
   267 
   268 #else
   269 
   270 int IMG_InitWEBP()
   271 {
   272 	IMG_SetError("WEBP images are not supported");
   273 	return(-1);
   274 }
   275 
   276 void IMG_QuitWEBP()
   277 {
   278 }
   279 
   280 /* See if an image is contained in a data source */
   281 int IMG_isWEBP(SDL_RWops *src)
   282 {
   283 	return(0);
   284 }
   285 
   286 /* Load a WEBP type image from an SDL datasource */
   287 SDL_Surface *IMG_LoadWEBP_RW(SDL_RWops *src)
   288 {
   289 	return(NULL);
   290 }
   291 
   292 #endif /* LOAD_WEBP */