From: honig@ruffles.ICS.UCI.EDU ("David A. Honig")
Newsgroups: alt.internet.services
Subject: Consuming transistors....Digital Weather Animation
Date: 30 Sep 92 19:19:37 GMT



Someone cc'd me some recent queries on this net.group re
weather animation.

I hope some of you find the following useful.  Heed the warning
though or may cosmic rays mess with your hard disk.

DH

..................................................
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 */