「ChatGPTでこれ作った!」
というSNSの投稿をたくさん目にするので、自分でもやってみたくなりやってみました。
実際に使えるデモとコードも載せておくので興味がある方はどうぞ!
読み込んだ画像にフィルターをかける
インスタみたいに画像を選択したらいろんなフィルターをかけられるプログラムをサクッと作りたいなと思いおねだりしてみました。
実際に使えるデモ
画像を選択してボタンを押すと効果がかけられます。「reset」だけうまく動作しませんね。
そして大きい画像だとはみ出しちゃいます。
この辺は修正が必要そうですね。
プロンプト
選択した画像にインスタグラムみたいないろんなフィルターがつけられるアプリケーションのHTMLを作って
「動画全体を」と言わないと始めの1フレームだけアスキーアートにするコードになってしまいます。
コード
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Filter App</title>
<style>
#filters {
display: flex;
justify-content: center;
}
button {
margin: 5px;
}
</style>
</head>
<body>
<h1>Image Filter App</h1>
<input type="file" id="inputImage" accept="image/*" />
<canvas id="canvas"></canvas>
<div id="filters">
<button onclick="applyFilter('grayscale')">Grayscale</button>
<button onclick="applyFilter('sepia')">Sepia</button>
<button onclick="applyFilter('brightness')">Brightness</button>
<button onclick="applyFilter('reset')">Reset</button>
</div>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const inputImage = document.getElementById('inputImage');
let img = new Image();
inputImage.addEventListener('change', (e) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = (event) => {
img.src = event.target.result;
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, img.width, img.height);
};
};
reader.readAsDataURL(file);
});
function applyFilter(filter) {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
let r = data[i];
let g = data[i + 1];
let b = data[i + 2];
if (filter === 'grayscale') {
const gray = 0.299 * r + 0.587 * g + 0.114 * b;
data[i] = data[i + 1] = data[i + 2] = gray;
} else if (filter === 'sepia') {
data[i] = 0.393 * r + 0.769 * g + 0.189 * b;
data[i + 1] = 0.349 * r + 0.686 * g + 0.168 * b;
data[i + 2] = 0.272 * r + 0.534 * g + 0.131 * b;
} else if (filter === 'brightness') {
data[i] = r * 1.2;
data[i + 1] = g * 1.2;
data[i + 2] = b * 1.2;
} else if (filter === 'reset') {
// Reset filter
}
}
ctx.putImageData(imageData, 0, 0);
}
</script>
</body>
</html>
ちなみに、ご丁寧にこんな補足もしてくれました。
このコードを使って、さらに他のフィルターを追加することができます。以下に、コントラストを追加する方法を説明します。
まず、新しいボタンをfilters
ディビジョンに追加し、applyFilter()
関数にcontrast
フィルターを適用するように指定します。<button onclick="applyFilter('contrast')">Contrast</button>
次に、
applyFilter()
関数内に新しい条件を追加して、コントラストの値を変更します。... } else if (filter === 'contrast') { const contrast = 1.5; const average = (r + g + b) / 3; data[i] = average + contrast * (r - average); data[i + 1] = average + contrast * (g - average); data[i + 2] = average + contrast * (b - average); } ...
この例では、コントラストの値を
1.5
に設定していますが、好みに合わせてこの値を調整することができます。このコードを既存のHTMLとJavaScriptのコードに追加することで、コントラストフィルターが適用されるようになります。同様に、他のフィルターも追加することができます。ただし、より高度な画像処理機能が必要な場合は、専用の画像処理ライブラリを使用することを検討してください。
動画ファイルを読み込ませるとアスキーアートに変換してくれる
タイトルの通り、
動画ファイルを読み込ませると、アスキーアートに変換
してくれます。
動画ファイルなのでアスキーアートが動画のように動いて楽しいです!
実際に使えるデモ
動画を選択してstartを押すと動画がアスキーアートになります。
プロンプト
動画ファイルを選択すると、ブラウザ上で動画全体をアスキーアートに変換してくれるプログラムを作って
「動画全体を」と言わないと始めの1フレームだけアスキーアートにするコードになってしまいます。
コード
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Video to ASCII Art Converter</title>
<style>
#asciiOutput {
font-family: monospace;
white-space: pre;
}
</style>
</head>
<body>
<h1>Video to ASCII Art Converter</h1>
<input type="file" id="fileInput" accept="video/*">
<button id="startButton" disabled>Start</button>
<pre id="asciiOutput"></pre>
<script>
const fileInput = document.getElementById('fileInput');
const startButton = document.getElementById('startButton');
const asciiOutput = document.getElementById('asciiOutput');
let video;
let canvas;
let ctx;
let animationFrameId;
fileInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
video = document.createElement('video');
canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
video.src = URL.createObjectURL(file);
await video.play();
video.pause();
const { videoWidth, videoHeight } = video;
canvas.width = videoWidth / 10;
canvas.height = videoHeight / 20;
startButton.disabled = false;
});
startButton.addEventListener('click', () => {
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
animationFrameId = null;
startButton.textContent = 'Start';
} else {
video.play();
animationFrameId = requestAnimationFrame(renderFrame);
startButton.textContent = 'Stop';
}
});
async function renderFrame() {
if (video.paused) return;
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
let ascii = '';
for (let y = 0; y < imageData.height; y++) {
for (let x = 0; x < imageData.width; x++) {
const i = (y * imageData.width + x) * 4;
const [r, g, b] = [imageData.data[i], imageData.data[i + 1], imageData.data[i + 2]];
const brightness = 1 - (0.299 * r + 0.587 * g + 0.114 * b) / 255;
const asciiChars = ' .:-=+*%@#';
const char = asciiChars[Math.round(brightness * (asciiChars.length - 1))];
ascii += char;
}
ascii += '\n';
}
asciiOutput.textContent = ascii;
animationFrameId = requestAnimationFrame(renderFrame);
}
</script>
</body>
</html>