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