#include <stdio.h>
#include <time.h>

#ifdef VMS
#include <file.h>
#else
#include <fcntl.h>
#endif

/*
********************************
**     Program: filmps        **
********************************

Purpose: Postscript print of a film or image plate data file (or part
         thereof) (with data reordering and byte swapping if required)

Author:  John Campbell, November 1991

*/
main (argc, argv)
int argc;
char ** argv;
{
   static char *ordstr[8]=   /* Axis order strings */
   {
     "+xf +yf",
     "+xf -yf",
     "-xf +yf",
     "-xf -yf",
     "+yf +xf",
     "+yf -xf",
     "-yf +xf",
     "-yf -xf"
   };
   char str[80],str2[80];    /* Temporary input strings */
   char filin[80];           /* Name of input file */
   char psout[80];           /* Name of output postscript file */
   char title[81];           /* Main (short) title string */
   char *comments[4];        /* Pointers to comment strings */
   char datstr[30];          /* Date and time string */
   char *p;                  /* Temp character pointer */
   int i,j,k,l;              /* Temp/loop variables */
   int ll;                   /* Character string length */
   int ic;                   /* Comments loop counter */
   int type;                 /* Image type 1=film 2=image-plate */
   int order;                /* Axis order flag */
   int swaptyp;              /* Byte swap type 1=no 2=yes 0=undefined */
   int annotate;             /* Additional annotation flag 1=yes 0=no */
   int addate;               /* Output date/time string 1=yes 0=no */
   int addcomment;           /* Output comments 1=yes 0=no */
   int ncomment;             /* No. of comments */
   int icomment;             /* No. of the longest comment (most chars) */
   int lenmax;               /* Max length of a comment (no. of chars) */
   int inscal;               /* Input user defined scaling 1=yes 0=no */
   int addkey;               /* Output key 1=yes 0=no */
   int blank;                /* Blank string 1=yes 0=no */
   int fin;                  /* File descriptor for input image file */
   int xrasts;               /* No. of x rasters in the image */
   int yrasts;               /* No. of y rasters in the image */
   int nxp, nyp;             /* Compression factor in x, y */
   int xo_pix, yo_pix;       /* Origin pixel for selected sectionof image */
   int nx_pixels, ny_pixels; /* Size in pixels of selected image section */
   int img_width, img_height;/* Compressed image width, height in pixels */
   int minval, maxval;       /* Minimum and maximum pixel values in the file */
   int range;                /* Range between min and max scaling thresholds */
   int min_thresh,max_thresh;/* Min and max scaling thresholds */
   int ih, iw;               /* Loop counters through compressed image */
   int nels;                 /* Number of pixel elements in compressed image */
   int high;                 /* Black high 1=high 0=low */
   int maxels;               /* Max no. of pixels along an axis of compressed
                                image */
   int ncompress;            /* Pixel compression factor */

   float xscal, yscal;       /* x, y postscript scaling factors for image */
   float xpcen, ypcen;       /* Page position for centre of image (mm) */
   float ytitl;              /* Page 'y' position for short title (mm) */
   float ydate;              /* Page 'y' position for date/time (mm) */
   float xorg, yorg;         /* Page origin position for image (points) */
   float xlen, ylen;         /* Image size on page (points) */
   float x1key, x2key, x3key;/* Page 'x' position for parts of key (mm) */
   float ykey, dykey;        /* Page 'y' position & lines offset for key (mm) */
   float ycomm, dycomm;      /* Page 'y' position & lines offset for comments
                                (mm) */
   float mmscal;             /* Scale factor mm to points */
   float xwidth;             /* User requested width of image plot (cms) */
   float xx;                 /* Temp floating point value */

   unsigned char *byte_img;  /* char * pointer to image */
   unsigned short *i2_img;   /* short * pointer to image */
   unsigned int ipix;        /* Pixel value (intensity) */
   unsigned char pixval;     /* Pixel value for display (0-255) */

   time_t tm;                /* Structure for timer routines */
   FILE *fpout;              /* FILE pointer for output postscript file */

   /* Initialisations */

   filin[0] = 0;
   psout[0] = 0;
   order = 0;
   swaptyp = 0;
   high = 1;
   mmscal = 2.8346;
   xpcen = mmscal*105;
   ypcen = mmscal*175;
   ytitl = mmscal*75;
   ydate = mmscal*280;
   x1key = mmscal*8;
   x2key = mmscal*20;
   x3key = mmscal*61;
   ykey = mmscal*35;
   dykey = mmscal*5;
   ycomm = mmscal*60;
   dycomm = mmscal*5;
   addate = 0;
   addkey = 0;
   addcomment = 0;
   for (i=0;i<4;++i) comments[i] = (char *) malloc(121);
   inscal = 0;

   /* Input control data items */
   /* ======================== */

   /* Film/image-plate */

   labfip:
   str[0] = 0;
   str2[0] = 0;
   printf("Film (f) or image-plate (i) file [f]: ");
   gets(str);
   sscanf(str,"%s",str2);
   switch (str2[0])
   {
      case '\0':
         type = 1;
         break;
      case 'f':
      case 'F':
         type = 1;
         break;
      case 'i':
      case 'I':
         type = 2;
         break;
      default:
         printf("**Error** Invalid file type\n");
         goto labfip;
   }      

   /* Input file name */

   labinf:
   str[0] = 0;
   if (type==1)
   {
      printf("Name of input film image file: ");
   }
   else
   {
      printf("Name of input image-plate data file: ");
   }
   gets(str);
   i = sscanf(str,"%s",filin);
   if (filin[0]==0) goto labinf;
   fin = open (filin, O_RDONLY, 0);
   if (fin<0)
   {
      printf("**Error** Unable to open input file\n");
      goto labinf;
   }

   /* Raster sizes */

   if (type==1)
   {
      xrasts = 2400;
      yrasts = 2400;
   }
   else
   {
      xrasts = 1200;
      yrasts = 1200;
   }
   labrast:
   str[0] = 0;
   printf("No. of x rasters, no. of y rasters [%d %d]: ",xrasts,yrasts);
   gets(str);
   i = sscanf(str,"%d%d",&j,&k);
   if (i!=-1&&i!=2)
   {
      printf("**Error** Invalid reply\n");
      goto labrast;
   }
   if (i>0) xrasts = j;
   if (i>1) yrasts = k;

   /* Get section details */

   labor:
   str[0] = 0;
   xo_pix = 1;
   yo_pix = 1;
   printf("Enter origin pixel x, y [1 1]: ");
   gets (str);
   i = sscanf(str,"%d%d", &j, &k);
   if (i!=-1&&i!=2)
   {
      printf("**Error** Invalid reply\n");
      goto labor;
   }
   if (i>0) xo_pix = j;
   if (i>1) yo_pix = k;

   labpx:
   str[0] = 0;
   nx_pixels = xrasts;
   ny_pixels = yrasts;
   printf("Enter no. of x, y pixels for image section [%d %d]: ", 
         nx_pixels, ny_pixels);
   gets (str);
   i = sscanf(str,"%d%d", &j, &k);
   if (i!=-1&&i!=2)
   {
      printf("**Error** Invalid reply\n");
      goto labpx;
   }
   if (i>0) nx_pixels = j;
   if (i>1) ny_pixels = k;

   /* Axis order */

   labord:
   str[0] = 0;
   printf("Order of axes is input data file [+x+y]: ");
   gets(str);
   i = axord (str,0,&order,&k);
   if (i>0)
   {
      printf("**Error** Invalid axis order string\n");
      switch (i)
      {
         case 1:
            printf("Only one axis defined\n");
            break;
         case 2:
            printf("Same axis defined twice\n");
            break;
         case 3:
            printf("More than two axes defined\n");
            break;
         case 4:
            printf("Cannot have swap bytes and noswap\n");
            break;
      }
      goto labord;
   }
   if (order==0) order = 1;
   if (k>0) swaptyp = k;

   /* Byte swap option */

   if (swaptyp==0&&type==2)
   {
      labswap:
      str[0] = 0;
      str2[0] = 0;
      swaptyp = 1;
      printf("Byte swap data [n]: ");
      gets(str);
      i = sscanf(str,"%s",str2);
      if (str2[0]!=0)
      {
         switch (str2[0])
         {
             case 'y':
             case 'Y':
                swaptyp = 2;
                break;
             case 'n':
             case 'N':
                swaptyp = 1;
                break;
             default:
                printf("**Error** Invalid reply\n");
                goto labswap;
                break;
         }
      }
   }

   /* Output postscript file name */

   laboutf:
   str[0] = 0;
   printf("Name of output postscript file: ");
   gets(str);
   i = sscanf(str,"%s",psout);
   if (psout[0]==0) goto laboutf;
   fpout = fopen(psout,"w");
   if (fpout==0)
   {
      printf("**Error** Unable to open output file\n");
      goto laboutf;
   }

   /* Black high or low in image */

   labpn:
   str[0] = 0;
   str2[0] = 0;
   printf("Black = high (h) or low (l) [h]: ");
   gets(str);
   i = sscanf(str,"%s",str2);
   switch (str2[0])
   {
      case '\0':
         high = 1;
         break;
      case 'h':
      case 'H':
         high = 1;
         break;
      case 'l':
      case 'L':
         high = 0;
         break;
      default:
         printf("**Error** Invalid image type\n");
         goto labpn;
   }      

   /* Scaling of image */

   labscal:
   str[0] = 0;
   str2[0] = 0;
   printf("Automatic (a) or user defined (u) scaling [a]: ");
   gets(str);
   i = sscanf(str,"%s",str2);
   switch (str2[0])
   {
      case '\0':
         inscal = 0;
         break;
      case 'a':
      case 'A':
         inscal = 0;
         break;
      case 'u':
      case 'U':
         inscal = 1;
         break;
      default:
         printf("**Error** Invalid scaling option\n");
         goto labscal;
   }      
   if (inscal)
   {
      printf("Note: Maximum dimension in xf, yf should not exceed 18.0 cms\n");
      labsc2:
      xwidth = 15.0;
      printf("Required width (xf) in cms [15.0]: ");
      gets(str);
      i = sscanf(str,"%f",&xx);
      if (i!=-1&&i!=1)
      {
         printf("**Error** Invalid value\n");
         goto labsc2;
      }
      if (i>0) xwidth = xx;
      if (xwidth<=0.0)
      {
         printf("**Error** Width %.2f <= 0.0\n");
         goto labsc2;
      }
   }
   
   /* Find required compression to give max of 600 pixels square */

   maxels = xrasts;
   if (yrasts>maxels) maxels = yrasts;
   ncompress = 1;
   while (maxels/ncompress>600) ncompress++;
   nxp = ncompress;
   nyp = ncompress;

   /* Read data from file */

   nels = (nx_pixels/nxp)*(ny_pixels/nyp);
   printf("*Reading data file*\n");
   if (type==1)
   {
      byte_img = (unsigned char *) malloc(nels);
      if (byte_img==0)
      {
         printf("**Error** Unable to allocate space for image\n");
         exit(1);
      }
      i = read_film(fin,order,xrasts,yrasts,xo_pix,yo_pix,nx_pixels,ny_pixels,
                    nxp,nyp,byte_img,&img_width,&img_height);
      if (i>0)
      {
         printf("**Error** Read error at record %d",i);
         exit(1);
      }
      maxval = 0;
      for (i=0;i<img_width*img_height;++i)
      {
         if (byte_img[i]>maxval) maxval = byte_img[i];
      }
   }
   else
   {
      i2_img = (unsigned short *) malloc(nels*sizeof(short));
      if (i2_img==0)
      {
         printf("**Error** Unable to allocate space for image\n");
         exit(1);
      }
      if (swaptyp==2) order = -order;
      i = read_i2(fin,order,xrasts,yrasts,xo_pix,yo_pix,nx_pixels,ny_pixels,
                  nxp,nyp,i2_img,&img_width,&img_height,&minval,&maxval);
      if (i>0)
      {
         printf("**Error** Read error at record %d",i);
         exit(1);
      }
   }
   printf("*Data read*\n");

   printf("Maximum pixel value found = %d\n",maxval);

   /* Input minimum, maximum thresholds for image pixel scaling */

   labthr:
   min_thresh = 0;
   str[0] = 0;
   if (type==1)
   {
      max_thresh = maxval;
      printf("Minimum, maximum pixel value thresholds for scaling [%d %d]: ",
              min_thresh, max_thresh);
   }
   else
   {
      max_thresh = maxval/10;
      if (max_thresh<1) max_thresh = 1;
      printf(
      "For image-plate default scaling threshold = 10%% of maximum value\n");
      printf("Minimum, maximum pixel value thresholds for scaling [%d %d]: ",
              min_thresh, max_thresh);
   }
   gets(str);
   i=sscanf(str,"%d%d",&j,&k);
   if (i!=-1&&i!=1&&i!=2)
   {
      printf("**Error** Invalid value(s)\n");
      goto labthr;
   }
   if (i>0) min_thresh = j;
   if (i>1) max_thresh = k;
   range = max_thresh - min_thresh;

   printf("Short title: ");
   gets(title);

   labannot:
   str[0] = 0;
   str2[0] = 0;
   annotate = 1;
   printf("Add further annotation [y]: ");
   gets(str);
   i = sscanf(str,"%s",str2);
   if (str2[0]!=0)
   {
      switch (str2[0])
      {
          case 'y':
          case 'Y':
             annotate = 1;
             break;
          case 'n':
          case 'N':
             annotate = 0;
             break;
          default:
             printf("**Error** Invalid reply\n");
             goto labannot;
             break;
      }
   }

   if (annotate)
   {
      labdate:
      str[0] = 0;
      str2[0] = 0;
      addate = 1;
      printf("Add heading with date [y]: ");
      gets(str);
      i = sscanf(str,"%s",str2);
      if (str2[0]!=0)
      {
         switch (str2[0])
         {
             case 'y':
             case 'Y':
                addate = 1;
                break;
             case 'n':
             case 'N':
                addate = 0;
                break;
             default:
                printf("**Error** Invalid reply\n");
                goto labdate;
                break;
         }
      }
      if (addate)
      {
         time(&tm);
         strcpy(datstr,ctime(&tm));
         datstr[24] = 0;
      }

      labkey:
      str[0] = 0;
      str2[0] = 0;
      addkey = 1;
      printf("Add key [y]: ");
      gets(str);
      i = sscanf(str,"%s",str2);
      if (str2[0]!=0)
      {
         switch (str2[0])
         {
             case 'y':
             case 'Y':
                addkey = 1;
                break;
             case 'n':
             case 'N':
                addkey = 0;
                break;
             default:
                printf("**Error** Invalid reply\n");
                goto labkey;
                break;
         }
      }

      labcomment:
      str[0] = 0;
      str2[0] = 0;
      addcomment = 1;
      printf("Add comments [y]: ");
      gets(str);
      i = sscanf(str,"%s",str2);
      if (str2[0]!=0)
      {
         switch (str2[0])
         {
             case 'y':
             case 'Y':
                addcomment = 1;
                break;
             case 'n':
             case 'N':
                addcomment = 0;
                break;
             default:
                printf("**Error** Invalid reply\n");
                goto labcomment;
                break;
         }
      }

      if (addcomment)
      {
         ncomment = 0;
         lenmax = 0;
         for (ic=0;ic<4;++ic)
         {
            printf(": ");
            gets(comments[ic]);
            blank = 1;
            ll = strlen(comments[ic]);
            if (ll>0)
            {
               p = comments[ic];
               for (l=0;l<ll;++l)
               {
                  if (p[l]!=' ')
                  {
                     blank = 0;
                     break;
                  }
               }
            }
            if (blank)
            {
               break;
            }
            else
            {
               ncomment = ic + 1;
               if (ll>lenmax)
               {
                  icomment = ncomment;
                  lenmax = ll;
               }
            }
         }
      }
   }

   /* Prepare postscript file */
   /* ======================= */

   printf("*Preparing postscript file*\n");

   /* Initialisation */

   fprintf(fpout,"%%!\n");
   fprintf(fpout,"newpath\n");

   /* Get image size and draw box */

   maxels = img_width;
   if (img_height>maxels) maxels = img_height;
   if (inscal)
   {
      xscal = 10.0*xwidth*mmscal/(float) img_width;
   }
   else
   {
      xscal = 432.0/(float) maxels;
   }
   yscal = xscal;
   xlen = xscal*img_width;
   ylen = yscal*img_height;
   xorg = xpcen - xscal*(img_width/2);
   yorg = ypcen - yscal*(img_height/2);
   fprintf(fpout,"%.2f %.2f moveto\n",xorg,yorg);
   fprintf(fpout,"%.2f 0 rlineto\n",xlen);
   fprintf(fpout,"0 %.2f rlineto\n",ylen);
   fprintf(fpout,"%.2f 0 rlineto\n",-xlen);
   fprintf(fpout,"0 %.2f rlineto\n",-ylen);
   fprintf(fpout,"stroke\n");

   /* Short title */

   fprintf(fpout,"/Helvetica findfont 20 scalefont setfont\n");
   fprintf(fpout,"%.2f %.2f moveto\n",xpcen,ytitl);
   fprintf(fpout,"(%s)\n",title);
   fprintf(fpout,"dup stringwidth pop 2 div neg 0 rmoveto show\n");

   /* Other annotation */

   if (addate)  /* Date/time string */
   {
      fprintf(fpout,"/Helvetica findfont 12 scalefont setfont\n");
      fprintf(fpout,"%.2f %.2f moveto\n",xpcen,ydate);
      if (type==1)
      {
         fprintf(fpout,"(Film Image Plot: %s)\n",datstr);
      }
      else
      {
         fprintf(fpout,"(Image-plate Image Plot: %s)\n",datstr);
      }
      fprintf(fpout,"dup stringwidth pop 2 div neg 0 rmoveto show\n");
   }

   if (addkey) /* Key */
   {
      fprintf(fpout,"/Helvetica findfont 15 scalefont setfont\n");
      fprintf(fpout,"%.2f %.2f moveto\n",x1key,ykey);
      fprintf(fpout,"(Key) show\n");
      fprintf(fpout,"/Helvetica findfont 12 scalefont setfont\n");
      fprintf(fpout,"%.2f %.2f moveto\n",x2key,ykey);
      fprintf(fpout,"(Image section details) show\n");
      fprintf(fpout,"%.2f %.2f moveto\n",x3key,ykey);
      fprintf(fpout,
              "(: xf %d to %d of %d,  yf %d to %d of %d) show\n",
              xo_pix,xo_pix+nx_pixels-1,xrasts,
              yo_pix,yo_pix+ny_pixels-1,yrasts);
      ykey -= dykey;
      fprintf(fpout,"%.2f %.2f moveto\n",x2key,ykey);
      fprintf(fpout,"(Image orientation) show\n");
      fprintf(fpout,"%.2f %.2f moveto\n",x3key,ykey);
      fprintf(fpout,"(: xf to the right, yf up) show\n");
      ykey -= dykey;
      fprintf(fpout,"%.2f %.2f moveto\n",x2key,ykey);
      if (swaptyp!=2)
      {
         k = order;
         if (k<0) k = -k;
         fprintf(fpout,"(Data order in file) show\n");
         fprintf(fpout,"%.2f %.2f moveto\n",x3key,ykey);
         fprintf(fpout,"(: %s) show\n",ordstr[k-1]);
      }
      else
      {
         k = order;
         if (k<0) k = -k;
         fprintf(fpout,"(Data order in file) show\n");
         fprintf(fpout,"%.2f %.2f moveto\n",x3key,ykey);
         fprintf(fpout,"(: %s, byte swapped) show\n",ordstr[k-1]);
      }
      ykey -= dykey;
      fprintf(fpout,"%.2f %.2f moveto\n",x2key,ykey);
      fprintf(fpout,"(Maximum pixel value) show\n");
      fprintf(fpout,"%.2f %.2f moveto\n",x3key,ykey);
      fprintf(fpout,"(: %d) show\n",maxval);
      ykey -= dykey;
      fprintf(fpout,"%.2f %.2f moveto\n",x2key,ykey);
      if(high)
      {
         fprintf(fpout,"(Scaling thresholds) show\n");
         fprintf(fpout,"%.2f %.2f moveto\n",x3key,ykey);
         fprintf(fpout,"(: minimum = %d, maximum = %d, black is high) show\n",
                 min_thresh, max_thresh);
      }
      else
      {
         fprintf(fpout,"(Scaling thresholds) show\n");
         fprintf(fpout,"%.2f %.2f moveto\n",x3key,ykey);
         fprintf(fpout,"(: minimum = %d, maximum = %d, black is low) show\n",
                 min_thresh, max_thresh);
      }
   }
   
   if (addcomment&&ncomment>0) /* Comments */
   {
      fprintf(fpout,"/Helvetica findfont 12 scalefont setfont\n");
      fprintf(fpout,"/xoff (%s) stringwidth pop 2 div neg def\n",
              comments[icomment-1]);
      if (ncomment>3) ycomm += dycomm;
      for (i=0;i<ncomment;++i)
      {
         fprintf(fpout,"%.2f %.2f moveto\n",xpcen,ycomm);
         fprintf(fpout,"xoff 0 rmoveto\n");      
         fprintf(fpout,"(%s) show\n",comments[i]);
         ycomm -= dycomm;
      }
   }

   /* Reset position */

   fprintf(fpout,"0 0 moveto\n");

   fprintf(fpout,"save\n");

   /* Output the image */

   fprintf(fpout,"%.2f %.2f translate\n",xorg,yorg);
   fprintf(fpout,"%.2f %.2f scale\n",xlen,ylen);

   fprintf(fpout,"/picstr %d string def\n",img_width); 
   fprintf(fpout,"%d %d 8\n",img_width,img_height);
   fprintf(fpout,"[ %d 0 0 %d 0 %d ]\n",img_width,-img_height,img_height);
   fprintf(fpout,"{ currentfile picstr readhexstring pop }\n");
   fprintf(fpout,"image\n");

   i = 0;
   for (ih=0;ih<img_height;++ih)
   {
      j = 0;
      for (iw=0;iw<img_width;++iw)
      {
         if (type==1)
         {
            ipix = byte_img[i];
         }
         else
         {
            ipix = i2_img[i];
         }
         if (ipix<=min_thresh)
         {
            pixval = 0;
         }
         else if (ipix>=max_thresh)
         {
            pixval = 255;
         }
         else
         {
            pixval = 255*(ipix-min_thresh)/range;
         }
         if (high) pixval = 255 - pixval;
         fprintf(fpout,"%02X",pixval);
         j++;
         if (j==40) {fprintf(fpout,"\n"); j=0;}
         i++; 
      }
      if (img_width%40!=0) fprintf(fpout,"\n");
   }

   /* Complete output */

   fprintf(fpout,"restore\n");
   fprintf(fpout,"showpage\n");
   printf("*Post script file written*\n");

   /* Tidy up and exit */

   close (fin);
   fclose (fpout);
}

/*
***************************
**         axord         **
***************************

Purpose: Interpret image axes order and byte swapping option string
         (as xdl_axord in xdl_view routines)

Return:  Error flag =0 no error; 
                    >0 syntax error   =1 Only one axis defined.
                                      =2 Both axes the same.
                                      =3 More than two axes defined.
                                      =4 Byte swapping and no byte
                                         swapping defined.

Author:  John W. Campbell, November 1991

*/

int axord (str,len,order,swaptyp)

char *str;       /* String containing the axes order and byte swap flags
                    (R)*/
int len;         /* Length of the string; if 0 then assume a null
                    terminated string was passed (R) */
int *order;      /* Returns the axis order given as a number from 1 to 8
                    (If none specified (or syntax error) return 0)
                     1   +xf slow   +yf fast
                     2   +xf slow   -yf fast
                     3   -xf slow   +yf fast
                     4   -xf slow   -yf fast
                     5   +yf slow   +xf fast
                     6   +yf slow   -xf fast
                     7   -yf slow   +xf fast
                     8   -yf slow   -xf fast
                     (W)*/
int *swaptyp;    /* Returns byte swap type   =1 do not swap bytes
                                             =2 swap bytes
                                             =0 not specified (or syntax
                                                error)
                    (W)*/

{
   int saxis, ssign;
   int faxis, fsign;
   int n;
   int l;
   int err;

   /* Initialisations */

   if (len<=0) len=strlen(str);
   saxis = 0;
   ssign = 1;
   faxis = 0;
   fsign = 1;
   err = 0;
   *swaptyp = 0;
   *order = 0;
   if (len==0) return 0;
   n = 1;

   /* Decode the string */

   for (l=0;l<len;++l)
   {
      switch (str[l])
      {
         case '-':
            if (n==1) { ssign = -1; }else{ fsign = -1; }
            break;
         case '+':
            if (n==1) { ssign = 1; }else{ fsign = 1; }
            break;
         case 'x':
         case 'X':
            if (n==1) 
            {
               saxis = 1;
               n = 2;
            }
            else
            {
               if (n==3) { err=3; goto synterr; }
               faxis = 1;
               n = 3;
            }
            break;
         case 'y':
         case 'Y':
            if (n==1) 
            {
               saxis = 2;
               n = 2;
            }
            else
            {
               if (n==3) { err=3; goto synterr; }
               faxis = 2;
               n = 3;
            }
            break;
         case 's':
         case 'S':
            if (*swaptyp>0) { err=4; goto synterr; }
            *swaptyp = 2;
            break;
         case 'n':
         case 'N':
            if (*swaptyp>0) goto synterr;
            *swaptyp = 1;
            break;
      }
   }
   if (saxis==0&&faxis==0) return 0;
   if (saxis==0||faxis==0) { err=1; goto synterr; }
   if (saxis==faxis) { err=2; goto synterr; }
   *order = 4*saxis - 3;
   if (ssign<0) *order += 2;
   if (fsign<0) *order += 1;
   return 0;
   synterr:
   *order = 0;
   *swaptyp = 0;
   return err;
}
/*
*****************************
**       read_film         **
*****************************

Purpose: Read a film image file and return the image data in an array. 
         The image may be compressed in the 'x' and 'y' directions. 
         The file must be opened before this routine
         is called and it is not closed by this routine. The user may
         select the rectangular area of the image to be read.

         Version of xdl_read_film_file (from XDL_VIEW) for filmps

Return:  =0 OK; >0 Record number where a read error occurred, -1 cannot
         allocate temporary buffer(s)

Author:  John Campbell, Nov 1991

*/

int read_film (fd, order, nxrasts, nyrasts, xo_pix, yo_pix, 
                        nx_pixels, ny_pixels, nxp, nyp, 
                        img, img_width, img_height)

int fd;           /* The file descriptor of the opened film format 
                     file (R)*/
int order;        /* Order of the data in the input film image file
                     in terms of the xf, yf coordinate system as
                     a number from 1 to 8.
                     1   +xf slow   +yf fast
                     2   +xf slow   -yf fast
                     3   -xf slow   +yf fast
                     4   -xf slow   -yf fast
                     5   +yf slow   +xf fast
                     6   +yf slow   -xf fast
                     7   -yf slow   +xf fast
                     8   -yf slow   -xf fast
                     (R)*/
int nxrasts;      /* The number of x-rasters (no. of records) R)*/
int nyrasts;      /* The number of y-rasters (pixels in a record) (R)*/
int xo_pix;       /* The x value of the required origin pixel (pixels 
                     numbered from 1 up). If this is less than 1 it 
                     will be reset to 1 and, if it is greater than the 
                     maximum x pixel number present, it will be set to 
                     the maximum x pixel number (R)*/
int yo_pix;       /* The y value of the required origin pixel (pixels 
                     numbered from 1 up). If this is less than 1 it 
                     will be reset to 1 and, if it is greater than the 
                     maximum y pixel number present, it will be set to 
                     the maximum y pixel number (R)*/
int nx_pixels;    /* The 'x' width of the image section to be read. 
                     If a value of less than 1 is given it will be 
                     reset to 1. If a value is given which takes the 
                     section beyond the image then it will be reset to 
                     be within bounds (R)*/
int ny_pixels;    /* The 'y' height of the image section to be read. 
                     If a value of less than 1 is given it will be 
                     reset to 1. If a value is given which takes the 
                     section beyond the image then it will be reset to 
                     be within bounds (R)*/
int nxp;          /* The number of pixels in the 'x' direction to 
                     compress to 1 pixel (R)*/
int nyp;          /* The number of pixels in the 'y' direction to 
                     compress to 1 pixel (R)*/
unsigned char img[];
                  /* Array returning the read image data; The pixels
                     will have been compressed in 'x' and 'y' as 
                     requested. The values will be averaged over 
                     nxp*nyp pixels. The slower moving index in
                     the returned data is y going from high y to 
                     low y and the faster moving index is x going 
                     from low x to high x (W)*/
int * img_width;  /* Returns image width as a number of elements. 
                     Fastest moving index in 'img' (= x in film file). 
                     (W)*/
int * img_height; /* Returns image height as a number of elements. 
                     Slowest moving index in 'img' (= y in film file). 
                     (W)*/

/* Note if nx (in the film file) is not a multiple of nxp then up to
   nxp-1 pixels may be lost from the high end of 'x' and similarly for
   ny and nyp. */
{
   int i,j;
   int ix, iix;
   int iy, iiy;
   int xoff, yoff;
   int nx, ny;
   unsigned char *buf;
   long *ibuf;
   long ival;
   int nx_els, ny_els;
   int irec;
   int ioff;
   int nr;
   int rec_step;

   /* Initialisations */

   if (order<1||order>8) order = 1;
   if (nxp<1) nxp = 1;
   if (nyp<1) nyp = 1;
   if (xo_pix<1) xo_pix=1;
   if (yo_pix<1) yo_pix=1;
   if (nx_pixels<1) nx_pixels=1;
   if (ny_pixels<1) ny_pixels=1;

   nx = nxrasts;
   ny = nyrasts;

   /* Further checks on dimensions */

   if (xo_pix>nx) xo_pix = nx;
   if (yo_pix>ny) yo_pix = ny;
   if ((xo_pix+nx_pixels-1)>nx) nx_pixels = nx - xo_pix + 1;
   if ((yo_pix+ny_pixels-1)>ny) ny_pixels = ny - yo_pix + 1;

   /* Read data */

   nx_els = nx_pixels/nxp;
   *img_width = nx_els;
   ny_els = ny_pixels/nyp;
   *img_height = ny_els;

   /* Compress image in xy */

   if (order<5) /*xf slow, yf fast*/
   {
      nr = nx_els * nxp;  
      buf = (unsigned char *) malloc (ny);
      if (buf==0) return -1;
      ibuf = (long *) malloc (ny*sizeof(long));
      if (ibuf==0) return -1;
      if (order==1||order==2)
      {
         irec = xo_pix;
         rec_step = 1;
      }
      else
      {
         irec = nxrasts + 1 - xo_pix;
         rec_step = -1;
      }
      for (ix=0;ix<nx_els;++ix)
      {
         for (i=0;i<ny_pixels;++i) ibuf[i] = 0;
         for (iix=0;iix<nxp;++iix)
         {
            i = lseek(fd, (long) (irec-1)*nyrasts,0);
            i = read (fd, buf, nyrasts);
            if (i!=nyrasts) goto tidy;
            if (order==1||order==3)
            {
               for (i=ny_pixels-1,j=yo_pix-1;i>=0;--i,++j)
               {
                  ibuf[i] +=  (long) buf[j];
               }
            }
            else
            {
               for (i=0,j=nyrasts+1-ny_pixels-yo_pix;i<ny_pixels;++i,++j)
               {
                  ibuf[i] += (long) buf[j];
               }
            }
            irec += rec_step;
         }
         yoff = 0;
         for (iy=0;iy<ny_els;++iy)
         {
            ival = 0;
            for (iiy=0;iiy<nyp;++iiy)
            {
               ival += ibuf[yoff];
               yoff++;
            }
            ival = ival / (nxp*nyp);
            img[iy*nx_els+ix] = (unsigned char) (ival);
         }
      }
   }
   else  /*yf slow, xf fast*/
   {
      nr = ny_els * nyp;  
      buf = (unsigned char *) malloc (nx);
      if (buf==0) return -1;
      ibuf = (long *) malloc (nx*sizeof(long));
      if (ibuf==0) return -1;
      ioff = 0;
      if (order==5||order==6)
      {
         irec = nyrasts + 1 - yo_pix;
         rec_step = -1;
      }
      else
      {
         irec = yo_pix;
         rec_step = 1;
      }
      for (iy=0;iy<ny_els;++iy)
      {
         for (i=0;i<nx_pixels;++i) ibuf[i] = 0;
         for (iiy=0;iiy<nyp;++iiy)
         {
            i = lseek(fd, (long) (irec-1)*nxrasts,0);
            i = read (fd, buf, nxrasts);
            if (i!=nxrasts) goto tidy;
            if (order==5||order==7)
            {
               for (i=0,j=xo_pix-1;i<nx_pixels;++i,++j)
               {
                  ibuf[i] +=  (long) buf[j];
               }
            }
            else
            {
               for (i=0,j=nxrasts-xo_pix;i<nx_pixels;++i,--j)
               {
                  ibuf[i] += (long) buf[j];
               }
            }
            irec += rec_step;
         }
         xoff = 0;
         for (ix=0;ix<nx_els;++ix)
         {
            ival = 0;
            for (iix=0;iix<nxp;++iix)
            {
               ival += ibuf[xoff];
               xoff++;
            }
            ival = ival / (nxp*nyp);
            img[ioff] = (unsigned char) (ival);
            ioff++;
         }
      }
   }
   irec = 0;
      
   /* Tidy up */

   tidy:
   free (buf);
   free (ibuf);
   return irec;
}
/*
***********************
**     read_i2       **
***********************

Purpose: Read a 'i2' unsigned 16 bit integer format image file and return the
         image data in an array. The image may be compressed in the 'x'
         and 'y' directions. The file must be opened before this routine
         is called and it is not closed by this routine. The user may
         select the rectangular area of the image to be read. 

         Version of xdl_read_i2 (from XDL_VIEW) for filmps

Return:  =0 OK; >0 Record number where a read error occurred.

Author:  John Campbell, Nov 1991

*/

int read_i2 (fd, order, nxrasts, nyrasts, xo_pix, yo_pix, 
                 nx_pixels, ny_pixels, 
                 nxp, nyp, 
                 img, img_width, img_height, minval, maxval)

int fd;           /* The file descriptor of the opened 'i2' format 
                     file (R)*/
int order;        /* Order of the data in the input film image file
                     in terms of the xf, yf coordinate system as
                     a number from 1 to 8. (-order can be given to
                     byte swap the data as well as change the order)
                     1   +xf slow   +yf fast
                     2   +xf slow   -yf fast
                     3   -xf slow   +yf fast
                     4   -xf slow   -yf fast
                     5   +yf slow   +xf fast
                     6   +yf slow   -xf fast
                     7   -yf slow   +xf fast
                     8   -yf slow   -xf fast
                     (R)*/
int nxrasts;      /* The number of x-rasters (records) (R)*/
int nyrasts;      /* The number of y-rasters (pixels in a record) (R)*/
int xo_pix;       /* The x value of the required origin pixel (pixels 
                     numbered from 1 up). If this is less than 1 it 
                     will be reset to 1 and, if it is greater than the 
                     maximum x pixel number present, it will be set to 
                     the maximum x pixel number (R)*/
int yo_pix;       /* The y value of the required origin pixel (pixels 
                     numbered from 1 up). If this is less than 1 it 
                     will be reset to 1 and, if it is greater than the 
                     maximum y pixel number present, it will be set to 
                     the maximum y pixel number (R)*/
int nx_pixels;    /* The 'x' width of the image section to be read. 
                     If a value of less than 1 is given it will be 
                     reset to 1. If a value is given which takes the 
                     section beyond the image then it will be reset to
                     be within bounds (R)*/
int ny_pixels;    /* The 'y' height of the image section to be read. 
                     If a value of less than 1 is given it will be 
                     reset to 1. If a value is given which takes the 
                     section beyond the image then it will be reset to 
                     be within bounds (R)*/
int nxp;          /* The number of pixels in the 'x' direction to 
                     compress to 1 pixel (R)*/
int nyp;          /* The number of pixels in the 'y' direction to 
                     compress to 1 pixel (R)*/
unsigned short img[];/* Array returning the read image data; The pixels 
                     will have been compressed in 'x' and 'y' as 
                     requested. The values will be averaged over 
                     nxp*nyp pixels and will be in unsigned 16 bit 
                     integer format. The slower moving index in the 
                     returned data is y going from high y to low y and
                     the faster moving index is x going from low x to 
                     high x (W)*/
int * img_width;  /* Returns image width as a number of elements. 
                     Fastest moving index in 'img' (= x in i2 file). (W)*/
int * img_height; /* Returns image height as a number of elements. 
                     Slowest moving index in 'img' (= y in i2 file). (W)*/
int * minval;     /* Returns minimum pixel value in the portion of the
                     image read (W)*/
int * maxval;     /* Returns maximum pixel value in the portion of the
                     image read (W)*/

/* Note if nx (in the i2 file) is not a multiple of nxp then up to
   nxp-1 pixels may be lost from the high end of 'x' and similarly for
   ny and nyp. */
{
   int i,j,k,l;
   int ix, iix;
   int iy, iiy;
   int xoff, yoff;
   int nx, ny;
   unsigned short *buf;
   unsigned char *cbuf;
   unsigned char tempc;
   long *ibuf;
   long ival;
   int nx_els, ny_els;
   int irec;
   int ioff;
   int nr;
   int rec_step;
   int swap;

   /* Initialisations */

   swap = 0;
   if (order<0)
   {
      swap = 1;
      order = -order;
   }
   if (order<1||order>8) order = 1;
   if (nxp<1) nxp = 1;
   if (nyp<1) nyp = 1;
   if (xo_pix<1) xo_pix=1;
   if (yo_pix<1) yo_pix=1;
   if (nx_pixels<1) nx_pixels=1;
   if (ny_pixels<1) ny_pixels=1;

   nx = nxrasts;
   ny = nyrasts;

   /* Further checks on dimensions */

   if (xo_pix>nx) xo_pix = nx;
   if (yo_pix>ny) yo_pix = ny;
   if ((xo_pix+nx_pixels-1)>nx) nx_pixels = nx - xo_pix + 1;
   if ((yo_pix+ny_pixels-1)>ny) ny_pixels = ny - yo_pix + 1;

   /* Read data */

   nx_els = nx_pixels/nxp;
   *img_width = nx_els;
   ny_els = ny_pixels/nyp;
   *img_height = ny_els;
   *minval = 1000000;
   *maxval = 0;

   /* Compress image in xy */

   if (order<5) /*xf slow, yf fast*/
   {
      nr = nx_els * nxp;  
      buf = (unsigned short *) malloc (ny*sizeof(unsigned short));
      if (buf==0) return -1;
      cbuf = (unsigned char *) buf;
      ibuf = (long *) malloc (ny*sizeof(long));
      if (ibuf==0) return -1;
      if (order==1||order==2)
      {
         irec = xo_pix;
         rec_step = 1;
      }
      else
      {
         irec = nxrasts + 1 - xo_pix;
         rec_step = -1;
      }
      for (ix=0;ix<nx_els;++ix)
      {
         for (i=0;i<ny_pixels;++i) ibuf[i] = 0;
         for (iix=0;iix<nxp;++iix)
         {
            i = lseek(fd, (long) (irec-1)*2*nyrasts,0);
            i = read (fd, buf, 2*nyrasts);
            if (i!=2*nyrasts) goto tidy;
            if (swap)
            {
               l=0;
               for (k=0;k<nyrasts;++k)
               {
                   tempc = cbuf[l];
                   cbuf[l] = cbuf[l+1];
                   cbuf[l+1] = tempc;
                   l += 2;
               }
            }
            if (order==1||order==3)
            {
               for (i=ny_pixels-1,j=yo_pix-1;i>=0;--i,++j)
               {
                  ibuf[i] +=  (long) buf[j];
                  if (buf[j]>*maxval) *maxval = buf[j];
                  if (buf[j]<*minval) *minval = buf[j];
               }
            }
            else
            {
               for (i=0,j=nyrasts+1-ny_pixels-yo_pix;i<ny_pixels;++i,++j)
               {
                  ibuf[i] += (long) buf[j];
                  if (buf[j]>*maxval) *maxval = buf[j];
                  if (buf[j]<*minval) *minval = buf[j];
               }
            }
            irec += rec_step;
         }
         yoff = 0;
         for (iy=0;iy<ny_els;++iy)
         {
            ival = 0;
            for (iiy=0;iiy<nyp;++iiy)
            {
               ival += ibuf[yoff];
               yoff++;
            }
            ival = ival / (nxp*nyp);
            img[iy*nx_els+ix] = (unsigned short) (ival);
         }
      }
   }
   else  /*yf slow, xf fast*/
   {
      nr = ny_els * nyp;  
      buf = (unsigned short *) malloc (nx*sizeof(unsigned short));
      if (buf==0) return -1;
      cbuf = (unsigned char *) buf;
      ibuf = (long *) malloc (nx*sizeof(long));
      if (ibuf==0) return -1;
      ioff = 0;
      if (order==5||order==6)
      {
         irec = nyrasts + 1 - yo_pix;
         rec_step = -1;
      }
      else
      {
         irec = yo_pix;
         rec_step = 1;
      }
      for (iy=0;iy<ny_els;++iy)
      {
         for (i=0;i<nx_pixels;++i) ibuf[i] = 0;
         for (iiy=0;iiy<nyp;++iiy)
         {
            i = lseek(fd, (long) (irec-1)*2*nxrasts,0);
            i = read (fd, buf, 2*nxrasts);
            if (i!=2*nxrasts) goto tidy;
            if (swap)
            {
               l=0;
               for (k=0;k<nxrasts;++k)
               {
                   tempc = cbuf[l];
                   cbuf[l] = cbuf[l+1];
                   cbuf[l+1] = tempc;
                   l += 2;
               }
            }
            if (order==5||order==7)
            {
               for (i=0,j=xo_pix-1;i<nx_pixels;++i,++j)
               {
                  ibuf[i] +=  (long) buf[j];
                  if (buf[j]>*maxval) *maxval = buf[j];
                  if (buf[j]<*minval) *minval = buf[j];
               }
            }
            else
            {
               for (i=0,j=nxrasts-xo_pix;i<nx_pixels;++i,--j)
               {
                  ibuf[i] += (long) buf[j];
                  if (buf[j]>*maxval) *maxval = buf[j];
                  if (buf[j]<*minval) *minval = buf[j];
               }
            }
            irec += rec_step;
         }
         xoff = 0;
         for (ix=0;ix<nx_els;++ix)
         {
            ival = 0;
            for (iix=0;iix<nxp;++iix)
            {
               ival += ibuf[xoff];
               xoff++;
            }
            ival = ival / (nxp*nyp);
            img[ioff] = (unsigned short) (ival);
            ioff++;
         }
      }
   }
   irec = 0;
      
   /* Tidy up */

   tidy:
   free (buf);
   free (ibuf);
   return irec;
}
