/*
 * Copyright 1990 by Baylor College of Medicine ALL RIGHTS RESERVED. 
 *
 * This program is subject to a license agreement between 
 * Baylor College of Medicine and MIT. Any use inconsistent with
 * said license and any use by persons other than the faculty, 
 * students and staff at MIT or any use on a computer not operated 
 * as part of the Athena Computing Environment (ACE) is expressly 
 * prohibited.
 */
/*
 *		Routines to read an write raster files to and from images.
 *		At present, images must be Z-Pixmap and only rasterfiles of depth
 *		less than that of the screen can be read in.
 */
#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
#include <fcntl.h>
#include <malloc.h>
#include <rasterfile.h>
#include <rast_img.h>

static int lbuf ;
static unsigned char buf[512] ;

/* Adds a char to buffer, flushing when necessary */
static
add_chr(fd,c)
	unsigned char c ;
{
	if (lbuf == sizeof buf)
	{
		write(fd,buf,lbuf) ;
		lbuf = 0 ;
	}
	buf[lbuf++] = c ;
}

/* Flushes run char */
static
int
flush_chrs(fd,chr,len)
	unsigned char chr ;
{
	if (len == 1)
	{
		if (chr == 128)
		{
			add_chr(fd,128) ;
			add_chr(fd,0) ;
			return 2 ;
		}
		else
		{
			add_chr(fd,chr) ;
			return 1 ;
		}
	}
	else if (len > 1)
	{
		add_chr(fd,128) ;
		add_chr(fd,len - 1) ;
		add_chr(fd,chr) ;
		return 3 ;
	}
	return 0 ;
}

/* Trasnfers a image read from a socket to a file */
write_rast_img_fd(fd,img)
	Rast_Img *img ;
{
	struct rasterfile rasterfile ;
	int size ;
	long width = img->width ;
	long height = img->height ;
	long depth = img->depth ;
	long map_type = img->cmap_type ;

	size = (((width * depth + 15) / 16) * 2) * height ;

	lseek(fd,sizeof rasterfile,L_SET) ;

	if (map_type == CMAP_RGB)
	{
		long map_size = img->cmap_data.rgb.map_size ;
		struct rgb *map = img->cmap_data.rgb.map ;
		unsigned char red[256] ;
		unsigned char green[256] ;
		unsigned char blue[256] ;
		int i ;
		for(i = 0; i < map_size; i++)
		{
			red[i] = map[i].r ;
			green[i] = map[i].g ;
			blue[i] = map[i].b ;
		}
		write(fd,red,map_size) ;
		write(fd,green,map_size) ;
		write(fd,blue,map_size) ;
		rasterfile.ras_maptype = RMT_EQUAL_RGB ;
		rasterfile.ras_maplength = map_size * 3 ;
	}
	else
	{
		rasterfile.ras_maptype = RMT_NONE ;
		rasterfile.ras_maplength = 0 ;
	}

	rasterfile.ras_magic =  RAS_MAGIC ;
	rasterfile.ras_width = width ;
	rasterfile.ras_height = height ;
	rasterfile.ras_depth = depth ;
	rasterfile.ras_type = RT_BYTE_ENCODED ;

	lbuf = 0 ;
	{
		int run_length = 0 ;
		unsigned char run_char ;
		unsigned char *data = img->data ;
		int len = 0 ;
		while(size)
		{
			unsigned char b = *data++ ;
			if (!run_length)
			{
				run_char = b ;
				run_length = 1 ;
			}
			else if (b != run_char || run_length > 255)
			{
				len += flush_chrs(fd,run_char,run_length) ;
				run_char = b ;
				run_length = 1 ;
			}
			else
			{
				run_length++ ;
			}
			size-- ;
		}
		len += flush_chrs(fd,run_char,run_length) ;
		rasterfile.ras_length = len ;
	}
	if (lbuf > 0)
	{
		write(fd,buf,lbuf) ;
	}

	lseek(fd,0L,L_SET) ;

	/* Write out the header */
	(void)write(fd,(char *)&rasterfile,sizeof rasterfile,1) ;

	return 0 ;
}

write_rast_img(fname,img)
	char *fname ;
	Rast_Img *img ;
{
        int fd = open(fname,O_WRONLY | O_CREAT | O_TRUNC,0600L) ;
        if (fd < 0)
        {
                return -5 ;
        }
        else
        {
                int rc = write_rast_img_fd(fd,img) ;
                close(fd) ;
                return rc ;
        }
}
