IMG_webp.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 21 May 2013 21:24:32 -0700
changeset 368 8a61842d00ce
parent 360 3d002acf103d
child 378 f83e70f2ec6c
permissions -rw-r--r--
Cleaned up whitespace for the 2.0.0 release
     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, "WebPDecodeRGBAInto" );
    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     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 #if WEBP_DECODER_ABI_VERSION < 0x0003 /* old versions don't support WEBPVP8X and WEBPVP8L */
   146                                          magic[15] == ' ') {
   147 #else
   148                                          (magic[15] == ' ' || magic[15] == 'X' || magic[15] == 'L')) {
   149 #endif
   150             is_WEBP = 1;
   151             if ( datasize ) {
   152                 *datasize = SDL_RWseek(src, 0, SEEK_END);
   153             }
   154         }
   155     }
   156     SDL_RWseek(src, start, RW_SEEK_SET);
   157     return(is_WEBP);
   158 }
   159 
   160 /* See if an image is contained in a data source */
   161 int IMG_isWEBP(SDL_RWops *src)
   162 {
   163     return webp_getinfo( src, NULL );
   164 }
   165 
   166 SDL_Surface *IMG_LoadWEBP_RW(SDL_RWops *src)
   167 {
   168     Sint64 start;
   169     const char *error = NULL;
   170     SDL_Surface *volatile surface = NULL;
   171     Uint32 Rmask;
   172     Uint32 Gmask;
   173     Uint32 Bmask;
   174     Uint32 Amask;
   175     WebPBitstreamFeatures features;
   176     int raw_data_size;
   177     uint8_t *raw_data = NULL;
   178     int r, s;
   179     uint8_t *ret;
   180 
   181     if ( !src ) {
   182         /* The error message has been set in SDL_RWFromFile */
   183         return NULL;
   184     }
   185 
   186     start = SDL_RWtell(src);
   187 
   188     if ( !IMG_Init(IMG_INIT_WEBP) ) {
   189         goto error;
   190     }
   191 
   192     raw_data_size = -1;
   193     if ( !webp_getinfo( src, &raw_data_size ) ) {
   194         error = "Invalid WEBP";
   195         goto error;
   196     }
   197 
   198     // seek to start of file
   199     SDL_RWseek(src, 0, RW_SEEK_SET );
   200 
   201     raw_data = (uint8_t*) SDL_malloc( raw_data_size );
   202     if ( raw_data == NULL ) {
   203         error = "Failed to allocate enought buffer for WEBP";
   204         goto error;
   205     }
   206 
   207     r = SDL_RWread(src, raw_data, 1, raw_data_size );
   208     if ( r != raw_data_size ) {
   209         error = "Failed to read WEBP";
   210         goto error;
   211     }
   212 
   213 #if 0
   214     // extract size of picture, not interesting since we don't know about alpha channel
   215     int width = -1, height = -1;
   216     if ( !WebPGetInfo( raw_data, raw_data_size, &width, &height ) ) {
   217         printf("WebPGetInfo has failed\n" );
   218         return NULL;
   219     }
   220 #endif
   221 
   222     if ( lib.webp_get_features_internal( raw_data, raw_data_size, &features, WEBP_DECODER_ABI_VERSION ) != VP8_STATUS_OK ) {
   223         error = "WebPGetFeatures has failed";
   224         goto error;
   225     }
   226 
   227     /* Check if it's ok !*/
   228 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   229     Rmask = 0x000000FF;
   230     Gmask = 0x0000FF00;
   231     Bmask = 0x00FF0000;
   232     Amask = (features.has_alpha) ? 0xFF000000 : 0;
   233 #else
   234     s = (features.has_alpha) ? 0 : 8;
   235     Rmask = 0xFF000000 >> s;
   236     Gmask = 0x00FF0000 >> s;
   237     Bmask = 0x0000FF00 >> s;
   238     Amask = 0x000000FF >> s;
   239 #endif
   240 
   241     surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
   242             features.width, features.height,
   243             features.has_alpha?32:24, Rmask,Gmask,Bmask,Amask);
   244 
   245     if ( surface == NULL ) {
   246         error = "Failed to allocate SDL_Surface";
   247         goto error;
   248     }
   249 
   250     if ( features.has_alpha ) {
   251         ret = lib.webp_decode_rgba_into( raw_data, raw_data_size, (uint8_t *)surface->pixels, surface->pitch * surface->h,  surface->pitch );
   252     } else {
   253         ret = lib.webp_decode_rgb_into( raw_data, raw_data_size, (uint8_t *)surface->pixels, surface->pitch * surface->h,  surface->pitch );
   254     }
   255 
   256     if ( !ret ) {
   257         error = "Failed to decode WEBP";
   258         goto error;
   259     }
   260 
   261     return surface;
   262 
   263 
   264 error:
   265 
   266     if ( surface ) {
   267         SDL_FreeSurface( surface );
   268     }
   269 
   270     if ( raw_data ) {
   271         SDL_free( raw_data );
   272     }
   273 
   274     if ( error ) {
   275         IMG_SetError( error );
   276     }
   277 
   278     SDL_RWseek(src, start, RW_SEEK_SET);
   279     return(NULL);
   280 }
   281 
   282 #else
   283 
   284 int IMG_InitWEBP()
   285 {
   286     IMG_SetError("WEBP images are not supported");
   287     return(-1);
   288 }
   289 
   290 void IMG_QuitWEBP()
   291 {
   292 }
   293 
   294 /* See if an image is contained in a data source */
   295 int IMG_isWEBP(SDL_RWops *src)
   296 {
   297     return(0);
   298 }
   299 
   300 /* Load a WEBP type image from an SDL datasource */
   301 SDL_Surface *IMG_LoadWEBP_RW(SDL_RWops *src)
   302 {
   303     return(NULL);
   304 }
   305 
   306 #endif /* LOAD_WEBP */