ご要望のプログラムを作成いたします。TauriとHTML5のCanvasを使用して、指定したmp3ファイルをBGMとして再生しながら、Canvas上にアニメーションを描画し、それを動画として保存するプログラムを作成します。
まず、プロジェクトの構造を設定し、必要なコンポーネントを実装していきます。
// src-tauri/src/main.rs
use tauri::Manager;
use std::fs::File;
use std::io::Write;
use base64::decode;
fn main() {
tauri::Builder::default()
.setup(|app| {
let window = app.get_window("main").unwrap();
Ok(())
})
.invoke_handler(tauri::generate_handler![save_video])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
#[tauri::command]
fn save_video(video_data: String) -> Result<String, String> {
let bytes = decode(video_data).map_err(|e| e.to_string())?;
let mut file = File::create("output.webm").map_err(|e| e.to_string())?;
file.write_all(&bytes).map_err(|e| e.to_string())?;
Ok("Video saved successfully".to_string())
}
これはTauriアプリケーションのRustバックエンドのコードです。save_video
関数は、フロントエンドから送られてくる動画データを受け取り、ファイルとして保存します。
次に、HTML、JavaScript、CSSを含むフロントエンドのコードを作成します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas Recorder</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
#canvas {
border: 1px solid black;
}
#controls {
margin-top: 20px;
}
textarea {
width: 100%;
height: 200px;
margin-top: 20px;
}
</style>
</head>
<body>
<canvas id="canvas" width="640" height="480"></canvas>
<div id="controls">
<button id="startBtn">Start Recording</button>
<button id="stopBtn" disabled>Stop Recording</button>
<input type="file" id="audioInput" accept="audio/mp3">
</div>
<textarea id="animationScript">
// Example animation script
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
let x = 0;
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(x, canvas.height / 2, 20, 0, Math.PI * 2);
ctx.fill();
x = (x + 5) % canvas.width;
}
function animate() {
draw();
requestAnimationFrame(animate);
}
animate();
</textarea>
<script src="<https://cdnjs.cloudflare.com/ajax/libs/js-base64/3.7.2/base64.min.js>"></script>
<script>
const { invoke } = window.__TAURI__.tauri;
let mediaRecorder;
let audioContext;
let audioSource;
const chunks = [];
const canvas = document.getElementById('canvas');
const startBtn = document.getElementById('startBtn');
const stopBtn = document.getElementById('stopBtn');
const audioInput = document.getElementById('audioInput');
const animationScript = document.getElementById('animationScript');
startBtn.addEventListener('click', startRecording);
stopBtn.addEventListener('click', stopRecording);
audioInput.addEventListener('change', loadAudio);
function loadAudio(e) {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = function(e) {
const arrayBuffer = e.target.result;
audioContext = new (window.AudioContext || window.webkitAudioContext)();
audioContext.decodeAudioData(arrayBuffer, (buffer) => {
audioSource = audioContext.createBufferSource();
audioSource.buffer = buffer;
audioSource.connect(audioContext.destination);
});
};
reader.readAsArrayBuffer(file);
}
function startRecording() {
const stream = canvas.captureStream(30);
mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/webm' });
mediaRecorder.ondataavailable = (e) => {
if (e.data.size > 0) {
chunks.push(e.data);
}
};
mediaRecorder.onstop = saveVideo;
mediaRecorder.start();
if (audioSource) {
audioSource.start(0);
}
startBtn.disabled = true;
stopBtn.disabled = false;
// Execute user's animation script
eval(animationScript.value);
}
function stopRecording() {
mediaRecorder.stop();
if (audioSource) {
audioSource.stop();
}
startBtn.disabled = false;
stopBtn.disabled = true;
}
async function saveVideo() {
const blob = new Blob(chunks, { type: 'video/webm' });
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
const base64data = reader.result.split(',')[1];
invoke('save_video', { videoData: base64data })
.then((response) => console.log(response))
.catch((error) => console.error(error));
};
}
</script>
</body>
</html>
このHTMLファイルには、Canvas要素、コントロール、アニメーションスクリプトを編集するためのテキストエリア、そしてJavaScriptコードが含まれています。ユーザーは animationScript
テキストエリアでアニメーションスクリプトを編集できます。
使い方:
注意点:
tauri.conf.json
ファイルで、必要な権限(ファイルシステムへのアクセスなど)を設定する必要があります。eval()
の使用には注意が必要です。実際の製品では、より安全なアプローチを検討してください。