rsalz@uunet.uu.net (Rich Salz) (05/10/88)
Submitted-by: Marc Majka <majka@grads.cs.ubc.cdn> Posting-number: Volume 14, Issue 86 Archive-name: rast Here is a set of library subroutines which I have found useful for reading and writing SUN rasterfiles. The package contains all the usual stuff: README, Makefile, sources, manuals, and a couple of sample programs. I have tested and debugged the library to some extent, but local hardware limitations precluded my from giving them a vigorous workout. There may be bugs. If you find or fix any, please let me know! --- Marc Majka #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # README # Makefile # rast.c # rast.h # rast.3 # rdemo.c # rsee.c export PATH; PATH=/bin:$PATH if test -f 'README' then echo shar: will not over-write existing file "'README'" else cat << \SHAR_EOF > 'README' This package contains a library of routines for reading and writing SUN rasterfiles in a pixel-at-a-time manner. The routines maintain a data structure called a RASTER, which contains all the usual file header information from a rasterfile, along with a file pointer and a memory cache of a single line (row) of the rasterfile. Bit stuffing and unpacking is accomplished with pixrect operations, which are about as fast as possible. Manifest: rast.h - header file to include rast.c - library source rast.3 - manual entry rdemo.c - demo program rsee.c - program to print rasterfile headers Makefile - to compile it all Note that, since the library pixrect operations, you must include -lpixrect in any programs which use the library. --- Marc Majka - UBC Laboratory for Computational Vision <majka@vision.ubc.cdn> <majka@ubc.bitnet> <majka@ubc-vision.uucp> SHAR_EOF fi # end of overwriting check if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else cat << \SHAR_EOF > 'Makefile' all: rast.o rdemo rsee rast.o: rast.c rast.h cc -c rast.c rdemo: rdemo.c rast.o cc -o rdemo rdemo.c rast.o -lpixrect rsee: rsee.c rast.o cc -o rsee rsee.c rast.o -lpixrect SHAR_EOF fi # end of overwriting check if test -f 'rast.c' then echo shar: will not over-write existing file "'rast.c'" else cat << \SHAR_EOF > 'rast.c' #include "rast.h" RASTER *Ropen(f,m) char *f; int m; { RASTER *im, *Ropen_read(), *Ropen_write(); im = NULL; if (m == R) im = Ropen_read(f); if (m == W) im = Ropen_write(f); return(im); } RASTER *Rdopen(f,m) int f,m; { RASTER *im, *Rdopen_stdin(), *Rdopen_stdout(); im = NULL; if (f == 0 && m == R) im = Rdopen_stdin(); if (f == 1 && m == W) im = Rdopen_stdout(); return(im); } RASTER *Ropen_read(f) char *f; { RASTER *im; char *malloc(); im = (RASTER *)malloc(sizeof(RASTER)); im->fp = fopen(f,"r"); im->mode = R; if (im->fp == NULL) { fprintf(stderr,"read open fails for file \"%s\"!\n",f); im = NULL; return(im); } return(im); } RASTER *Rdopen_stdin() { RASTER *im; char *malloc(); im = (RASTER *)malloc(sizeof(RASTER)); im->fp = stdin; im->mode = R; if (im->fp == NULL) { fprintf(stderr,"read open fails for stdin!\n"); im = NULL; return(im); } return(im); } RASTER *Ropen_write(f) char *f; { RASTER *im; char *malloc(); im = (RASTER *)malloc(sizeof(RASTER)); im->fp = fopen(f,"w"); if (im->fp == NULL) { fprintf(stderr,"write open fails for file \"%s\"!\n",f); im = NULL; return(im); } im->mode = W; im->width = 0; im->height = 0; im->depth = 0; im->maplength = 0; im->maptype = RMT_NONE; if (im->fp == NULL) im = NULL; return(im); } RASTER *Rdopen_stdout() { RASTER *im; char *malloc(); im = (RASTER *)malloc(sizeof(RASTER)); im->fp = stdout; if (im->fp == NULL) { fprintf(stderr,"write open fails for stdout!\n"); im = NULL; return(im); } im->mode = W; im->width = 0; im->height = 0; im->depth = 0; im->maplength = 0; im->maptype = RMT_NONE; return(im); } Rgetheader(im) RASTER *im; { char *malloc(); int i, rc, ll, extra; struct rasterfile rhead; rc = fread(&rhead,(sizeof (struct rasterfile)),1,im->fp); if (rc <= 0) { fprintf(stderr,"Rgetheader failed!\n"); return(0); } if (rhead.ras_magic != RAS_MAGIC) return(0); im->height = rhead.ras_height; im->width = rhead.ras_width; im->depth = rhead.ras_depth; im->length = rhead.ras_length; im->type = rhead.ras_type; im->maptype = rhead.ras_maptype; im->maplength = rhead.ras_maplength; extra = (16 - ((im->width * im->depth) % 16)) % 16; ll = ((im->width * im->depth) + extra) / 8; im->linelen = ll; im->cache = malloc(ll); im->c_pixel = im->width + 1; im->c_pr = mem_point(im->width,1,im->depth,im->cache); if (im->maplength > 0) { im->map = malloc(im->maplength); for (i = 0; i < im->maplength; i++) im->map[i] = getc(im->fp); } return(1); } Rputheader(im) RASTER *im; { char *malloc(); int i, rc, ll, extra; struct rasterfile rhead; extra = (16 - ((im->width * im->depth) % 16)) % 16; ll = ((im->width * im->depth) + extra) / 8; if (im->width == 0) { fprintf(stderr,"rasterfile width is zero!\n"); return(0); } if (im->height == 0) { fprintf(stderr,"rasterfile height is zero!\n"); return(0); } if (im->depth == 0) { fprintf(stderr,"rasterfile depth is zero!\n"); return(0); } rhead.ras_magic = RAS_MAGIC; rhead.ras_width = im->width; rhead.ras_height = im->height; rhead.ras_depth = im->depth; rhead.ras_length = ll * im->height; rhead.ras_type = RT_STANDARD; rhead.ras_maptype = im->maptype; rhead.ras_maplength = im->maplength; im->linelen = ll; im->cache = malloc(ll); im->c_pixel = 0; im->c_pr = mem_point(im->width,1,im->depth,im->cache); rc = fwrite(&rhead,(sizeof (struct rasterfile)),1,im->fp); if (rc <= 0) { fprintf(stderr,"Rputheader failed!\n"); return(0); } if (im->maptype != RMT_NONE && im->maplength > 0) fwrite(im->map,im->maplength,1,im->fp); return(1); } Rgetpix(im) RASTER *im; { int pix; if (im->mode != R) { fprintf(stderr,"attempt to read rasterfile opened for write!\n"); return(-1); } if (im->c_pixel >= im->width) { fread(im->cache,im->linelen,1,im->fp); im->c_pixel = 0; } pix = pr_get(im->c_pr,im->c_pixel,0); im->c_pixel++; return(pix); } Rputpix(im,pix) RASTER *im; int pix; { if (im->mode != W) { fprintf(stderr,"attempt to write rasterfile opened for read!\n"); return(-1); } pr_put(im->c_pr,im->c_pixel,0,pix); im->c_pixel++; if (im->c_pixel >= im->width) { fwrite(im->cache,im->linelen,1,im->fp); im->c_pixel = 0; } } Rclose(im) RASTER *im; { if (im->mode == W) fflush(im->fp); fclose(im->fp); } Rinfo(im) RASTER *im; { fprintf(stderr," height = %d\n",im->height); fprintf(stderr," width = %d\n",im->width); fprintf(stderr," depth = %d\n",im->depth); fprintf(stderr," length = %d\n",im->length); fprintf(stderr," type = %d\n",im->type); fprintf(stderr," maptype = %d\n",im->maptype); fprintf(stderr," maplength = %d\n",im->maplength); } Rinitmap(im,t,l) RASTER *im; int t,l; { char *malloc(); im->maptype = t; im->maplength = l; im->map = malloc(l); } Rputmap(im,i,r,g,b) RASTER *im; int i,r,g,b; { int x; switch (im->maptype) { case RMT_NONE: fprintf(stderr,"can't put in a null map!\n"); break; case RMT_RAW: im->map[i] = r; break; case RMT_EQUAL_RGB: x = i * 3; im->map[x++] = r; im->map[x++] = g; im->map[x] = b; break; default: fprintf(stderr,"unknown map type in rasterfile!\n"); } } Rgetmap(im,i,r,g,b) RASTER *im; int i,*r,*g,*b; { int x; switch (im->maptype) { case RMT_NONE: fprintf(stderr,"can't get from a null map!\n"); break; case RMT_RAW: *r = im->map[i]; break; case RMT_EQUAL_RGB: x = i * 3; *r = im->map[x++]; *g = im->map[x++]; *b = im->map[x]; break; default: fprintf(stderr,"unknown map type in rasterfile!\n"); } } Rgetmappedpix(im,r,g,b) RASTER *im; int *r,*g,*b; { int pix, x; if (im->mode != R) { fprintf(stderr,"attempt to read rasterfile opened for write!\n"); return(-1); } if (im->c_pixel >= im->width) { fread(im->cache,im->linelen,1,im->fp); im->c_pixel = 0; } pix = pr_get(im->c_pr,im->c_pixel,0); im->c_pixel++; switch (im->maptype) { case RMT_RAW: *r = im->map[pix]; break; case RMT_EQUAL_RGB: x = pix * 3; *r = im->map[x++]; *g = im->map[x++]; *b = im->map[x]; break; default: *r = pix; break; } } SHAR_EOF fi # end of overwriting check if test -f 'rast.h' then echo shar: will not over-write existing file "'rast.h'" else cat << \SHAR_EOF > 'rast.h' #include <stdio.h> #include <pixrect/pixrect_hs.h> #define R 0 #define W 1 typedef struct RASTER_STRUCT { int height; /* number of rows */ int width; /* number of columns */ int depth; /* bits per pixel */ int length; /* bytes of data following header */ int type; /* rasterfile type */ int maptype; /* type of lookup table */ int maplength; /* length of lookup table */ char *map; /* lookup table */ int linelen; /* bytes in a row (padded to even 16 bits) */ FILE *fp; /* file pointer */ int mode; /* read (R) or write (W) mode flag */ char *cache; /* cache of 1 row */ int c_pixel; /* current pixel in row cache */ struct pixrect *c_pr; /* make cache look like a pixrect */ } RASTER; SHAR_EOF fi # end of overwriting check if test -f 'rast.3' then echo shar: will not over-write existing file "'rast.3'" else cat << \SHAR_EOF > 'rast.3' .TH RAST 3 .SH NAME rast - SUN rasterfile interface .SH SYNOPSIS .B #include \*(lqrast.h\*(rq .sp .B RASTER *Ropen(filename,mode) .br .B char *filename; .br .B int mode; .sp .B RASTER Rdopen(filedes,mode) .br .B int filedes, mode; .sp .B Rgetheader(raster) .br .B RASTER *raster; .sp .B Rputheader(raster) .br .B RASTER *raster; .sp .B Rgetpix(raster) .br .B RASTER *raster; .sp .B Rputpix(raster,pixel) .br .B RASTER *raster; .br .B int pixel; .sp .B Rgetmappedpix(raster,value) .br .B RASTER *raster; .br .B int *value; .sp .B Rgetmappedpix(raster,red,green,blue) .br .B RASTER *raster; .br .B int *red, *green, *blue; .sp .B Rinitmap(raster,type,length) .br .B RASTER *raster; .br .B int type, length; .sp .B Rputmap(raster,index,value) .br .B RASTER *raster; .br .B int index, value; .sp .B Rputmap(raster,index,red,green,blue) .br .B RASTER *raster; .br .B int index, red, green, blue; .sp .B Rgetmap(raster,index,value) .br .B RASTER *raster; .br .B int index, *value; .sp .B Rgetmap(raster,index,red,green,blue) .br .B RASTER *raster; .br .B int index, *red, *green, *blue; .sp .B Rclose(raster) .br .B RASTER *raster; .sp .SH DESCRIPTION This library provides pixel I/O for SUN rasterfiles. .sp .I Ropen opens a SUN rasterfile for reading or writing, and returns a RASTER structure. The mode should be R for read, W for write. R and W are defined in the file rast.h. .I Rdopen opens a stream, specified by a UNIX file descriptor. The RASTER structure is defined below. .sp After a rasterfile has been opened to read, data from the rasterfile header is fetched and placed in the RASTER structure with a call to .I Rgetheader. A rasterfile opened for output must have (at least) it's width, height, and depth set before the header may be written with .I Rputheader. If the header is to include a map, the map must be initialized with a call to .I Rinitmap. Map values may be set directly in the RASTER structure, or they my be set using .I Rputmap. The map type must be one defined in the include file <rasterfile.h>. .sp For convenience, map values may be retrieved with .I Rgetmap. .sp Each call to .I Rgetpix will return a raw pixel value from the rasterfile. .I Rgetmappedpix returns the result of putting the raw pixel value through the rasterfile map. .I Rputpix writes pixel values to the rasterfile. .sp A rasterfile is closed with .I Rclose. .SH "RASTER STRUCTURE" The data structure maintained by these routines is defined in the file rast.h. .sp .nf typedef struct RASTER_STRUCT { int height; /* number of rows */ int width; /* number of columns */ int depth; /* bits per pixel */ int length; /* bytes of data following header */ int type; /* rasterfile type */ int maptype; /* type of lookup table */ int maplength; /* length of lookup table */ char *map; /* lookup table */ int linelen; /* bytes in a row (padded to even 16 bits) */ FILE *fp; /* file pointer */ int mode; /* read (R) or write (W) mode flag */ char *cache; /* cache of 1 row */ int c_pixel; /* current pixel in row cache */ struct pixrect *c_pr; /* make cache look like a pixrect */ } RASTER; .fi .sp The height, width, depth, length, type, maptype, and maplength fields have exactly the same meaning as they do in rasterfiles. The map field is used to store the rasterfile map data. .sp The linelen field gives the number of bytes in a single line (row) in the rasterfile. This is different from the width because each line is padded with zero bits to make it an integer multiple of 16 bits in length. .sp The UNIX file pointer is kept in the fp field, and a read/write flag is kept in the mode field. .sp Pixels are stored in the cache field, which holds one line (row) of the raster. The cache is maintained by .I Rgetpix and .I Rputpix. The current pixel (column) within the cache is recorded by in the c_pixel field. The cache is efficiently accessed by turning it into a memory pixrect and using .I pr_get and .I pr_put to do the necessary bit stuffing. The memory pixrect is kept in the c_pr field. Because of this, programs using this library must be compiled with -lpixrect. .SH AUTHOR Marc Majka SHAR_EOF fi # end of overwriting check if test -f 'rdemo.c' then echo shar: will not over-write existing file "'rdemo.c'" else cat << \SHAR_EOF > 'rdemo.c' /*********************************************************************** rdemo - reads a rasterfile, computes the average of the colour values (if applicable) of the pixels, and writes a new rasterfile with the average. An inverting colour map is added. ***********************************************************************/ #include <stdio.h> #include "rast.h" main(argc,argv) int argc; char *argv[]; { int r, g, b, avg, row, col, i, pix, ifile, ofile; RASTER *irast, *orast, *Ropen(), *Rdopen(); ifile = 0; ofile = 0; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { case 'i': ifile = ++i; break; case 'o': ofile = ++i; break; default: usage(); } } } if (ifile) irast = Ropen(argv[ifile],R); else irast = Rdopen(0,R); if (irast == NULL) { fprintf(stderr,"rdemo: input rasterfile open failed!\n"); exit(1); } if (ofile) orast = Ropen(argv[ofile],W); else orast = Rdopen(1,W); if (irast == NULL) { fprintf(stderr,"rdemo: output rasterfile open failed!\n"); exit(1); } if (!Rgetheader(irast)) { fprintf(stderr,"input file is not a raster file!\n"); exit(1); } orast->height = irast->height; orast->width = irast->width; orast->depth = irast->depth; Rinitmap(orast,RMT_EQUAL_RGB,256*3); for (i = 0; i < 256; i++) Rputmap(orast,255-i,i,i,i); Rputheader(orast); if (irast->maptype == RMT_EQUAL_RGB) { for (row = 0; row < irast->height; row++) for (col = 0; col < irast->width; col++) { Rgetmappedpix(irast,&r,&g,&b); avg = (r + g + b) / 3; Rputpix(orast,avg); } } else if (irast->maptype == RMT_RAW) { for (row = 0; row < irast->height; row++) for (col = 0; col < irast->width; col++) { Rgetmappedpix(irast,&pix); Rputpix(orast,pix); } } else if (irast->maptype == RMT_NONE) { for (row = 0; row < irast->height; row++) for (col = 0; col < irast->width; col++) { pix = Rgetpix(irast); Rputpix(orast,pix); } } else { fprintf(stderr,"rdemo: unknown map type in input rasterfile!\n"); exit(1); } Rclose(irast); Rclose(orast); } usage() { fprintf(stderr,"usage: rdemo [-i file] [-o file]\n"); fprintf(stderr," -i input rasterfile [default is stdin]\n"); fprintf(stderr," -o output rasterfile [default is stdout]\n"); exit(0); } SHAR_EOF fi # end of overwriting check if test -f 'rsee.c' then echo shar: will not over-write existing file "'rsee.c'" else cat << \SHAR_EOF > 'rsee.c' #include <stdio.h> #include "rast.h" main(argc,argv) int argc; char *argv[]; { RASTER *irast, *Ropen(); int i, rc; for (i = 1; i < argc; i++) { irast = Ropen(argv[i],R); if (irast == NULL) fprintf(stderr,"rasterfile open failed for \"%s\"!\n",argv[i]); else { rc = Rgetheader(irast); fprintf(stderr,"%s:\n",argv[i]); if (rc) Rinfo(irast); else fprintf(stderr,"not a rasterfile!\n"); fprintf(stderr,"\n"); Rclose(irast); } } exit(0); } SHAR_EOF fi # end of overwriting check # End of shell archive exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.