将HTML画布导出为图像序列

时间:2012-01-17 19:26:50

标签: javascript python html html5 three.js

我创建了一个非常天真的页面,它将采用Three.js场景(尽管这可能是任何非WebGL <canvas>动画)并导出单个图像(或图像序列) )然后转换成视频。

我这样做是为了学习Python的一种方式,但是能够在Three.js中快速创建原型然后导出大量高分辨率丝滑视频的想法对我来说非常有吸引力。在过去,我使用屏幕捕获软件来抓取视频,虽然它总是感觉有点笨拙,FPS中的实时下降也会在最终视频中显示出来。

我目前的流程如下:

Javascript

  • 创建WebGL场景并设置渲染周期
  • 将画布宽度/高度设置为所需尺寸
  • 使用requestAnimationFrame
  • 渲染场景
  • 暂停场景的渲染/更新周期
  • 在canvas元素上调用toDataURL()并检索base64字符串
  • 对python脚本发出POST请求,传递base64字符串(以及其他内容,例如目标目录以保存到以及是否捕获单个图像或序列)

的Python:

  • 剥离MIME标头内容类型并解码base64字符串
  • 将字符串写入图像文件
  • 如果文件已写入,则打印/返回表示成功状态的字符串,否则打印出有问题的错误消息

import base64, cgi, cgitb, datetime, glob, re, os

cgitb.enable() #cgitb.enable(display=0, logdir='/tmp') print "Content-type: text/html" print def main(): form = cgi.FieldStorage() saveLocation = "../httpdocs/export/" # POST variables dataURL = form['dataURL'].value captureSequence = form['captureSequence'].value folderName = saveLocation + form['folderName'].value saveImage(dataURL, captureSequence, saveLocation, folderName) def saveImage(dataURL, captureSequence, saveLocation, folderName): # strip out MIME content-type (e.g. "data:image/png;base64,") dataURL = dataURL[dataURL.index(','):] decodedString = base64.decodestring(dataURL) if captureSequence == 'true': # based off http://www.akeric.com/blog/?p=632 currentImages = glob.glob(folderName + "/*.jpg") # TODO: perhaps filenames shouldnt start at %08d+1 but rather %08d+0? numList = [0] if not os.path.exists(folderName): os.makedirs(folderName) for img in currentImages: i = os.path.splitext(img)[0] try: num = re.findall('[0-9]+$', i)[0] numList.append(int(num)) except IndexError: pass numList = sorted(numList) newNum = numList[-1] + 1 saveName = folderName + '/%08d.jpg' % newNum else: if not os.path.exists(saveLocation): os.makedirs(saveLocation) saveName = saveLocation + datetime.datetime.now().isoformat().replace(':', '.') + '.jpg' # TODO; rather than returning a simple string, consider returning an object? try: output = open(saveName, 'w') output.write(decodedString) output.close() print 'true' except Exception, e: print e if __name__ == '__main__': main()

的Javascript

  • 从Python脚本接收响应并显示返回的消息
  • 恢复/更新渲染周期
  • (根据需要重复多个帧的过程)

这是我总是在本地运行的东西,因此不存在冲突写入或任何类型的风险。

我做了一些快速测试,它似乎在很大程度上起作用,如果有点慢。


  • 我是否遗漏了一些完全明显的事情?怎么可以改进? (尤其是在python方面......)
  • 每张图片执行单独的ajax调用是否效率低?一个优点是我可以随时停止/关闭标签,它将保存所有图像直到那一点。存储所有这些base64字符串并在最后发送它们会有什么好处吗?
  • 由于requestAnimationFrame会将更新周期限制为60fps,是否可以轻松设置较低的帧速率?让我们说出于一些风格上的原因,我想以15fps更新所有内容,唯一的选择是使用setTimeout(callback, 1000 / targetFPS)并理解它将drift over time
  • 从上面开始,此动画的var frame在每个更新周期增加1。然后,此变量用于控制动画的各个部分(例如,旋转立方体,并传递给顶点/片段着色器以操纵颜色和纹理UV坐标)。

    如果我想模拟15 fps之类的东西,那么我需要通过frame来增加(60 / 15)吗?是否有更优雅的方式可以轻松切换上限帧速率?

  • 最后,是否有任何技术可以用来提高渲染图像的质量? (大声思考,以双倍大小保存,然后减少它们?)

我真的希望这是有道理的,任何见解或建议都会受到大力赞赏。

源文件: http://cl.ly/3V46120C2d3B0A1o3o25(在Mac / Chrome上测试稳定,需要WebGL)

1 个答案:

答案 0 :(得分:-3)

在EaselJS中,您可以设置FPS

EaselJS Ticker