Welcome, guest | Sign In | My Account | Store | Cart

Given paths to image files, produces the html file with embedded javascript to animate those images as a web page.

Python, 186 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/usr/bin/env python
from __future__ import print_function
'''makes html with javascript to animate a sequence of images'''

__author__ = 'Brian Fiedler'
# This module can be imported to access the function makeanim. 
# Or it can be run independently as a script from the command line.
# Suppose the command "ls mydir/*.png" gives the list of files to be animated.
#
# python janim.py myimages/*.png > myanimator.html
# 
# python janim.py -i listofimageurls.txt -o myanimator.html -t "rainfall animation"
#
# myanimator.html wll be viewable in a browser, but you may want to add more html to it.
# Or you can embed myanimator.html within another web page, with html code like:
# <object type="text/html" data="myanimator.html" width="930" height="680" >error message here</object>
# (The width and height in the above example is for 900x600 images, with controls at the bottom.)
#
# Alternative to using janim.py from the command line:
# files = glob.glob("pngs/*.png")
# janim.makeanim(files,outfile="myanimator.html",sortOrder=True,ctlOnSide=True,titlestring="rainfall animation")
#
# For a similar animator, but with more features, see http://www.ssec.wisc.edu/hanis/

def makeanim(files=[],ctlOnSide=False,revOrder=False,sortOrder=False,
             titlestring="animation",fileOfFileNames="",outfile=""):
    # files is a list of paths to the image files

    # possible to append more paths to files:
    if fileOfFileNames: # file with image file names, either on new lines or separated by white space
        urls = open(fileOfFileNames).read().split()
        files += [x.strip() for x in urls if x.strip()]

    if sortOrder: files.sort()
    if revOrder: files.reverse()

    nim=len(files) #number of image files

    #### some large template strings follow:

    top = """<html>
    <title>%s</title>
    <script>
    // semi-colons are optional in javascript, and are often not included in this code!  
    var maxFrameNum=%d 
    var delay = 1000 // time between frames in milliseconds
    var frameNum = 0    // The frame counter: keeps track of current frame
    var timeout_id = null  // Allows us to stop the animation with clearTimeout( )
    var aniFrames = new Array()
    """
    script = """

    document.onkeydown = myKeyDownHandler;

    function myKeyDownHandler(e){
        if (timeout_id!=null) {killAnimate()} 
    //  if (e.which==13) {Animate()} // oddly, the enter key seems to be reserved for repeating the last click  
        if (e.which==39 || e.which==40) {incrementFrame()} // rightarrow
        if (e.which==37 || e.which==38) {decrementFrame()} // leftarrow
    //    alert(e.which+" was pressed")
    }

    // This function performs the animation. 
    function xanimate() {
        incrementFrame()
        timeout_id = setTimeout("xanimate()", delay )  // Display the next frame after delay millisecs
    }
    //A better way? http://creativejs.com/resources/requestanimationframe/ 
    function yanimate() {
        timeout_id = setTimeout( function() {
        requestAnimationFrame(yanimate);
        incrementFrame();
        }, delay );  // Display the next frame after delay millisecs
    }

    function slower() {
        delay=delay*1.5
        if (delay > 4000) delay = 4000
    }

    function faster() {
        delay=delay*2/3
        if (delay < 50 ) delay = 50
    }

    function incrementFrame(){
        frameNum++ 
        if (frameNum > maxFrameNum) { frameNum = 0  }
        showFrame()
    }

    function decrementFrame(){
        frameNum+=-1 
        if (frameNum < 0 ) { frameNum = maxFrameNum  }
        showFrame()
    }

    // Note that we refer to the onscreen image and text using the id imageWindow and textWindow,  defined by us.
    function showFrame(){
        var str = "" + frameNum
        var pad = "000"
        var frameNumPad = pad.substring(0, pad.length - str.length) + str    
        document.getElementById('textWindow').innerHTML = frameNumPad // Display frame number as text 
        document.imageWindow.src = aniFrames[frameNum].src // Display the current frame image
    }

    function killAnimate(){
    if (timeout_id) clearTimeout(timeout_id)
    timeout_id=null
    }
    </script>
    """


    form = """
    <form>  <!-- This form contains buttons to control the animation -->
        <input value="Slower" onclick="slower()" type="button">
        <input value="1 sec" onclick="delay=1000;" type="button">
        <input value="Faster" onclick="faster()" type="button">
        <input style="color: rgb(0, 0, 0); background-color: rgb(153, 255, 153);"
               value="Start" onclick="if (timeout_id == null) yanimate( );" type="button">
        <input value="Stop" onclick="killAnimate();" type="button">
        <input value="-1" onclick="killAnimate(); decrementFrame();" type="button">
        <input value="+1" onclick="killAnimate(); incrementFrame();" type="button">
        <input value="First" onclick="killAnimate(); frameNum=0; showFrame();" type="button">
        <input value="Last" onclick="killAnimate(); frameNum=maxFrameNum; showFrame();" type="button">
        &nbsp;&nbsp;<b id='textWindow'>000</b> 
    </form>
    """

    ### use the paths to images stored in files list to make javascript links to the images: 

    imagecode = """aniFrames[%d] = new Image();\naniFrames[%d].src = "%s";\n"""
    imagepaths = "" 
    for i in range(nim):
        imagepaths += imagecode % (i,i,files[i])

    # show the first image, before animation replaces it:
    firstimgtag = '<img name="imageWindow" src="%s" alt="your image should have been seen here!">' % files[0] 

    ### now put together the web page containing javascript and html for your animation:

    webpage = top % (titlestring,nim-1) 
    webpage += imagepaths
    webpage += script 
    webpage += "<body><center>\n"
    if ctlOnSide: #controls are on the left side of the image
        webpage += "<table><tr><td width=1>\n"
        webpage += form
        webpage += "</td><td>\n"
        webpage += firstimgtag
        webpage += "</td></tr></table>\n"
    else: #controls are below the image
        webpage += firstimgtag
        webpage += form 
    webpage += "</center></body></html>\n"
    if outfile: # write out the html file
        ouf = open(outfile,'w')
        ouf.write(webpage)
        ouf.close()
    else: # written the html file contents as a string
        return webpage


#### optionally process command line arguments for a call to makeanim
if __name__ == '__main__':
    import argparse 
    parser = argparse.ArgumentParser(description= "produces html with javascript for animation" )
    parser.add_argument("-s","--side", dest="ctlOnSide",action="store_true",help="put controls on side")
    parser.add_argument("--sort", dest="sortOrder",action="store_true",help="sorts the image order")
    parser.add_argument("--rev", dest="revOrder",action="store_true",help="reverses the image order")
    parser.add_argument("-t","--title", dest="titlestring",type=str,
                     help="title string in quotes",default="javascript animation")
    parser.add_argument("-i","--fof", dest="fileOfFileNames",type=str,help="name of file containing file urls",default="")
    parser.add_argument("-o","--outfile", dest="outfile",type=str,help="name of html output file",default="")
    parser.add_argument("files",help="paths to image files",nargs='*')
    args = parser.parse_args()

    if len(args.files) == 0:
        parser.print_help()
        
    else: 
        webpage = makeanim(args.files,ctlOnSide=args.ctlOnSide,revOrder=args.revOrder,sortOrder=args.sortOrder,
             titlestring=args.titlestring, fileOfFileNames=args.fileOfFileNames,outfile=args.outfile)
        if not args.outfile:
            print(webpage)

Similar intent to what http://www.ssec.wisc.edu/hanis/ is for, but this is more limited in features, and simpler.

However, this code has one feature that HAniS does not have, as of 1 June 2016: Ability to place the animation controls on the side of the images.

This module can be imported to access the function makeanim. Or it can be run independently as a script from the command line. Suppose the command "ls mydir/*.png" gives the list of files to be animated.

$ python janim.py myimages/*.png > myanimator.html

$ python janim.py -i listofimageurls.txt -o myanimator.html -t "rainfall animation"

myanimator.html wll be viewable in a browser, but you may want to add more html to it. Or you can embed myanimator.html within another web page, with html code like:

<object type="text/html" data="myanimator.html" width="930" height="680" >error message here</object>

(The width and height in the above example is for 900x600 images, with controls at the bottom.)

Alternative to using janim.py from the command line:

files = glob.glob("pngs/*.png")
janim.makeanim(files,outfile="myanimator.html",sortOrder=True,ctlOnSide=True,titlestring="rainfall animation")
Created by Brian Fiedler on Wed, 1 Jun 2016 (MIT)
Python recipes (4591)
Brian Fiedler's recipes (2)

Required Modules

Other Information and Tasks