2010-07-27 100 views
20

的每個幀這些調色板週期圖像是驚人的:http://www.effectgames.com/demos/canvascycle/?sound=0抓一個HTML5畫布

我想做出一些(或全部)的這些成桌面背景。

我可以使用動畫GIF版本,但我不知道如何從畫布「動畫」中獲取該版本。有沒有可用的東西可以根據這些方面做些什麼(特別是對於那個環節和一般來說)。

+4

這些都是驚人的,技術和藝術!最接近我得到一個答案是這樣的:http://stackoverflow.com/questions/923885/capture-html-canvas-as-gif-jpg-png-pdf 問題是,它似乎只允許靜態圖像,而不是動畫。也許有可能以編程方式將每個「幀」捕獲爲一個單獨的圖像,然後將它們作爲GIF拼接在一起? – peterjmag 2010-07-27 20:29:34

+0

只是可能工作,也許你應該讓你的評論一個答案,所以我可以給你的觀點,如果沒有人提出了一個想法:) – 2010-07-28 13:36:29

+3

我的嘗試:http://imgur.com/p9gcV。gif – 2010-08-20 22:33:34

回答

24

我有一個解決方案,但它是,這取決於您熟悉Firefox中的Javascript控制檯(安裝Firebug plugin),Chrome或Safari。

如果你不是,谷歌,或嘗試只是右鍵單擊頁面上的任何地方,選擇「檢查元素」並查找「控制檯」 ...

的代碼做什麼:

它可以讓你把CANVAS元素秒每1/10的10屏幕爭奪。這兩個值很容易修改,因爲你可以調整以找到你想要得到的迭代次數。對於您給出的示例,畫布元素ID爲'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-輸入執行它。

它應該需要幾秒鐘的運行,所以請耐心等待。

之後,你應該有所有必要的框架(任何可能更多)來通過ImageMagick,這個網站MakeAGif.com,或其他應用程序創建一個動畫GIF。

旁註

如果由於某種原因,你需要爲JPG,而不是PNG的GIF輸出只需更新,根據需要,這樣的:這些

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

一個:

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

支持輸出爲gifjpg可能不在所有瀏覽器中(應該是最多的)。

(BIG)更新#1

首先,我讓上面的代碼不變,而不是更新它,因爲這兩種方法可以幫助他人。

其次,這個新的代碼不解決問題。它種類不過是一個主要缺點。它創建了一個動畫GIF(Yipee!),但它的各種深淺不一的綠色(Boooo!)。不知道如何/爲什麼,但也許有人可以從這裏拿走它,看看我錯過了什麼。

所以我們現在就去...應用相同的規則 - 將其複製並粘貼到瀏覽器的Javascript控制檯(它滯後於Firefox,但谷歌瀏覽器相當快... 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 to (Animated) GIF引用。我直接使用一些JS文件,但如果您要使用它們,您應該在本地複製這些文件。

對我來說,輸出是這個GIF: alt text

所以它的東西,而不是你需要什麼...

+0

聲明之後,您從不使用'context'變量。它有什麼用處? – 2010-08-18 19:06:15

+1

糟糕。你是對的。忘了刪除它。我已經相應地更新了代碼。感謝您的注意。 – donohoe 2010-08-18 19:53:39

+0

這是一個夢幻般的解決方案,但我無法弄清楚如何實際將圖像保存到文件。 DownThemAll或Opera鏈接似乎都無法看到圖像。 – 2010-08-19 03:44:40

1

不幸的是,根據art creator,由於圖片中具有不同週期的不同部分,將其轉換爲GIF動畫是不太可能的。

+1

我認爲,由於GIF可以非常有效地壓縮幀間的匹配像素,因此需要數千幀的事實上並不像藝術家懷疑的那樣嚴重。當然,他的審美傾向於經濟,所以他自然會反對在這個問題上拋出硬盤空間,但這並不意味着這是不可能的! – WCWedin 2010-08-18 18:49:11

+0

這是 - 只是不直接。 WCWedin所說的+1。 – donohoe 2010-08-18 20:04:48

+0

好的,那麼你只需要找出所有動畫週期的最低公分母。這將是您需要保存的圖像數量。 – syockit 2011-04-17 13:53:33

12

編輯:終於把該代碼使用,這裏的結果:

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字符串到屏幕。將它們複製並保存到文本文件中,然後將其上傳到Web服務器。然後運行其他腳本(見下文),它會將圖像寫入您的Web服務器。由此產生的圖像會很大並且可能會變得不穩定,所以請打開GIMP並針對差異和GIF進行優化。保存時,強制它對所有幀使用相同的延遲,以便動畫平滑。


使用PHP可能不太難。

  1. 用JS獲取每個幀的dataURL(base64編碼的字符串)併發送給服務器。
  2. 解碼base64字符串並將它們轉換爲Imagick對象。
  3. 將這些Imagick對象作爲框架添加到新的Imagick對象。
  4. 將Imagick對象保存爲GIF文件系統。

    <?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一年或兩個如此:

由於邁克爾已經發布了一個漂亮的JS解決方案,我如果要自動將其添加服務器端代碼一定要仔細檢查一切,等等。

+1

我的意思並不是貶低(畢竟這是對這個問題提出的最成功的努力),但我確實想指出,你的形象遭受了藝術家警告的那種不合時宜的循環和尷尬的循環。最終動畫的週期長度必須非常仔細地選擇,以儘量減少這些文物。儘管如此,一些小小的試驗和錯誤或者一些紙筆數學可能會訣竅。工作很好。 – WCWedin 2010-08-27 15:53:52

+1

@WCWedin:我同意 - 儘管它非常流暢,直到動畫結束時,它並沒有像預期的那樣結束循環最初的開始。我會更多地考慮它,但想出一個產生gif的「概念驗證」就足夠了 - 同時考慮到我在提出圖像時已經選擇了答案,那裏沒有什麼動機接着說。雖然如果任何人都可以得到我正確的幀數據,我很樂意重新生成gif。如果我有時間的話,我想我可以給消息來源一看,看看我能否抽出一個完整的週期。 – 2010-08-27 17:22:36

2

我接過一看代碼,現在看來似乎應該是可能的有點黑客攻擊。

通過查看Palette.Cycles中的循環對象列表,您應該能夠通過cycle.high,cycle.low和cycle.rate字段找出每個循環的循環長度。也就是說,對於cycle.reverse的六個可能值中的每一個,您都需要使用不同的算法。

一旦知道列表中每個週期的長度(以毫秒爲單位,如果我正確讀取代碼),您可以找到所有周期長度的最小公倍數,它會告訴您總長度的動畫。但在實踐中,爲了獲得更低的公倍數,您首先需要按照您的採樣週期(例如,每秒10幀的100毫秒)對它們進行分割。

然後在main.js中安裝動畫函數,以獲取tickCount參數並將其傳遞到palette.cycle,而不是基於實時使用任何東西。在每次迭代中增加樣本週期的滴答計數。

從那裏,你應該能夠修改Bitmap類的渲染方法,添加必要的邏輯來將畫布翻錄到文件。似乎有一些庫可以爲你管理這最後一點。我建議使用滴答計數作爲文件名保存文件(帶有足夠的前導零以保持順序)。將所有圖像拼接成動畫GIF可能可以使用正確的軟件作爲批處理作業執行。

當然,我還沒有嘗試過這個。例如,您可能希望進行檢查,以確保您不會偶然發現具有史詩週期長度的動畫,並在硬盤上創建數百萬張圖像。另外,你也可以多做一點工作,找出下一次更新的準確時間,並採取不規則的樣本,但是你必須弄清楚如何存儲延遲信息,以便你可以用它來組裝完成的GIF。

1

Try PhantomJS

該腳本可以節省100幀。

var webPage = require('webpage'); 
var fs = require('fs'); 
var page = webPage.create(); 

var NB_FRAME = 100; 
var current = 0; 

page.open('http://www.effectgames.com/demos/canvascycle/?sound=0', 
function(status) { 
    if (status === "success") { 
    var current = 0; 
    var grabber = setInterval(function() { 
     var frame = page.evaluate(function() { 
     return document.getElementById('mycanvas').toDataURL("image/png").split(",")[1]; 
     }); 
     fs.write("./frame-" + current + ".png",atob(frame), 'wb'); 
    if (++current === NB_FRAME) { 
    window.clearInterval(grabber); 
    phantom.exit(0); 
    } 
    }, 1000); 
} 
}); 

運行:

phantomjs SaveCanvasFrame.js 

然後使用ImageMagick

convert *.png animated.gif 

這裏,我們去: animated