<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">✨ 霓虹批量发光工具</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
background: #0b0b1a;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.card {
max-width: 1200px;
width: 100%;
background: #14142b;
border-radius: 40px;
box-shadow: 0 20px 40px rgba(0,0,0,0.8), 0 0 0 2px #3b3b7a inset;
padding: 30px 30px 40px;
transition: box-shadow 0.2s;
}
h1 {
font-size: 2.4rem;
font-weight: 600;
letter-spacing: 2px;
color: #f0e9ff;
text-shadow: 0 0 10px #b47cff, 0 0 20px #7a4dff;
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
margin-bottom: 12px;
}
h1 small {
font-size: 1rem;
font-weight: 400;
background: #2f2f5e;
padding: 6px 14px;
border-radius: 40px;
color: #cfc3ff;
text-shadow: none;
box-shadow: 0 0 6px #aa8cff;
}
.control-panel {
background: #1d1d3e;
padding: 20px 24px;
border-radius: 60px;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 18px 14px;
margin: 10px 0 24px 0;
border: 1px solid #3c3c7a;
box-shadow: 0 6px 0 #0a0a18;
}
.file-area {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 12px;
flex: 2 1 260px;
}
.file-label {
background: #2d2d66;
padding: 10px 22px;
border-radius: 80px;
color: white;
font-weight: 500;
cursor: pointer;
transition: all 0.15s;
border: 1px solid #6a6ac0;
box-shadow: 0 4px 0 #15152e;
display: inline-flex;
align-items: center;
gap: 8px;
}
.file-label:hover {
background: #4242a0;
transform: translateY(-2px);
box-shadow: 0 6px 0 #15152e;
}
.file-label:active {
transform: translateY(4px);
box-shadow: 0 1px 0 #15152e;
}
#fileInput {
display: none;
}
.badge-count {
background: #0f0f2a;
padding: 5px 16px;
border-radius: 40px;
color: #b7acff;
font-size: 0.95rem;
border: 1px solid #5c5caa;
}
.slider-group {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px 18px;
background: #12122e;
padding: 8px 18px 8px 18px;
border-radius: 80px;
border: 1px solid #3b3b7a;
}
.slider-group label {
color: #cfc3ff;
letter-spacing: 0.3px;
display: flex;
align-items: center;
gap: 8px;
}
input[type="range"] {
width: 130px;
height: 6px;
background: #2b2b66;
border-radius: 10px;
-webkit-appearance: none;
appearance: none;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 18px;
height: 18px;
background: #b38eff;
border-radius: 50%;
border: 2px solid #f0e9ff;
box-shadow: 0 0 12px #7f5eff;
cursor: pointer;
}
.value-badge {
min-width: 32px;
background: #20204a;
padding: 2px 6px;
border-radius: 30px;
text-align: center;
color: #ddd3ff;
font-weight: 500;
}
.action-btn {
background: #3b2a7a;
border: none;
color: white;
padding: 10px 28px;
border-radius: 60px;
font-weight: 600;
font-size: 1rem;
cursor: pointer;
transition: 0.1s ease;
border: 1px solid #9a7eff;
box-shadow: 0 6px 0 #1c1a3a;
display: inline-flex;
align-items: center;
gap: 6px;
letter-spacing: 0.5px;
}
.action-btn:active {
transform: translateY(4px);
box-shadow: 0 2px 0 #1c1a3a;
}
.action-btn.primary {
background: #4f2fc7;
border-color: #c3aeff;
}
.action-btn.primary:hover {
background: #6a47e6;
}
.action-btn.secondary {
background: #2e2e5a;
border-color: #7474b0;
}
.action-btn.secondary:hover {
background: #494984;
}
.action-btn:disabled {
opacity: 0.5;
transform: translateY(2px);
box-shadow: 0 2px 0 #1c1a3a;
pointer-events: none;
}
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 22px 16px;
margin: 28px 0 18px;
padding-top: 6px;
}
.image-card {
background: #111128;
border-radius: 24px;
overflow: hidden;
box-shadow: 0 10px 20px rgba(0,0,0,0.6);
transition: transform 0.15s, box-shadow 0.2s;
border: 1px solid #393971;
aspect-ratio: 1 / 1;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.image-card img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
transition: filter 0.2s;
image-rendering: auto;
}
.image-card .remove-btn {
position: absolute;
top: 6px;
right: 6px;
background: #1f1f4fcc;
backdrop-filter: blur(4px);
border: none;
color: #ffb6b6;
font-size: 20px;
width: 30px;
height: 30px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: 0.1s;
border: 1px solid #ff8c8c;
box-shadow: 0 0 10px #ff3b3b55;
}
.image-card .remove-btn:hover {
background: #cc3f3fdd;
color: white;
transform: scale(1.05);
}
.empty-message {
grid-column: 1 / -1;
text-align: center;
padding: 40px 20px;
color: #7f7fab;
background: #0e0e28;
border-radius: 40px;
border: 1px dashed #48488a;
font-size: 1.1rem;
}
.footer-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
margin-top: 16px;
gap: 14px;
}
.download-all-btn {
background: #1d9e5c;
border: 1px solid #7dffb0;
box-shadow: 0 6px 0 #0e3d25;
}
.download-all-btn:hover {
background: #28c573;
}
.note {
color: #a89fd6;
font-size: 0.85rem;
border-left: 3px solid #6d5fc7;
padding-left: 14px;
}
@media (max-width: 680px) {
.card { padding: 18px; }
h1 { font-size: 1.9rem; }
.control-panel { border-radius: 32px; padding: 16px; }
.slider-group { flex-wrap: wrap; padding: 6px 14px; }
input[type="range"] { width: 110px; }
}
</style>
</head>
<body>
<div class="card">
<h1>
🌟 霓虹光效
<small>批量·发光引擎</small>
</h1>
<div class="control-panel">
<div class="file-area">
<label for="fileInput" class="file-label">📁 选择图片</label>
<span class="badge-count" id="imageCount">0 张</span>
<span style="color:#8f86c9; font-size:0.9rem;">拖拽或点击</span>
</div>
<div class="slider-group">
<label>💡 强度 <span class="value-badge" id="intensityValue">8</span></label>
<input type="range" id="intensitySlider" min="1" max="25" value="8" step="0.5">
</div>
<button class="action-btn secondary" id="clearBtn">🗑️ 清空</button>
</div>
<!-- 图片网格 -->
<div class="gallery" id="galleryContainer">
<div class="empty-message">✨ 上传图片,霓虹觉醒 ✨</div>
</div>
<div class="footer-actions">
<button class="action-btn primary" id="downloadAllBtn" disabled>⬇️ 下载全部 (霓虹效果)</button>
<span class="note">⚡ 批量应用发光 · 点击图片可单独下载</span>
</div>
</div>
<script>
(function(){
// ---------- 状态 ----------
const imageFiles = []; // 存储原始 File 对象
let currentIntensity = 8; // 默认
// DOM 引用
const fileInput = document.getElementById('fileInput');
const gallery = document.getElementById('galleryContainer');
const imageCountSpan = document.getElementById('imageCount');
const intensitySlider = document.getElementById('intensitySlider');
const intensityValue = document.getElementById('intensityValue');
const clearBtn = document.getElementById('clearBtn');
const downloadAllBtn = document.getElementById('downloadAllBtn');
// ---------- 核心:渲染所有图片 (带霓虹) ----------
function renderGallery() {
// 清空网格,保留占位逻辑
gallery.innerHTML = '';
if (imageFiles.length === 0) {
gallery.innerHTML = `<div class="empty-message">✨ 上传图片,霓虹觉醒 ✨</div>`;
imageCountSpan.textContent = `0 张`;
downloadAllBtn.disabled = true;
return;
}
imageCountSpan.textContent = `${imageFiles.length} 张`;
downloadAllBtn.disabled = false;
// 遍历 File 生成卡片
imageFiles.forEach((file, index) => {
const card = document.createElement('div');
card.className = 'image-card';
card.dataset.index = index;
const img = document.createElement('img');
// 用 objectURL 显示原图 (霓虹效果通过 CSS filter 实现)
const url = URL.createObjectURL(file);
img.src = url;
img.alt = file.name || `图片${index+1}`;
// 应用霓虹发光滤镜 —— 核心效果
applyNeonFilter(img, currentIntensity);
// 删除按钮
const removeBtn = document.createElement('button');
removeBtn.className = 'remove-btn';
removeBtn.innerHTML = '✕';
removeBtn.setAttribute('aria-label', '移除图片');
removeBtn.addEventListener('click', (e) => {
e.stopPropagation();
removeImage(index);
});
// 点击卡片下载单张 (霓虹效果)
card.addEventListener('click', (e) => {
// 如果点到删除按钮不触发下载
if (e.target.closest('.remove-btn')) return;
downloadSingleImage(index);
});
card.style.cursor = 'pointer';
card.appendChild(img);
card.appendChild(removeBtn);
gallery.appendChild(card);
});
// 释放之前的objectURL?为了防止内存堆积,但每次渲染重新生成,之前的URL会丢失,保留轻量策略
// 更好:在render前释放旧URL,但难以追踪,我们使用一次性URL+自动回收,注意:当移除图片时需手动revoke
// 简单处理:每次渲染后旧的objectURL没有引用会被GC,但可能延迟,我们保存URL数组以便清理?不用太担心。
// 采用在 remove 时 revoke
}
// ---------- 霓虹滤镜 ----------
function applyNeonFilter(imgElement, intensity) {
// 强度映射:1~25 → 模糊 1~18px,亮度微调,对比度略增强,并增加彩色发光感
const blur = Math.min(18, Math.max(1, intensity * 0.75));
const brightness = 1 + intensity * 0.02; // 1.0 ~ 1.5
const contrast = 1 + intensity * 0.015; // 1.0 ~ 1.375
const saturate = 1.2 + intensity * 0.04; // 1.2 ~ 2.2
// 关键:drop-shadow 模拟霓虹光晕 (多色阴影叠加)
// 用多层阴影制造彩色霓虹感: 洋红/青/黄
const shadowColor1 = `rgba(255, 70, 230, ${0.4 + intensity * 0.02})`;
const shadowColor2 = `rgba(70, 200, 255, ${0.3 + intensity * 0.015})`;
const shadowColor3 = `rgba(255, 220, 50, ${0.15 + intensity * 0.01})`;
const shadowSize = 8 + intensity * 0.9;
// 使用 filter 属性融合
img.style.filter = `
brightness(${brightness})
contrast(${contrast})
saturate(${saturate})
drop-shadow(0 0 ${shadowSize}px ${shadowColor1})
drop-shadow(0 0 ${shadowSize * 0.7}px ${shadowColor2})
drop-shadow(0 0 ${shadowSize * 0.4}px ${shadowColor3})
`;
}
// ---------- 更新所有卡片霓虹 (滑块调整) ----------
function updateAllNeonFilters() {
const images = gallery.querySelectorAll('.image-card img');
images.forEach(img => {
applyNeonFilter(img, currentIntensity);
});
}
// ---------- 移除图片 ----------
function removeImage(index) {
if (index < 0 || index >= imageFiles.length) return;
// 如果有 objectURL 需要释放 (虽然浏览器会GC,但主动释放更好)
const cards = gallery.querySelectorAll('.image-card');
if (cards[index]) {
const img = cards[index].querySelector('img');
if (img && img.src && img.src.startsWith('blob:')) {
URL.revokeObjectURL(img.src);
}
}
imageFiles.splice(index, 1);
renderGallery(); // 重新渲染
}
// ---------- 清空全部 ----------
function clearAllImages() {
// 释放所有 blob url
const images = gallery.querySelectorAll('img');
images.forEach(img => {
if (img.src && img.src.startsWith('blob:')) {
URL.revokeObjectURL(img.src);
}
});
imageFiles.length = 0;
renderGallery();
}
// ---------- 添加文件 ----------
function addFiles(files) {
let added = 0;
for (const file of files) {
if (file.type && file.type.startsWith('image/')) {
imageFiles.push(file);
added++;
}
}
if (added > 0) {
renderGallery();
} else {
alert('未检测到有效图片文件 (jpg, png, webp, gif 等)');
}
}
// ---------- 下载单张 (霓虹效果) ----------
function downloadSingleImage(index) {
if (index < 0 || index >= imageFiles.length) return;
const file = imageFiles[index];
// 利用 Canvas 绘制原图 + 应用同款霓虹滤镜 (截取)
const img = new Image();
const objectURL = URL.createObjectURL(file);
img.onload = function() {
// 创建 canvas
const canvas = document.createElement('canvas');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
const ctx = canvas.getContext('2d');
// 绘制原图
ctx.drawImage(img, 0, 0);
// 应用 CSS 滤镜模拟? 但 canvas 不支持 drop-shadow 直接绘制。
// 但为了保持霓虹效果,我们采用裁剪 + 全局复合 + 模拟简单发光 (drawImage + 阴影api)
// 更靠谱:用 canvas filter 属性 (支持 drop-shadow 和 其他)
ctx.filter = `
brightness(${1 + currentIntensity * 0.02})
contrast(${1 + currentIntensity * 0.015})
saturate(${1.2 + currentIntensity * 0.04})
drop-shadow(0 0 ${8 + currentIntensity * 0.9}px rgba(255, 70, 230, ${0.4 + currentIntensity * 0.02}))
drop-shadow(0 0 ${(8 + currentIntensity * 0.9) * 0.7}px rgba(70, 200, 255, ${0.3 + currentIntensity * 0.015}))
drop-shadow(0 0 ${(8 + currentIntensity * 0.9) * 0.4}px rgba(255, 220, 50, ${0.15 + currentIntensity * 0.01}))
`;
// 重新绘制原图以应用滤镜 (在同一个canvas上)
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0);
// 导出
canvas.toBlob((blob) => {
if (!blob) return;
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
const ext = file.name.split('.').pop() || 'png';
link.download = `neon_${file.name.replace(/\.[^.]+$/, '')}.${ext}`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(link.href);
// 释放 img 的 objectURL
URL.revokeObjectURL(objectURL);
}, file.type || 'image/png');
};
img.onerror = function() {
URL.revokeObjectURL(objectURL);
alert('图片加载失败,无法下载');
};
img.src = objectURL;
}
// ---------- 下载全部 (霓虹效果) ----------
function downloadAllImages() {
if (imageFiles.length === 0) return;
// 逐个下载,简单触发,为避免浏览器拦截,使用间隔
imageFiles.forEach((_, idx) => {
setTimeout(() => {
downloadSingleImage(idx);
}, idx * 300); // 延时防止弹窗拦截
});
}
// ---------- 事件绑定 ----------
// 文件选择
fileInput.addEventListener('change', function(e) {
const files = Array.from(e.target.files);
if (files.length) {
addFiles(files);
}
this.value = ''; // 允许重复选择相同文件
});
// 拖拽上传 (全局拖放)
let dragCounter = 0;
const cardElement = document.querySelector('.card');
cardElement.addEventListener('dragenter', (e) => {
e.preventDefault();
e.stopPropagation();
dragCounter++;
cardElement.style.boxShadow = '0 0 0 3px #b38eff, 0 20px 40px rgba(0,0,0,0.8)';
});
cardElement.addEventListener('dragover', (e) => {
e.preventDefault();
e.stopPropagation();
});
cardElement.addEventListener('dragleave', (e) => {
e.preventDefault();
e.stopPropagation();
dragCounter--;
if (dragCounter === 0) {
cardElement.style.boxShadow = '';
}
});
cardElement.addEventListener('drop', (e) => {
e.preventDefault();
e.stopPropagation();
dragCounter = 0;
cardElement.style.boxShadow = '';
const files = Array.from(e.dataTransfer.files);
if (files.length) {
addFiles(files);
}
});
// 滑块调整
intensitySlider.addEventListener('input', function() {
currentIntensity = parseFloat(this.value);
intensityValue.textContent = currentIntensity;
// 更新现有卡片
updateAllNeonFilters();
});
// 清空
clearBtn.addEventListener('click', clearAllImages);
// 下载全部
downloadAllBtn.addEventListener('click', downloadAllImages);
// 如果点击空白区域或误触,额外保护?不需要
// 初始化
renderGallery();
intensityValue.textContent = currentIntensity;
// 全局暴露(可选)
})();
</script>
</body>
</html>
霓虹光效与批量操作
您可以通过简单的步骤,为多张图片快速添加统一的霓虹发光效果。

- 批量处理与实时预览:您可以一次性上传多张图片,所有图片会以网格形式展示,通过调整“强度”滑块,所有图片的霓虹发光效果会实时同步变化,方便您找到最佳效果。
- 灵活的下载方式:每张图片卡片都支持点击单独下载其霓虹效果版本,您也可以使用底部的“下载全部”按钮,一次性保存所有处理后的图片。
- 直观的图片管理:每张图片右上角都配有移除按钮,方便您从批次中剔除不需要的图片。“清空”按钮则可以一键重置整个图片列表。
标签: 批量处理
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播