IMG_pnm.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 21 May 2013 21:24:32 -0700
changeset 368 8a61842d00ce
parent 367 b2aa197f6774
child 451 48116d511e5d
permissions -rw-r--r--
Cleaned up whitespace for the 2.0.0 release
     1 /*
     2   SDL_image:  An example image loading library for use with SDL
     3   Copyright (C) 1997-2013 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  * PNM (portable anymap) image loader:
    24  *
    25  * Supports: PBM, PGM and PPM, ASCII and binary formats
    26  * (PBM and PGM are loaded as 8bpp surfaces)
    27  * Does not support: maximum component value > 255
    28  */
    29 
    30 #include <stdio.h>
    31 #include <stdlib.h>
    32 #include <ctype.h>
    33 #include <string.h>
    34 
    35 #include "SDL_image.h"
    36 
    37 #ifdef LOAD_PNM
    38 
    39 /* See if an image is contained in a data source */
    40 int IMG_isPNM(SDL_RWops *src)
    41 {
    42     Sint64 start;
    43     int is_PNM;
    44     char magic[2];
    45 
    46     if ( !src )
    47         return 0;
    48     start = SDL_RWtell(src);
    49     is_PNM = 0;
    50     if ( SDL_RWread(src, magic, sizeof(magic), 1) ) {
    51         /*
    52          * PNM magic signatures:
    53          * P1   PBM, ascii format
    54          * P2   PGM, ascii format
    55          * P3   PPM, ascii format
    56          * P4   PBM, binary format
    57          * P5   PGM, binary format
    58          * P6   PPM, binary format
    59          * P7   PAM, a general wrapper for PNM data
    60          */
    61         if ( magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6' ) {
    62             is_PNM = 1;
    63         }
    64     }
    65     SDL_RWseek(src, start, RW_SEEK_SET);
    66     return(is_PNM);
    67 }
    68 
    69 /* read a non-negative integer from the source. return -1 upon error */
    70 static int ReadNumber(SDL_RWops *src)
    71 {
    72     int number;
    73     unsigned char ch;
    74 
    75     /* Initialize return value */
    76     number = 0;
    77 
    78     /* Skip leading whitespace */
    79     do {
    80         if ( ! SDL_RWread(src, &ch, 1, 1) ) {
    81             return(0);
    82         }
    83         /* Eat comments as whitespace */
    84         if ( ch == '#' ) {  /* Comment is '#' to end of line */
    85             do {
    86                 if ( ! SDL_RWread(src, &ch, 1, 1) ) {
    87                     return -1;
    88                 }
    89             } while ( (ch != '\r') && (ch != '\n') );
    90         }
    91     } while ( isspace(ch) );
    92 
    93     /* Add up the number */
    94     do {
    95         number *= 10;
    96         number += ch-'0';
    97 
    98         if ( !SDL_RWread(src, &ch, 1, 1) ) {
    99             return -1;
   100         }
   101     } while ( isdigit(ch) );
   102 
   103     return(number);
   104 }
   105 
   106 SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
   107 {
   108     Sint64 start;
   109     SDL_Surface *surface = NULL;
   110     int width, height;
   111     int maxval, y, bpl;
   112     Uint8 *row;
   113     Uint8 *buf = NULL;
   114     char *error = NULL;
   115     Uint8 magic[2];
   116     int ascii;
   117     enum { PBM, PGM, PPM, PAM } kind;
   118 
   119 #define ERROR(s) do { error = (s); goto done; } while(0)
   120 
   121     if ( !src ) {
   122         /* The error message has been set in SDL_RWFromFile */
   123         return NULL;
   124     }
   125     start = SDL_RWtell(src);
   126 
   127     SDL_RWread(src, magic, 2, 1);
   128     kind = magic[1] - '1';
   129     ascii = 1;
   130     if(kind >= 3) {
   131         ascii = 0;
   132         kind -= 3;
   133     }
   134 
   135     width = ReadNumber(src);
   136     height = ReadNumber(src);
   137     if(width <= 0 || height <= 0)
   138         ERROR("Unable to read image width and height");
   139 
   140     if(kind != PBM) {
   141         maxval = ReadNumber(src);
   142         if(maxval <= 0 || maxval > 255)
   143             ERROR("unsupported PNM format");
   144     } else
   145         maxval = 255;   /* never scale PBMs */
   146 
   147     /* binary PNM allows just a single character of whitespace after
   148        the last parameter, and we've already consumed it */
   149 
   150     if(kind == PPM) {
   151         /* 24-bit surface in R,G,B byte order */
   152         surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 24,
   153 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   154                        0x000000ff, 0x0000ff00, 0x00ff0000,
   155 #else
   156                        0x00ff0000, 0x0000ff00, 0x000000ff,
   157 #endif
   158                        0);
   159     } else {
   160         /* load PBM/PGM as 8-bit indexed images */
   161         surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 8,
   162                        0, 0, 0, 0);
   163     }
   164     if ( surface == NULL )
   165         ERROR("Out of memory");
   166     bpl = width * surface->format->BytesPerPixel;
   167     if(kind == PGM) {
   168         SDL_Color *c = surface->format->palette->colors;
   169         int i;
   170         for(i = 0; i < 256; i++)
   171             c[i].r = c[i].g = c[i].b = i;
   172         surface->format->palette->ncolors = 256;
   173     } else if(kind == PBM) {
   174         /* for some reason PBM has 1=black, 0=white */
   175         SDL_Color *c = surface->format->palette->colors;
   176         c[0].r = c[0].g = c[0].b = 255;
   177         c[1].r = c[1].g = c[1].b = 0;
   178         surface->format->palette->ncolors = 2;
   179         bpl = (width + 7) >> 3;
   180         buf = (Uint8 *)SDL_malloc(bpl);
   181         if(buf == NULL)
   182             ERROR("Out of memory");
   183     }
   184 
   185     /* Read the image into the surface */
   186     row = (Uint8 *)surface->pixels;
   187     for(y = 0; y < height; y++) {
   188         if(ascii) {
   189             int i;
   190             if(kind == PBM) {
   191                 for(i = 0; i < width; i++) {
   192                     Uint8 ch;
   193                     do {
   194                         if(!SDL_RWread(src, &ch,
   195                                    1, 1))
   196                                ERROR("file truncated");
   197                         ch -= '0';
   198                     } while(ch > 1);
   199                     row[i] = ch;
   200                 }
   201             } else {
   202                 for(i = 0; i < bpl; i++) {
   203                     int c;
   204                     c = ReadNumber(src);
   205                     if(c < 0)
   206                         ERROR("file truncated");
   207                     row[i] = c;
   208                 }
   209             }
   210         } else {
   211             Uint8 *dst = (kind == PBM) ? buf : row;
   212             if(!SDL_RWread(src, dst, bpl, 1))
   213                 ERROR("file truncated");
   214             if(kind == PBM) {
   215                 /* expand bitmap to 8bpp */
   216                 int i;
   217                 for(i = 0; i < width; i++) {
   218                     int bit = 7 - (i & 7);
   219                     row[i] = (buf[i >> 3] >> bit) & 1;
   220                 }
   221             }
   222         }
   223         if(maxval < 255) {
   224             /* scale up to full dynamic range (slow) */
   225             int i;
   226             for(i = 0; i < bpl; i++)
   227                 row[i] = row[i] * 255 / maxval;
   228         }
   229         row += surface->pitch;
   230     }
   231 done:
   232     SDL_free(buf);
   233     if(error) {
   234         SDL_RWseek(src, start, RW_SEEK_SET);
   235         if ( surface ) {
   236             SDL_FreeSurface(surface);
   237             surface = NULL;
   238         }
   239         IMG_SetError(error);
   240     }
   241     return(surface);
   242 }
   243 
   244 #else
   245 
   246 /* See if an image is contained in a data source */
   247 int IMG_isPNM(SDL_RWops *src)
   248 {
   249     return(0);
   250 }
   251 
   252 /* Load a PNM type image from an SDL datasource */
   253 SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src)
   254 {
   255     return(NULL);
   256 }
   257 
   258 #endif /* LOAD_PNM */