From 23c8e8b300d6b71eb8573731ff6b653b5a5d68f5 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 7 Mar 2001 16:59:28 +0000 Subject: [PATCH] Added general PNM (PPM/PGM/PBM) support --- CHANGES | 2 + IMG.c | 6 +- IMG_pcx.c | 2 + IMG_ppm.c | 155 ++++++++++++++++++++++++++++++++++----------------- README | 3 +- SDL_image.h | 4 +- configure.in | 10 ++-- 7 files changed, 121 insertions(+), 61 deletions(-) diff --git a/CHANGES b/CHANGES index a266d202..61222e5f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,7 @@ 1.1.1: +Mattias Engdegård - Wed Mar 7 09:01:49 PST 2001 + * Added general PNM (PPM/PGM/PBM) support Mattias Engdegård - Sun Mar 4 14:23:42 PST 2001 * Fixed bugs in PPM support, added ASCII PPM support Mattias Engdegård - Fri Mar 2 14:48:09 PST 2001 diff --git a/IMG.c b/IMG.c index 35ef9f5a..97729be9 100644 --- a/IMG.c +++ b/IMG.c @@ -38,10 +38,10 @@ static struct { int (*is)(SDL_RWops *src); SDL_Surface *(*load)(SDL_RWops *src); } supported[] = { - /* keep magicless formats first (denoted by is==NULL) */ - { "TGA", NULL, IMG_LoadTGA_RW }, + /* keep magicless formats first */ + { "TGA", 0, IMG_LoadTGA_RW }, { "BMP", IMG_isBMP, IMG_LoadBMP_RW }, - { "PPM", IMG_isPPM, IMG_LoadPPM_RW }, + { "PNM", IMG_isPNM, IMG_LoadPNM_RW }, /* P[BGP]M share code */ { "XPM", IMG_isXPM, IMG_LoadXPM_RW }, { "PCX", IMG_isPCX, IMG_LoadPCX_RW }, { "GIF", IMG_isGIF, IMG_LoadGIF_RW }, diff --git a/IMG_pcx.c b/IMG_pcx.c index f33a0547..d1c08f5d 100644 --- a/IMG_pcx.c +++ b/IMG_pcx.c @@ -29,6 +29,8 @@ * 8 bits/pixel in single-planar format (8 bits/plane/pixel) * 24 bits/pixel in 3-plane format (8 bits/plane/pixel) * + * (The <8bpp formats are expanded to 8bpp surfaces) + * * Doesn't support: * single-planar packed-pixel formats other than 8bpp * 4-plane 32bpp format with a fourth "intensity" plane diff --git a/IMG_ppm.c b/IMG_ppm.c index 907bb643..316f4500 100644 --- a/IMG_ppm.c +++ b/IMG_ppm.c @@ -23,31 +23,38 @@ */ /* - * PPM (portable pixmap) image loader: + * PNM (portable anymap) image loader: * - * Supports: ASCII (P3) and binary (P6) formats + * Supports: PBM, PGM and PPM, ASCII and binary formats + * (PBM and PGM are loaded as 8bpp surfaces) * Does not support: maximum component value > 255 - * - * TODO: add PGM (greyscale) and PBM (monochrome bitmap) support. - * Should be easy since almost all code is already in place */ #include +#include #include #include #include "SDL_image.h" -#ifdef LOAD_PPM +#ifdef LOAD_PNM /* See if an image is contained in a data source */ -int IMG_isPPM(SDL_RWops *src) +int IMG_isPNM(SDL_RWops *src) { char magic[2]; - /* "P3" is the ASCII PPM format, "P6" the binary PPM format */ + /* + * PNM magic signatures: + * P1 PBM, ascii format + * P2 PGM, ascii format + * P3 PPM, ascii format + * P4 PBM, binary format + * P5 PGM, binary format + * P6 PPM, binary format + */ return (SDL_RWread(src, magic, 2, 1) - && magic[0] == 'P' && (magic[1] == '3' || magic[1] == '6')); + && magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6'); } /* read a non-negative integer from the source. return -1 upon error */ @@ -87,70 +94,117 @@ static int ReadNumber(SDL_RWops *src) return(number); } -SDL_Surface *IMG_LoadPPM_RW(SDL_RWops *src) +SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src) { SDL_Surface *surface = NULL; int width, height; int maxval, y, bpl; Uint8 *row; + Uint8 *buf = NULL; char *error = NULL; Uint8 magic[2]; int ascii; + enum { PBM, PGM, PPM } kind; - if ( ! src ) { - goto done; - } +#define ERROR(s) do { error = (s); goto done; } while(0) + + if(!src) + return NULL; SDL_RWread(src, magic, 2, 1); - ascii = (magic[1] == '3'); + kind = magic[1] - '1'; + ascii = 1; + if(kind >= 3) { + ascii = 0; + kind -= 3; + } width = ReadNumber(src); height = ReadNumber(src); - if(width <= 0 || height <= 0) { - error = "Unable to read image width and height"; - goto done; - } - - maxval = ReadNumber(src); - if(maxval <= 0 || maxval > 255) { - error = "unsupported ppm format"; - goto done; - } - /* binary PPM allows just a single character of whitespace after - the maxval, and we've already consumed it */ - - /* 24-bit surface in R,G,B byte order */ - surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 24, + if(width <= 0 || height <= 0) + ERROR("Unable to read image width and height"); + + if(kind != PBM) { + maxval = ReadNumber(src); + if(maxval <= 0 || maxval > 255) + ERROR("unsupported PNM format"); + } else + maxval = 255; /* never scale PBMs */ + + /* binary PNM allows just a single character of whitespace after + the last parameter, and we've already consumed it */ + + if(kind == PPM) { + /* 24-bit surface in R,G,B byte order */ + surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 24, #if SDL_BYTEORDER == SDL_LIL_ENDIAN - 0x000000ff, 0x0000ff00, 0x00ff0000, + 0x000000ff, 0x0000ff00, 0x00ff0000, #else - 0x00ff0000, 0x0000ff00, 0x000000ff, + 0x00ff0000, 0x0000ff00, 0x000000ff, #endif - 0); - if ( surface == NULL ) { - error = "Out of memory"; - goto done; + 0); + } else { + /* load PBM/PGM as 8-bit indexed images */ + surface = SDL_AllocSurface(SDL_SWSURFACE, width, height, 8, + 0, 0, 0, 0); + } + if ( surface == NULL ) + ERROR("Out of memory"); + bpl = width * surface->format->BytesPerPixel; + if(kind == PGM) { + SDL_Color *c = surface->format->palette->colors; + int i; + for(i = 0; i < 256; i++) + c[i].r = c[i].g = c[i].b = i; + surface->format->palette->ncolors = 256; + } else if(kind == PBM) { + /* for some reason PBM has 1=black, 0=white */ + SDL_Color *c = surface->format->palette->colors; + c[0].r = c[0].g = c[0].b = 255; + c[1].r = c[1].g = c[1].b = 0; + surface->format->palette->ncolors = 2; + bpl = (width + 7) >> 3; + buf = malloc(bpl); + if(buf == NULL) + ERROR("Out of memory"); } /* Read the image into the surface */ row = surface->pixels; - bpl = width * 3; for(y = 0; y < height; y++) { if(ascii) { int i; - for(i = 0; i < bpl; i++) { - int c; - c = ReadNumber(src); - if(c < 0) { - error = "file truncated"; - goto done; + if(kind == PBM) { + for(i = 0; i < width; i++) { + Uint8 ch; + do { + if(!SDL_RWread(src, &ch, + 1, 1)) + ERROR("file truncated"); + ch -= '0'; + } while(ch > 1); + row[i] = ch; + } + } else { + for(i = 0; i < bpl; i++) { + int c; + c = ReadNumber(src); + if(c < 0) + ERROR("file truncated"); + row[i] = c; } - row[i] = c; } } else { - if(!SDL_RWread(src, row, bpl, 1)) { - error = "file truncated"; - goto done; + Uint8 *dst = (kind == PBM) ? buf : row; + if(!SDL_RWread(src, dst, bpl, 1)) + ERROR("file truncated"); + if(kind == PBM) { + /* expand bitmap to 8bpp */ + int i; + for(i = 0; i < width; i++) { + int bit = 7 - (i & 7); + row[i] = (buf[i >> 3] >> bit) & 1; + } } } if(maxval < 255) { @@ -162,6 +216,7 @@ SDL_Surface *IMG_LoadPPM_RW(SDL_RWops *src) row += surface->pitch; } done: + free(buf); if(error) { SDL_FreeSurface(surface); IMG_SetError(error); @@ -173,15 +228,15 @@ SDL_Surface *IMG_LoadPPM_RW(SDL_RWops *src) #else /* See if an image is contained in a data source */ -int IMG_isPPM(SDL_RWops *src) +int IMG_isPNM(SDL_RWops *src) { return(0); } -/* Load a PPM type image from an SDL datasource */ -SDL_Surface *IMG_LoadPPM_RW(SDL_RWops *src) +/* Load a PNM type image from an SDL datasource */ +SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src) { return(NULL); } -#endif /* LOAD_PPM */ +#endif /* LOAD_PNM */ diff --git a/README b/README index 1ffe753e..af32d926 100644 --- a/README +++ b/README @@ -5,7 +5,8 @@ The latest version of this library is available from: http://www.devolution.com/~slouken/SDL/projects/SDL_image/ This is a simple library to load images of various formats as SDL surfaces. -This library supports BMP, PPM, XPM, PCX, GIF, JPEG, PNG, TGA, and TIFF formats. +This library supports BMP, PNM (PPM/PGM/PBM), XPM, PCX, GIF, JPEG, PNG, +TGA, and TIFF formats. API: #include "SDL_image.h" diff --git a/SDL_image.h b/SDL_image.h index b259d580..f4164921 100644 --- a/SDL_image.h +++ b/SDL_image.h @@ -56,7 +56,7 @@ extern DECLSPEC int IMG_InvertAlpha(int on); /* Functions to detect a file type, given a seekable source */ extern DECLSPEC int IMG_isBMP(SDL_RWops *src); -extern DECLSPEC int IMG_isPPM(SDL_RWops *src); +extern DECLSPEC int IMG_isPNM(SDL_RWops *src); extern DECLSPEC int IMG_isXPM(SDL_RWops *src); extern DECLSPEC int IMG_isPCX(SDL_RWops *src); extern DECLSPEC int IMG_isGIF(SDL_RWops *src); @@ -66,7 +66,7 @@ extern DECLSPEC int IMG_isPNG(SDL_RWops *src); /* Individual loading functions */ extern DECLSPEC SDL_Surface *IMG_LoadBMP_RW(SDL_RWops *src); -extern DECLSPEC SDL_Surface *IMG_LoadPPM_RW(SDL_RWops *src); +extern DECLSPEC SDL_Surface *IMG_LoadPNM_RW(SDL_RWops *src); extern DECLSPEC SDL_Surface *IMG_LoadXPM_RW(SDL_RWops *src); extern DECLSPEC SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src); extern DECLSPEC SDL_Surface *IMG_LoadGIF_RW(SDL_RWops *src); diff --git a/configure.in b/configure.in index f8f5dcb7..970cb711 100644 --- a/configure.in +++ b/configure.in @@ -131,11 +131,11 @@ if test x$enable_png = xyes; then AC_MSG_WARN([PNG image loading disabled]) fi fi -AC_ARG_ENABLE(ppm, -[ --enable-ppm support loading PPM images [default=yes]], - , enable_ppm=yes) -if test x$enable_ppm = xyes; then - CFLAGS="$CFLAGS -DLOAD_PPM" +AC_ARG_ENABLE(pnm, +[ --enable-pnm support loading PNM images [default=yes]], + , enable_pnm=yes) +if test x$enable_pnm = xyes; then + CFLAGS="$CFLAGS -DLOAD_PNM" fi AC_ARG_ENABLE(tga, [ --enable-tga support loading TGA images [default=yes]],