home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
NETWORK
/
netpbm_src.lzh
/
NETPBM
/
PNM
/
pnmtosgi.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-11-18
|
10KB
|
371 lines
/* pnmtosgi.c - convert portable anymap to SGI image
**
** Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
**
** Based on the SGI image description v0.9 by Paul Haeberli (paul@sgi.comp)
** Available via ftp from sgi.com:graphics/SGIIMAGESPEC
**
** 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.
**
** 29Jan94: first version
*/
#include "pnm.h"
#include "sgi.h"
/*#define DEBUG*/
typedef short ScanElem;
typedef struct {
ScanElem * data;
long length;
} ScanLine;
/* prototypes */
static void put_big_short ARGS((short s));
static void put_big_long ARGS((long l));
#define put_byte(b) (void)(putc((unsigned char)(b), stdout))
static void put_short_as_byte ARGS((short s));
static void write_header ARGS((int cols, int rows, xelval maxval, int bpc, int dimensions, int channels, char *imagename));
static void write_table ARGS((long *table, int tabsize));
static void write_channels ARGS((int cols, int rows, int channels, void (*put) ARGS((short)) ));
static long * build_channels ARGS((FILE *ifp, int cols, int rows, xelval maxval, int format, int bpc, int channels));
static ScanElem *compress ARGS((ScanElem *temp, int row, int rows, int cols, int chan_no, long *table, int bpc));
static int rle_compress ARGS((ScanElem *inbuf, int cols));
static void * xmalloc ARGS((int bytes));
#define MALLOC(n, type) (type *)xmalloc((n) * sizeof(type))
#define WORSTCOMPR(x) (2*(x) + 2)
#define MAXVAL_BYTE 255
#define MAXVAL_WORD 65535
static char storage = STORAGE_RLE;
static ScanLine * channel[3];
static ScanElem * rletemp;
static xel * pnmrow;
int
main(argc, argv)
int argc;
char *argv[];
{
FILE *ifp;
int argn;
char *usage = "[-verbatim|-rle] [-imagename <name>] [pnmfile]";
int cols, rows, format;
xelval maxval;
char *imagename = "no name";
int bpc, dimensions, channels;
long *table = NULL;
pnm_init(&argc, argv);
argn = 1;
while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
if( pm_keymatch(argv[argn], "-verbatim", 2) )
storage = STORAGE_VERBATIM;
else
if( pm_keymatch(argv[argn], "-rle", 2) )
storage = STORAGE_RLE;
else
if( pm_keymatch(argv[argn], "-imagename", 2) ) {
if( ++argn >= argc )
pm_usage(usage);
imagename = argv[argn];
}
else
pm_usage(usage);
++argn;
}
if( argn < argc ) {
ifp = pm_openr( argv[argn] );
argn++;
}
else
ifp = stdin;
if( argn != argc )
pm_usage(usage);
pnm_pbmmaxval = PNM_MAXMAXVAL; /* use larger value for better results */
pnm_readpnminit(ifp, &cols, &rows, &maxval, &format);
pnmrow = pnm_allocrow(cols);
switch( PNM_FORMAT_TYPE(format) ) {
case PBM_TYPE:
pm_message("promoting PBM to PGM");
case PGM_TYPE:
dimensions = 2; channels = 1;
break;
case PPM_TYPE:
dimensions = 3; channels = 3;
break;
default:
pm_error("can\'t happen");
}
if( maxval <= MAXVAL_BYTE )
bpc = 1;
else if( maxval <= MAXVAL_WORD )
bpc = 2;
else
pm_error("maxval too large - try using \"pnmdepth %d\"", MAXVAL_WORD);
table = build_channels(ifp, cols, rows, maxval, format, bpc, channels);
pnm_freerow(pnmrow);
pm_close(ifp);
write_header(cols, rows, maxval, bpc, dimensions, channels, imagename);
if( table )
write_table(table, rows * channels);
if( bpc == 1 )
write_channels(cols, rows, channels, put_short_as_byte);
else
write_channels(cols, rows, channels, put_big_short);
exit(0);
}
static void
write_header(cols, rows, maxval, bpc, dimensions, channels, imagename)
int cols, rows;
xelval maxval;
int bpc, dimensions, channels;
char *imagename;
{
int i;
#ifdef DEBUG
pm_message("writing header");
#endif
put_big_short(SGI_MAGIC);
put_byte(storage);
put_byte((char)bpc);
put_big_short(dimensions);
put_big_short(cols);
put_big_short(rows);
put_big_short(channels);
put_big_long(0); /* PIXMIN */
put_big_long(maxval); /* PIXMAX */
for( i = 0; i < 4; i++ )
put_byte(0);
for( i = 0; i < 79 && imagename[i] != '\0'; i++ )
put_byte(imagename[i]);
for(; i < 80; i++ )
put_byte(0);
put_big_long(CMAP_NORMAL);
for( i = 0; i < 404; i++ )
put_byte(0);
}
static void
write_table(table, tabsize)
long *table;
int tabsize;
{
int i;
long offset;
#ifdef DEBUG
pm_message("writing table");
#endif
offset = HeaderSize + tabsize * 8;
for( i = 0; i < tabsize; i++ ) {
put_big_long(offset);
offset += table[i];
}
for( i = 0; i < tabsize; i++ )
put_big_long(table[i]);
}
static void
write_channels(cols, rows, channels, put)
int cols, rows, channels;
void (*put) ARGS((short));
{
int i, row, col;
#ifdef DEBUG
pm_message("writing image data");
#endif
for( i = 0; i < channels; i++ ) {
for( row = 0; row < rows; row++ ) {
for( col = 0; col < channel[i][row].length; col++ ) {
(*put)(channel[i][row].data[col]);
}
}
}
}
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;
}
static void
put_big_short(s)
short s;
{
if ( pm_writebigshort( stdout, s ) == -1 )
pm_error( "write error" );
}
static void
put_big_long(l)
long l;
{
if ( pm_writebiglong( stdout, l ) == -1 )
pm_error( "write error" );
}
static void
put_short_as_byte(s)
short s;
{
put_byte((unsigned char)s);
}
static long *
build_channels(ifp, cols, rows, maxval, format, bpc, channels)
FILE *ifp;
int cols, rows;
xelval maxval;
int format, bpc, channels;
{
int i, row, col, sgirow;
long *table = NULL;
ScanElem *temp;
#ifdef DEBUG
pm_message("building channels");
#endif
if( storage != STORAGE_VERBATIM ) {
table = MALLOC(channels * rows, long);
rletemp = MALLOC(WORSTCOMPR(cols), ScanElem);
}
temp = MALLOC(cols, ScanElem);
for( i = 0; i < channels; i++ )
channel[i] = MALLOC(rows, ScanLine);
for( row = 0, sgirow = rows-1; row < rows; row++, sgirow-- ) {
pnm_readpnmrow(ifp, pnmrow, cols, maxval, format);
if( channels == 1 ) {
for( col = 0; col < cols; col++ )
temp[col] = (ScanElem)PNM_GET1(pnmrow[col]);
temp = compress(temp, sgirow, rows, cols, 0, table, bpc);
}
else {
for( col = 0; col < cols; col++ )
temp[col] = (ScanElem)PPM_GETR(pnmrow[col]);
temp = compress(temp, sgirow, rows, cols, 0, table, bpc);
for( col = 0; col < cols; col++ )
temp[col] = (ScanElem)PPM_GETG(pnmrow[col]);
temp = compress(temp, sgirow, rows, cols, 1, table, bpc);
for( col = 0; col < cols; col++ )
temp[col] = (ScanElem)PPM_GETB(pnmrow[col]);
temp = compress(temp, sgirow, rows, cols, 2, table, bpc);
}
}
free(temp);
if( table )
free(rletemp);
return table;
}
static ScanElem *
compress(temp, row, rows, cols, chan_no, table, bpc)
ScanElem *temp;
int row, rows, cols, chan_no;
long *table;
int bpc;
{
int len, i, tabrow;
ScanElem *p;
switch( storage ) {
case STORAGE_VERBATIM:
channel[chan_no][row].length = cols;
channel[chan_no][row].data = temp;
temp = MALLOC(cols, ScanElem);
break;
case STORAGE_RLE:
tabrow = chan_no * rows + row;
len = rle_compress(temp, cols); /* writes result into rletemp */
channel[chan_no][row].length = len;
channel[chan_no][row].data = p = MALLOC(len, ScanElem);
for( i = 0; i < len; i++, p++ )
*p = rletemp[i];
table[tabrow] = len * bpc;
break;
default:
pm_error("unknown storage type - can\'t happen");
}
return temp;
}
/*
slightly modified RLE algorithm from ppmtoilbm.c
written by Robert A. Knop (rknop@mop.caltech.edu)
*/
static int
rle_compress(inbuf, size)
ScanElem *inbuf;
int size;
{
int in, out, hold, count;
ScanElem *outbuf = rletemp;
in=out=0;
while( in<size ) {
if( (in<size-1) && (inbuf[in]==inbuf[in+1]) ) { /*Begin replicate run*/
for( count=0,hold=in; in<size && inbuf[in]==inbuf[hold] && count<127; in++,count++)
;
outbuf[out++]=(ScanElem)(count);
outbuf[out++]=inbuf[hold];
}
else { /*Do a literal run*/
hold=out; out++; count=0;
while( ((in>=size-2)&&(in<size)) || ((in<size-2) && ((inbuf[in]!=inbuf[in+1])||(inbuf[in]!=inbuf[in+2]))) ) {
outbuf[out++]=inbuf[in++];
if( ++count>=127 )
break;
}
outbuf[hold]=(ScanElem)(count | 0x80);
}
}
outbuf[out++] = (ScanElem)0; /* terminator */
return(out);
}