我正在p5.js中创建一个简单的动画程序。当用户单击“保存”按钮时,我想下载动画视频。
我有一个名为frames
的对象,其中每个键都标有frame_1
,frame_2
等等。与每个键相关联的值是构成该帧的array
个线段。
我正在尝试一种获取此数据并创建mp4视频的方法。 p5.js有一个内置的save function我认为可能会有所帮助,但它本身并不是一个完整的解决方案。我可以将每个帧保存为单个图像,然后以某种方式将这些图像拼接在客户端,但我还没有找到解决方案。
任何其他方法都会很棒。唯一的要求是它是在客户端完成的。
答案 0 :(得分:8)
由于p5.js是基于Canvas API构建的,因此在现代浏览器中,您可以使用MediaRecorder来完成这项工作。
const btn = document.querySelector('button'),
chunks = [];
function record() {
chunks.length = 0;
let stream = document.querySelector('canvas').captureStream(30),
recorder = new MediaRecorder(stream);
recorder.ondataavailable = e => {
if (e.data.size) {
chunks.push(e.data);
}
};
recorder.onstop = exportVideo;
btn.onclick = e => {
recorder.stop();
btn.textContent = 'start recording';
btn.onclick = record;
};
recorder.start();
btn.textContent = 'stop recording';
}
function exportVideo(e) {
var blob = new Blob(chunks);
var vid = document.createElement('video');
vid.id = 'recorded'
vid.controls = true;
vid.src = URL.createObjectURL(blob);
document.body.appendChild(vid);
vid.play();
}
btn.onclick = record;
// taken from pr.js docs
var x, y;
function setup() {
createCanvas(300, 200);
// Starts in the middle
x = width / 2;
y = height;
}
function draw() {
background(200);
// Draw a circle
stroke(50);
fill(100);
ellipse(x, y, 24, 24);
// Jiggling randomly on the horizontal axis
x = x + random(-1, 1);
// Moving up at a constant speed
y = y - 1;
// Reset to the bottom
if (y < 0) {
y = height;
}
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.7/p5.min.js"></script>
<button>start recording</button><br>
&#13;
答案 1 :(得分:1)
当您遇到不知道如何接近的问题时,您需要做的第一件事就是将问题分解为更小的子问题。然后你可以一次一个地处理这些小问题。推荐阅读:How to Program
我会说你所描述的并不是微不足道的。 JavaScript具有许多内置的安全功能,使得操作本地文件变得困难 - 毕竟,您不希望任何访问过的网站都能访问您的硬盘。
一种解决方案是将图像发送到服务器并让服务器创建视频。但是如果你刚刚开始使用P5.js,创建服务器将是一项巨大的工作。
基本的Google搜索this library,它似乎支持将画布动画(这是P5.js)保存到视频中。我还发现this question导致this library。
另一种选择是切换到常规处理并将动画导出为应用程序而不是webapp。然后你可以用本地文件做任何你想做的事情。但是你失去了嵌入浏览器的能力。
答案 2 :(得分:1)
正如您在评论中指出的那样,gif也可以运行,这是一个解决方案:
下面是一个示例p5草图,它使用gif.js记录画布动画并将其转换为gif。
适用于支持以下工具的浏览器:Web Workers,File API和Typed Arrays。
我已经提供了这段代码,因此你可以了解如何使用这个库,因为没有为它提供太多的文档,我自己很难搞清楚。
var cnv;
var gif, recording = false;
function setup() {
cnv = createCanvas(400, 400);
var start_rec = createButton("Start Recording");
start_rec.mousePressed(saveVid);
var stop_rec = createButton("Stop Recording");
stop_rec.mousePressed(saveVid);
start_rec.position(500, 500);
stop_rec.position(650, 500);
setupGIF();
}
function saveVid() {
recording = !recording;
if (!recording) {
gif.render();
}
}
var x = 0;
var y = 0;
function draw() {
background(51);
fill(255);
ellipse(x, y, 20, 20);
x++;
y++;
if (recording) {
gif.addFrame(cnv.elt, {
delay: 1,
copy: true
});
}
}
function setupGIF() {
gif = new GIF({
workers: 5,
quality: 20
});
gif.on('finished', function(blob) {
window.open(URL.createObjectURL(blob));
});
}
当您单击start_rec
时,此草图开始记录帧,而当您点击stop_rec
时,此草图停止,您可能希望以不同方式控制事物,但请记住addFrame
仅添加draw
一个框架到gif所以你需要在ImageElement
函数中调用它来添加多个框架,你可以传入CanvasElement
,CanvasContext
或gif.on
以及其他可选参数。
在quality
函数中,您可以使用gif指定回调函数来执行任何操作。
如果您想微调gif的设置,例如repeat
,background
,const url = 'https://dl.dropboxusercontent.com/s/4e90e48s5vtmfbd/aaa.png?' + Math.random();
// the same for both requests, but different for each snippets
function requestData(cb){
let xhr = new XMLHttpRequest(),
startTime;
xhr.open('get', url);
xhr.onload = e => {
console.log(performance.now() - startTime);
if(cb){
cb();
}
}
startTime = performance.now();
xhr.send();
}
requestData(requestData);
,您可以阅读更多here。希望这有帮助!
答案 3 :(得分:0)