Skip to content

Commit

Permalink
Added general PNM (PPM/PGM/PBM) support
Browse files Browse the repository at this point in the history
  • Loading branch information
Sam Lantinga committed Mar 7, 2001
1 parent 0379340 commit 23c8e8b
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 61 deletions.
2 changes: 2 additions & 0 deletions 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
Expand Down
6 changes: 3 additions & 3 deletions IMG.c
Expand Up @@ -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 },
Expand Down
2 changes: 2 additions & 0 deletions IMG_pcx.c
Expand Up @@ -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
Expand Down
155 changes: 105 additions & 50 deletions IMG_ppm.c
Expand Up @@ -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 <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#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 */
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand All @@ -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 */
3 changes: 2 additions & 1 deletion README
Expand Up @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions SDL_image.h
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
10 changes: 5 additions & 5 deletions configure.in
Expand Up @@ -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]],
Expand Down

0 comments on commit 23c8e8b

Please sign in to comment.