User:Jasper van Loenen/Prototyping/svgMovie
Converting a YouTube video to an animated svg file.
Example (this svg seems to work only in Chrome... (not Firefox))
import Image, os, sys
#set some initial values which can be overwritten using arguments
frameStep = 10 #the image will animate from frame to frame. To decrease load/filesize it will use every Nth frame
gridSize = 20.0 #how many blocks
tweenSpeed = (1.0 / 24.0) * frameStep #it calculates the relative FPS
# Download the video given as the first argument, if no argument is found: die
if len(sys.argv)<=1:
print "Error: this script takes a single YouTube URL as argument!"
exit()
else:
if len(sys.argv) > 2:
gridSize = sys.argv[2]
if len(sys.argv) > 3:
frameStep = sys.argv[3]
#create a temp folder to save the video and such (clear if already exists)
os.system("rm -r tmp")
os.system("mkdir tmp")
os.system("youtube-dl -quiet -o tmp/video.%\(ext\)s "+sys.argv[1])
# Check if the file was downloaded and get a path to it. If no file found, clear temp folder and die
files = os.listdir("tmp/")
if len(files)==0:
if os.listdir("tmp/"):
os.system("rm -r tmp")
print "Error: the tmp folder is empty."
print "I guess something went wrong while downloading the video :("
exit()
else:
totalFrames = len(files)
vidPath = "tmp/"+files[0]
# Split the audio and save it seperately for possible later use
os.system("ffmpeg -i "+vidPath+" tmp/audio.wav")
# Render the frames to images
os.system("ffmpeg -i "+vidPath+" -f image2 tmp/originalFrame-%06d.png")
os.system("convert -sample 10% -sample 1000% tmp/originalFrame-%06d.png tmp/newFrame-%06d.png")
class GridBlock:
def __init__(self, _x, _y, _width, _height, _number) :
self.x = _x
self.y = _y
self.w = _width
self.h = _height
self.number = _number
self.firstRun = True
self.blockFrame = 0;
self.prevR, self.prevG, self.prevB = 0, 0, 0
self.blockOutput = "<rect id=\"block"+str(self.number)+"\" x=\""+str(self.x)+"\" y=\""+str(self.y)+"\" width=\""+str(self.w)+"\" height=\""+str(self.h)+"\" style=\"fill:black\">\n"
return
def updateColor(self, im):
source = im.split()
totalR, totalG, totalB = 0, 0, 0
totalChecked = 0
totalR, totalG, totalB = 0, 0, 0
for xPos in range(self.x, int(self.x+self.w)):
for yPos in range(self.y, int(self.y+self.h)):
pix = im.getpixel((xPos,yPos))
totalR += pix[0]
totalG += pix[1]
totalB += pix[2]
totalChecked+=1
currR = totalR / totalChecked
currG = totalG / totalChecked
currB = totalB / totalChecked
if self.firstRun==True:
self.prevR = currR
self.prevG = currG
self.prevB = currB
self.firstRun = False
self.blockOutput += "\t<animateColor attributeName=\"fill\" attributeType=\"CSS\"\n\tfrom=\"rgb("+str(self.prevR)+", "+str(self.prevG)+", "+str(self.prevB)+")\" to=\"rgb("+str(currR)+", "+str(currG)+", "+str(currB)+")\" begin=\""+str(self.blockFrame*tweenSpeed)+"s\" dur=\""+str(tweenSpeed)+"s\" fill=\"freeze\"/>\n"
self.prevR = currR
self.prevG = currG
self.prevB = currB
self.blockFrame+=1
return
def endOutput(self):
self.blockOutput += "</rect>\n\n"
return
gridWidth = 0
gridHeight = 0
blocksList = []
formattedCurrFrame = ""
W, H = 0, 1
frameImg = Image.open("tmp/originalFrame-000001.png")
if gridSize > frameImg.size[W]:
gridSize = frameImg.size[W]
elif gridSize > frameImg.size[H]:
gridSize = frameImg.size[H]
elif gridSize < 1:
gridSize = 1
gridWidth = frameImg.size[W] / gridSize;
gridHeight = frameImg.size[H] / gridSize;
index = 0;
for y in xrange(0, frameImg.size[H], int(gridHeight)):
for x in xrange(0, frameImg.size[W], int(gridWidth)):
if index < gridSize*gridSize:
blocksList.append(GridBlock(x, y, gridWidth, gridHeight, index))
index+=1
#There must be a more efficient way to do the following, didn't look it up yet
for currFrame in xrange(1, totalFrames+1, frameStep):
if currFrame < 10:
formattedCurrFrame = "00000" + str(currFrame)
elif currFrame < 100:
formattedCurrFrame = "0000" + str(currFrame)
elif currFrame < 1000:
formattedCurrFrame = "000" + str(currFrame)
elif currFrame < 10000:
formattedCurrFrame = "00" + str(currFrame)
elif currFrame < 100000:
formattedCurrFrame = "0" + str(currFrame)
else:
formattedCurrFrame = ""+str(currFrame)
frameImg = Image.open("tmp/originalFrame-"+formattedCurrFrame+".png")
frameImg.load()
index = 0
for i in xrange(0, len(blocksList)):
blocksList[i].updateColor(frameImg)
svgOut = "<?xml version=\"1.0\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">";
svgOut += "\n\n<svg width=\""+str(frameImg.size[0])+"\" height=\""+str(frameImg.size[1])+"\" version=\"1.1\"\nxmlns=\"http://www.w3.org/2000/svg\">\n\n";
for i in xrange(0, len(blocksList)):
blocksList[i].endOutput()
svgOut += blocksList[i].blockOutput
svgOut += "</svg>"
# Output the results so they can be piped into another script
print "Saving svg file..."
outputFile = open("result.svg", "w")
outputFile.write(svgOut)
outputFIle.close()
# Clean up by deleting the downloaded video and generated images
os.system("rm -r tmp")
print "All done!"