Захват каждого кадра холста HTML5

Эти изображения цикла палитры захватывают дух: http://www.effectgames.com/demos/canvascycle/?sound=0

Я хотел бы сделать некоторых (или все) их в настольные фоны.

Я мог использовать анимированную gif версию, но я понятия не имею, как получить это от холста "анимация". Есть ли что-либо доступное все же, которое может сделать что-то вдоль этих строк (speficially для той ссылки и вообще говоря).

20
задан Matthew Groves 27 July 2010 в 17:10
поделиться

4 ответа

У меня есть решение, но оно зависит от того, знакомы ли вы с консолью Javascript в Firefox (установите плагин Firebug ), Chrome или Safari. .

Если это не так, погуглите или попробуйте просто щелкнуть правой кнопкой мыши в любом месте страницы, выберите « Проверить элемент » и найдите « Консоль » ...

Что делает код:

Он позволяет делать 10 снимков экрана элемента CANVAS каждые 1/10 секунды. Оба эти значения легко изменить, так как вы можете настроить, чтобы найти количество итераций, которое вы хотите получить. В приведенном вами примере идентификатор элемента холста - « mycanvas ».

После захвата экрана он выводит изображения на страницу. На этом этапе вы можете сохранить отдельные изображения.

Выполнение кода

Вставьте следующий код в консоль Javascript :

var canvas = document.getElementById("mycanvas");
var shots  = [];
var grabLimit = 10;  // Number of screenshots to take
var grabRate  = 100; // Miliseconds. 500 = half a second

var count     = 0;

function showResults() {
    //console.log(shots);
    for (var i=0; i<shots.length; i++) {
      document.write('<img src="' + shots[i] + '"/>\n');
    }
}

var grabber = setInterval(function(){
  count++;

  if (count>grabLimit) {
    clearInterval(grabber);
    showResults();
  }

  var img     = canvas.toDataURL("image/png");
  shots.push(img);
}, grabRate);

и нажмите CTRL-Enter , чтобы выполнить его.

Запуск должен занять несколько секунд, так что проявите терпение.

После этого у вас должны быть все необходимые кадры (а может и больше) для создания анимированного GIF с помощью ImageMagick, этого веб-сайта MakeAGif.com или другого приложения.

Боковое примечание

Если по какой-то причине вам нужно вывести как GIF из JPG, а не PNG, просто обновите, если необходимо, это:

var img     = canvas.toDataURL("image/png");

до одного из следующих:

var img     = canvas.toDataURL("image/gif");
var img     = canvas.toDataURL("image/jpg");

Поддержка вывода как gif или jpg могут быть не во всех браузерах (должно быть в большинстве).

(БОЛЬШОЕ) ОБНОВЛЕНИЕ №1

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

Во-вторых, этот новый код НЕ РЕШАЕТ проблему. В этом есть один серьезный недостаток. Он создает анимированный GIF ( Yipee! ), но его различные оттенки зеленого ( Boooo! ). Не уверен, как / почему, но, может быть, кто-то сможет взять это отсюда и посмотреть, что я пропустил.

Итак, поехали ... применяются те же правила - скопируйте и вставьте его в консоль Javascript браузера (он тормозит в Firefox, но Google Chrome работает довольно быстро ... 10 секунд или около того, чтобы запустить).

var jsf  = ["/Demos/b64.js", "LZWEncoder.js", "NeuQuant.js", "GIFEncoder.js"];
var head = document.getElementsByTagName("head")[0];

for (var i=0;i<jsf.length;i++) {
  var newJS = document.createElement('script');
  newJS.type = 'text/javascript';
  newJS.src = 'http://github.com/antimatter15/jsgif/raw/master/' + jsf[i];
  head.appendChild(newJS);
}

// This post was very helpful!
// http://antimatter15.com/wp/2010/07/javascript-to-animated-gif/

var w = setTimeout(function() { // give external JS 1 second of time to load

    console.log('Starting');

    var canvas = document.getElementById("mycanvas");
    var context = canvas.getContext('2d');
    var shots  = [];
    var grabLimit = 10;  // Number of screenshots to take
    var grabRate  = 100; // Miliseconds. 500 = half a second
    var count     = 0;

    function showResults() {
        console.log('Finishing');
        encoder.finish();
        var binary_gif = encoder.stream().getData();
        var data_url = 'data:image/gif;base64,'+encode64(binary_gif);
        document.write('<img src="' +data_url + '"/>\n');
    }

    var encoder = new GIFEncoder();
    encoder.setRepeat(0);  //0  -> loop forever, 1+ -> loop n times then stop
    encoder.setDelay(500); //go to next frame every n milliseconds
    encoder.start();

    var grabber = setInterval(function(){
      console.log('Grabbing '+count);
      count++;

      if (count>grabLimit) {
        clearInterval(grabber);
        showResults();
      }

      var imdata = context.getImageData(0,0,canvas.width,canvas.height);
      encoder.addFrame(context);

    }, grabRate);

}, 1000);

Он использует некоторый полезный код, указатели и файлы JS, упомянутые в этом сообщении в блоге JavaScript в (Анимированный) GIF . Я использую некоторые файлы JS напрямую, но вы должны скопировать их локально, если собираетесь использовать их много.

На выходе я получил этот GIF: alt text

Значит, это кое-что, но не то, что вам нужно ...

24
ответ дан 29 November 2019 в 23:52
поделиться

РЕДАКТИРОВАТЬ : Наконец, примените этот код, вот результат:

alt text

Imagick сгенерировал большое изображение, поэтому я пошел дальше и оптимизировал с помощью gimp.

Клиентский код представляет собой модифицированную версию кода Майкла:

var canvas = document.getElementById("mycanvas");
var shots  = [];
var grabLimit = 30;  // Number of screenshots to take
var grabRate  = 100; // Miliseconds. 500 = half a second

var count     = 0;

function postResults() {
   console.log("START---------");
   for (var i = 0; i < shots.length; i++) {
      document.write(shots[i]+"<br />");
   }    
   console.log("END-----------");
}

var grabber = setInterval(function(){
  count++;

  if (count>grabLimit) {
    clearInterval(grabber);
    postResults();
  }

  var img     = canvas.toDataURL("image/png");
  shots.push(img.replace("data:image/png;base64,",""));
}, grabRate);

Он выводит на экран кучу строк base64. Скопируйте их и сохраните в текстовый файл, а затем загрузите на свой веб-сервер.Затем запустите другой сценарий (см. Ниже), и он запишет изображение на ваш веб-сервер. Полученное изображение будет большим и, возможно, прерывистым, поэтому откройте GIMP и оптимизируйте его для различий и GIF. При сохранении заставьте его использовать одинаковую задержку для всех кадров, чтобы анимация была плавной.


Использование PHP может быть не слишком сложным.

  1. Получите dataURL (строка в кодировке base64) для каждого кадра с помощью JS и отправьте его на сервер.
  2. Декодируйте строки base64 и преобразуйте их в объекты Imagick.
  3. Добавьте эти объекты Imagick как рамки к новому объекту Imagick.
  4. Сохраните объект Imagick в файловой системе как GIF.

Так как Майкл уже опубликовал красивое JS-решение, я добавлю код на стороне сервера, если вы хотите его автоматизировать:

<?php
$imageData = array_map('rtrim', file('data.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)); //base 64 strings separated by newlines
$delay = 100;
$filename = 'coolmoviebro.gif';
$gif = new Imagick();

for($i = 0; $i < count($imageData); $i++) {
   $tempImg = new Imagick();
   $tempImg->readimageblob(base64_decode($imageData[$i]));
   $gif->addImage($tempImg);
}

$gif->setFormat('gif');
$gif->setImageDelay($delay);
$gif->writeImages($filename, true);

?>

Я не писал много PHP год или два, так что не забудьте все перепроверить и скоро.

12
ответ дан 29 November 2019 в 23:52
поделиться

К сожалению, согласно создателю рисунка , преобразовать его в анимацию GIF не совсем возможно из-за того, что разные части изображения имеют разные циклы.

1
ответ дан 29 November 2019 в 23:52
поделиться

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

Посмотрев на список объектов цикла в Palette.Cycles, вы сможете определить длину цикла каждого цикла с помощью полей cycle.high, cycle.low и cycle.rate. При этом для каждого из шести возможных значений для cycle.reverse вам понадобится свой алгоритм.

Узнав длительность каждого цикла в списке (в миллисекундах, если я правильно понял код), вы можете найти наименьшее общее кратное всех циклов, что даст вам общую длину анимации. На практике, однако, вы захотите сначала разделить их на период выборки (скажем, 100 миллисекунд для десяти кадров в секунду), чтобы получить меньшее общее кратное.

Затем настройте функцию animate в main.js так, чтобы она принимала параметр tickCount и передавала его в palette.cycle, вместо того чтобы использовать что-то, основанное на реальном времени. С каждой итерацией увеличивайте количество тиков на период выборки.

После этого вы сможете модифицировать метод render класса Bitmap, добавив необходимую логику для копирования холста в файл. Кажется, существуют библиотеки, которые могут сделать это за вас. Я бы рекомендовал сохранять файлы, используя счетчик тиков в качестве имени файла (с достаточным количеством ведущих нулей, чтобы сохранить порядок). Сшивание всех изображений вместе в анимированный GIF может быть возможно выполнить как пакетное задание с помощью соответствующего программного обеспечения.

Конечно, я не пробовал это делать. Возможно, вам захочется ввести проверки, например, чтобы убедиться, что вы не наткнетесь на анимацию с эпической длиной цикла и не создадите миллионы изображений на жестком диске.

В качестве отступления, вы также можете, приложив немного больше усилий, выяснить точное время до следующего обновления и взять нерегулярные образцы, но вам придется придумать, как хранить информацию о задержке так, чтобы ее можно было использовать для сборки готового GIF.

2
ответ дан 29 November 2019 в 23:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: