From 79f8b1320efd45f995976ac560f729a04f0a90d8 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 29 Nov 2000 11:55:32 +0000 Subject: [PATCH] 1.1.0: Sam Lantinga - Wed Nov 29 00:46:27 PST 2000 * Added XPM file format support Supports color, greyscale, and mono XPMs with and without transparency Mattias Engdeg?rd - Thu, 2 Nov 2000 23:23:17 +0100 (MET) * Fixed array overrun when loading an unsupported format * Minor compilation fixes for various platforms --- CHANGES | 8 + IMG.c | 7 +- IMG_gif.c | 2 +- IMG_jpg.c | 1 + IMG_pcx.c | 1 - IMG_png.c | 6 +- IMG_ppm.c | 1 + IMG_xpm.c | 470 +++++++++++++++++++++++++++++++++++++++++++++++++++ Makefile.am | 3 +- SDL_image.h | 2 + configure.in | 14 +- showimage.c | 4 +- 12 files changed, 506 insertions(+), 13 deletions(-) create mode 100644 IMG_xpm.c diff --git a/CHANGES b/CHANGES index 393c1624..f37c0e95 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,12 @@ +1.1.0: +Sam Lantinga - Wed Nov 29 00:46:27 PST 2000 + * Added XPM file format support + Supports color, greyscale, and mono XPMs with and without transparency +Mattias Engdegård - Thu, 2 Nov 2000 23:23:17 +0100 (MET) + * Fixed array overrun when loading an unsupported format + * Minor compilation fixes for various platforms + 1.0.10: Mattias Engdegård - Wed Aug 9 20:32:22 MET DST 2000 * Removed the alpha flipping, made IMG_InvertAlpha() a noop diff --git a/IMG.c b/IMG.c index eaf0d087..aff7eac9 100644 --- a/IMG.c +++ b/IMG.c @@ -30,6 +30,8 @@ #include "SDL_image.h" +#define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0])) + /* Table of image detection and loading functions */ static struct { char *type; @@ -40,11 +42,12 @@ static struct { { "TGA", NULL, IMG_LoadTGA_RW }, { "BMP", IMG_isBMP, IMG_LoadBMP_RW }, { "PPM", IMG_isPPM, IMG_LoadPPM_RW }, + { "XPM", IMG_isXPM, IMG_LoadXPM_RW }, { "PCX", IMG_isPCX, IMG_LoadPCX_RW }, { "GIF", IMG_isGIF, IMG_LoadGIF_RW }, { "JPG", IMG_isJPG, IMG_LoadJPG_RW }, { "TIF", IMG_isTIF, IMG_LoadTIF_RW }, - { "PNG", IMG_isPNG, IMG_LoadPNG_RW }, + { "PNG", IMG_isPNG, IMG_LoadPNG_RW } }; /* Load an image from a file */ @@ -96,7 +99,7 @@ SDL_Surface *IMG_LoadTyped_RW(SDL_RWops *src, int freesrc, char *type) /* Detect the type of image being loaded */ start = SDL_RWtell(src); image = NULL; - for ( i=0; supported[i].type && !image; ++i ) { + for ( i=0; i < ARRAYSIZE(supported) && !image; ++i ) { if( (supported[i].is && (SDL_RWseek(src, start, SEEK_SET), supported[i].is(src))) diff --git a/IMG_gif.c b/IMG_gif.c index e56c9808..d7d65e5a 100644 --- a/IMG_gif.c +++ b/IMG_gif.c @@ -254,7 +254,7 @@ IMG_LoadGIF_RW(SDL_RWops *src) #ifdef USED_BY_SDL if ( Gif89.transparent > 0 ) { - SDL_SetColorKey(image, SDL_SRCCOLORKEY, Gif89. transparent); + SDL_SetColorKey(image, SDL_SRCCOLORKEY, Gif89.transparent); } #endif diff --git a/IMG_jpg.c b/IMG_jpg.c index 253310f6..ace0f447 100644 --- a/IMG_jpg.c +++ b/IMG_jpg.c @@ -25,6 +25,7 @@ /* This is a JPEG image file loading framework */ #include +#include #include "SDL_image.h" diff --git a/IMG_pcx.c b/IMG_pcx.c index 1ec0444f..eb132cb2 100644 --- a/IMG_pcx.c +++ b/IMG_pcx.c @@ -113,7 +113,6 @@ SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src) Gmask = 0x0000FF00; Bmask = 0x00FF0000; } else { - int s = (pcxh.NPlanes == 4) ? 0 : 8; Rmask = 0xFF0000; Gmask = 0x00FF00; Bmask = 0x0000FF; diff --git a/IMG_png.c b/IMG_png.c index cae94482..270aa4f4 100644 --- a/IMG_png.c +++ b/IMG_png.c @@ -93,7 +93,7 @@ static void png_read_data(png_structp ctx, png_bytep area, png_size_t size) } SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src) { - SDL_Surface *surface; + SDL_Surface *volatile surface; png_structp png_ptr; png_infop info_ptr; png_uint_32 width, height; @@ -103,9 +103,9 @@ SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src) Uint32 Bmask; Uint32 Amask; SDL_Palette *palette; - png_bytep *row_pointers; + png_bytep *volatile row_pointers; int row, i; - int ckey = -1; + volatile int ckey = -1; png_color_16 *transv; /* Initialize the data we will clean up when we're done */ diff --git a/IMG_ppm.c b/IMG_ppm.c index 1485a4cd..b08d25b4 100644 --- a/IMG_ppm.c +++ b/IMG_ppm.c @@ -88,6 +88,7 @@ static int ReadNumber(SDL_RWops *src) return(number); } + SDL_Surface *IMG_LoadPPM_RW(SDL_RWops *src) { SDL_Surface *surface; diff --git a/IMG_xpm.c b/IMG_xpm.c new file mode 100644 index 00000000..6b8e1c5f --- /dev/null +++ b/IMG_xpm.c @@ -0,0 +1,470 @@ +/* + IMGLIB: An example image loading library for use with SDL + Copyright (C) 1999 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + 5635-34 Springhouse Dr. + Pleasanton, CA 94588 (USA) + slouken@devolution.com +*/ + +/* This is an XPM image file loading framework */ + +#include +#include +#include + +#include "SDL_image.h" + +#ifdef LOAD_XPM + +/* See if an image is contained in a data source */ +int IMG_isXPM(SDL_RWops *src) +{ + int is_XPM; + char magic[10]; + + is_XPM = 0; + if ( SDL_RWread(src, magic, sizeof(magic), 1) ) { + if ( strncmp(magic, "/* XPM */", 9) == 0 ) { + is_XPM = 1; + } + } + return(is_XPM); +} + +static char *SDL_RWgets(char *string, int maxlen, SDL_RWops *src) +{ + int i; + + for ( i=0; i<(maxlen-1); ++i ) { + if ( SDL_RWread(src, &string[i], 1, 1) <= 0 ) { + /* EOF or error */ + if ( i == 0 ) { + /* Hmm, EOF on initial read, return NULL */ + string = NULL; + } + break; + } + /* In this case it's okay to use either '\r' or '\n' + as line separators because blank lines are just + ignored by the XPM format. + */ + if ( (string[i] == '\n') || (string[i] == '\n') ) { + break; + } + } + if ( string ) { + string[i] = '\0'; + } + return(string); +} + +/* Hash table to look up colors from pixel strings */ +#define HASH_SIZE 256 +struct color_hash { + struct hash_entry { + int keylen; + char *key; + Uint32 color; + struct hash_entry *next; + } *entries[HASH_SIZE]; +}; + +static int hash_key(const char *key, int cpp) +{ + int hash; + + hash = 0; + while ( cpp-- > 0 ) { + hash += *key++; + } + return(hash%HASH_SIZE); +} + +static struct color_hash *create_colorhash(void) +{ + struct color_hash *hash; + + hash = (struct color_hash *)malloc(sizeof *hash); + if ( hash ) { + memset(hash, 0, (sizeof *hash)); + } + return(hash); +} + +static int add_colorhash(struct color_hash *hash, + const char *key, int cpp, Uint32 color) +{ + int hash_index; + struct hash_entry *prev, *entry; + + /* Create the hash entry */ + entry = (struct hash_entry *)malloc(sizeof *entry); + if ( ! entry ) { + return(0); + } + entry->keylen = cpp; + entry->key = strdup(key); + if ( ! entry->key ) { + free(entry); + return(0); + } + entry->color = color; + entry->next = NULL; + + /* Add it to the hash table */ + hash_index = hash_key(key, cpp); + for ( prev = hash->entries[hash_index]; + prev && prev->next; prev = prev->next ) { + /* Go to the end of the list */ ; + } + if ( prev ) { + prev->next = entry; + } else { + hash->entries[hash_index] = entry; + } + return(1); +} + +static int get_colorhash(struct color_hash *hash, + const char *key, int cpp, Uint32 *color) +{ + int hash_index; + struct hash_entry *entry; + + hash_index = hash_key(key, cpp); + for ( entry = hash->entries[hash_index]; entry; entry = entry->next ) { + if ( strncmp(key, entry->key, entry->keylen) == 0 ) { + *color = entry->color; + return(1); + } + } + return(0); +} + +static void free_colorhash(struct color_hash *hash) +{ + int i; + struct hash_entry *entry, *freeable; + + for ( i=0; ientries[i]; + while ( entry ) { + freeable = entry; + entry = entry->next; + free(freeable->key); + free(freeable); + } + } + free(hash); +} + +static int color_to_rgb(const char *colorspec, int *r, int *g, int *b) +{ + char rbuf[3]; + char gbuf[3]; + char bbuf[3]; + + /* Handle monochrome black and white */ + if ( strcasecmp(colorspec, "black") == 0 ) { + *r = 0; + *g = 0; + *b = 0; + return(1); + } + if ( strcasecmp(colorspec, "white") == 0 ) { + *r = 255; + *g = 255; + *b = 255; + return(1); + } + + /* Normal hexidecimal color */ + switch (strlen(colorspec)) { + case 3: + rbuf[0] = colorspec[0]; + rbuf[1] = colorspec[0]; + gbuf[0] = colorspec[1]; + gbuf[1] = colorspec[1]; + bbuf[0] = colorspec[2]; + bbuf[1] = colorspec[2]; + break; + case 6: + rbuf[0] = colorspec[0]; + rbuf[1] = colorspec[1]; + gbuf[0] = colorspec[2]; + gbuf[1] = colorspec[3]; + bbuf[0] = colorspec[4]; + bbuf[1] = colorspec[5]; + break; + case 12: + rbuf[0] = colorspec[0]; + rbuf[1] = colorspec[1]; + gbuf[0] = colorspec[4]; + gbuf[1] = colorspec[5]; + bbuf[0] = colorspec[8]; + bbuf[1] = colorspec[9]; + break; + default: + return(0); + } + rbuf[2] = '\0'; + *r = (int)strtol(rbuf, NULL, 16); + gbuf[2] = '\0'; + *g = (int)strtol(gbuf, NULL, 16); + bbuf[2] = '\0'; + *b = (int)strtol(bbuf, NULL, 16); + return(1); +} + +/* Load a XPM type image from an SDL datasource */ +SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src) +{ + SDL_Surface *image; + char line[1024]; + char *here, *stop; + int index; + int i, x, y; + int w, h, ncolors, cpp; + int found; + int r, g, b; + Uint32 colorkey; + char *colorkey_string; + int pixels_len; + char *pixels; + int indexed; + Uint8 *dst; + Uint32 pixel; + struct color_hash *colors; + + /* Skip to the first string, which describes the image */ + image = NULL; + do { + here = SDL_RWgets(line, sizeof(line), src); + if ( ! here ) { + IMG_SetError("Premature end of data"); + return(NULL); + } + if ( *here == '"' ) { + ++here; + /* Skip to width */ + while ( isspace(*here) ) ++here; + w = atoi(here); + while ( ! isspace(*here) ) ++here; + /* Skip to height */ + while ( isspace(*here) ) ++here; + h = atoi(here); + while ( ! isspace(*here) ) ++here; + /* Skip to number of colors */ + while ( isspace(*here) ) ++here; + ncolors = atoi(here); + while ( ! isspace(*here) ) ++here; + /* Skip to characters per pixel */ + while ( isspace(*here) ) ++here; + cpp = atoi(here); + while ( ! isspace(*here) ) ++here; + + /* Verify the parameters */ + if ( !w || !h || !ncolors || !cpp ) { + IMG_SetError("Invalid format description"); + return(NULL); + } + pixels_len = 1+w*cpp+1+1; + pixels = (char *)malloc(pixels_len); + if ( ! pixels ) { + IMG_SetError("Out of memory"); + return(NULL); + } + + /* Create the new surface */ + if ( ncolors <= 256 ) { + indexed = 1; + image = SDL_CreateRGBSurface(SDL_SWSURFACE, + w, h, 8, 0, 0, 0, 0); + } else { + int rmask, gmask, bmask; + indexed = 0; + if ( SDL_BYTEORDER == SDL_BIG_ENDIAN ) { + rmask = 0x000000ff; + gmask = 0x0000ff00; + bmask = 0x00ff0000; + } else { + rmask = 0x00ff0000; + gmask = 0x0000ff00; + bmask = 0x000000ff; + } + image = SDL_CreateRGBSurface(SDL_SWSURFACE, + w, h, 32, + rmask, gmask, bmask, 0); + } + if ( ! image ) { + /* Hmm, some SDL error (out of memory?) */ + free(pixels); + return(NULL); + } + } + } while ( ! image ); + + /* Read the colors */ + colors = create_colorhash(); + if ( ! colors ) { + SDL_FreeSurface(image); + free(pixels); + IMG_SetError("Out of memory"); + return(NULL); + } + colorkey_string = NULL; + for ( index=0; index < ncolors; ++index ) { + here = SDL_RWgets(line, sizeof(line), src); + if ( ! here ) { + SDL_FreeSurface(image); + image = NULL; + IMG_SetError("Premature end of data"); + goto done; + } + if ( *here == '"' ) { + const char *key; + ++here; + /* Grab the pixel key */ + key = here; + for ( i=0; iformat->palette->colors[index]; + color->r = (Uint8)r; + color->g = (Uint8)g; + color->b = (Uint8)b; + pixel = index; + } else { + pixel = (r<<16)|(g<<8)|b; + } + add_colorhash(colors, key, cpp, pixel); + } + *here = '\0'; + } + if ( ! found ) { + /* Hum, couldn't parse a color.. */; + } + } + } + + /* Read the pixels */ + for ( y=0; y < h; ) { + here = SDL_RWgets(pixels, pixels_len, src); + if ( ! here ) { + SDL_FreeSurface(image); + image = NULL; + IMG_SetError("Premature end of data"); + goto done; + } + if ( *here == '"' ) { + ++here; + dst = (Uint8 *)image->pixels + y*image->pitch; + for ( x=0; xw, image->h, depth, SDL_GetError()); + SDL_Quit(); exit(3); } @@ -141,5 +142,6 @@ int main(int argc, char *argv[]) /* We're done! */ SDL_FreeSurface(image); + SDL_Quit(); exit(0); }