From: honig@ruffles.ICS.UCI.EDU ("David A. Honig")
Subject: Animated Weather --- animating a bunch of .gifs
Newsgroups: comp.graphics.animation
Date: 1 Oct 92 01:25:36 GMT



Clouds, Iclouds Distribution File

30 Sept 92

(c) 1992 David Honig	[Copying OK iff this copyright retained.]
honig@ics.uci.edu   	(reply not guarenteed, I'm busy)


Clouds is a script that ftps the weather satellite GIFs from a computer
in the midwest, turns them into a greyscale movie, and animates them.
The animation requires that you have compiled my X program, "mov".
The script also uses ftp, giftoppm, tail, head, delete.
You must have a greyscale X display.

DON'T RUN THIS DURING REGULAR HOURS AS IT USES WAY TOO MUCH NET BANDWIDTH
AND ABUSES THE HOST WITH THE IMAGES.

Thanks to "James N. Stricherz - stricher@masig3.ocean.fsu.edu"
for public domain code that I altered.

--------------------------------------------------


Put the "clouds" cshell script in a file called "clouds", editing
out the rest of this text.  Then "chmod +x clouds".

Put the mov.c program into a file, "mov.c", editing out the
rest of this file.  Then compile the program with
"cc mov.c -lm -lX11 -o mov"

And put the executable "mov" in a place where it can be executed by
the clouds script.  The directory containing "clouds" or your personal
bin/ directory are fine, as long as they are in your normal path.

Make sure your $DISPLAY variable is correct.

Type "clouds &" and wait a while.


..............................cut here....................
#!/bin/csh -f

echo Weather Animation Script  v1.0
# (c) 1992 David Honig
# Uses: ftp, mov, giftoppm, tail, head, delete
# 14 Sept 92
# Use either CV for visual bands or CI for IR bands

set BAND="CV"
# set BAND="CI"

set getftp=1
set display=1
set compress=1
set rm_movie=1
set rm_gif=1
set rm_pgm=1

set noglob
set getfiles=$BAND*.GIF

# define names for weather movie
set moviefile="wmovie"
set msizefile="wmovie_size"
set host=vmd.cso.uiuc.edu

# ftp GIFs
if ( $getftp == 1 ) then
	echo Will ftp new $getfiles
      echo "user anonymous anonymous@host.host.edu  \
      binary \
      cd wx \
      mget $getfiles \
      quit " | ftp -n -v -i $host  > /dev/null

echo Got GIFs

unset noglob


# now make movie from .GIFs

# erase old moviefile
echo -n "" >! $moviefile

# erase old size file
if ( -e $msizefile ) then
	/bin/rm $msizefile
endif


# turn each GIF into frame of movie
set count=0
foreach FILE ( `ls $BAND??????.GIF` )
	# if haven't gotten size yet..
	if ( ! -e $msizefile ) 	then
		set firstname = $FILE
		giftoppm $FILE | ppmtopgm >! $FILE.pgm
		if ( $rm_gif == 1) /bin/rm $FILE
		head -3 $FILE.pgm | tail -2 | head -1 >! $msizefile
		tail +4 $FILE.pgm >> $moviefile
		if ( $rm_pgm == 1) /bin/rm $FILE.pgm
	# else just directly go from gif to raw w/out saving pgm in file.
	else
		giftoppm $FILE | ppmtopgm | tail +4 >> $moviefile
		if ( $rm_gif == 1 ) /bin/rm $FILE
	endif

	@ count += 1
end

echo Got $count .GIFs

endif


set wid = ` awk -  ' { print $1 } ' < $msizefile `
set ht = ` awk -  ' { print $2 } ' < $msizefile `

# display movie
if ( $display == 1 ) then
	echo Displaying..
	mov -w $wid -h $ht -r 10 < $moviefile  > /dev/null &
endif

if ( $compress == 1 ) then
	echo Compressing, making $firstname.jpg
	set mht = $ht
	@ mht *= $count

	echo P5 >! $moviefile.pgm
	echo $wid $mht >> $moviefile.pgm
	echo 255 >> $moviefile.pgm
	cat $moviefile >> $moviefile.pgm
	cjpeg -Q 50 $moviefile.pgm >! $firstname.jpg ; /bin/rm $moviefile.pgm &
endif

if ( $rm_movie == 1 ) then
	echo Deleting $moviefile
	/bin/rm $moviefile
endif


echo Done.

..................................................


Here is mov.c

..............................cut here....................


/* add: < > keys sequence single frames */

/* "xmov" Portable X b/w movie viewer */

/* (c) 1992 David Honig	*/
/* 26 Aug 92 */
/* Permission to propogate is granted if you keep the copyright and
always disseminate the source as well. */


/*

Function:
  Display a headerless greyscale movie on an X display.


Compilation:
  cc mov.c -lX11 -lm -o mov
 (This is pure XLIB code)


Usage:
   mov < movie.raw [options]

   Options:
   -w WIDTH
   -h HEIGHT
   -s SIZE (width=height=size)
   -r FRAMERATE (fps)
   -c CACHESIZE (pixmaps to get on the server; must be less than MAXMAPS)
   -g GAMMA (float)
   -b BIAS
   -d debug mode
   -n no numbers
   -l seesaw looping

Defaults:
   256 x 256 image, 30 cached, 30 fps, gamma=1.0, bias=0


Requires:
   X, 8-bit screen, width*height*CACHESIZE bytes of server memory




Notes on IMAGE FORMATS:

A .pgm is obtained from a raw headerless file with
        rawtopgm WIDTH HEIGHT filename > file.pgm

(If you fake the "HEIGHT" to be  real_height * frame_count,
it will work.)



You can look at the (ascii) header of a .pgm image:
        head -3 file.pgm
(The second line contains "width height".)


The .pgm file can be compressed:
        cjpeg -Q 70 -o file.pgm > file.jpg


A raw movie is obtained from a .pgm by running:
	tail +4 movie.pgm > movie.raw
	(though this step isn't really necessary)


A jpeg'd .pgm movie could be decompressed, stripped of its header, and
viewed thusly:
        djpeg file.jpg | tail + 4 | mov -w width -h height





MOV Design Notes:
* Dynamically allocate one frame buffer to read.
* Turn buffer into XImage.  (Display this as they're loaded.)
* Make pixmaps (on machine running the display) from XImages (which are on
the client-side).
* Loop through pixmaps.



*/







#include <stdio.h>
#include <X11/Xlib.h>





/* MAX NO. OF PIXMAPS TO TRY FOR */
#define MAXIMS	60
#define MAXMAPS	(MAXIMS*2)

/* INTERFRAME TIME */
#define DELAY	40000
#define XIM_DELAY 250000

#define LUTMAX  256

#define streq(a,b)        ( ! (strcmp(a,b)))





char *authstring=    "Mov 0.6  [9 Sept 92]   (c) 1992 David A. Honig ";
char temps[10];



Display *disp;
Window win;
GC	gc;
Colormap cm;
XEvent xev;


XImage *xi;
Pixmap pm[MAXMAPS];






int width,height;
int cached;
int delay;
int debug;
double gamma,bias;
int addnums;
int seesaw;
int frame;

unsigned char *buff = NULL;






main(argc,argv)
     int argc;
     char **argv;
{  register i,nc,count=0, nmaps;
   int loopok;

   handle_flags(argc,argv);

   print_stuff();

   open_disp();


   if (cached > MAXMAPS) nmaps=MAXMAPS; else nmaps=cached;
   /* MAKE PIXMAPS */
   for (i=0; i<nmaps;i++)
     {pm[i]=XCreatePixmap(disp,win,width,height,8);
      if (debug) fprintf(stderr,"Made pixmap %d\n",i);
    }

   if (debug) fprintf(stderr,"Made %d pms\n",cached);


   /* get fread buffer, size of one frame */
   if ( (buff= (unsigned char *) memalign(4,width*height)) == NULL)
     {fprintf(stderr,"couldn't get read buffer\n");
      exit(0);
    }

   if (debug) fprintf(stderr,"Got read buffer\n");

   /* CREATE AN XIMAGE */
   xi=XCreateImage(disp,DefaultVisual(disp,0),8,ZPixmap,0,
		   buff,width,height,0,width);

   if (debug) fprintf(stderr,"Made XImage\n");

   memset(buff,128,width*height);

   XPutImage(disp,win,gc,xi, 0,0, 0,0, width,height);
   XDrawString(disp,win,gc,32,height/2, authstring, strlen(authstring));
   XFlush(disp);

   usleep(XIM_DELAY);

   /* draw test pattern in pixmap, display */
   for (i=0; i<250; i++) {
     XSetForeground(disp,gc, i);
     XDrawLine(disp,pm[0],gc, 0,i,width,i);
   }

   XCopyArea(disp,pm[0],win,gc,0,0,width,height,0,0);
   XDrawString(disp,win,gc,32,height/2, authstring, strlen(authstring));
   XFlush(disp);

   usleep(XIM_DELAY);

   if (debug) fprintf(stderr,"Displayed pm \n");


   nc=1;
   while(nc)  /* loop til eof */
     {
       for (i=0; i<cached;i++)     /* for each pixmap */
	 {
	   nc=fread(buff,1,height*width,stdin);   /* read a frame */

	   fprintf(stderr,"read #%d %d\n",count, nc);	/* report progress */

	   if ( (nc < height*width) )             /* if eof, break */
	     {if (count<cached) cached=i;
	      break;}

	   /* THIS LINE WORKS FOR xim -> win, BUT BETTER TO USE PIXMAPS  */
	   XPutImage(disp,win,gc,xi, 0,0, 0,0, width,height);   /* show it */


	   /* MAKE PIXMAPS FROM XIMS */
	   XPutImage(disp,pm[i],gc,xi, 0,0, 0,0, width,height);

	   /* add numbers */
	if ( addnums )
		{
	   sprintf(temps,"%3d",count++);
	   XDrawString(disp,pm[i],gc,0,32,temps,strlen(temps));
		}
	 }
       /* done making cache pixmaps */


       /* NOW LOOP THROUGH PIXMAPS */
       for (i=0; i<cached;i++)
	 {
	   show(i);
	 }
     }


   fprintf(stderr,"Done loading. %d\n",cached);

loopok=1;
   while(1)
     {if (loopok)
	{for (frame=0; frame<cached;frame++) 	    {	show(frame);     }
	  if (seesaw)
	    {for (frame=cached-2; frame>0 ;frame--)     {show(frame);  	      }
	    }
	}
      check_quit(&loopok);
    }
 }






show(i)
{
  XCopyArea(disp,pm[i],win,gc,0,0,width,height,0,0);
  XFlush(disp);
  usleep(delay);
}







handle_flags(argc,argv)
int argc;
char **argv;
{
int i, recognized;
double atof();

 width=256;
 height=256;
 delay=DELAY;
 gamma=1.0;
 bias=0.;
 cached= -1;
 debug=0;
 addnums=1;
seesaw=0;

/* scan through cmd-line args */
for (i=1; i<argc; i++)
  {recognized=0;

   /*	if (streq(argv[i],"-?") |  streq(argv[i],"help") )
	{printhelp();
	recognized=1;
	}
	*/

   if (streq(argv[i],"-d"))
     {debug=1;
      recognized=1;
    }


   if (streq(argv[i],"-n"))
     {addnums=0;
      recognized=1;
    }

   if (streq(argv[i],"-l"))
     {seesaw=1;
      recognized=1;
    }



   if (streq(argv[i],"-g"))
     {gamma=atof(argv[++i]);
      recognized=1;
    }

   if (streq(argv[i],"-b"))
     {bias=atof(argv[++i]);
      recognized=1;
    }


   if (streq(argv[i],"-s"))
     {width=height=atoi(argv[++i]);
   		recognized=1;
    }


   if (streq(argv[i],"-w"))
     {width=atoi(argv[++i]);
      recognized=1;
    }


   if (streq(argv[i],"-h"))
     {height=atoi(argv[++i]);
      recognized=1;
    }


   if (streq(argv[i],"-c"))
     {cached=atoi(argv[++i]);
      recognized=1;
    }

   if (streq(argv[i],"-r"))
     {delay=1000000/atoi(argv[++i]);
      recognized=1;
    }


   if (! recognized)
     {fprintf(stderr,"Command-line option %s not recognized! ",
	      argv[i]);
    }
 }

if (cached<0)   /* if not user set */
  {cached=(256*256*MAXIMS)/(width*height);
 }
}




open_disp()
{long mask;

 disp=XOpenDisplay(NULL);

 if (DisplayPlanes(disp,0) < 8)
 {
  fprintf(stderr, "Mov: Error: Must use an 8-bit or better display.\n");
  exit(0);
 }

else if (debug) {fprintf(stderr, "Opened Display\n");}


 win=XCreateSimpleWindow(disp,DefaultRootWindow(disp),
     0,0, width, height, 2,2,BlackPixel(disp,0));

mask=KeyPressMask | KeyReleaseMask /*  | ButtonPressMask */ ;

XSelectInput(disp,/*DefaultRootWindow(disp)*/ win,mask);

 XMapWindow(disp,win);
 XFlush(disp);

 init_colors();

}






init_colors()
{
 register i,j;
 long int mask, npl,np,pix,masks;
 XGCValues values;
 XColor xc;
 int stat;
double pow(), v;

/* create and init gc */
 values.function=GXcopy;
 masks=0;

 gc=XCreateGC(disp, win, masks, &values);

 XCopyGC(disp,DefaultGC(disp,0), !0, gc);

 XSetForeground(disp, gc, WhitePixel(disp, 0));
 XSetBackground(disp, gc, BlackPixel(disp, 0));


/* create and init colormap */
 cm=XCreateColormap(disp,win, DefaultVisual(disp,0), AllocAll);

 npl=8;
 np=LUTMAX;
 pix=LUTMAX;
 masks=255;
 XAllocColorCells(disp,cm,1, &masks, npl, &pix, np);


 xc.flags=DoRed | DoGreen | DoBlue;

 for (i=256-LUTMAX; i<LUTMAX; i++)
 {v=(double) i;
  v=v/255.0;
  v=pow(v,gamma);
  v=v*255.0;
  v=v+bias;
  j=(int) v;

  if (j>255) j=255;
  else if (j<0) j=0;

  xc.red=xc.green=xc.blue= (j<<8);
  xc.pixel=i;

  XAllocColor(disp,cm,&xc);
  XStoreColor(disp,cm, &xc);
 }

 XSetWindowColormap(disp,win,cm);
 XFlush(disp);

 XSetForeground(disp, gc, WhitePixel(disp, 0));
 XSetBackground(disp, gc, BlackPixel(disp, 0));


}


print_stuff()
{
 fprintf(stderr, "\n\n");
 fprintf(stderr, "%s\n",authstring);

 fprintf(stderr, "Type \"q\" in window to quit when done loading.\n");
 fprintf(stderr, "MAXIMS: %d \n",cached);
 fprintf(stderr, "Size: %d x %d \n",width,height);
 fprintf(stderr, "Gamma: %f  Bias: %f \n",gamma,bias);
 fprintf(stderr, "Debugging: %d\n",debug);

}




check_quit(i)
int *i;
{

 while(XPending(disp))
   {XNextEvent(disp,&xev);
    if (xev.type == KeyPress)
      {
	/*printf("%d %d %d\n",xev.type, xev.keycode, XKeysymToKeycode(disp, 'q'));*/

      if (xev.keycode == XKeysymToKeycode(disp, 'q'))
	{printf("Quitting.\n");
	 exit(0);}

      if (xev.keycode == XKeysymToKeycode(disp, 's'))
	{printf("Stopping.\n");
	 *i=0;}

      if (xev.keycode == XKeysymToKeycode(disp, '.'))
	{frame++;
	 if (frame>=cached) frame=cached-1;
	 show(frame);
	 }

      if (xev.keycode == XKeysymToKeycode(disp, ','))
	{frame--;
	 if (frame<0) frame=0;
	 show(frame);
	 }



    }
  }
}


/* eof */