[comp.sys.sgi] Trouble with Iris IMG library

lansd@dgp.toronto.edu (Robert Lansdale) (03/19/90)

	Several months ago I added Iris 'IMG' file output capabilities
to my 3d renderer, but everytime I outputed an image and 'ipaste'd it to the
screen, the image was always displayed black. After spending too much time
trying to narrow the problem down (including examining the file directly),
I gave up and placed it at the bottom of my list of things to eventually
fix.

	Well, here we are several months later, but now I must convert
an Iris IMG file created with Alias's Quickpaint program to our native
RLE file format. To make a long story short, the converter did its job
but the resulting colour image was displayed in grey-scale. To see who was at
fault, I converted the 'max5.rgb' image and it displayed just fine. I
then tried the 'toalias' converter in 4Dgifts/iristools/imgtools on the
Quickpaint output, then used a (known-to-be-working) Alias image display
program to paste the Alias pic to the Iris display - same 'greyscale'
effect.

	So, the question is: why does both my renderer and the converter
programs have problems with the Image file library? I made sure I recompiled
the libraries in 4Dgifts/iristools before I made the toalias program and
before I linked libimage.a into my renderer.

	Also, does the "image->zsize" variable really reflect the depth of
the IMG file? From what I recall, most of the IMG related files in 4Dgifts
don't bother looking at the image depth.

--> Rob Lansdale

paul@manray.sgi.com (Paul Haeberli) (03/20/90)

The reason you had problems converting a file from Alias QuickPaint is that 
QuickPaint saves its images as colo(u)r index pixels.  To use a QuickPaint
image with the image processing tools or the image library it is best to 
convert it into an RGB image.  

The following script does just that by first saving the current colo(u)r-map, 
and then mapping the color indexed pixels into rgb space.  The programs 
"savemap" and "mapimg" can be found in /usr/people/4Dgifts/iristools/imgtools
if they aren't found in /usr/sbin.


This is fromqp:

#! /bin/sh
if [ $# != 2 ]
then
	echo "usage: fromqp in.qp out.rgb"
	exit 1
fi
savemap /tmp/qp.map
mapimg $1 $2 /tmp/qp.map
rm /tmp/qp.map




To write out an rgb IRIS image from a renderer use a sequence of image
library calls like this:


#include "gl/image.h"
/*
 *	writeiris - 
 *		This function takes three arrays of unsigned characters and 
 *	writes these as pixel data to an IRIS image file that can be ipasted
 *	to the screen.
 *
 */
writeiris(rbuf,gbuf,bbuf,xsize,ysize)
unsigned char *rbuf, *gbuf, *bbuf;
int xsize, ysize;
{
    IMAGE *oimage;
    unsigned short *rs, *gs, *bs;
    int x, y;

    rs = (unsigned short *)malloc(xsize*sizeof(unsigned short));
    gs = (unsigned short *)malloc(xsize*sizeof(unsigned short));
    bs = (unsigned short *)malloc(xsize*sizeof(unsigned short));
    oimage = iopen("render.rgb","w",RLE(1),3,xsize,ysize,3);
    for(y=0; y<ysize; y++) {
	for(x=0; x<xsize; x++) {
	    rs[x] = *rbuf++;
	    gs[x] = *gbuf++;
	    bs[x] = *bbuf++;
	}
	putrow(oimage,rs,y,0);
	putrow(oimage,gs,y,1);
	putrow(oimage,bs,y,2);
    }
    iclose(oimage);
    free(rs);
    free(gs);
    free(bs);
}



Please let me know if you still have problems . . . . .

paul haeberli

paul@sgi.com

pbreslin@dragon.tmc.edu (Paul Breslin) (03/20/90)

>...
>    Well, here we are several months later, but now I must convert
>an Iris IMG file created with Alias's Quickpaint program to our native
>RLE file format. ...

The Iris image library is capable of storing four "types" of image files.
These are (from image.h): CM_NORMAL, CM_DITHERED, CM_SCREEN, CM_COLORMAP.
Some of the image tools in 4Dgifts prefer and/or assume CM_NORMAL type,
which is the most common type (pixel values are channel intensities).

Since QuickPaint operates in colormap mode, it stores images using
type CM_SCREEN. Since QuickPaint also allows you to modify the colormap,
it saves a secondary file (.M) containing the colormap used to create
the image. This .M file is of type CM_COLORMAP. If one of these
doesn't exist you usually assume the default NeWS colormap should be
used.

So, say you wanted to convert a QuickPaint image to RGB format. You
should first read in the colormap file. It should be 4 by 256. The
X dimension contains the colormap index, R, G, and B.

Then to read the image itself, you read in the CM_SCREEN type image
whose pixel values represent colormap indices and map them to RGB
values using the colormap from above.

Here's a program I just created to read in a quickpaint file,
convert it to RGB and blast it into a window using lrectwrite.
It was created with 4 space tabs and compiled with the command:

	cc -O qp.c -lgutil -limage -lgl_s -lm -lc_s

It's rather sparse on diagnostics. If you turn this into a real
tool then please add more of these. It was also whipped together
somewhat quickly so I apologize in advance for any errors. I've
only tested it on the images in /usr/demos/quickpaint.

Also note that the SGI image library has a nasty habit of calling
exit. A hack was added to it to trap errors by calling "i_seterror"
with an error handling function pointer. I would suggest using this.
Locally we've modified the library to be slightly improved in this
area.

cheers,
Paul Breslin
Alias Research Inc.
--------------------------------------------------------------------
#include <stdio.h>
#include <gl.h>
#include <device.h>
#include <gl/image.h>

typedef struct {
	unsigned char a, b, g, r;
} RGBA;

static RGBA	*ColorMap;
static RGBA	*Image;
static int	 Xres, Yres;
static char	 ErrorMsg[256];

extern unsigned char   red_map[256];
extern unsigned char green_map[256];
extern unsigned char  blue_map[256];

static int
LoadColorMap(char *filename)
{
	register IMAGE  *cmap;
	register RGBA   *rgbp;
	register int	 y;
	register int	 index;
	short			 rowbuf[4];
	char			 cmapname[512];

	sprintf(cmapname, "%s.M", filename);
	if( !(cmap = iopen(cmapname, "r")) )
		return 0;
 
	if( cmap->xsize != 4 )
	{
		iclose(cmap);
		return 0;
	}
	rgbp = ColorMap = (RGBA *)malloc(cmap->ysize * sizeof(RGBA));
	for( y = 0;  y < cmap->ysize;  y++ )
		if( getrow(cmap, rowbuf, y, 0) >= 0 )
		{
			index = rowbuf[0];
			rgbp->r = rowbuf[1];
			rgbp->g = rowbuf[2];
			rgbp->b = rowbuf[3];
			++rgbp;
		}
	iclose(cmap);
	return 1;
}

static int
LoadImage(char *filename)
{
	register Colorindex *scanline;
	register RGBA		*rgbp;
	register IMAGE		*image;
	register int		 y;
	register int		 x;
	register int		 index;
	register int		 file_zsize;

	if( !(image = iopen(filename,"r")) )
		return 0;

	file_zsize = image->zsize;
	Xres = image->xsize;
	Yres = image->ysize;

	if( file_zsize != 1 )
	{
		sprintf(ErrorMsg, "\"%s\" is not a normal QP file", filename);
		iclose(image);
		return 0;
	}
	scanline = (Colorindex *)malloc(Xres * sizeof(Colorindex));
	rgbp = Image =   (RGBA *)malloc(Xres * Yres * sizeof(RGBA));

	for( y = 0;  y < Yres;  ++y )
	{
		if( getrow(image, scanline, y, 0) < 0 ) break;
		for( x = 0;  x < Xres;  ++x, ++rgbp )
		{
			index = scanline[x];
			if( !ColorMap )
			{
				if( index < 256 )
				{
					rgbp->r =   red_map[index];
					rgbp->g = green_map[index];
					rgbp->b =  blue_map[index];
				}
				else
				{
					rgbp->r = 0;
					rgbp->g = 0;
					rgbp->b = 0;
				}
			}
			else
				*rgbp = ColorMap[index];
		}
	}
	iclose(image);
	free((char *)scanline);
	return y == Yres;
}

int
main(int argc, char **argv)
{
	Device	event;
	short	value;
	long	window;

	if( argc != 2 )
	{
		fprintf(stderr, "Usage: %s <quickpaint_file>\n", argv[0]);
		return 1;
	}
	LoadColorMap(argv[1]);

	if( LoadImage(argv[1]) )
	{
		prefposition(0, Xres - 1, 0, Yres - 1);
		noborder();
		foreground();
		if( (window = winopen("Hi")) <= 0 ) return 1;

		RGBmode();
		gconfig();

		qdevice(WINQUIT);
		qdevice(WINSHUT);
		qenter(REDRAW, window);

		while( event = qread(&value) )
		{
			switch( event )
			{
				case WINQUIT:
				case WINSHUT:
					break;

				case REDRAW:
					lrectwrite(0, 0, Xres - 1, Yres - 1, Image);
					continue;

				default:
					continue;
			}
			break;
		}
	}
	return 0;
}