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