


/* Copyright (c) 1991, 1992 Cornell University.  All Rights Reserved.
 *
 * Use, reproduction and preparation of derivative works of this software is
 * permitted.  Any copy of this software or of any derivative work must
 * include both the above copyright notices of Cornell University and this
 * paragraph.  This software is made available AS IS, and Cornell University
 * disclaims all warranties, express or implied.
 */


/* PTLTOPNM.C ---  Convert a (C)PTL file to either PBM or PPM.  See usage below.*/
/* Written by Greg Klanderman, Spring 1991.  Updated Fall 1992 */


#include <stdio.h>
#include <ctype.h>
#include <math.h>

#include "clarg.h"
#include "image.h"
#include "ptl.h"
#include "magic.h"
#include "string-support.h"


static char *USAGE =  
  "\n%s:    Convert a pointlist (PTL or CPTL) to a PBM or PPM file.\n"
  "\n"
  "   Command line arguments:\n"
  "     -input file:         Specify the input file (PTL or CPTL)\n"
  "     -output file:        Specify the output file (PBM or PPM)\n"
  "     -scale sx [sy]:      Specify x and y scales (float)\n"
  "     -pbm <or> -binary:   Force PBM output\n"
  "     -ppm <or> -color:    Force PPM output. Optional argument\n"
  "                          specifies the background color.\n"
  "\n"
  "If no input file is specified, input is from stdin, and if no output file\n"
  "is specified, output is to stdout.  If no scales are specified, no scaling\n"
  "is performed.  If only one scale is specified, it is used  for both x and y.\n"
  "By default, the output is PPM when the intput is a CPTL file and PBM when the\n"
  "input is a PTL file, but these defaults may be overridden.  Argument names\n"
  "may be abbreviated.\n"
  "\n"
  "Point list (PTL and CPTL) files consist of a header followed by a list of\n"
  "points and line segments, one per line.  The header contains either the\n"
  "\"magic\" string \"PTL\", indicating a regular point list file, or the\n"
  "\"magic\" string \"CPTL\", indicating a color point list file.  This\n"
  "string is followed by four numbers, XBASE, YBASE, WIDTH, and HEIGHT\n"
  "indicating the area in which the points and lines should be plotted.\n"
  "After this header line, blank lines and comment lines (which start with\n"
  "a \"#\") may appear interspersed with lines specifying points or line\n"
  "segments.\n"
  "\n"
  "Lines specifying points are of the form:\n"
  "        \"<weight> p <x> <y>\"           for PTL files, or\n"
  "        \"<weight> p <x> <y> <color>\"   for CPTL files.\n"
  "\n"
  "Lines specifying line segments are of the form:\n"
  "        \"<weight> l <x1> <y1> <x2> <y2>\"           for PTL files, or\n"
  "        \"<weight> l <x1> <y1> <x2> <y2> <color>\"   for CPTL files.\n"
  "\n"
  "Colors are specified by 24-bit integers (in hex, decimal, or octal); bits\n"
  "23..16 give the red intensity, bits 15..8 give the green intensity, and\n"
  "bits 7..0 give the blue intensity.  The point and line weights are optional;\n"
  "if not specified, a weight of 0 is used, giving \"thin\" points and lines.\n"
  "All X and Y coordinates and weights may be real numbers.\n\n"
  "Weights are implemented in a very losing and slow way.\n\n";


#define INPUT	 "i.nput"
#define OUTPUT   "o.utput"
#define SCALE    "s.cale"
#define PBM      "pb.m"
#define BINARY   "b.inary"
#define PPM      "pp.m"
#define COLOR    "c.olor"


static CLINIT clinit[] = {{INPUT,  1, 1, NULL,    0},
			  {OUTPUT, 1, 1, NULL,    0},
			  {SCALE,  1, 2, cl_real, 0},
			  {PBM,    0, 0, NULL,    0},
			  {BINARY, 0, 0, NULL,    0},
			  {PPM,    0, 1, NULL,    0},
			  {COLOR,  0, 1, NULL,    0},
			  {NULL,   1, 1, NULL,    0}};

static char *depend[] = {"("PBM"|"BINARY")+("PPM"|"COLOR") <= 1",
			 "!(UNNAMED && "INPUT")",
			 NULL};




int main(int argc, char **argv, char **envp)
{
  float sx, sy;
  RGB background;
  ImageType type = (ImageType) 0;
  String magic = NULL;
  FILE *fp;
  boolean iscolor;
  char *infile;
  AnyImage img;
  boolean warn;
  

  if (cl_init(argc, argv, envp, clinit, depend, USAGE, CL_NORESTRICT))
    return 0;

  infile = (cl_opt(INPUT)
	    ? cl_arg1(INPUT)
	    : cl_opt(CL_UNNAMED) ? cl_arg1(CL_UNNAMED) : NULL);

  sx = sy = 1.0;

  if (cl_opt(SCALE)) {			/* get the scales */
    if (cl_numarg(SCALE) == 1)    /* only one specified => use for both */
      sx = sy = atof(cl_arg1(SCALE));
    else    	  			/* 2 scales were specified */
      sx = atof(cl_arg1(SCALE)), sy = atof(cl_arg2(SCALE));
  }

  if ((fp = infile ? fopen(infile, "r") : stdin) == (FILE *) NULL) {
    fprintf(stderr, "PTLTOPNM: Error opening input\n");
    return 1;
  }
  
  if (magicStart()                   ||
      magicGetString(fp, &magic)     ||
      (!strcmp(strGet(magic), "PTL")  &&  !strcmp(strGet(magic), "CPTL"))) {
    fprintf(stderr, "PTLTOPNM: Error reading input\n");
    return 1;
  }

  iscolor = !strcmp(strGet(magic), "CPTL");

  background = ((RGB) {r: 0, g: 0, b:0}); /* default backgound */

  if (cl_opt(PBM)  ||  cl_opt(BINARY)) {
    type = IMAGE_BINARY;
  }
  else if (cl_opt(PPM)) {
    type = IMAGE_RGB;
    if (cl_numarg(PPM) > 0) {
      uint bkcolor;
      sscanf(cl_arg1(PPM), "%i", &bkcolor);
      background = ((RGB) {r: (bkcolor >> 16) & 0xFF,
			   g: (bkcolor >> 8) & 0xFF,
			   b: (bkcolor & 0xFF)});
    }
  }
  else if (cl_opt(COLOR)) {
    type = IMAGE_RGB;
    if (cl_numarg(COLOR) > 0) {
      uint bkcolor;
      sscanf(cl_arg1(COLOR), "%i", &bkcolor);
      background = ((RGB) {r: (bkcolor >> 16) & 0xFF,
			   g: (bkcolor >> 8) & 0xFF,
			   b: (bkcolor & 0xFF)});
    }
  }
  else {
    type = iscolor ? IMAGE_RGB : IMAGE_BINARY;
  }

  img = (AnyImage) ptlLoadAndRender(fp, iscolor, type, sx, sy, background, &warn);

  if (img == (AnyImage) NULL) {
    fprintf(stderr, "PTLTOPNM:  Error reading and rendering point list\n");
    return 1;
  }

  if (warn) {
    fprintf(stderr, "PTLTOPNM: Some points may not have been plotted\n");
  }

  { String old_doc = imDocString(img);
    imDocString(img) = strNewComment(argc, argv, envp, imDocString(img), NULLSTRING);
    strFree(old_doc);
  }
  
  if (imSave(img, cl_opt(OUTPUT) ? cl_arg1(OUTPUT) : NULL)) {
    fprintf(stderr, "PTLTOPNM: Error writing output image\n");
    return 1;
  }

  imFree(img);
  
  if (infile) {
    fclose(fp);
  }

  return 0;
}

