/***********************************************************************/
/* assembleppm.c                                                       */
/*                                                                     */
/* Combine a series of ppm files from POVRAY into a single PPM image.  */
/* Assume the files each represent consecutive row chunks as generated */
/* by POVRAY.  Individually, these are invalid PPM images, because     */
/* POVRAY puts the total image size (not the size of a chunk) in the   */
/* header when rendering an image by pieces.                           */
/*                                                                     */
/* On the command line, this utility expects a list of filenames like  */
/* "chunk.700.ppm" where 700 is the position of the chunk in the final */
/* image (the y coordinate of the first row in the file).  The first   */
/* contiguous block of digits in the filename is parsed to give the    */
/* row number.                                                         */
/*                                                                     */
/* Based on 'combineppm.c'                                             */
/* by Paul Bourke                                                      */
/*   http://local.wasp.uwa.edu.au/~pbourke/                            */
/*   paul.bourke@uwa.edu.au                                            */
/*                                                                     */
/* modified by David Dumas                                             */
/*   http://www.math.brown.edu/~ddumas/                                */
/*   daviddumas@gmail.com)                                             */
/*                                                                     */
/* January 2007                                                        */
/***********************************************************************/

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#include "ctype.h"

int getrow(char *inputname)
{
  char name[256];
  char *p = name;
  char *q;
  strncpy(name,inputname,256);
  name[255] = '\0';

  while (!isdigit((int)(*p)) && (*p != '\0'))
    p++;
  if ((*p) == '\0')
    return 0;
  q = p;
  while (isdigit((int)(*p)) && (*p != '\0'))
    p++;
  *p = '\0';
  return(atoi(q));
}


int main(int argc,char **argv)
{
	int i,j,c,file,w,h;
	int height=0,width=0,bits;
	int filenum = 0;
	FILE *fptr;
	char header[32];
	char *buf = NULL, *cur;
	size_t offset;
	size_t nfile=0L, ntotal=0L;

	if (argc < 2) {
		fprintf(stderr,"Usage: %s FILE1 FILE2 ... \n",argv[0]);
		exit(-1);
	}

	for (filenum=1;filenum<argc;filenum++) {
		fprintf(stderr,"Reading \"%s\"\n",argv[filenum]);

		fprintf(stderr,"\t+%d rows\n",getrow(argv[filenum]));

		/* Read the header */
		if ((fptr = fopen(argv[filenum],"r")) == NULL) {
			fprintf(stderr,"\tFailed to read \"%s\"\n",argv[filenum]);
			/* break; */
			continue;
		}
		if (fscanf(fptr,"%s",header) != 1 || strstr(header,"P6") == NULL) {
			fprintf(stderr,"\tUnexpected header in \"%s\"\n",argv[filenum]);
			/*exit(-1); */
			continue;
		}
/* 		fprintf(stderr,"\tPPM magic\n"); */

		/* Read the width and height */
		if (fscanf(fptr,"%d %d",&w,&h) != 2) {
		  fprintf(stderr,"\tUnexpected height and width in \"%s\"\n",argv[filenum]);
		  /*exit(-1); */
		  continue;
		}
		if (width == 0)
			width = w;
		if (width != w) {
			fprintf(stderr,"\tBad image width!\n");
			/*exit(-1);*/
			continue;
		}
		if (height == 0)
			height = h;
		if (height != h) {
			fprintf(stderr,"\tBad image height!\n");
			/*exit(-1);*/
			continue;
		}

		if (buf == NULL) {
		  buf = calloc(3L * (size_t)height * (size_t)width,(size_t)1);
		  if (buf == NULL) {
		    fprintf(stderr,"Could not allocate buffer.");
		    exit(-1);
		  }
		}
		
		/* Read the number of bits per pixel */
		if (fscanf(fptr,"%d",&bits) != 1 || bits != 255) {
			fprintf(stderr,"\tUnexpected number of bits in \"%s\"\n",argv[filenum]);
			/*exit(-1); */
			continue;
		}
/* 		fprintf(stderr,"\t24bpp\n"); */

		/* Skip to the binary data */
		while ((c = fgetc(fptr)) != '\n' && c != EOF)
		  ;
		
		nfile = 0L;
		offset = 3L * (size_t)width * (size_t)(getrow(argv[filenum]) - 1);
		cur = buf + offset;
		/* Write the binary for the all the files */
		while ((c = fgetc(fptr)) != EOF) {
		  *cur = (char)c;
		  cur++;
		  nfile++;
		}
		ntotal += nfile;
		fprintf(stderr,"\t%lu bytes = %lu rows\n",nfile,(nfile / (3L*(size_t)width)));

		fclose(fptr);
	}

	fprintf(stderr,"\nWriting output.\n");
	/* Write the header for the first file */
	printf("P6\n");
	printf("%d %d\n255\n",width,height);
	for (offset = 0; offset < (3L * (size_t)height * (size_t)width); offset++)
	  putc(buf[offset],stdout);

	fprintf(stderr,"Read %lu bytes = %lu rows = %2.1f%%.\n",ntotal,(ntotal / (3L*(size_t)width)),100.0 * (float)ntotal / (float)(3L*(size_t)width*(size_t)height));
}


