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