/* pnmtofits.c - read a portable anymap and produce a FITS file
**
** Copyright (C) 1989 by Wilson H. Bent (whb@hoh-2.att.com).
**
** 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.
**
** Modified by Alberto Accomazzi (alberto@cfa.harvard.edu), Dec 1, 1992.
**
** Added support for PPM files, the program is renamed pnmtofits.
** This program produces files with NAXIS = 2 if input file is in PBM
** or PGM format, and NAXIS = 3, NAXIS3 = 3 if input file is a PPM file.
** Data is written out as either 8 bits/pixel or 16 bits/pixel integers,
** depending on the value of maxval in the input file.
** Flags -max, -min can be used to set DATAMAX, DATAMIN, BSCALE and BZERO
** in the FITS header, but do not cause the data to be rescaled.
*/

#include "pnm.h"
#define write_card(s)    fwrite( s, sizeof(char), 80, stdout )

int
main( argc, argv )
    int argc;
    char* argv[];
    {
    FILE* ifp;
    xel** xels;
    xel* xelrow;
    register xel* xP;
    int argn, row, col, rows, cols, planes, format, i, npad,
        bitpix, forcemin, forcemax;
    double datamin, datamax, bscale, fits_bzero, frmax, frmin;
    xelval maxval;
    register unsigned short color;
    char card[81];
    const char* const usage = "[-max f] [-min f] [pnmfile]";

    pnm_init( &argc, argv );

    forcemin = 0;
    forcemax = 0;
    argn = 1;

    while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
	{
        if ( pm_keymatch( argv[argn], "-max", 3 ) )
	  {
	  ++argn;
	  forcemax = 1;
	  if ( argn == argc || sscanf( argv[argn], "%lf", &frmax ) != 1 )
	    pm_usage( usage );
	  }
        else if ( pm_keymatch( argv[argn], "-min", 3 ) )
	  {
	  ++argn;
	  forcemin = 1;
	  if ( argn == argc || sscanf( argv[argn], "%lf", &frmin ) != 1 )
	    pm_usage( usage );
	  }
        else
	    pm_usage( usage );
	++argn;
	}

    if ( argn != argc )
	{
	ifp = pm_openr( argv[argn] );
	++argn;
	}
    else
	ifp = stdin;

    if ( argn != argc )
	pm_usage( usage );

    xels = pnm_readpnm( ifp, &cols, &rows, &maxval, &format );

    datamin = 0.0;
    datamax = (double) maxval;
    if (forcemin) datamin = frmin;
    if (forcemax) datamax = frmax;
    fits_bzero = datamin;
    if (maxval > 255) fits_bzero += (1<<15);
    bscale = ( datamax - datamin ) / ( double ) maxval;

    bitpix = 8;
    if (maxval > 255) bitpix = 16;

    pm_close( ifp );

    /* Figure out the proper depth */
    switch ( PNM_FORMAT_TYPE(format) )
	{
	case PPM_TYPE:
	planes = 3;
	break;

	default:
	planes = 1;
	break;
	}

    /* write out fits header */
    i = 0;
    sprintf( card, "SIMPLE  =                    T                                                  " );
    write_card( card ); ++i;
    sprintf( card, "BITPIX  =           %10d                                                  ", bitpix );
    write_card( card ); ++i;
    sprintf( card, "NAXIS   =           %10d                                                  ", ( planes == 3 ) ? 3 : 2 );
    write_card( card ); ++i;
    sprintf( card, "NAXIS1  =           %10d                                                  ", cols );
    write_card( card ); ++i;
    sprintf( card, "NAXIS2  =           %10d                                                  ", rows );
    write_card( card ); ++i;
    if ( planes == 3 )
	{
    	sprintf( card, "NAXIS3  =                    3                                                  " );
    	write_card( card ); ++i;
	}
    sprintf( card, "BSCALE  =         %E                                                   ", bscale );
    write_card( card ); ++i;
    sprintf( card, "BZERO   =         %E                                                   ", fits_bzero );
    write_card( card ); ++i;
    sprintf( card, "DATAMAX =         %E                                                   ", datamax );
    write_card( card ); ++i;
    sprintf( card, "DATAMIN =         %E                                                   ", datamin );
    write_card( card ); ++i;
    sprintf( card, "HISTORY Created by pnmtofits.                                                   " );
    write_card( card ); ++i;
    sprintf( card, "END                                                                             " );
    write_card( card ); ++i;

    /* pad end of header with blanks */
    npad = ( i * 80 ) % 2880;
    if ( npad == 0 )
	npad = 2880;
    while ( npad++ < 2880 )
	putchar ( ' ' );
    
    for ( i = 0; i < planes; i++ )
    	for ( row = 0; row < rows; ++row )
	    {
	    xelrow = xels[row];
	    for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
		{
		if ( planes == 3 )
		    {
		    /* we are reading a ppm file */
		    if ( i == 0 ) 	color = PPM_GETR( *xP );
		    else if ( i == 1 ) 	color = PPM_GETG( *xP );
		    else 		color = PPM_GETB( *xP );
		    }
		else
		    color = PNM_GET1( *xP );
		
		if ( bitpix == 16 ) {
            int const fitsSample = (int)color - (1<<15);
            pm_writebigshort(stdout, (short)fitsSample);
        } else
            putchar( color & 0xff );
		}
	    }
	
    /* pad end of file with nulls */
    npad = ( rows * cols * planes * bitpix / 8 ) % 2880;
    if ( npad == 0 )
	npad = 2880;
    while ( npad++ < 2880 )
	putchar ( 0 );

    exit( 0 );
    }

