IMG_webp.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 22 Oct 2017 14:40:31 -0700
changeset 537 8959a43f5590
parent 531 4491ac456363
child 575 36e9e2255178
permissions -rwxr-xr-x
Fixed warnings building 64-bit with Visual Studio
slouken@278
     1
/*
slouken@280
     2
  SDL_image:  An example image loading library for use with SDL
slouken@496
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
slouken@278
     4
slouken@280
     5
  This software is provided 'as-is', without any express or implied
slouken@280
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@280
     7
  arising from the use of this software.
slouken@278
     8
slouken@280
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@280
    10
  including commercial applications, and to alter it and redistribute it
slouken@280
    11
  freely, subject to the following restrictions:
slouken@278
    12
slouken@280
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@280
    14
     claim that you wrote the original software. If you use this software
slouken@280
    15
     in a product, an acknowledgment in the product documentation would be
slouken@280
    16
     appreciated but is not required.
slouken@280
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@280
    18
     misrepresented as being the original software.
slouken@280
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@278
    20
*/
slouken@278
    21
slouken@278
    22
/* This is a WEBP image file loading framework */
slouken@278
    23
slouken@278
    24
#include "SDL_image.h"
slouken@278
    25
slouken@278
    26
#ifdef LOAD_WEBP
slouken@278
    27
slouken@278
    28
/*=============================================================================
slouken@278
    29
        File: SDL_webp.c
slouken@368
    30
     Purpose: A WEBP loader for the SDL library
slouken@368
    31
    Revision:
slouken@278
    32
  Created by: Michael Bonfils (Murlock) (26 November 2011)
slouken@278
    33
              murlock42@gmail.com
slouken@278
    34
slouken@278
    35
=============================================================================*/
slouken@278
    36
slouken@278
    37
#include "SDL_endian.h"
slouken@278
    38
slouken@278
    39
#ifdef macintosh
slouken@278
    40
#define MACOS
slouken@278
    41
#endif
slouken@278
    42
#include <webp/decode.h>
slouken@278
    43
slouken@278
    44
static struct {
slouken@368
    45
    int loaded;
slouken@368
    46
    void *handle;
slouken@537
    47
    VP8StatusCode (*WebPGetFeaturesInternal) (const uint8_t *data, size_t data_size, WebPBitstreamFeatures* features, int decoder_abi_version);
slouken@537
    48
    uint8_t*    (*WebPDecodeRGBInto) (const uint8_t* data, size_t data_size, uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
slouken@537
    49
    uint8_t*    (*WebPDecodeRGBAInto) (const uint8_t* data, size_t data_size, uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
slouken@278
    50
} lib;
slouken@278
    51
slouken@278
    52
#ifdef LOAD_WEBP_DYNAMIC
slouken@537
    53
#define FUNCTION_LOADER(FUNC, SIG) \
slouken@537
    54
    lib.FUNC = (SIG) SDL_LoadFunction(lib.handle, #FUNC); \
slouken@537
    55
    if (lib.FUNC == NULL) { SDL_UnloadObject(lib.handle); return -1; }
slouken@537
    56
#else
slouken@537
    57
#define FUNCTION_LOADER(FUNC, SIG) \
slouken@537
    58
    lib.FUNC = FUNC;
slouken@537
    59
#endif
slouken@537
    60
slouken@278
    61
int IMG_InitWEBP()
slouken@278
    62
{
slouken@368
    63
    if ( lib.loaded == 0 ) {
slouken@537
    64
#ifdef LOAD_WEBP_DYNAMIC
slouken@368
    65
        lib.handle = SDL_LoadObject(LOAD_WEBP_DYNAMIC);
slouken@368
    66
        if ( lib.handle == NULL ) {
slouken@368
    67
            return -1;
slouken@368
    68
        }
slouken@537
    69
#endif
slouken@537
    70
        FUNCTION_LOADER(WebPGetFeaturesInternal, VP8StatusCode (*) (const uint8_t *data, size_t data_size, WebPBitstreamFeatures* features, int decoder_abi_version))
slouken@537
    71
        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))
slouken@537
    72
        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))
slouken@368
    73
    }
slouken@368
    74
    ++lib.loaded;
slouken@278
    75
slouken@368
    76
    return 0;
slouken@278
    77
}
slouken@278
    78
void IMG_QuitWEBP()
slouken@278
    79
{
slouken@368
    80
    if ( lib.loaded == 0 ) {
slouken@368
    81
        return;
slouken@368
    82
    }
slouken@368
    83
    if ( lib.loaded == 1 ) {
slouken@537
    84
#ifdef LOAD_WEBP_DYNAMIC
slouken@368
    85
        SDL_UnloadObject(lib.handle);
slouken@537
    86
#endif
slouken@368
    87
    }
slouken@368
    88
    --lib.loaded;
slouken@278
    89
}
slouken@278
    90
slouken@278
    91
static int webp_getinfo( SDL_RWops *src, int *datasize ) {
slouken@368
    92
    Sint64 start;
slouken@368
    93
    int is_WEBP;
slouken@368
    94
    Uint8 magic[20];
slouken@278
    95
slouken@368
    96
    if ( !src )
slouken@368
    97
        return 0;
slouken@368
    98
    start = SDL_RWtell(src);
slouken@368
    99
    is_WEBP = 0;
slouken@368
   100
    if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
slouken@368
   101
        if ( magic[ 0] == 'R' &&
slouken@531
   102
             magic[ 1] == 'I' &&
slouken@531
   103
             magic[ 2] == 'F' &&
slouken@531
   104
             magic[ 3] == 'F' &&
slouken@531
   105
             magic[ 8] == 'W' &&
slouken@531
   106
             magic[ 9] == 'E' &&
slouken@531
   107
             magic[10] == 'B' &&
slouken@531
   108
             magic[11] == 'P' &&
slouken@531
   109
             magic[12] == 'V' &&
slouken@531
   110
             magic[13] == 'P' &&
slouken@531
   111
             magic[14] == '8' &&
slouken@360
   112
#if WEBP_DECODER_ABI_VERSION < 0x0003 /* old versions don't support WEBPVP8X and WEBPVP8L */
slouken@531
   113
             magic[15] == ' ') {
slouken@360
   114
#else
slouken@531
   115
             (magic[15] == ' ' || magic[15] == 'X' || magic[15] == 'L')) {
slouken@360
   116
#endif
slouken@368
   117
            is_WEBP = 1;
slouken@368
   118
            if ( datasize ) {
slouken@537
   119
                *datasize = (int)(SDL_RWseek(src, 0, RW_SEEK_END) - start);
slouken@368
   120
            }
slouken@368
   121
        }
slouken@368
   122
    }
slouken@368
   123
    SDL_RWseek(src, start, RW_SEEK_SET);
slouken@368
   124
    return(is_WEBP);
slouken@278
   125
}
slouken@278
   126
slouken@278
   127
/* See if an image is contained in a data source */
slouken@278
   128
int IMG_isWEBP(SDL_RWops *src)
slouken@278
   129
{
slouken@368
   130
    return webp_getinfo( src, NULL );
slouken@278
   131
}
slouken@278
   132
slouken@278
   133
SDL_Surface *IMG_LoadWEBP_RW(SDL_RWops *src)
slouken@278
   134
{
slouken@368
   135
    Sint64 start;
slouken@368
   136
    const char *error = NULL;
slouken@368
   137
    SDL_Surface *volatile surface = NULL;
slouken@368
   138
    Uint32 Rmask;
slouken@368
   139
    Uint32 Gmask;
slouken@368
   140
    Uint32 Bmask;
slouken@368
   141
    Uint32 Amask;
slouken@368
   142
    WebPBitstreamFeatures features;
slouken@368
   143
    int raw_data_size;
slouken@368
   144
    uint8_t *raw_data = NULL;
aschiffler@406
   145
    int r;
slouken@368
   146
    uint8_t *ret;
slouken@278
   147
slouken@368
   148
    if ( !src ) {
slouken@368
   149
        /* The error message has been set in SDL_RWFromFile */
slouken@368
   150
        return NULL;
slouken@368
   151
    }
slouken@278
   152
slouken@368
   153
    start = SDL_RWtell(src);
slouken@278
   154
slouken@490
   155
    if ( (IMG_Init(IMG_INIT_WEBP) & IMG_INIT_WEBP) == 0 ) {
slouken@368
   156
        goto error;
slouken@368
   157
    }
slouken@278
   158
slouken@368
   159
    raw_data_size = -1;
slouken@368
   160
    if ( !webp_getinfo( src, &raw_data_size ) ) {
slouken@368
   161
        error = "Invalid WEBP";
slouken@368
   162
        goto error;
slouken@368
   163
    }
slouken@278
   164
slouken@368
   165
    raw_data = (uint8_t*) SDL_malloc( raw_data_size );
slouken@368
   166
    if ( raw_data == NULL ) {
slouken@537
   167
        error = "Failed to allocate enough buffer for WEBP";
slouken@368
   168
        goto error;
slouken@368
   169
    }
slouken@278
   170
slouken@537
   171
    r = (int)SDL_RWread(src, raw_data, 1, raw_data_size );
slouken@368
   172
    if ( r != raw_data_size ) {
slouken@368
   173
        error = "Failed to read WEBP";
slouken@368
   174
        goto error;
slouken@368
   175
    }
slouken@368
   176
slouken@278
   177
#if 0
slouken@368
   178
    // extract size of picture, not interesting since we don't know about alpha channel
slouken@368
   179
    int width = -1, height = -1;
slouken@368
   180
    if ( !WebPGetInfo( raw_data, raw_data_size, &width, &height ) ) {
slouken@368
   181
        printf("WebPGetInfo has failed\n" );
slouken@368
   182
        return NULL;
slouken@368
   183
    }
slouken@278
   184
#endif
slouken@278
   185
slouken@537
   186
    if ( lib.WebPGetFeaturesInternal( raw_data, raw_data_size, &features, WEBP_DECODER_ABI_VERSION ) != VP8_STATUS_OK ) {
slouken@368
   187
        error = "WebPGetFeatures has failed";
slouken@368
   188
        goto error;
slouken@368
   189
    }
slouken@278
   190
slouken@368
   191
    /* Check if it's ok !*/
slouken@358
   192
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
slouken@368
   193
    Rmask = 0x000000FF;
slouken@368
   194
    Gmask = 0x0000FF00;
slouken@368
   195
    Bmask = 0x00FF0000;
slouken@368
   196
    Amask = (features.has_alpha) ? 0xFF000000 : 0;
slouken@358
   197
#else
slouken@426
   198
    {
slouken@426
   199
        int s = (features.has_alpha) ? 0 : 8;
slouken@426
   200
        Rmask = 0xFF000000 >> s;
slouken@426
   201
        Gmask = 0x00FF0000 >> s;
slouken@426
   202
        Bmask = 0x0000FF00 >> s;
slouken@426
   203
        Amask = 0x000000FF >> s;
slouken@426
   204
    }
slouken@355
   205
#endif
slouken@278
   206
slouken@368
   207
    surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
slouken@368
   208
            features.width, features.height,
slouken@368
   209
            features.has_alpha?32:24, Rmask,Gmask,Bmask,Amask);
slouken@278
   210
slouken@368
   211
    if ( surface == NULL ) {
slouken@368
   212
        error = "Failed to allocate SDL_Surface";
slouken@368
   213
        goto error;
slouken@368
   214
    }
slouken@278
   215
slouken@368
   216
    if ( features.has_alpha ) {
slouken@537
   217
        ret = lib.WebPDecodeRGBAInto( raw_data, raw_data_size, (uint8_t *)surface->pixels, surface->pitch * surface->h,  surface->pitch );
slouken@368
   218
    } else {
slouken@537
   219
        ret = lib.WebPDecodeRGBInto( raw_data, raw_data_size, (uint8_t *)surface->pixels, surface->pitch * surface->h,  surface->pitch );
slouken@368
   220
    }
slouken@278
   221
slouken@368
   222
    if ( !ret ) {
slouken@368
   223
        error = "Failed to decode WEBP";
slouken@368
   224
        goto error;
slouken@368
   225
    }
slouken@278
   226
slouken@436
   227
    if ( raw_data ) {
slouken@436
   228
        SDL_free( raw_data );
slouken@436
   229
    }
slouken@436
   230
slouken@368
   231
    return surface;
slouken@278
   232
slouken@278
   233
slouken@278
   234
error:
slouken@278
   235
slouken@436
   236
    if ( raw_data ) {
slouken@436
   237
        SDL_free( raw_data );
slouken@436
   238
    }
slouken@436
   239
slouken@368
   240
    if ( surface ) {
slouken@368
   241
        SDL_FreeSurface( surface );
slouken@368
   242
    }
slouken@278
   243
slouken@368
   244
    if ( error ) {
slouken@452
   245
        IMG_SetError( "%s", error );
slouken@368
   246
    }
slouken@278
   247
slouken@368
   248
    SDL_RWseek(src, start, RW_SEEK_SET);
slouken@368
   249
    return(NULL);
slouken@278
   250
}
slouken@278
   251
slouken@278
   252
#else
slouken@278
   253
slouken@278
   254
int IMG_InitWEBP()
slouken@278
   255
{
slouken@368
   256
    IMG_SetError("WEBP images are not supported");
slouken@368
   257
    return(-1);
slouken@278
   258
}
slouken@278
   259
slouken@278
   260
void IMG_QuitWEBP()
slouken@278
   261
{
slouken@278
   262
}
slouken@278
   263
slouken@278
   264
/* See if an image is contained in a data source */
slouken@278
   265
int IMG_isWEBP(SDL_RWops *src)
slouken@278
   266
{
slouken@368
   267
    return(0);
slouken@278
   268
}
slouken@278
   269
slouken@278
   270
/* Load a WEBP type image from an SDL datasource */
slouken@278
   271
SDL_Surface *IMG_LoadWEBP_RW(SDL_RWops *src)
slouken@278
   272
{
slouken@368
   273
    return(NULL);
slouken@278
   274
}
slouken@278
   275
slouken@278
   276
#endif /* LOAD_WEBP */