moonphase2avi



#!/usr/bin/env perl
# moonphase2avi - Creates a moon-phase AVI or an animated GIF
# License:  Creative Commons Attribution-NonCommercial-ShareAlike 2.5
# Revision: 070909

#---------------------------------------------------------------------
#                         license information
#---------------------------------------------------------------------

# This section may not be modified except as approved by the author or
# licensor, or to make non-content changes such as adjustments to par-
# agraph formatting or white space.

# This  version of this software is  distributed  under  the following
# license:
#
#       Creative Commons Attribution-NonCommercial-ShareAlike 2.5

# You may use, modify, and redistribute this software without fees  or
# royalties, but only under the terms and conditions set forth  by the
# license.  In particular, copies and derived works cannot be used for
# commercial purposes.  Additionally, the license propagates to copies
# and derived works. Furthermore, you must provide attribution "in the
# manner  specified  by the  author or licensor".  The latter point is
# discussed below.

# The author [and licensor] hereby specifies that  attribution must be
# handled in the following manner:  a. If the software is interactive,
# any  About or Credits dialog boxes, windows, or output text provided
# by the  original version must be preserved and readily accessible to
# the end user at runtime.  b. If the software is non-interactive,  or
# if it does not  provide  About or Credits dialog boxes, windows,  or
# output text,  the  operating system and/or  desktop environment used
# must provide attribution that is  visible and/or  readily accessible
# to the end user at runtime.

# The following techniques  do not meet the  attribution requirements:
# Attribution through text  files, attribution  through  printed docu-
# mentation,  verbal  attribution, or postings on  external  web sites
# [i.e.,  web  sites  that are not an intrinsic local component of the
# operating system or  desktop environment used].  These  examples are
# provided for illustrative purposes only.

# It should be noted that trademarks are an additional issue.  If this
# software  uses any  trademarks,  trademark-related  restrictions may
# apply.

# This is not a  complete explanation of the  terms and conditions in-
# volved.  For more information, see the Creative Commons Attribution-
# NonCommercial-ShareAlike 2.5 license.

#---------------------------------------------------------------------
#                           important note
#---------------------------------------------------------------------

# This program is  provided on an  AS IS basis with ABSOLUTELY NO WAR-
# RANTY. The entire risk as to the quality and performance of the pro-
# gram is with you. Should the program prove defective, you assume the
# cost of all necessary  servicing, repair or correction.  In no event
# will any of the developers, or any other party,  be liable to anyone
# for damages arising out of  use of the program,  or inability to use
# the program.

#---------------------------------------------------------------------
#                              overview
#---------------------------------------------------------------------

                                # "END" must be single-quoted here
my $DOCUMENTATION = << "END_OF_DOCUMENTATION";

__META_PROGNAME__ rev. __META_REVISION__
- Creates a moon-phase video clip

Usage:  moonphase2avi --avi         # Make high-quality AVI
        moonphase2avi --gif         # Make animated GIF instead
        moonphase2avi --needs       # List software requirements
        moonphase2avi --license     # Show license information

"--avi" creates  an  AVI file  named "moonphase.avi" that displays one
month in the life of  the Moon.  The AVI file is MPEG4-encoded. You'll
need  write  access to  the  current directory and  about 8 MB of disk
space. However, the AVI file is only about 210 KB in size.

"--gif" is similar, but  it  creates  a  low-resolution  animated  GIF
instead of an AVI.

For software requirements or license information, specify "--needs" or
"--license".

END_OF_DOCUMENTATION

#---------------------------------------------------------------------
#                        standard module setup
#---------------------------------------------------------------------

require 5.6.1;
use strict;
use Carp;
use warnings;
                                # Trap warnings
$SIG {__WARN__} = sub { die @_; };

#---------------------------------------------------------------------
#                           basic constants
#---------------------------------------------------------------------

use constant ZERO  => 0;        # Zero
use constant ONE   => 1;        # One
use constant TWO   => 2;        # Two

use constant FALSE => 0;        # Boolean FALSE
use constant TRUE  => 1;        # Boolean TRUE

#---------------------------------------------------------------------
#                         program parameters
#---------------------------------------------------------------------

my $PROGNAME = 'moonphase2avi'; # Program name [should be one word]
my $REVISION = '070909';        # Revision string

#---------------------------------------------------------------------

# AVI-file parameters:

my $AVI_FPS       =  20;        # Frames per second [10 to 30]
my $AVI_NUMFRAMES = 200;        # No. of frames [100 to 300]
                                # Output    -file name
my $AVI_OFNAME    = 'moonphase.avi';
                                # Temporary -file name
my $AVI_TFNAME    = "temp$$.tmp";
my $AVI_WIDTH     = 320;        # Image width [in pixels]

#---------------------------------------------------------------------

# GIF-file parameters:

my $GIF_FPS       =  10;        # Frames per second [10 to 30]
my $GIF_NUMFRAMES = 150;        # No. of frames [100 to 300]
                                # Output    -file name
my $GIF_OFNAME    = 'moonphase.gif';
                                # Temporary -file name
my $GIF_TFNAME    = "temp$$.gif";
my $GIF_WIDTH     = 120;        # Image width [in pixels]

my $IGNUMCOLORS   =  28;        # Max no. of colors in final GIF file

#---------------------------------------------------------------------
#                            main routine
#---------------------------------------------------------------------

sub Main
{
    my $cmd;                    # Shell-level command string
    my $cmderr  = FALSE;        # Flag: Command-line error
    my $is_avi  = TRUE;         # Flag: Make AVI [as opposed to GIF]
    my $run     = FALSE;        # Flag: Proceed with main operation

    my $license = FALSE;        # Flag: Saw "--license" switch
    my $needs   = FALSE;        # Flag: Saw "--need[s]" switch
    
#---------------------------------------------------------------------
# Initial setup.

    select STDERR; $| = ONE;
    select STDOUT; $| = ONE;

#---------------------------------------------------------------------
# Process the command line.

    for my $arg (@ARGV)
    {
        if ($arg =~ s@^-+(make|)avi\w*\z@@i)
            { $is_avi = TRUE  ; $run = TRUE; }

        if ($arg =~ s@^-+(make|)gif\w*\z@@i)
            { $is_avi = FALSE ; $run = TRUE; }

        $license  = TRUE  if $arg =~ s@^-+lic\w*\z@@i;
        $needs    = TRUE  if $arg =~ s@^-+need\w*\z@@i;
        $needs    = TRUE  if $arg =~ s@^-+require\w*\z@@i;
        $run      = TRUE  if $arg =~ s@^-+run\w*\z@@i;
        $cmderr   = TRUE  if length $arg;
    }

#---------------------------------------------------------------------
# Handle "--license" and/or "--need[s]" switches.

    if ($license || $needs)
    {
        print << 'END';

Requirements: "moonphase2avi" requires "moonphasepic" [a distro-speci-
fic program]  and  "povray" 3.6.1.  Additionally,  AVI output mode re-
quires "mencoder" [mid-2007 versions or later] and GIF output mode re-
quires "gifsicle" 1.48 and "intergif" 6.15.

License information:  "moonphase2avi" and  "moonphasepic" are licensed
under Creative Commons Attribution-NonCommercial-ShareAlike 2.5. "gif-
sicle" and "mencoder" are licensed under GNU GPL 2. "intergif" is dis-
tributed under a BSD-style license.

END
        exit ONE;
    }

#---------------------------------------------------------------------
# If necessary, print usage text and exit.

    if ($cmderr || ($run == FALSE))
    {
        $DOCUMENTATION =~ s@^\s+@@s;
        $DOCUMENTATION =~ s@(__META_REVISION__)\n(-)@$1 $2@;
        $DOCUMENTATION =~ s@__META_PROGNAME__@$PROGNAME@g;
        $DOCUMENTATION =~ s@__META_REVISION__@$REVISION@g;
        $DOCUMENTATION =~ s@\s*\z@\n@s;

        print "\n", $DOCUMENTATION, "\n";
        exit ONE;
    }

#---------------------------------------------------------------------
# Additional setup.

                                # Move some of the parameters
    my $FPS       = $is_avi ? $AVI_FPS       : $GIF_FPS         ;
    my $NUMFRAMES = $is_avi ? $AVI_NUMFRAMES : $GIF_NUMFRAMES   ;
    my $OFNAME    = $is_avi ? $AVI_OFNAME    : $GIF_OFNAME      ;
    my $TFNAME    = $is_avi ? $AVI_TFNAME    : $GIF_TFNAME      ;
    my $WIDTH     = $is_avi ? $AVI_WIDTH     : $GIF_WIDTH       ;

                                # Compute image height [in pixels]
    my $HEIGHT = int (($WIDTH * 0.75) + 0.5);

                                # Check "write" access
    die "Error: Can't write to current directory: $!\n"
        unless open (OFD, ">$TFNAME") &&
            close (OFD) && unlink ($TFNAME);

                                # Remove old files
    system "rm -f moonphase*.{gif,png} $OFNAME";

                                # Consistency check
    die "Error: Couldn't remove old file [$OFNAME]\n"
        if (-e $OFNAME) || (-l $OFNAME);

                                # Max. frame number [starting at zero]
    my $MaxFrameNum = $NUMFRAMES - ONE;

#---------------------------------------------------------------------
# Main loop.

    for my $ii (ZERO..$MaxFrameNum)
    {                           # Generate the next frame
        my $nn = sprintf ('%03d', $ii);
        my $xx = sprintf ('%.3f', $ii/$NUMFRAMES);

        my $pngfile = "moonphase$nn.png";
        my $giffile = "moonphase$nn.gif";

        system << "END";        # "END" must be double-quoted here
moonphasepic $xx --output=$pngfile --width=$WIDTH
END
        if (!$is_avi)           # Is the target an  animated GIF ?
        {                       # Yes - Convert PNG frame to GIF frame
            system "convert $pngfile $giffile";
            unlink $pngfile;    # Discard PNG frame
        }
    }

#---------------------------------------------------------------------
# If GIF mode is selected, make an animated GIF.

# The  "gifsicle" command executed below creates a temporary [unoptim-
# ized]  animated-GIF  file  using 256 colors.  The "intergif" command
# executed afterwards  creates the final [optimized] animated-GIF file
# using $IGNUMCOLORS colors.

# Note: The extra spaces used in the $cmd block defined below are sig-
# nificant.  Don't  add  spaces or  remove them  unless you know  what
# you're doing.

    if (!$is_avi)               # Is the target an animated GIF ?
    {                           # Yes
        my $IGDELAY;
        $IGDELAY = int ((($FPS / $NUMFRAMES) * 100) + 0.5);
        $IGDELAY = 2 if $IGDELAY < 2;

        $cmd = << "END";        # "END" must be double-quoted here
gifsicle -i -O -l --colors 256
    moonphase[0-9][0-9][0-9].gif -o $TFNAME
intergif -i -t -trim -d $IGDELAY -loop -diffuse -zigzag
    -best $IGNUMCOLORS $TFNAME -o $OFNAME
rm -f $TFNAME moonphase[0-9][0-9][0-9].gif
END
        $cmd =~ s@\s*\n[\011\040]+@ @gs;
        $cmd =~ s@\s+\z@@s;
        system $cmd;
    }

#---------------------------------------------------------------------
# If AVI mode is selected, make an AVI file.

# Note: The extra spaces used in the $cmd block defined below are sig-
# nificant.  Don't  add  spaces or  remove them  unless you know  what
# you're doing.

    if ($is_avi)                # Is the target an AVI file?
    {                           # Yes
        $cmd = << "END";        # "END" must be double-quoted here
mencoder "mf://moonphase*.png"
    -mf w=$WIDTH:h=$HEIGHT:fps=$FPS:type=png
    -ovc lavc -lavcopts vcodec=mpeg4 -oac copy -o $OFNAME
rm -f moonphase*.png
END
        $cmd =~ s@\s*\n[\011\040]+@ @gs;
        $cmd =~ s@\s+\z@@s;
        system $cmd;
    }

#---------------------------------------------------------------------
# Wrap it up.

    die "Error: Operation failed\n" unless -f $OFNAME;
    print "Created $OFNAME\n";
    undef;
}

#---------------------------------------------------------------------
#                            main program
#---------------------------------------------------------------------

&Main();                        # Call the main routine
exit ZERO;                      # Normal exit



To continue, press the browser's Back button.