/**
 **	$Header: /import/dev-vis/image/imtools/v2.0/libim/src/RCS/imx.c,v 1.11 92/12/03 01:56:31 nadeau Exp $
 **	Copyright (c) 1989-1992  San Diego Supercomputer Center (SDSC)
 **		San Diego, California, USA
 **
 **	Users and possessors of this source code are hereby granted a
 **	nonexclusive, royalty-free copyright and design patent license to
 **	use this code in individual software.  License is not granted for
 **	commercial resale, in whole or in part, without prior written
 **	permission from SDSC.  This source is provided "AS IS" without express
 **	or implied warranty of any kind.
 **
 **	For further information contact:
 **		E-Mail:		info@sds.sdsc.edu
 **
 **		Surface Mail:	Information Center
 **				San Diego Supercomputer Center
 **				P.O. Box 85608
 **				San Diego, CA  92138-5608
 **				(619) 534-5000
 **/

#define HEADER        "    $Header: /import/dev-vis/image/imtools/v2.0/libim/src/RCS/imx.c,v 1.11 92/12/03 01:56:31 nadeau Exp $"

/**
 **  FILE
 **	imx.c		-  Stardent AVS X image file I/O
 **
 **  PROJECT
 **	libim	-  SDSC image manipulation library
 **
 **  DESCRIPTION
 **	imx.c contains routines to read and write Stardent AVS X files for
 **	the image manipulation library.  Raster data read in is stored
 **	in a VFB.  Raster data written out is taken from a tag table.
 **
 **  PUBLIC CONTENTS
 **			d =defined constant
 **			f =function
 **			m =defined macro
 **			t =typedef/struct/union
 **			v =variable
 **			? =other
 **
 **	ImXRead		f  read a Stardent AVS X file
 **	ImXWrite	f  write a Stardent AVS X X file
 **
 **  PRIVATE CONTENTS
 **	none
 **
 **  HISTORY
 **	$Log:	imx.c,v $
 **	Revision 1.11  92/12/03  01:56:31  nadeau
 **	Corrected info messages.
 **	
 **	Revision 1.10  92/11/24  11:52:29  groening
 **	Removed bogus code dealing with mythical, but not actual,
 **	DEC AVS version of the X format.
 **	
 **	Revision 1.9  92/11/18  12:29:21  groening
 **	added error statements to correspond
 **	with addition of new imdecx.c file
 **	
 **	Revision 1.8  92/11/04  12:10:22  groening
 **	put ImFIleFormat info and magic number info
 **	from imfmt.c into this file.
 **	
 **	Revision 1.7  92/10/19  14:05:46  groening
 **	added ImInfo features
 **	
 **	Revision 1.6  92/09/25  12:07:04  groening
 **	added print information for ImInfo
 **	
 **	Revision 1.5  92/09/02  11:12:38  vle
 **	Fixed copyright notice.
 **	
 **	Revision 1.4  92/08/31  17:43:50  vle
 **	Updated copyright notice.
 **	
 **	Revision 1.3  91/10/03  09:24:45  nadeau
 **	Fixed problem with alpha channel handling.
 **	
 **	Revision 1.2  91/02/12  10:47:13  nadeau
 **	Removed the tag table error checking now handled by
 **	ImFileWrite.  Removed VFB conversion also now handled by
 **	ImFileWrite.
 **	
 **	Revision 1.1  91/01/30  18:17:56  nadeau
 **	Initial revision
 **	
 **/

#include "iminternal.h"


#ifndef L_SET
#define L_SET   0               /* Absolute offset                      */
#define L_CUR   1
#define L_END   2
#endif




/*
 *  FORMAT
 *	X	-  Stardent AVS X image file
 *
 *  DESCRIPTION
 *	Stardent AVS X image files start with a two 32-bit words giving the
 *	image width and height, respectively.  Following these size words
 *	are a stream of (widht*height) 32-bit words giving the RGB value
 *	for consecutive pixels.  Scanlines are not padded.
 *
 *	Each 32-bit pixel value is structured as four 8-bit quantities:
 *
 *		high-order	matte (alpha)
 *				red
 *				green
 *		low-order	blue
 */


/*
 *  X - Stardent AVS image file
 *      For information on these structures, how to use them, etc. please
 *      see imfmt.c.
 */
extern int ImXRead( );
extern int ImXWrite( );
private char *imXNames[ ]  = { "x", "avs", "mbfx", "mbfavs", NULL };
private ImFileFormatReadMap imXReadMap[ ] =
{
        /* in                   out                                     */
        /* type,ch,dep, attr.   VFB type        attr.                   */
        { RGB,3,8,      A,      IMVFBRGB,       A },
        { -1,           0,      -1,             0 },
};
private ImFileFormatWriteMap imXWriteMap[ ] =
{
        /* in                   out                                     */
        /* VFB type,    attr.,  type,ch,dep,    attr.,  func            */
        { IMVFBRGB,     0,      RGB,3,8,        A,      ImXWrite },
        { IMVFBRGB,     A,      RGB,3,8,        A,      ImXWrite },
        { -1,           0,      -1,             0,      NULL },
};

private ImFileMagic *imFileXMagic []=
{
	NULL
};

public ImFileFormat ImFileXFormat =
{
	imXNames, "AVS X image file",
	"AVS Inc.",
	"24-bit RGB + 8-bit Alpha plane uncompressed image files.",
	"24-bit RGB + 8-bit Alpha plane uncompressed image files.",
	imFileXMagic,
	FALSE, TRUE,
	FALSE, TRUE,
	ImXRead, imXReadMap, imXWriteMap
};


/*
 *  FUNCTION
 *	ImXRead	-  read a Stardent AVS X file
 *
 *  DESCRIPTION
 *	The image size is read in, followed by the pixel values.
 *	A VFB is added to the tag table.
 */

public int				/* Returns # tags read in	*/
ImXRead( ioType, fd, fp, flagsTable, tagTable )
	int         ioType;		/* I/O flags			*/
	int         fd;			/* Input file descriptor	*/
	FILE	   *fp;			/* Input file pointer		*/
	TagTable   *flagsTable;		/* Flags			*/
	TagTable   *tagTable;		/* Tag table to add to		*/
{
	ImVfb        *vfb;		/* Read in image		*/
	ImVfbPtr     pPixel;		/* Pixel pointer		*/
	uint32      *buffer;		/* Run buffer			*/
	uint32      *pBuffer;		/* Run buffer pointer		*/
	int          width, height;	/* Image dimensions		*/
	int          i;			/* Counter			*/
	char	     message[200];	/* contains information for ImInfo */

	/*
	 *  Read in the image size.
	 */
	BinByteOrder( BINMBF );
	if ( ImBinRead( ioType, fd, fp, &width, INT, 4, 1 ) == -1 )
	{
		ImReturnBinError( );
	}
	if ( ImBinRead( ioType, fd, fp, &height, INT, 4, 1 ) == -1 )
	{
		ImReturnBinError( );
	}

	sprintf (message, "Most Significant Byte First");
	ImInfo ("Byte Order",message);
	sprintf (message, "%d x %d", width, height);
	ImInfo ("Resolution",message);
	ImInfo ("Type","24-bit RGB");
	ImInfo ("Alpha Channel","8-bit");

	/*
	 *  Allocate an RGB and Alpha plane VFB of the required size.
	 */
	if ( (vfb = ImVfbAlloc( width, height, IMVFBRGB|IMVFBALPHA )) == IMVFBNULL )
	{
		ImErrorFatal( ImQError( ), -1, ImErrNo );
	}


	/*
	 *  Read in and copy to the VFB, one scanline at a time.
	 */
	pPixel = ImVfbQFirst( vfb );
	ImMalloc( buffer, uint32 *, sizeof( uint32 ) * width );
	while ( height-- )
	{
		pBuffer = buffer;
		if ( ImBinRead( ioType, fd, fp, buffer, UINT32, 4, width )== -1)
		{
			free( (char *)buffer );
			ImVfbFree( vfb );
			ImReturnBinError( );
		}

		for ( i = 0; i < width; i++, pBuffer++ )
		{
			ImVfbSAlpha( vfb, pPixel, ((*pBuffer)>>24) & 0xFF );
			ImVfbSRed(   vfb, pPixel, ((*pBuffer)>>16) & 0xFF );
			ImVfbSGreen( vfb, pPixel, ((*pBuffer)>>8)  & 0xFF );
			ImVfbSBlue(  vfb, pPixel, (*pBuffer)       & 0xFF );
			ImVfbSInc(   vfb, pPixel );
		}
	}
	free( (char *)buffer );

	TagTableAppend( tagTable, TagEntryAlloc( "image vfb", POINTER, &vfb ) );

	return ( 1 );
}





/*
 *  FUNCTION
 *	ImXWrite	-  write a Stardent AVS X file
 *
 *  DESCRIPTION
 *	That VFB is queried, and the X file header written out.
 *	The VFB data is then copied to the file.
 */

public int				/* Returns # of tags used	*/
ImXWrite( pMap, ioType, fd, fp, flagsTable, tagTable )
	ImFileFormatWriteMap *pMap;	/* Write map entry to adhear to	*/
	int          ioType;		/* I/O flags			*/
	int          fd;		/* Input file descriptor	*/
	FILE	    *fp;		/* Input file pointer		*/
	TagTable   *flagsTable;		/* Flags			*/
	TagTable    *tagTable;		/* Tag table to read from	*/
{
	ImVfb        *vfb;		/* Read in image		*/
	ImVfbPtr     pPixel;		/* Pixel pointer		*/
	uint32      *buffer;		/* Run buffer			*/
	uint32      *pBuffer;		/* Run buffer pointer		*/
	int          width, height;	/* Image dimensions		*/
	int          i;			/* Counter			*/
	char	     message[200];	/* contains information for ImInfo */


	/*
	 *  Write out the image size.
	 */
	TagEntryQValue( TagTableQDirect( tagTable, "image vfb", 0 ), &vfb );
	width  = ImVfbQWidth( vfb );
	height = ImVfbQHeight( vfb );
	BinByteOrder( BINMBF );
	if ( ImBinWrite( ioType, fd, fp, &width, INT, 4, 1 ) == -1 )
	{
		ImReturnBinError( );
	}
	if ( ImBinWrite( ioType, fd, fp, &height, INT, 4, 1 ) == -1 )
	{
		ImReturnBinError( );
	}


	sprintf (message, "Most Significant Byte First");
	ImInfo ("Byte Order",message);
	sprintf (message, "%d x %d", width, height);
	ImInfo ("Resolution",message);
	ImInfo ("Type","24-bit RGB" );
	ImInfo ("Alpha Channel","8-bit");

	/*
	 *  Copy the image to the file.  If there's an alpha channel, add it.
	 */
	pPixel = ImVfbQFirst( vfb );
	ImMalloc( buffer, uint32 *, sizeof( uint32 ) * width );
	if ( ImVfbQFields( vfb ) & IMVFBALPHA )
	{
		while ( height-- )
		{
			pBuffer = buffer;
			for ( i = 0; i < width; i++, pBuffer++ )
			{
				*pBuffer =
					(((ImVfbQAlpha(vfb,pPixel))&0xFF)<<24) |
					(((ImVfbQRed(vfb,pPixel))&0xFF)<<16)|
					(((ImVfbQGreen(vfb,pPixel))&0xFF)<<8)|
					((ImVfbQBlue(vfb,pPixel))&0xFF);
				ImVfbSInc( vfb, pPixel );
			}

			if ( ImBinWrite( ioType, fd, fp, buffer, UINT32, 4, width ) == -1 )
			{
				free( (char *)buffer );
				ImReturnBinError( );
			}
		}
		free( (char *)buffer );
		return ( 1 );
	}

	while ( height-- )
	{
		pBuffer = buffer;
		for ( i = 0; i < width; i++, pBuffer++ )
		{
			*pBuffer =
				(((ImVfbQRed(vfb,pPixel))&0xFF)<<16)  |
				(((ImVfbQGreen(vfb,pPixel))&0xFF)<<8) |
				((ImVfbQBlue(vfb,pPixel))&0xFF);
			ImVfbSInc( vfb, pPixel );
		}

		if ( ImBinWrite( ioType, fd, fp, buffer, UINT32, 4, width)== -1)
		{
			free( (char *)buffer );
			ImReturnBinError( );
		}
	}
	free( (char *)buffer );
	return ( 1 );
}
