home *** CD-ROM | disk | FTP | other *** search
- /* rletopnm.c - convert Utah Raster Toolkit image to portable anymap
- **
- ** Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
- **
- ** Permission to use, copy, modify, and distribute this software and its
- ** documentation for any purpose and without fee is hereby granted, provided
- ** that the above copyright notice appear in all copies and that both that
- ** copyright notice and this permission notice appear in supporting
- ** documentation. This software is provided "as is" without express or
- ** implied warranty.
- **
- ** 09/Dec/94: first version
- */
- #include "pnm.h"
- #include "rle.h"
-
- /*#define DEBUG*/
-
- /* prototypes */
- static Header * read_header ARGS((FILE *ifp));
- static xel ** read_rle_image ARGS((FILE *ifp, Header *hdr));
- static int do_bytedata ARGS((FILE *ifp, Header *hdr, xel *imagerow, int col, long nbytes, int channel));
- static int do_rundata ARGS((FILE *ifp, Header *hdr, xel *imagerow, int col, long nbytes, int channel));
- static void readerr ARGS((FILE *fp));
- static unsigned short get_short ARGS((FILE *ifp));
- static unsigned char get_byte ARGS((FILE *ifp));
- static void skip_bytes ARGS((FILE *ifp, long nbytes));
- static void * xmalloc ARGS((int bytes));
- #define MALLOC(n, type) ((type *)xmalloc((n) * sizeof(type)))
- #define plural(x) ((x) == 1 ? "" : "s")
-
- static int mode;
- #define MODE_COLORMAP 0 /* colormap file (0 channels) */
- #define MODE_GRAYSCALE 1 /* 1 channel, no colormap */
- #define MODE_PSEUDOCOLOR 2 /* 1 channel with colormap */
- #define MODE_TRUECOLOR 3 /* 3 channels with colormap */
- #define MODE_DIRECTCOLOR 4 /* 3 channels, no colormap */
-
- static xel bg_xel;
-
- static short verbose = 0;
- static pixel *colormap = (pixel *)NULL;
- static long colors = 0;
-
- int
- main(argc, argv)
- int argc;
- char *argv[];
- {
- Header *hdr;
- FILE *ifp;
- xel **image;
- xelval maxval;
- int argn, format;
- char *usage = "[-verbose] [rlefile]";
-
- pnm_init(&argc, argv);
-
- argn = 1;
- while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
- if( pm_keymatch(argv[argn], "-verbose", 2) )
- verbose++;
- else
- if( pm_keymatch(argv[argn], "-noverbose", 4) )
- verbose = 0;
- else
- pm_usage(usage);
- ++argn;
- }
- if( argn < argc ) {
- ifp = pm_openr( argv[argn] );
- argn++;
- }
- else
- ifp = stdin;
- if( argn != argc )
- pm_usage(usage);
-
- hdr = read_header(ifp);
- maxval = pm_bitstomaxval(hdr->pixelbits);
- if( mode != MODE_COLORMAP ) {
- image = read_rle_image(ifp, hdr);
-
- if( mode == MODE_GRAYSCALE ) {
- if( hdr->pixelbits == 1 ) {
- pm_message("writing PBM image");
- format = PBM_TYPE;
- }
- else {
- pm_message("writing PGM image");
- format = PGM_TYPE;
- }
- }
- else {
- pm_message("writing PPM image");
- format = PPM_TYPE;
- }
- pnm_writepnm(stdout, image, hdr->xsize, hdr->ysize, maxval, format, 0);
- }
- else {
- pm_message("writing colormap file (PPM P3 ASCII)");
- ppm_writeppminit(stdout, colors, 1, maxval, 1);
- ppm_writeppmrow(stdout, colormap, colors, maxval, 1);
- }
- pm_close(ifp);
- exit(0);
- }
-
-
- static Header *
- read_header(ifp)
- FILE *ifp;
- {
- Header *hdr = MALLOC(1, Header);
-
- hdr->magic = get_short(ifp);
- if( hdr->magic != RLE_MAGIC )
- pm_error("bad magic number - not an Utah Raster file");
-
- hdr->xpos = get_short(ifp);
- hdr->ypos = get_short(ifp);
- hdr->xsize = get_short(ifp);
- hdr->ysize = get_short(ifp);
- hdr->flags = get_byte(ifp);
- hdr->ncolors = get_byte(ifp);
- hdr->pixelbits = get_byte(ifp);
- hdr->ncmap = get_byte(ifp);
- hdr->cmaplen = get_byte(ifp);
-
- /* some sanity checks */
- if( hdr->pixelbits > 8 )
- pm_error("too many bits per pixel: %d (max 8)", hdr->pixelbits);
-
- if( verbose ) {
- pm_message("dimensions: %d x %d, %d channel%s, %d bit%s/pixel (per channel)",
- hdr->xsize, hdr->ysize,
- hdr->ncolors, plural(hdr->ncolors),
- hdr->pixelbits, plural(hdr->pixelbits));
- }
-
- switch( hdr->ncolors ) {
- case 0:
- if( hdr->ncmap == 3 )
- mode = MODE_COLORMAP;
- else
- goto fail1;
- break;
- case 1:
- if( hdr->ncmap == 0 )
- mode = MODE_GRAYSCALE;
- else
- if( hdr->ncmap == 3 )
- mode = MODE_PSEUDOCOLOR;
- else
- goto fail1;
- break;
- case 3:
- if( hdr->ncmap == 0 )
- mode = MODE_DIRECTCOLOR;
- else
- if( hdr->ncmap == 3 )
- mode = MODE_TRUECOLOR;
- else
- goto fail1;
- break;
- default:
- fail1:
- pm_error("don't know how to handle %d channels with %d color map channels", hdr->ncolors, hdr->ncmap);
- break;
- }
-
- #ifdef DEBUG
- pm_message("mode = %d", mode);
- #endif
-
- if( hdr->flags & H_NO_BACKGROUND ) {
- /* set bg_xel to black */
- bg_xel = pnm_blackxel(pm_bitstomaxval(hdr->pixelbits), mode == MODE_GRAYSCALE ? PGM_TYPE : PPM_TYPE);
- get_byte(ifp); /* skip pad byte */
- }
- else {
- unsigned char r, g, b;
- if( hdr->ncolors == 1 ) {
- r = get_byte(ifp);
- PNM_ASSIGN1(bg_xel, r);
- }
- else
- if( hdr->ncolors == 3 ) {
- r = get_byte(ifp);
- g = get_byte(ifp);
- b = get_byte(ifp);
- PPM_ASSIGN(bg_xel, r, g, b);
- }
-
- if( !odd(hdr->ncolors) )
- (void)get_byte(ifp); /* skip pad byte */
- }
-
- if( hdr->ncmap ) {
- long i;
-
- colors = 1 << hdr->cmaplen;
- colormap = ppm_allocrow(colors);
-
- /* 3 colormap channels (because of the previous switch) */
- for( i = 0; i < colors; i++ )
- PPM_PUTR(colormap[i], get_short(ifp) & 0xff);
- for( i = 0; i < colors; i++ )
- PPM_PUTG(colormap[i], get_short(ifp) & 0xff);
- for( i = 0; i < colors; i++ )
- PPM_PUTB(colormap[i], get_short(ifp) & 0xff);
- }
-
- if( hdr->flags & H_COMMENT ) {
- unsigned short length = (unsigned short)get_short(ifp);
- skip_bytes(ifp, (long)length);
- if( odd(length) )
- (void)get_byte(ifp); /* skip pad byte */
- }
-
- #ifdef DEBUG
- pm_message("file position after reading header: %ld", ftell(ifp));
- #endif
-
- return hdr;
- }
-
-
- static xel **
- read_rle_image(ifp, hdr)
- FILE *ifp;
- Header *hdr;
- {
- int col, row, cols, rows, rlerow;
- xel **image;
- int opcode;
- unsigned short channel = CHANNEL_RED;
- unsigned short datum;
- long nbytes;
-
- cols = hdr->xsize;
- rows = hdr->ysize;
-
- image = pnm_allocarray(cols, rows);
-
- /* clear image to background color */
- for( row = 0; row < rows; row++ )
- for( col = 0; col < cols; col++ )
- image[row][col] = bg_xel;
-
- row = rows-1; col = 0; /* RLE files have origin in lower left corner */
- rlerow = 0;
- for(;;) {
- opcode = fgetc(ifp);
- if( opcode == EOF || opcode == OP_EOF || opcode == (OP_EOF|OP_LONG_DATUM) )
- return image;
- datum = (unsigned short)get_byte(ifp);
- if( opcode & OP_LONG_DATUM ) {
- datum = get_short(ifp);
- opcode &= ~OP_LONG_DATUM;
- }
-
- switch( opcode ) {
- case OP_SKIPLINES:
- row -= datum;
- rlerow += datum;
- break;
- case OP_SETCOLOR:
- channel = datum;
- col = 0;
- break;
- case OP_SKIPPIXELS:
- col += datum;
- break;
- case OP_BYTEDATA:
- nbytes = (long)datum + 1;
- if( nbytes > cols-col )
- pm_error("row %d: %ld bytes ByteData, space left %d", rlerow, nbytes, cols-col);
- if( (hdr->flags & H_ALPHA) && channel == CHANNEL_ALPHA ) {
- skip_bytes(ifp, nbytes);
- }
- else
- if( channel >= hdr->ncolors )
- pm_error("** TODO **");
- else
- col = do_bytedata(ifp, hdr, image[row], col, nbytes, (int)channel);
- if( odd(nbytes) )
- (void)get_byte(ifp);
- break;
- case OP_RUNDATA:
- nbytes = (long)datum + 1;
- if( nbytes > cols-col )
- pm_error("row %d: %ld bytes RunData, space left %d", rlerow, nbytes, cols-col);
- if( (hdr->flags & H_ALPHA) && channel == CHANNEL_ALPHA ) {
- (void)get_short(ifp);
- }
- else
- if( channel >= hdr->ncolors )
- pm_error("** TODO **");
- else
- col = do_rundata(ifp, hdr, image[row], col, nbytes, (int)channel);
- break;
- default:
- pm_error("unkown opcode %d @ file pos %ld", opcode, ftell(ifp));
- }
- }
- }
-
-
- static int
- do_bytedata(ifp, hdr, imagerow, col, nbytes, channel)
- FILE *ifp;
- Header *hdr;
- xel *imagerow;
- int col;
- long nbytes;
- int channel;
- {
- long i;
- int byte;
-
- for( i = 0; i < nbytes; i++ ) {
- byte = get_byte(ifp);
- switch( mode ) {
- case MODE_GRAYSCALE:
- PNM_ASSIGN1(imagerow[col], byte);
- break;
- case MODE_PSEUDOCOLOR:
- byte = get_byte(ifp);
- imagerow[col] = colormap[byte];
- break;
- case MODE_TRUECOLOR:
- switch( channel ) {
- case CHANNEL_RED:
- PPM_PUTR(imagerow[col], PPM_GETR(colormap[byte]));
- break;
- case CHANNEL_GREEN:
- PPM_PUTG(imagerow[col], PPM_GETG(colormap[byte]));
- break;
- case CHANNEL_BLUE:
- PPM_PUTB(imagerow[col], PPM_GETB(colormap[byte]));
- break;
- }
- break;
- case MODE_DIRECTCOLOR:
- switch( channel ) {
- case CHANNEL_RED:
- PPM_PUTR(imagerow[col], byte);
- break;
- case CHANNEL_GREEN:
- PPM_PUTG(imagerow[col], byte);
- break;
- case CHANNEL_BLUE:
- PPM_PUTB(imagerow[col], byte);
- break;
- }
- break;
- }
- ++col;
- }
- return col;
- }
-
-
- static int
- do_rundata(ifp, hdr, imagerow, col, nbytes, channel)
- FILE *ifp;
- Header *hdr;
- xel *imagerow;
- int col;
- long nbytes;
- int channel;
- {
- long i;
- int byte;
-
- byte = get_short(ifp) & 0xff;
-
- for( i = 0; i < nbytes; i++ ) {
- switch( mode ) {
- case MODE_GRAYSCALE:
- PNM_ASSIGN1(imagerow[col], byte);
- break;
- case MODE_PSEUDOCOLOR:
- byte = get_byte(ifp);
- imagerow[col] = colormap[byte];
- break;
- case MODE_TRUECOLOR:
- switch( channel ) {
- case CHANNEL_RED:
- PPM_PUTR(imagerow[col], PPM_GETR(colormap[byte]));
- break;
- case CHANNEL_GREEN:
- PPM_PUTG(imagerow[col], PPM_GETG(colormap[byte]));
- break;
- case CHANNEL_BLUE:
- PPM_PUTB(imagerow[col], PPM_GETB(colormap[byte]));
- break;
- }
- break;
- case MODE_DIRECTCOLOR:
- switch( channel ) {
- case CHANNEL_RED:
- PPM_PUTR(imagerow[col], byte);
- break;
- case CHANNEL_GREEN:
- PPM_PUTG(imagerow[col], byte);
- break;
- case CHANNEL_BLUE:
- PPM_PUTB(imagerow[col], byte);
- break;
- }
- break;
- }
- ++col;
- }
- return col;
- }
-
-
- static void
- readerr(fp)
- FILE *fp;
- {
- if( ferror(fp) )
- pm_error("read error");
- else
- pm_error("premature EOF");
- }
-
-
- static unsigned short
- get_short(ifp)
- FILE *ifp;
- {
- short s;
-
- if( pm_readlittleshort(ifp, &s) == -1 )
- readerr(ifp);
- return s;
- }
-
-
- static unsigned char
- get_byte(ifp)
- FILE *ifp;
- {
- int i;
-
- i = fgetc(ifp);
- if( i == EOF )
- readerr(ifp);
- return (unsigned char)i;
- }
-
-
- static void
- skip_bytes(ifp, nbytes)
- FILE *ifp;
- long nbytes;
- {
- while( nbytes-- )
- (void)get_byte(ifp);
- }
-
-
- static void *
- xmalloc(bytes)
- int bytes;
- {
- void *mem;
-
- if( bytes == 0 )
- return NULL;
-
- mem = malloc(bytes);
- if( mem == NULL )
- pm_error("out of memory allocating %d bytes", bytes);
- return mem;
- }
-
-