月曜日, 11月 24, 2025

Let's start JavaScript 88 
指定画像をキュビスム風の画像に変換

指定画像をキュビスム風の画像に変換します。あくまでも「〜風」です(^o^)

<!-- index.html -->
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>キュビスム風画像変換</title>
<style>
body {
background: #1e1e1e;
color: #eee;
font-family: sans-serif;
text-align: center;
}
canvas {
border: 1px solid #555;
margin-top: 10px;
background: #ccc;
}
.controls {
margin: 10px;
}
input[type="range"] {
width: 300px;
}
</style>
</head>
<body>
<h2>キュビスム風変換(サイズ調整対応)</h2>

<input type="file" id="fileInput" accept="image/*"><br>

<div class="controls">
<label>ブロックサイズ:
<input type="range" id="sizeSlider"
        min="5" max="80" value="25">
<span id="sizeValue">25</span>px
</label>
</div>

<canvas id="canvas"></canvas>

<script>
const fileInput = document.getElementById("fileInput");
const sizeSlider = document.getElementById("sizeSlider");
const sizeValue = document.getElementById("sizeValue");
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

let img = null;
let imgData = null;

// ファイル選択 → キュビスム変換
fileInput.addEventListener("change", e => {
const file = e.target.files[0];
if (!file) return;
img = new Image();
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
imgData = ctx.getImageData(0, 0, img.width, img.height);
drawCubism();
};
img.src = URL.createObjectURL(file);
});

// サイズ変更スライダー
sizeSlider.addEventListener("input", () => {
sizeValue.textContent = sizeSlider.value;
if (imgData) drawCubism();
});

function drawCubism() {
const blockSize = parseInt(sizeSlider.value);
const width = canvas.width;
const height = canvas.height;
const data = imgData.data;

// 背景をリセット
ctx.fillStyle = "#e0e0e0";
ctx.fillRect(0, 0, width, height);

// 幾何的に分解再構成
const total = (width * height) / (blockSize * blockSize);
for (let i = 0; i < total; i++) {
const x = Math.random() * width;
const y = Math.random() * height;
const px = (Math.floor(y) * width + Math.floor(x)) * 4;
const r = data[px];
const g = data[px + 1];
const b = data[px + 2];

const sides = 3 + Math.floor(Math.random() * 3); // 3〜5角形
const angle = Math.random() * Math.PI * 2;
const size = blockSize * (0.8 + Math.random() * 0.4);

ctx.beginPath();
for (let j = 0; j < sides; j++) {
const theta = angle + j * (Math.PI * 2 / sides);
const dx = x + Math.cos(theta) * size;
const dy = y + Math.sin(theta) * size;
j === 0 ? ctx.moveTo(dx, dy) : ctx.lineTo(dx, dy);
}
ctx.closePath();

// 塗りと線でキュビスム感
ctx.fillStyle =
        `rgba(${r},${g},${b},${0.7 + Math.random()*0.3})`;
ctx.fill();
if (Math.random() < 0.1) {
ctx.strokeStyle = `rgba(0,0,0,${0.2 + Math.random()*0.3})`;
ctx.lineWidth = 0.5 + Math.random() * 1.2;
ctx.stroke();
}
}
}
</script>
</body>
</html>
<!-- index.html -->

実行したら画像を指定するだけです。

元画像

結果はこんな感じです。ブロックサイズを調整すれば・・・

ソレっぽい雰囲気を演出できます。