IMG_pcx.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 15 Jun 2014 13:16:42 -0700
changeset 451 48116d511e5d
parent 368 8a61842d00ce
child 486 7bb8af91e887
permissions -rw-r--r--
Fixed format warnings: format not a string literal and no format arguments
slouken@0
     1
/*
slouken@280
     2
  SDL_image:  An example image loading library for use with SDL
slouken@347
     3
  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
slouken@0
     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@0
     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@0
    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@0
    20
*/
slouken@0
    21
slouken@20
    22
/*
slouken@20
    23
 * PCX file reader:
slouken@20
    24
 * Supports:
slouken@20
    25
 *  1..4 bits/pixel in multiplanar format (1 bit/plane/pixel)
slouken@20
    26
 *  8 bits/pixel in single-planar format (8 bits/plane/pixel)
slouken@20
    27
 *  24 bits/pixel in 3-plane format (8 bits/plane/pixel)
slouken@20
    28
 *
slouken@24
    29
 * (The <8bpp formats are expanded to 8bpp surfaces)
slouken@24
    30
 *
slouken@20
    31
 * Doesn't support:
slouken@20
    32
 *  single-planar packed-pixel formats other than 8bpp
slouken@20
    33
 *  4-plane 32bpp format with a fourth "intensity" plane
slouken@20
    34
 */
slouken@0
    35
#include <stdio.h>
slouken@20
    36
#include <stdlib.h>
slouken@0
    37
slouken@0
    38
#include "SDL_endian.h"
slouken@0
    39
slouken@0
    40
#include "SDL_image.h"
slouken@0
    41
slouken@0
    42
#ifdef LOAD_PCX
slouken@0
    43
slouken@0
    44
struct PCXheader {
slouken@368
    45
    Uint8 Manufacturer;
slouken@368
    46
    Uint8 Version;
slouken@368
    47
    Uint8 Encoding;
slouken@368
    48
    Uint8 BitsPerPixel;
slouken@368
    49
    Sint16 Xmin, Ymin, Xmax, Ymax;
slouken@368
    50
    Sint16 HDpi, VDpi;
slouken@368
    51
    Uint8 Colormap[48];
slouken@368
    52
    Uint8 Reserved;
slouken@368
    53
    Uint8 NPlanes;
slouken@368
    54
    Sint16 BytesPerLine;
slouken@368
    55
    Sint16 PaletteInfo;
slouken@368
    56
    Sint16 HscreenSize;
slouken@368
    57
    Sint16 VscreenSize;
slouken@368
    58
    Uint8 Filler[54];
slouken@0
    59
};
slouken@0
    60
slouken@0
    61
/* See if an image is contained in a data source */
slouken@0
    62
int IMG_isPCX(SDL_RWops *src)
slouken@0
    63
{
slouken@368
    64
    Sint64 start;
slouken@368
    65
    int is_PCX;
slouken@368
    66
    const int ZSoft_Manufacturer = 10;
slouken@368
    67
    const int PC_Paintbrush_Version = 5;
slouken@368
    68
    const int PCX_Uncompressed_Encoding = 0;
slouken@368
    69
    const int PCX_RunLength_Encoding = 1;
slouken@368
    70
    struct PCXheader pcxh;
slouken@0
    71
slouken@368
    72
    if ( !src )
slouken@368
    73
        return 0;
slouken@368
    74
    start = SDL_RWtell(src);
slouken@368
    75
    is_PCX = 0;
slouken@368
    76
    if ( SDL_RWread(src, &pcxh, sizeof(pcxh), 1) == 1 ) {
slouken@368
    77
        if ( (pcxh.Manufacturer == ZSoft_Manufacturer) &&
slouken@368
    78
             (pcxh.Version == PC_Paintbrush_Version) &&
slouken@368
    79
             (pcxh.Encoding == PCX_RunLength_Encoding ||
slouken@368
    80
              pcxh.Encoding == PCX_Uncompressed_Encoding) ) {
slouken@368
    81
            is_PCX = 1;
slouken@368
    82
        }
slouken@368
    83
    }
slouken@368
    84
    SDL_RWseek(src, start, RW_SEEK_SET);
slouken@368
    85
    return(is_PCX);
slouken@0
    86
}
slouken@0
    87
slouken@0
    88
/* Load a PCX type image from an SDL datasource */
slouken@0
    89
SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
slouken@0
    90
{
slouken@368
    91
    Sint64 start;
slouken@368
    92
    struct PCXheader pcxh;
slouken@368
    93
    Uint32 Rmask;
slouken@368
    94
    Uint32 Gmask;
slouken@368
    95
    Uint32 Bmask;
slouken@368
    96
    Uint32 Amask;
slouken@368
    97
    SDL_Surface *surface = NULL;
slouken@368
    98
    int width, height;
slouken@368
    99
    int y, bpl;
slouken@368
   100
    Uint8 *row, *buf = NULL;
slouken@368
   101
    char *error = NULL;
slouken@368
   102
    int bits, src_bits;
slouken@0
   103
slouken@368
   104
    if ( !src ) {
slouken@368
   105
        /* The error message has been set in SDL_RWFromFile */
slouken@368
   106
        return NULL;
slouken@368
   107
    }
slouken@368
   108
    start = SDL_RWtell(src);
slouken@118
   109
slouken@368
   110
    if ( ! SDL_RWread(src, &pcxh, sizeof(pcxh), 1) ) {
slouken@368
   111
        error = "file truncated";
slouken@368
   112
        goto done;
slouken@368
   113
    }
slouken@368
   114
    pcxh.Xmin = SDL_SwapLE16(pcxh.Xmin);
slouken@368
   115
    pcxh.Ymin = SDL_SwapLE16(pcxh.Ymin);
slouken@368
   116
    pcxh.Xmax = SDL_SwapLE16(pcxh.Xmax);
slouken@368
   117
    pcxh.Ymax = SDL_SwapLE16(pcxh.Ymax);
slouken@368
   118
    pcxh.BytesPerLine = SDL_SwapLE16(pcxh.BytesPerLine);
slouken@0
   119
slouken@368
   120
    /* Create the surface of the appropriate type */
slouken@368
   121
    width = (pcxh.Xmax - pcxh.Xmin) + 1;
slouken@368
   122
    height = (pcxh.Ymax - pcxh.Ymin) + 1;
slouken@368
   123
    Rmask = Gmask = Bmask = Amask = 0;
slouken@368
   124
    src_bits = pcxh.BitsPerPixel * pcxh.NPlanes;
slouken@368
   125
    if((pcxh.BitsPerPixel == 1 && pcxh.NPlanes >= 1 && pcxh.NPlanes <= 4)
slouken@368
   126
       || (pcxh.BitsPerPixel == 8 && pcxh.NPlanes == 1)) {
slouken@368
   127
        bits = 8;
slouken@368
   128
    } else if(pcxh.BitsPerPixel == 8 && pcxh.NPlanes == 3) {
slouken@368
   129
        bits = 24;
aschiffler@343
   130
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
slouken@368
   131
            Rmask = 0x000000FF;
slouken@368
   132
            Gmask = 0x0000FF00;
slouken@368
   133
            Bmask = 0x00FF0000;
aschiffler@343
   134
#else
slouken@368
   135
            Rmask = 0xFF0000;
slouken@368
   136
            Gmask = 0x00FF00;
slouken@368
   137
            Bmask = 0x0000FF;
aschiffler@343
   138
#endif
slouken@368
   139
    } else {
slouken@368
   140
        error = "unsupported PCX format";
slouken@368
   141
        goto done;
slouken@368
   142
    }
slouken@368
   143
    surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height,
slouken@368
   144
                   bits, Rmask, Gmask, Bmask, Amask);
slouken@368
   145
    if ( surface == NULL )
slouken@368
   146
        goto done;
slouken@20
   147
slouken@368
   148
    bpl = pcxh.NPlanes * pcxh.BytesPerLine;
slouken@368
   149
    if (bpl > surface->pitch) {
slouken@368
   150
        error = "bytes per line is too large (corrupt?)";
slouken@368
   151
    }
slouken@368
   152
    buf = (Uint8 *)SDL_malloc(bpl);
slouken@368
   153
    row = (Uint8 *)surface->pixels;
slouken@368
   154
    for ( y=0; y<surface->h; ++y ) {
slouken@368
   155
        /* decode a scan line to a temporary buffer first */
slouken@368
   156
        int i, count = 0;
slouken@368
   157
        Uint8 ch;
slouken@368
   158
        Uint8 *dst = (src_bits == 8) ? row : buf;
slouken@368
   159
        if ( pcxh.Encoding == 0 ) {
slouken@368
   160
            if(!SDL_RWread(src, dst, bpl, 1)) {
slouken@368
   161
                error = "file truncated";
slouken@368
   162
                goto done;
slouken@368
   163
            }
slouken@368
   164
        } else {
slouken@368
   165
            for(i = 0; i < bpl; i++) {
slouken@368
   166
                if(!count) {
slouken@368
   167
                    if(!SDL_RWread(src, &ch, 1, 1)) {
slouken@368
   168
                        error = "file truncated";
slouken@368
   169
                        goto done;
slouken@368
   170
                    }
slouken@368
   171
                    if( (ch & 0xc0) == 0xc0) {
slouken@368
   172
                        count = ch & 0x3f;
slouken@368
   173
                        if(!SDL_RWread(src, &ch, 1, 1)) {
slouken@368
   174
                            error = "file truncated";
slouken@368
   175
                            goto done;
slouken@368
   176
                        }
slouken@368
   177
                    } else
slouken@368
   178
                        count = 1;
slouken@368
   179
                }
slouken@368
   180
                dst[i] = ch;
slouken@368
   181
                count--;
slouken@368
   182
            }
slouken@368
   183
        }
slouken@20
   184
slouken@368
   185
        if(src_bits <= 4) {
slouken@368
   186
            /* expand planes to 1 byte/pixel */
slouken@368
   187
            Uint8 *innerSrc = buf;
slouken@368
   188
            int plane;
slouken@368
   189
            for(plane = 0; plane < pcxh.NPlanes; plane++) {
slouken@368
   190
                int j, k, x = 0;
slouken@368
   191
                for(j = 0; j < pcxh.BytesPerLine; j++) {
slouken@368
   192
                    Uint8 byte = *innerSrc++;
slouken@368
   193
                    for(k = 7; k >= 0; k--) {
slouken@368
   194
                        unsigned bit = (byte >> k) & 1;
slouken@368
   195
                        /* skip padding bits */
slouken@368
   196
                        if (j * 8 + k >= width)
slouken@368
   197
                            continue;
slouken@368
   198
                        row[x++] |= bit << plane;
slouken@368
   199
                    }
slouken@368
   200
                }
slouken@368
   201
            }
slouken@368
   202
        } else if(src_bits == 24) {
slouken@368
   203
            /* de-interlace planes */
slouken@368
   204
            Uint8 *innerSrc = buf;
slouken@368
   205
            int plane;
slouken@368
   206
            for(plane = 0; plane < pcxh.NPlanes; plane++) {
slouken@368
   207
                int x;
slouken@368
   208
                dst = row + plane;
slouken@368
   209
                for(x = 0; x < width; x++) {
slouken@368
   210
                    *dst = *innerSrc++;
slouken@368
   211
                    dst += pcxh.NPlanes;
slouken@368
   212
                }
slouken@368
   213
            }
slouken@368
   214
        }
slouken@20
   215
slouken@368
   216
        row += surface->pitch;
slouken@368
   217
    }
slouken@0
   218
slouken@368
   219
    if(bits == 8) {
slouken@368
   220
        SDL_Color *colors = surface->format->palette->colors;
slouken@368
   221
        int nc = 1 << src_bits;
slouken@368
   222
        int i;
slouken@20
   223
slouken@368
   224
        surface->format->palette->ncolors = nc;
slouken@368
   225
        if(src_bits == 8) {
slouken@368
   226
            Uint8 ch;
slouken@368
   227
            /* look for a 256-colour palette */
slouken@368
   228
            do {
slouken@368
   229
                if ( !SDL_RWread(src, &ch, 1, 1)) {
slouken@368
   230
                    error = "file truncated";
slouken@368
   231
                    goto done;
slouken@368
   232
                }
slouken@368
   233
            } while ( ch != 12 );
slouken@20
   234
slouken@368
   235
            for(i = 0; i < 256; i++) {
slouken@368
   236
                SDL_RWread(src, &colors[i].r, 1, 1);
slouken@368
   237
                SDL_RWread(src, &colors[i].g, 1, 1);
slouken@368
   238
                SDL_RWread(src, &colors[i].b, 1, 1);
slouken@368
   239
            }
slouken@368
   240
        } else {
slouken@368
   241
            for(i = 0; i < nc; i++) {
slouken@368
   242
                colors[i].r = pcxh.Colormap[i * 3];
slouken@368
   243
                colors[i].g = pcxh.Colormap[i * 3 + 1];
slouken@368
   244
                colors[i].b = pcxh.Colormap[i * 3 + 2];
slouken@368
   245
            }
slouken@368
   246
        }
slouken@368
   247
    }
slouken@0
   248
slouken@0
   249
done:
slouken@368
   250
    SDL_free(buf);
slouken@368
   251
    if ( error ) {
slouken@368
   252
        SDL_RWseek(src, start, RW_SEEK_SET);
slouken@368
   253
        if ( surface ) {
slouken@368
   254
            SDL_FreeSurface(surface);
slouken@368
   255
            surface = NULL;
slouken@368
   256
        }
slouken@451
   257
        IMG_SetError("%s", error);
slouken@368
   258
    }
slouken@368
   259
    return(surface);
slouken@0
   260
}
slouken@0
   261
slouken@0
   262
#else
slouken@0
   263
slouken@0
   264
/* See if an image is contained in a data source */
slouken@0
   265
int IMG_isPCX(SDL_RWops *src)
slouken@0
   266
{
slouken@368
   267
    return(0);
slouken@0
   268
}
slouken@0
   269
slouken@0
   270
/* Load a PCX type image from an SDL datasource */
slouken@0
   271
SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
slouken@0
   272
{
slouken@368
   273
    return(NULL);
slouken@0
   274
}
slouken@0
   275
slouken@0
   276
#endif /* LOAD_PCX */