Экспорт HTML-холста в виде последовательности изображений - PullRequest
2 голосов
/ 17 января 2012

Я создал очень наивную страницу, которая будет брать сцену Three.js (хотя это может быть любая анимация, отличная от WebGL <canvas>) и экспортировать отдельные изображения (или последовательности изображений) в затембыть преобразованным в видео.

Я делаю это частично как способ изучения Python, но также и возможность быстро прототипировать что-то в Three.js и затем экспортировать массивное шелковистое гладкое видео с высоким разрешением,супер привлекательный для меня.В прошлом я использовал программное обеспечение для захвата экрана, чтобы захватывать видео, хотя это всегда казалось немного неуклюжим, и падение FPS в реальном времени просвечивало и в финальном видео.

Процесс, который у меня сейчас есть, выглядит следующим образом:

Javascript :

  • Создание сцены WebGL и настройка цикла рендеринга
  • Установите ширину / высоту холста в соответствии с желаемыми размерами
  • Визуализируйте сцену, используя requestAnimationFrame
  • Приостановите цикл рендеринга / обновления сцены
  • Вызовите toDataURL() наэлемент canvas и извлекает строку base64
  • POST-запрос к скрипту Python, передавая строку base64 (и другие вещи, например, целевой каталог для сохранения и захватывается ли отдельное изображение или последовательность)

Python:

  • Обрезать тип содержимого заголовка MIME и декодировать строку base64
  • Записать строку в файл изображения
  • Распечатать / вернуть строку, которая означает успешное состояние, если файл был записан, в противном случае распечатать сообщение об ошибке

import base64, cgi, cgitb, datetime, glob, re, os</p>

<code>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()
</code>

Javascript :

  • Получение ответа от скрипта Python и диспlay return message
  • Возобновить / обновить цикл рендеринга
  • (Повторить процесс столько раз, сколько нужно)

Это то, что я всегда запускаю локально, поэтомуне было бы риска конфликтующих записей или чего-то в этом роде.

Я провел несколько быстрых тестов, и, похоже, он работает по большей части, хотя и немного медленно.


  • Я упускаю что-то совершенно очевидное в том, как это делается?Как это можно улучшить?( Особенно на стороне Python вещей ..)
  • Неэффективно ли делать отдельный вызов ajax для изображения?Одним из преимуществ является то, что я могу просто остановить / закрыть вкладку в любое время, и она сохранит все изображения до этого момента.Будет ли какая-то польза от хранения всех этих строк base64 и отправки их в самом конце?
  • Поскольку requestAnimationFrame ограничит цикл обновления до 60 кадров в секунду, можно ли легко установить более низкую частоту кадров?Допустим, по какой-то стилистической причине я хотел бы обновить все со скоростью 15 кадров в секунду, будет ли единственный вариант использовать setTimeout(callback, 1000 / targetFPS) с пониманием того, что со временем он будет дрейфовать ?
  • Исходя из вышеизложенного, эта анимация имеет переменную frame, которая увеличивается на 1 каждый цикл обновления.Затем эта переменная используется для управления различными частями анимации (например, вращением куба и передачей вершинным / фрагментным шейдерам для управления цветами и координатами текстуры UV).

    Если я хочу смоделировать что-то вроде 15fps, я был бы прав, если бы вместо этого я увеличил frame на (60 / 15)?Существует ли более элегантный способ легко переключаться между ограниченными частотами кадров?

  • Наконец , существуют ли какие-либо методы, которые можно было бы использовать для улучшения качества визуализируемых изображений?(Размышляя вслух, экономя в двойном размере, а затем уменьшая их?)

Я действительно надеюсь, что это имеет смысл, любая идея или совет будут высоко оценены.

Исходные файлы: http://cl.ly/3V46120C2d3B0A1o3o25 (протестировано на Mac / Chrome стабильный, требуется WebGL)

1 Ответ

0 голосов
/ 31 марта 2012

В EaselJS вы можете установить FPS

Тикер EaselJS

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...