怎么用脚本转换图片底色

wen 实用脚本 1
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">🎨 图片底色转换工具</title>
    <style>
        * {
            box-sizing: border-box;
        }
        body {
            background: linear-gradient(145deg, #0f172a 0%, #1e293b 100%);
            font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
            min-height: 100vh;
            margin: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }
        .card {
            background: rgba(255, 255, 255, 0.08);
            backdrop-filter: blur(10px);
            -webkit-backdrop-filter: blur(10px);
            border-radius: 32px;
            padding: 30px;
            box-shadow: 0 20px 50px rgba(0, 0, 0, 0.6), inset 0 1px 2px rgba(255, 255, 255, 0.1);
            border: 1px solid rgba(255, 255, 255, 0.15);
            max-width: 950px;
            width: 100%;
            transition: all 0.2s ease;
        }
        h1 {
            margin: 0 0 20px 0;
            font-size: 2.2rem;
            font-weight: 600;
            color: #f0f9ff;
            text-align: center;
            letter-spacing: -0.5px;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 12px;
            text-shadow: 0 4px 10px rgba(0,0,0,0.3);
        }
        h1 span {
            background: #38bdf8;
            width: 14px;
            height: 14px;
            border-radius: 50%;
            box-shadow: 0 0 20px #38bdf8;
        }
        .toolbar {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            align-items: flex-end;
            justify-content: center;
            background: rgba(15, 23, 42, 0.7);
            border-radius: 60px;
            padding: 20px 25px;
            margin-bottom: 30px;
            border: 1px solid rgba(148, 163, 184, 0.2);
        }
        .color-picker-wrap {
            display: flex;
            align-items: center;
            gap: 12px;
            background: rgba(51, 65, 85, 0.6);
            padding: 8px 18px;
            border-radius: 40px;
            backdrop-filter: blur(4px);
        }
        .color-picker-wrap label {
            color: #cbd5e1;
            font-weight: 500;
            font-size: 0.9rem;
            letter-spacing: 0.3px;
        }
        #bgColor {
            width: 60px;
            height: 60px;
            border-radius: 30px;
            border: 2px solid #fff;
            background: #ffffff;
            cursor: pointer;
            box-shadow: 0 4px 12px rgba(0,0,0,0.3);
            transition: 0.1s;
        }
        #bgColor:hover {
            transform: scale(1.05);
        }
        .action-buttons {
            display: flex;
            gap: 12px;
            flex-wrap: wrap;
        }
        .btn {
            background: #ffffff10;
            border: 1px solid #ffffff30;
            padding: 12px 28px;
            border-radius: 60px;
            font-size: 1rem;
            font-weight: 500;
            color: #f8fafc;
            cursor: pointer;
            transition: 0.2s;
            display: flex;
            align-items: center;
            gap: 8px;
            backdrop-filter: blur(4px);
            letter-spacing: 0.3px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
        }
        .btn-primary {
            background: #38bdf8;
            border-color: #7dd3fc;
            color: #0c1a2a;
            font-weight: 600;
            box-shadow: 0 8px 20px rgba(56, 189, 248, 0.3);
        }
        .btn-primary:hover {
            background: #0ea5e9;
            transform: translateY(-2px);
        }
        .btn-outline:hover {
            background: #ffffff20;
            border-color: #ffffff70;
        }
        .btn:active {
            transform: scale(0.96);
        }
        .canvas-section {
            display: flex;
            flex-direction: column;
            align-items: center;
        }
        .canvas-container {
            background-color: rgba(255, 255, 255, 0.03);
            border-radius: 28px;
            padding: 12px;
            border: 1px dashed #afc3d8;
            box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.3);
            margin-bottom: 20px;
            width: 100%;
            display: flex;
            justify-content: center;
        }
        canvas {
            width: 100%;
            height: auto;
            max-width: 800px;
            max-height: 500px;
            border-radius: 16px;
            background: repeating-conic-gradient(#2a3b4e 0% 25%, #1e2a3a 0% 50%) 50% / 20px 20px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
            display: block;
            transition: box-shadow 0.2s;
        }
        .upload-area {
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
            gap: 16px;
            margin-bottom: 10px;
        }
        .file-label {
            background: #2a3b4e;
            padding: 14px 24px;
            border-radius: 60px;
            color: #e2e8f0;
            font-weight: 500;
            cursor: pointer;
            transition: 0.2s;
            box-shadow: 0 4px 10px rgba(0,0,0,0.2);
            display: inline-flex;
            align-items: center;
            gap: 10px;
            border: 1px solid #475569;
        }
        .file-label:hover {
            background: #3b4f66;
            border-color: #64748b;
        }
        .file-input {
            display: none;
        }
        .info-text {
            color: #94a3b8;
            text-align: center;
            font-size: 0.9rem;
            margin-top: 12px;
            border-top: 1px solid #334155;
            padding-top: 20px;
            letter-spacing: 0.2px;
        }
        .download-btn {
            background: #22c55e;
            border: none;
            color: #fff;
            font-weight: 600;
            box-shadow: 0 6px 16px #22c55e40;
        }
        .download-btn:hover {
            background: #16a34a;
        }
        .filename-badge {
            font-size: 0.85rem;
            background: #1e293b;
            padding: 6px 18px;
            border-radius: 60px;
            color: #a5d8ff;
            display: inline-flex;
            align-items: center;
            gap: 6px;
            max-width: 260px;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        .filename-badge img {
            width: 16px;
            height: 16px;
            filter: invert(0.8);
        }
        .split-line {
            display: flex;
            align-items: center;
            gap: 16px;
            margin: 16px 0;
        }
        .split-line span {
            background: #1e3a5f;
            height: 1px;
            flex: 1;
            opacity: 0.3;
        }
        @media (max-width: 700px) {
            .toolbar {
                flex-direction: column;
                align-items: stretch;
                border-radius: 32px;
            }
            .color-picker-wrap, .action-buttons {
                justify-content: center;
            }
        }
    </style>
</head>
<body>
<div class="card">
    <h1>
        <span></span> 底色转换器 <span></span>
    </h1>
    <!-- 上传 + 工具栏 -->
    <div class="toolbar">
        <div class="upload-area" style="margin-bottom:0;">
            <label for="fileInput" class="file-label">
                📂 选择图片
            </label>
            <input type="file" id="fileInput" class="file-input" accept="image/*">
            <span class="filename-badge" id="fileNameDisplay">📄 未选择文件</span>
        </div>
        <div class="color-picker-wrap">
            <label for="bgColor">🎯 目标底色</label>
            <input type="color" id="bgColor" value="#ffffff">
        </div>
        <div class="action-buttons">
            <button id="convertBtn" class="btn btn-primary">✨ 转换底色</button>
            <button id="downloadBtn" class="btn download-btn">⬇️ 下载图片</button>
        </div>
    </div>
    <!-- Canvas 预览区 -->
    <div class="canvas-section">
        <div class="canvas-container">
            <canvas id="canvas" width="800" height="500"></canvas>
        </div>
        <div class="info-text">
            💡 点击【选择图片】载入本地图像,再选取目标背景色,点击「转换底色」<br>
            背景将变为纯色(自动去除白色或浅色背景)
        </div>
    </div>
</div>
<script>
    (function() {
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d', { willReadFrequently: true });
        const fileInput = document.getElementById('fileInput');
        const fileNameDisplay = document.getElementById('fileNameDisplay');
        const bgColorInput = document.getElementById('bgColor');
        const convertBtn = document.getElementById('convertBtn');
        const downloadBtn = document.getElementById('downloadBtn');
        // 状态: 保存原始图像数据 (ImageData 或 canvas)
        let originalCanvas = null;      // 存储原始图片的canvas
        let hasImage = false;
        // 默认画一个示例图片 (渐变+圆,方便演示)
        function drawPlaceholder() {
            const w = canvas.width;
            const h = canvas.height;
            ctx.clearRect(0, 0, w, h);
            // 渐变背景
            const grad = ctx.createLinearGradient(0, 0, w*0.6, h);
            grad.addColorStop(0, '#faa7c0');
            grad.addColorStop(0.5, '#ffe0e9');
            grad.addColorStop(1, '#ffffff');
            ctx.fillStyle = grad;
            ctx.fillRect(0, 0, w, h);
            // 画一些图形
            ctx.fillStyle = '#5b8def';
            ctx.shadowColor = 'rgba(0,0,0,0.3)';
            ctx.shadowBlur = 10;
            ctx.beginPath();
            ctx.arc(w*0.6, h*0.45, 80, 0, Math.PI*2);
            ctx.fill();
            ctx.fillStyle = '#eb8f8f';
            ctx.shadowBlur = 14;
            ctx.beginPath();
            ctx.arc(w*0.3, h*0.3, 55, 0, Math.PI*2);
            ctx.fill();
            ctx.fillStyle = '#c0a5fb';
            ctx.shadowBlur = 8;
            ctx.beginPath();
            ctx.arc(w*0.45, h*0.7, 65, 0, Math.PI*2);
            ctx.fill();
            ctx.shadowBlur = 0;
            // 添加文字
            ctx.font = 'bold 28px "Segoe UI", sans-serif';
            ctx.fillStyle = '#003153';
            ctx.fillText('示例图片', 50, 90);
            // 保存为原始canvas
            originalCanvas = document.createElement('canvas');
            originalCanvas.width = w;
            originalCanvas.height = h;
            const octx = originalCanvas.getContext('2d');
            octx.drawImage(canvas, 0, 0);
            hasImage = true;
            fileNameDisplay.innerHTML = '📄 内置示例';
        }
        // 重新绘制为当前原始内容 (不改变)
        function restoreOriginal() {
            if (originalCanvas) {
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                ctx.drawImage(originalCanvas, 0, 0);
                hasImage = true;
            } else {
                drawPlaceholder();
            }
        }
        // 初始画占位图
        drawPlaceholder();
        // ---------- 文件上传 ----------
        fileInput.addEventListener('change', function(e) {
            const file = e.target.files[0];
            if (!file) return;
            const reader = new FileReader();
            reader.onload = function(event) {
                const img = new Image();
                img.onload = function() {
                    // 设置canvas尺寸适配图像比例,但限制最大宽度 800,高度 500
                    let imgW = img.width;
                    let imgH = img.height;
                    const maxW = 800;
                    const maxH = 500;
                    // 缩放比例
                    let ratio = Math.min(maxW/imgW, maxH/imgH, 1);
                    let scaledW = Math.floor(imgW * ratio);
                    let scaledH = Math.floor(imgH * ratio);
                    canvas.width = scaledW;
                    canvas.height = scaledH;
                    ctx.clearRect(0, 0, scaledW, scaledH);
                    // 背景填充为白色,便于后续处理(默认展示白色底)
                    ctx.fillStyle = '#ffffff';
                    ctx.fillRect(0, 0, scaledW, scaledH);
                    ctx.drawImage(img, 0, 0, scaledW, scaledH);
                    // 保存原始canvas
                    originalCanvas = document.createElement('canvas');
                    originalCanvas.width = scaledW;
                    originalCanvas.height = scaledH;
                    const octx = originalCanvas.getContext('2d');
                    octx.drawImage(canvas, 0, 0);
                    hasImage = true;
                    // 更新显示文件名
                    fileNameDisplay.textContent = `📄 ${file.name}`;
                    // 清掉文件input内部(但保留同文件可选)
                    fileInput.value = '';
                };
                img.src = event.target.result;
            };
            reader.readAsDataURL(file);
        });
        // ---------- 转换底色核心算法 ----------
        function convertBackground(targetHex) {
            if (!hasImage || !originalCanvas) {
                alert('请先选择图片');
                return;
            }
            // 获取原始图像数据
            const origCtx = originalCanvas.getContext('2d', { willReadFrequently: true });
            const origData = origCtx.getImageData(0, 0, originalCanvas.width, originalCanvas.height);
            const data = new Uint8ClampedArray(origData.data); // 复制一份进行修改
            // 解析目标RGB
            let targetR = parseInt(targetHex.substr(1,2), 16);
            let targetG = parseInt(targetHex.substr(3,2), 16);
            let targetB = parseInt(targetHex.substr(5,2), 16);
            const tolerance = 165;      // 背景识别容差(大于等于245的像素都视为“浅色/白色”背景区域)
            const outputR = targetR;
            const outputG = targetG;
            const outputB = targetB;
            const totalPixels = data.length / 4;
            // 第一步:扫描所有像素,找出“背景像素”——即亮度很高且颜色饱和度较低的浅色像素(近似白色、灰色、很浅的彩色)
            // 阈值:RGB 每个通道 > 245 或 亮度 > 245 且饱和度低,但更通用:只要三个通道都 > 200且接近无色(最大通道差<30)都视为底色
            // 但是这里图片可能含有白色物体,所以只处理“浅色占大部分”的边缘情况,为了简化,我们处理纯白色或接近白色像素。
            // 可以调整策略: 将 R,G,B 都大于 245 的像素判定为背景。
            const isBackground = new Uint8Array(totalPixels);
            for (let i = 0; i < totalPixels; i++) {
                const idx = i * 4;
                const r = data[idx];
                const g = data[idx+1];
                const b = data[idx+2];
                // 背景像素: 非常亮且饱和度低的颜色 (白色、极浅灰色)
                // 增加兼容:所有通道 > 240 或 (亮度>240且max-min<15)
                const maxC = Math.max(r, g, b);
                const minC = Math.min(r, g, b);
                if (r > 240 && g > 240 && b > 240) {
                    isBackground[i] = 1;
                } else if (maxC > 235 && (maxC - minC) < 12) {
                    isBackground[i] = 1;
                }
                // 可额外处理接近白色的背景,否则略过
            }
            // 第二步:将背景像素替换为目标颜色,非背景像素保持不变
            for (let i = 0; i < totalPixels; i++) {
                if (isBackground[i]) {
                    const idx = i * 4;
                    data[idx] = outputR;
                    data[idx+1] = outputG;
                    data[idx+2] = outputB;
                    data[idx+3] = 255;   // 不透明
                }
            }
            // 写入canvas
            const imageData = new ImageData(data, originalCanvas.width, originalCanvas.height);
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.putImageData(imageData, 0, 0);
            // 注意:转换后originalCanvas不应该更新,因为要保留原图,如果再次转换会丢失原始信息。
            // 这里我们保持originalCanvas不变,但canvas预览变为已转换的图像,后续点击下载导出基于canvas即可。
        }
        // ---------- 事件绑定 ----------
        convertBtn.addEventListener('click', function() {
            const hexColor = bgColorInput.value; // #ff00aa
            if (!hasImage) {
                alert('请先选择一张图片');
                return;
            }
            convertBackground(hexColor);
        });
        // 恢复原始图片 (其实为了用户体验,可以把未修改的原始图片存到originalCanvas,每次转换仅基于originalCanvas)
        // 但为了可以在转换后再点转换,我们需要基于原始originalCanvas重建,而不是基于已经被修改的canvas。
        // 改进:convertBackground 每次基于 originalCanvas 的图像数据,所以不管canvas现在是什么,都不影响。
        // 现在convert函数内使用origData,完美。
        // 可添加“重置”按钮?为了体验,可以双击canvas重置,但不做复杂UI,临时加一个监听: 点击文件名区域重置
        // 但工具已经够用,用户点击【选择图片】会自动重置。
        // 下载
        downloadBtn.addEventListener('click', function() {
            if (!hasImage) {
                alert('没有图片可下载');
                return;
            }
            const link = document.createElement('a');
            link.download = `converted_${Date.now()}.png`;
            link.href = canvas.toDataURL('image/png');
            link.click();
        });
        // 当点击选择图片后,如果读图失败或者空,就不动。
        // 同时添加一个重置小功能:双击预览恢复原始图像
        canvas.addEventListener('dblclick', function() {
            // 恢复显示originalCanvas
            if (originalCanvas) {
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                ctx.drawImage(originalCanvas, 0, 0);
                hasImage = true;
            } else {
                drawPlaceholder();
            }
        });
        // 如果文件为空,保留默认示例,同时如果用户没有上传图片但是点击转换,会提示先选择图片(默认示例也是图,可以展示转换效果)
        // 但hasImage默认是true,因为drawPlaceholder设置了originalCanvas,可以转换示例图片,很棒。
        // 但是目前placeholder生成的是示例,已经可以测试。
        // 处理窗口变化预留(无)
        // 修改颜色选择器默认白色
        // 初始化: 让原始画布清晰
        restoreOriginal();
        // 如果样例颜色改变,用户再次点击转换,会基于originalCanvas,不受之前转换影响 (因为我们每次convert都从originalCanvas取值)
        // 转换后canvas更新的图像不会更新originalCanvas,因此再次点击依旧用原图。
        console.log('✅ 图片底色转换脚本已就绪。');
    })();
</script>
</body>
</html>

功能与操作说明

您可以轻松上传图片并一键替换其浅色背景,非常适合快速制作纯色背景的图片。

怎么用脚本转换图片底色

  • 图片上传与预览:页面顶部提供“选择图片”按钮,支持从本地加载常见格式的图片,加载后,图片会显示在中央的预览画布上,文件名也会同步更新。
  • 核心功能操作:通过颜色选择器选取您想要的目标底色,然后点击“转换底色”按钮,工具会智能识别并替换图片中的白色或浅色背景区域,其他颜色像素将保持不变。
  • 结果处理与提示:转换后的图片会立即在画布上预览,您可以使用“下载图片”按钮将其保存为PNG格式,双击预览区域可以随时恢复显示原始图片,方便对比效果。

抱歉,评论功能暂时关闭!