IMG_tga.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 02 Jan 2016 10:42:34 -0800
changeset 486 7bb8af91e887
parent 471 c5078fe7c32c
child 496 6332f9425dcc
permissions -rw-r--r--
Updated copyright to 2016
     1 /*
     2   SDL_image:  An example image loading library for use with SDL
     3   Copyright (C) 1997-2016 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 #if !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND)
    23 
    24 /* This is a Targa image file loading framework */
    25 
    26 #include <stdlib.h>
    27 #include <stdio.h>
    28 #include <string.h>
    29 
    30 #include "SDL_endian.h"
    31 
    32 #include "SDL_image.h"
    33 
    34 #ifdef LOAD_TGA
    35 
    36 /*
    37  * A TGA loader for the SDL library
    38  * Supports: Reading 8, 15, 16, 24 and 32bpp images, with alpha or colourkey,
    39  *           uncompressed or RLE encoded.
    40  *
    41  * 2000-06-10 Mattias Engdegård <f91-men@nada.kth.se>: initial version
    42  * 2000-06-26 Mattias Engdegård <f91-men@nada.kth.se>: read greyscale TGAs
    43  * 2000-08-09 Mattias Engdegård <f91-men@nada.kth.se>: alpha inversion removed
    44  */
    45 
    46 struct TGAheader {
    47     Uint8 infolen;      /* length of info field */
    48     Uint8 has_cmap;     /* 1 if image has colormap, 0 otherwise */
    49     Uint8 type;
    50 
    51     Uint8 cmap_start[2];    /* index of first colormap entry */
    52     Uint8 cmap_len[2];      /* number of entries in colormap */
    53     Uint8 cmap_bits;        /* bits per colormap entry */
    54 
    55     Uint8 yorigin[2];       /* image origin (ignored here) */
    56     Uint8 xorigin[2];
    57     Uint8 width[2];     /* image size */
    58     Uint8 height[2];
    59     Uint8 pixel_bits;       /* bits/pixel */
    60     Uint8 flags;
    61 };
    62 
    63 enum tga_type {
    64     TGA_TYPE_INDEXED = 1,
    65     TGA_TYPE_RGB = 2,
    66     TGA_TYPE_BW = 3,
    67     TGA_TYPE_RLE_INDEXED = 9,
    68     TGA_TYPE_RLE_RGB = 10,
    69     TGA_TYPE_RLE_BW = 11
    70 };
    71 
    72 #define TGA_INTERLEAVE_MASK 0xc0
    73 #define TGA_INTERLEAVE_NONE 0x00
    74 #define TGA_INTERLEAVE_2WAY 0x40
    75 #define TGA_INTERLEAVE_4WAY 0x80
    76 
    77 #define TGA_ORIGIN_MASK     0x30
    78 #define TGA_ORIGIN_LEFT     0x00
    79 #define TGA_ORIGIN_RIGHT    0x10
    80 #define TGA_ORIGIN_LOWER    0x00
    81 #define TGA_ORIGIN_UPPER    0x20
    82 
    83 /* read/write unaligned little-endian 16-bit ints */
    84 #define LE16(p) ((p)[0] + ((p)[1] << 8))
    85 #define SETLE16(p, v) ((p)[0] = (v), (p)[1] = (v) >> 8)
    86 
    87 /* Load a TGA type image from an SDL datasource */
    88 SDL_Surface *IMG_LoadTGA_RW(SDL_RWops *src)
    89 {
    90     Sint64 start;
    91     const char *error = NULL;
    92     struct TGAheader hdr;
    93     int rle = 0;
    94     int alpha = 0;
    95     int indexed = 0;
    96     int grey = 0;
    97     int ckey = -1;
    98     int ncols, w, h;
    99     SDL_Surface *img = NULL;
   100     Uint32 rmask, gmask, bmask, amask;
   101     Uint8 *dst;
   102     int i;
   103     int bpp;
   104     int lstep;
   105     Uint32 pixel;
   106     int count, rep;
   107 
   108     if ( !src ) {
   109         /* The error message has been set in SDL_RWFromFile */
   110         return NULL;
   111     }
   112     start = SDL_RWtell(src);
   113 
   114     if (!SDL_RWread(src, &hdr, sizeof(hdr), 1)) {
   115         error = "Error reading TGA data";
   116         goto error;
   117     }
   118     ncols = LE16(hdr.cmap_len);
   119     switch(hdr.type) {
   120     case TGA_TYPE_RLE_INDEXED:
   121         rle = 1;
   122         /* fallthrough */
   123     case TGA_TYPE_INDEXED:
   124         if (!hdr.has_cmap || hdr.pixel_bits != 8 || ncols > 256)
   125             goto unsupported;
   126         indexed = 1;
   127         break;
   128 
   129     case TGA_TYPE_RLE_RGB:
   130         rle = 1;
   131         /* fallthrough */
   132     case TGA_TYPE_RGB:
   133         indexed = 0;
   134         break;
   135 
   136     case TGA_TYPE_RLE_BW:
   137         rle = 1;
   138         /* fallthrough */
   139     case TGA_TYPE_BW:
   140         if (hdr.pixel_bits != 8)
   141             goto unsupported;
   142         /* Treat greyscale as 8bpp indexed images */
   143         indexed = grey = 1;
   144         break;
   145 
   146     default:
   147         goto unsupported;
   148     }
   149 
   150     bpp = (hdr.pixel_bits + 7) >> 3;
   151     rmask = gmask = bmask = amask = 0;
   152     switch(hdr.pixel_bits) {
   153     case 8:
   154         if (!indexed) {
   155                 goto unsupported;
   156         }
   157         break;
   158 
   159     case 15:
   160     case 16:
   161         /* 15 and 16bpp both seem to use 5 bits/plane. The extra alpha bit
   162            is ignored for now. */
   163         rmask = 0x7c00;
   164         gmask = 0x03e0;
   165         bmask = 0x001f;
   166         break;
   167 
   168     case 32:
   169         alpha = 1;
   170         /* fallthrough */
   171     case 24:
   172 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
   173         {
   174         int s = alpha ? 0 : 8;
   175         amask = 0x000000ff >> s;
   176         rmask = 0x0000ff00 >> s;
   177         gmask = 0x00ff0000 >> s;
   178         bmask = 0xff000000 >> s;
   179         }
   180 #else
   181         amask = alpha ? 0xff000000 : 0;
   182         rmask = 0x00ff0000;
   183         gmask = 0x0000ff00;
   184         bmask = 0x000000ff;
   185 #endif
   186         break;
   187 
   188     default:
   189         goto unsupported;
   190     }
   191 
   192     if ((hdr.flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE
   193        || hdr.flags & TGA_ORIGIN_RIGHT) {
   194         goto unsupported;
   195     }
   196 
   197     SDL_RWseek(src, hdr.infolen, RW_SEEK_CUR); /* skip info field */
   198 
   199     w = LE16(hdr.width);
   200     h = LE16(hdr.height);
   201     img = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
   202                    bpp * 8,
   203                    rmask, gmask, bmask, amask);
   204     if (img == NULL) {
   205         error = "Out of memory";
   206         goto error;
   207     }
   208 
   209     if (hdr.has_cmap) {
   210         int palsiz = ncols * ((hdr.cmap_bits + 7) >> 3);
   211         if (indexed && !grey) {
   212             Uint8 *pal = (Uint8 *)SDL_malloc(palsiz), *p = pal;
   213             SDL_Color *colors = img->format->palette->colors;
   214             img->format->palette->ncolors = ncols;
   215             SDL_RWread(src, pal, palsiz, 1);
   216             for(i = 0; i < ncols; i++) {
   217                 switch(hdr.cmap_bits) {
   218                 case 15:
   219                 case 16:
   220                     {
   221                     Uint16 c = p[0] + (p[1] << 8);
   222                     p += 2;
   223                     colors[i].r = (c >> 7) & 0xf8;
   224                     colors[i].g = (c >> 2) & 0xf8;
   225                     colors[i].b = c << 3;
   226                     }
   227                     break;
   228                 case 24:
   229                 case 32:
   230                     colors[i].b = *p++;
   231                     colors[i].g = *p++;
   232                     colors[i].r = *p++;
   233                     if (hdr.cmap_bits == 32 && *p++ < 128)
   234                     ckey = i;
   235                     break;
   236                 }
   237             }
   238             SDL_free(pal);
   239             if (ckey >= 0)
   240                 SDL_SetColorKey(img, SDL_TRUE, ckey);
   241         } else {
   242             /* skip unneeded colormap */
   243             SDL_RWseek(src, palsiz, RW_SEEK_CUR);
   244         }
   245     }
   246 
   247     if (grey) {
   248         SDL_Color *colors = img->format->palette->colors;
   249         for(i = 0; i < 256; i++)
   250             colors[i].r = colors[i].g = colors[i].b = i;
   251         img->format->palette->ncolors = 256;
   252     }
   253 
   254     if (hdr.flags & TGA_ORIGIN_UPPER) {
   255         lstep = img->pitch;
   256         dst = (Uint8 *)img->pixels;
   257     } else {
   258         lstep = -img->pitch;
   259         dst = (Uint8 *)img->pixels + (h - 1) * img->pitch;
   260     }
   261 
   262     /* The RLE decoding code is slightly convoluted since we can't rely on
   263        spans not to wrap across scan lines */
   264     count = rep = 0;
   265     for(i = 0; i < h; i++) {
   266         if (rle) {
   267             int x = 0;
   268             for(;;) {
   269                 Uint8 c;
   270 
   271                 if (count) {
   272                     int n = count;
   273                     if (n > w - x)
   274                         n = w - x;
   275                     SDL_RWread(src, dst + x * bpp, n * bpp, 1);
   276                     count -= n;
   277                     x += n;
   278                     if (x == w)
   279                         break;
   280                 } else if (rep) {
   281                     int n = rep;
   282                     if (n > w - x)
   283                         n = w - x;
   284                     rep -= n;
   285                     while (n--) {
   286                         SDL_memcpy(dst + x * bpp, &pixel, bpp);
   287                         x++;
   288                     }
   289                     if (x == w)
   290                         break;
   291                 }
   292 
   293                 SDL_RWread(src, &c, 1, 1);
   294                 if (c & 0x80) {
   295                     SDL_RWread(src, &pixel, bpp, 1);
   296                     rep = (c & 0x7f) + 1;
   297                 } else {
   298                     count = c + 1;
   299                 }
   300             }
   301         } else {
   302             SDL_RWread(src, dst, w * bpp, 1);
   303         }
   304 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   305         if (bpp == 2) {
   306             /* swap byte order */
   307             int x;
   308             Uint16 *p = (Uint16 *)dst;
   309             for(x = 0; x < w; x++)
   310             p[x] = SDL_Swap16(p[x]);
   311         }
   312 #endif
   313         dst += lstep;
   314     }
   315     return img;
   316 
   317 unsupported:
   318     error = "Unsupported TGA format";
   319 
   320 error:
   321     SDL_RWseek(src, start, RW_SEEK_SET);
   322     if ( img ) {
   323         SDL_FreeSurface(img);
   324     }
   325     IMG_SetError("%s", error);
   326     return NULL;
   327 }
   328 
   329 #else
   330 
   331 /* dummy TGA load routine */
   332 SDL_Surface *IMG_LoadTGA_RW(SDL_RWops *src)
   333 {
   334     return(NULL);
   335 }
   336 
   337 #endif /* LOAD_TGA */
   338 
   339 #endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */