こんにちは、tampopo256です!
今回は、ブラウザだけで手軽に画像にぼかし加工をかけて保存できるWebツールを作ったのでご紹介します。
📍 サイトURL
🎨 ツールの特徴
- 完全無料・インストール不要
- 画像をアップロードして、スライダーでぼかし強度を調整
- ブラウザ上でリアルタイムプレビュー
- 加工後はワンクリックで保存可能(JPG / PNG)
- スマホ対応
🛠️ 開発背景
以下のようなシーンで使いたくて作りました。
- SNS投稿前に情報を隠したいとき
- 手元にPhotoshopなどがないとき
- スマホやPCブラウザだけでサクッと加工したいとき
👨💻 使用技術・構成
- HTML / CSS / JavaScript(バニラJS)
- Canvas APIによる画像処理
- レスポンシブ対応(スマホOK)
- デプロイ先:Tokai Club ドメインで自前ホスティング
💻 ソースコード全文
以下が今回のHTML + CSS + JSの全文です。
コードを見る
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>画像ぼかしツール</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 100vh;
display: flex;
flex-direction: column;
}
.container {
max-width: 900px;
margin: 0 auto;
padding: 20px;
flex: 1;
}
.header {
text-align: center;
margin-bottom: 40px;
}
.title {
font-size: 2.5rem;
font-weight: 700;
color: #2c3e50;
margin-bottom: 10px;
text-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.subtitle {
font-size: 1.1rem;
color: #7f8c8d;
line-height: 1.6;
max-width: 600px;
margin: 0 auto;
}
.main-content {
background: white;
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
padding: 40px;
margin-bottom: 40px;
}
.upload-area {
border: 3px dashed #bdc3c7;
border-radius: 15px;
padding: 60px 20px;
text-align: center;
margin-bottom: 30px;
transition: all 0.3s ease;
background: #f8f9fa;
}
.upload-area:hover {
border-color: #3498db;
background: #e3f2fd;
}
.upload-area.dragover {
border-color: #2980b9;
background: #bbdefb;
transform: scale(1.02);
}
.upload-icon {
font-size: 3rem;
color: #95a5a6;
margin-bottom: 20px;
}
.upload-text {
font-size: 1.2rem;
color: #7f8c8d;
margin-bottom: 15px;
}
.upload-subtext {
font-size: 0.9rem;
color: #95a5a6;
}
.file-input {
display: none;
}
.upload-btn {
background: linear-gradient(135deg, #3498db, #2980b9);
color: white;
border: none;
padding: 12px 30px;
border-radius: 25px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(52, 152, 219, 0.3);
}
.upload-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(52, 152, 219, 0.4);
}
.controls {
display: none;
margin-bottom: 30px;
}
.control-group {
margin-bottom: 25px;
}
.control-label {
display: block;
font-weight: 600;
color: #2c3e50;
margin-bottom: 10px;
font-size: 1.1rem;
}
.blur-control {
display: flex;
align-items: center;
gap: 15px;
background: #f8f9fa;
padding: 20px;
border-radius: 12px;
}
.blur-slider {
flex: 1;
height: 8px;
border-radius: 4px;
background: #e0e0e0;
outline: none;
cursor: pointer;
}
.blur-slider::-webkit-slider-thumb {
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #3498db;
cursor: pointer;
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
}
.blur-value {
min-width: 60px;
font-weight: 600;
color: #2c3e50;
font-size: 1.1rem;
}
.preview-area {
display: none;
margin-bottom: 30px;
}
.preview-title {
text-align: center;
margin-bottom: 20px;
font-weight: 600;
color: #2c3e50;
font-size: 1.1rem;
}
.preview-container {
text-align: center;
background: #f8f9fa;
border-radius: 15px;
padding: 20px;
min-height: 300px;
display: flex;
align-items: center;
justify-content: center;
}
.preview-image {
max-width: 100%;
max-height: 400px;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
}
.action-buttons {
display: none;
justify-content: center;
}
.btn {
padding: 12px 30px;
border: none;
border-radius: 25px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
min-width: 120px;
}
.btn-primary {
background: linear-gradient(135deg, #e74c3c, #c0392b);
color: white;
box-shadow: 0 4px 15px rgba(231, 76, 60, 0.3);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(231, 76, 60, 0.4);
}
.btn-secondary {
background: linear-gradient(135deg, #27ae60, #219a52);
color: white;
box-shadow: 0 4px 15px rgba(39, 174, 96, 0.3);
}
.btn-secondary:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(39, 174, 96, 0.4);
}
.format-select {
display: none;
align-items: center;
gap: 10px;
margin-top: 15px;
justify-content: center;
}
.format-select select {
padding: 8px 15px;
border: 2px solid #bdc3c7;
border-radius: 20px;
background: white;
font-weight: 600;
color: #2c3e50;
}
.footer {
text-align: center;
padding: 20px;
color: #7f8c8d;
font-size: 0.9rem;
}
.footer a {
color: #3498db;
text-decoration: none;
font-weight: 600;
}
@media (max-width: 768px) {
.main-content {
padding: 20px;
margin: 0 10px 20px;
}
.title {
font-size: 2rem;
}
.action-buttons {
flex-direction: column;
align-items: center;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1 class="title">画像ぼかしツール</h1>
<p class="subtitle">
画像をアップロードして、お好みの強度でぼかし効果を適用できます。<br>
操作は簡単で、プレビューを確認しながら調整可能です。
</p>
</div>
<div class="main-content">
<div class="upload-area" id="uploadArea">
<div class="upload-icon">📷</div>
<div class="upload-text">画像をドラッグ&ドロップ</div>
<div class="upload-subtext">または</div>
<br>
<button class="upload-btn" onclick="document.getElementById('fileInput').click()">
ファイルを選択
</button>
<input type="file" id="fileInput" class="file-input" accept="image/*">
</div>
<div class="controls" id="controls">
<div class="control-group">
<label class="control-label">ぼかし強度</label>
<div class="blur-control">
<input type="range" id="blurSlider" class="blur-slider" min="0" max="20" value="0" step="0.5">
<span class="blur-value"><span id="blurValue">0</span>px</span>
</div>
</div>
</div>
<div class="preview-area" id="previewArea">
<div class="preview-title">プレビュー</div>
<div class="preview-container">
<img id="previewImage" class="preview-image" alt="プレビュー">
</div>
</div>
<div class="action-buttons" id="actionButtons">
<button class="btn btn-secondary" id="downloadBtn">保存</button>
</div>
<div class="format-select" id="formatSelect">
<span>保存形式:</span>
<select id="formatDropdown">
<option value="png">PNG</option>
<option value="jpg">JPG</option>
</select>
</div>
</div>
</div>
<div class="footer">
<p>© 2025 画像ぼかしツール</p>
</div>
<script>
let originalImage = null;
let processedImage = null;
let currentBlur = 0;
// DOM要素の取得
const uploadArea = document.getElementById('uploadArea');
const fileInput = document.getElementById('fileInput');
const controls = document.getElementById('controls');
const previewArea = document.getElementById('previewArea');
const actionButtons = document.getElementById('actionButtons');
const formatSelect = document.getElementById('formatSelect');
const blurSlider = document.getElementById('blurSlider');
const blurValue = document.getElementById('blurValue');
const previewImage = document.getElementById('previewImage');
const downloadBtn = document.getElementById('downloadBtn');
const formatDropdown = document.getElementById('formatDropdown');
// ファイルアップロード処理
fileInput.addEventListener('change', handleFileSelect);
uploadArea.addEventListener('dragover', handleDragOver);
uploadArea.addEventListener('dragleave', handleDragLeave);
uploadArea.addEventListener('drop', handleDrop);
// スライダーイベント
blurSlider.addEventListener('input', function() {
currentBlur = parseFloat(this.value);
blurValue.textContent = currentBlur;
if (originalImage) {
updatePreview();
// 自動的にぼかし効果を適用
applyBlur();
}
});
// ボタンイベント
downloadBtn.addEventListener('click', downloadImage);
function handleFileSelect(e) {
const file = e.target.files[0];
if (file && file.type.startsWith('image/')) {
loadImage(file);
}
}
function handleDragOver(e) {
e.preventDefault();
uploadArea.classList.add('dragover');
}
function handleDragLeave(e) {
e.preventDefault();
uploadArea.classList.remove('dragover');
}
function handleDrop(e) {
e.preventDefault();
uploadArea.classList.remove('dragover');
const file = e.dataTransfer.files[0];
if (file && file.type.startsWith('image/')) {
loadImage(file);
}
}
function loadImage(file) {
const reader = new FileReader();
reader.onload = function(e) {
originalImage = new Image();
originalImage.onload = function() {
previewImage.src = e.target.result;
showControls();
updatePreview(); // 初期表示で処理後画像を表示
};
originalImage.src = e.target.result;
};
reader.readAsDataURL(file);
}
function showControls() {
controls.style.display = 'block';
previewArea.style.display = 'block';
actionButtons.style.display = 'flex';
formatSelect.style.display = 'flex';
}
function updatePreview() {
if (currentBlur > 0) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = originalImage.width;
canvas.height = originalImage.height;
ctx.filter = `blur(${currentBlur}px)`;
ctx.drawImage(originalImage, 0, 0);
previewImage.src = canvas.toDataURL();
} else {
previewImage.src = originalImage.src;
}
}
function applyBlur() {
if (currentBlur > 0) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = originalImage.width;
canvas.height = originalImage.height;
ctx.filter = `blur(${currentBlur}px)`;
ctx.drawImage(originalImage, 0, 0);
processedImage = canvas;
} else {
// ぼかしが0の場合は元画像を使用
processedImage = null;
}
}
function downloadImage() {
if (!originalImage) return;
const canvas = processedImage || document.createElement('canvas');
if (!processedImage) {
const ctx = canvas.getContext('2d');
canvas.width = originalImage.width;
canvas.height = originalImage.height;
ctx.filter = `blur(${currentBlur}px)`;
ctx.drawImage(originalImage, 0, 0);
}
const format = formatDropdown.value;
const mimeType = format === 'jpg' ? 'image/jpeg' : 'image/png';
const quality = format === 'jpg' ? 0.9 : 1.0;
canvas.toBlob(function(blob) {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `blurred_image.${format}`;
a.click();
URL.revokeObjectURL(url);
}, mimeType, quality);
}
</script>
</body>
</html>
📸 使用イメージ
- ファイルをドラッグ&ドロップ or ファイル選択
- スライダーでぼかし量を調整
- プレビューを確認
- 「保存」ボタンでダウンロード!
スマホでもこんな感じで動きます👇
(スクリーンショットは省略。必要なら後から追加してください)
🚀 今後追加したい機能(予定)
- モザイク処理への切り替え
- 部分ぼかし(範囲選択)
- 複数画像一括処理
✅ 実際のサイトはこちら
🙏 最後に
「もっとこうして欲しい」「この機能つけて!」などあればQiitaコメントかX(旧Twitter)@kurosangurasuまで気軽にどうぞ!