怎么用脚本转换图片为黑白

wen 实用脚本 1

我会为您生成一个可直接运行的HTML文档,它利用浏览器原生的Canvas功能,帮助您将彩色图片转换为黑白效果。

怎么用脚本转换图片为黑白

<!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;
            font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
        }
        body {
            background: #f4f6f9;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            margin: 2rem 1rem;
        }
        .card {
            background: white;
            max-width: 800px;
            width: 100%;
            border-radius: 28px;
            box-shadow: 0 12px 30px rgba(0, 0, 0, 0.08);
            padding: 2rem 2rem 2.5rem;
            transition: 0.2s;
        }
        h1 {
            font-size: 1.9rem;
            font-weight: 500;
            letter-spacing: -0.3px;
            color: #1e293b;
            margin-top: 0.2rem;
            margin-bottom: 0.5rem;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        h1 small {
            font-size: 1rem;
            font-weight: 400;
            color: #64748b;
            margin-left: 8px;
        }
        .sub {
            color: #475569;
            border-left: 4px solid #94a3b8;
            padding-left: 14px;
            margin: 0.8rem 0 1.8rem 0;
            font-size: 0.95rem;
            background: #f8fafc;
            border-radius: 0 8px 8px 0;
            line-height: 1.5;
        }
        .upload-area {
            border: 2px dashed #cbd5e1;
            border-radius: 24px;
            padding: 2.5rem 1rem;
            text-align: center;
            background: #fafcff;
            transition: all 0.2s;
            cursor: pointer;
        }
        .upload-area:hover {
            border-color: #3b82f6;
            background: #f0f7ff;
        }
        .upload-area.dragover {
            border-color: #2563eb;
            background: #eef2ff;
            transform: scale(1.01);
        }
        .upload-icon {
            font-size: 2.8rem;
            margin-bottom: 8px;
        }
        .upload-text {
            font-size: 1.1rem;
            font-weight: 450;
            color: #1e293b;
        }
        .upload-hint {
            font-size: 0.9rem;
            color: #64748b;
            margin-top: 6px;
        }
        #fileInput {
            display: none;
        }
        .preview-grid {
            display: flex;
            flex-wrap: wrap;
            gap: 1.8rem;
            margin: 2rem 0 1.2rem;
            justify-content: center;
        }
        .img-box {
            flex: 1 1 200px;
            min-width: 160px;
            background: #f1f5f9;
            border-radius: 18px;
            padding: 12px 12px 16px;
            box-shadow: 0 2px 6px rgba(0,0,0,0.02);
            transition: 0.1s;
        }
        .img-box p {
            margin: 6px 0 4px 0;
            font-weight: 450;
            font-size: 0.9rem;
            color: #334155;
            display: flex;
            justify-content: space-between;
        }
        .img-box img, .img-box canvas {
            width: 100%;
            height: auto;
            border-radius: 12px;
            display: block;
            background: #ffffff;
            box-shadow: 0 2px 8px rgba(0,0,0,0.04);
        }
        .action-bar {
            display: flex;
            flex-wrap: wrap;
            align-items: center;
            justify-content: space-between;
            margin: 1.6rem 0 0.6rem;
            gap: 12px;
        }
        .btn-group {
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
        }
        .btn {
            background: #ffffff;
            border: 1px solid #d1d9e8;
            padding: 0.6rem 1.2rem;
            border-radius: 40px;
            font-weight: 500;
            font-size: 0.9rem;
            color: #1e293b;
            cursor: pointer;
            transition: 0.15s;
            display: inline-flex;
            align-items: center;
            gap: 6px;
            box-shadow: 0 1px 2px rgba(0,0,0,0.02);
        }
        .btn-primary {
            background: #1e293b;
            border: 1px solid #1e293b;
            color: white;
        }
        .btn-primary:hover {
            background: #0f172a;
            border-color: #0f172a;
        }
        .btn-outline {
            border: 1px solid #cbd5e1;
            background: white;
        }
        .btn-outline:hover {
            background: #f1f5f9;
        }
        .btn:active {
            transform: scale(0.96);
        }
        .btn:disabled {
            opacity: 0.4;
            pointer-events: none;
            filter: grayscale(0.3);
        }
        .slider-box {
            display: flex;
            align-items: center;
            gap: 12px;
            background: #f8fafc;
            padding: 0.2rem 1rem 0.2rem 1.2rem;
            border-radius: 40px;
            border: 1px solid #e2e8f0;
        }
        .slider-box label {
            font-size: 0.85rem;
            font-weight: 450;
            color: #334155;
        }
        input[type="range"] {
            width: 100px;
            height: 4px;
            -webkit-appearance: none;
            background: #cbd5e1;
            border-radius: 4px;
        }
        input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            width: 16px;
            height: 16px;
            border-radius: 50%;
            background: #1e293b;
            cursor: pointer;
            border: 2px solid white;
            box-shadow: 0 1px 4px rgba(0,0,0,0.2);
        }
        .status {
            color: #475569;
            font-size: 0.9rem;
            margin-top: 8px;
            min-height: 28px;
            padding: 0 4px;
        }
        .footer-note {
            border-top: 1px solid #e9edf2;
            margin-top: 1.8rem;
            padding-top: 1.2rem;
            font-size: 0.8rem;
            color: #6b7280;
            display: flex;
            justify-content: space-between;
            flex-wrap: wrap;
        }
        @media (max-width: 550px) {
            .card { padding: 1.5rem; }
            .preview-grid { flex-direction: column; }
            .action-bar { flex-direction: column; align-items: stretch; }
            .slider-box { justify-content: center; }
        }
    </style>
</head>
<body>
<div class="card">
    <h1>
        🎯 图片转黑白
        <small>· 浏览器脚本</small>
    </h1>
    <div class="sub">
        ⚡ 上传彩色图片,使用 Canvas 像素操作实时转换为黑白 · 可调节灰度强度
    </div>
    <!-- 上传区域 -->
    <div class="upload-area" id="dropZone">
        <div class="upload-icon">📸</div>
        <div class="upload-text">点击上传 或 拖拽图片到这里</div>
        <div class="upload-hint">支持 JPG / PNG / WebP</div>
        <input type="file" id="fileInput" accept="image/*">
    </div>
    <!-- 预览区域 -->
    <div class="preview-grid" id="previewContainer">
        <div class="img-box" id="originalBox">
            <p>🖼️ 原图 <span style="font-weight:400; color:#64748b;" id="originalInfo">—</span></p>
            <img id="originalImage" src="" alt="原始图片" style="display:none;">
            <canvas id="originalCanvas" style="display:none;"></canvas>
            <div style="min-height:120px; display: flex; align-items: center; justify-content: center; color:#94a3b8;" id="placeholderOriginal">
                <span>等待上传</span>
            </div>
        </div>
        <div class="img-box" id="bwBox">
            <p>⚫ 黑白效果 <span style="font-weight:400; color:#64748b;" id="bwInfo">—</span></p>
            <canvas id="bwCanvas" style="display:none; width:100%; height:auto;"></canvas>
            <div style="min-height:120px; display: flex; align-items: center; justify-content: center; color:#94a3b8;" id="placeholderBW">
                <span>等待转换</span>
            </div>
        </div>
    </div>
    <!-- 控制栏 -->
    <div class="action-bar">
        <div class="btn-group">
            <button class="btn btn-primary" id="convertBtn" disabled>✨ 转换为黑白</button>
            <button class="btn btn-outline" id="downloadBtn" disabled>⬇ 下载黑白图</button>
        </div>
        <div class="slider-box">
            <label for="strengthSlider">强度</label>
            <input type="range" id="strengthSlider" min="0" max="100" value="100">
            <span style="font-size:0.8rem; min-width:32px; font-weight:500;" id="strengthValue">100%</span>
        </div>
    </div>
    <div class="status" id="statusMessage">💡 请上传一张图片开始</div>
    <div class="footer-note">
        <span>🛠 基于 Canvas · 像素级灰度算法</span>
        <span>⚙️ 调节「强度」可混合原图色彩</span>
    </div>
</div>
<script>
    (function() {
        // DOM 元素
        const fileInput = document.getElementById('fileInput');
        const dropZone = document.getElementById('dropZone');
        const originalImage = document.getElementById('originalImage');
        const originalCanvas = document.getElementById('originalCanvas');
        const bwCanvas = document.getElementById('bwCanvas');
        const placeholderOriginal = document.getElementById('placeholderOriginal');
        const placeholderBW = document.getElementById('placeholderBW');
        const convertBtn = document.getElementById('convertBtn');
        const downloadBtn = document.getElementById('downloadBtn');
        const strengthSlider = document.getElementById('strengthSlider');
        const strengthValue = document.getElementById('strengthValue');
        const statusMessage = document.getElementById('statusMessage');
        const originalInfo = document.getElementById('originalInfo');
        const bwInfo = document.getElementById('bwInfo');
        // 状态
        let currentFile = null;          // 当前上传的文件
        let imageLoaded = false;        // 原图是否已加载到 img
        let bwGenerated = false;        // 是否已生成黑白图
        let bwDataUrl = '';             // 最近生成的黑白 dataURL (用于下载)
        // ---------- 辅助: 隐藏占位,显示图片/画布 ----------
        function showOriginalElement() {
            placeholderOriginal.style.display = 'none';
            originalImage.style.display = 'block';
            originalCanvas.style.display = 'none';   // 原图用img展示
        }
        function showOriginalPlaceholder() {
            placeholderOriginal.style.display = 'flex';
            originalImage.style.display = 'none';
            originalCanvas.style.display = 'none';
        }
        function showBWCanvas() {
            placeholderBW.style.display = 'none';
            bwCanvas.style.display = 'block';
        }
        function showBWPlaceholder() {
            placeholderBW.style.display = 'flex';
            bwCanvas.style.display = 'none';
        }
        // ---------- 重置状态 (除了文件信息) ----------
        function resetStates(keepFile = false) {
            if (!keepFile) {
                currentFile = null;
                imageLoaded = false;
            }
            bwGenerated = false;
            bwDataUrl = '';
            convertBtn.disabled = true;
            downloadBtn.disabled = true;
            // 不重置滑块值
        }
        // ---------- 加载图片文件 ----------
        function loadImageFile(file) {
            // 校验类型
            if (!file || !file.type.startsWith('image/')) {
                statusMessage.textContent = '❌ 请上传有效的图片文件 (jpg/png/webp)';
                return;
            }
            resetStates(true);    // 保留 currentFile (下面会覆盖)
            currentFile = file;
            const reader = new FileReader();
            reader.onload = (e) => {
                const dataURL = e.target.result;
                originalImage.onload = () => {
                    // 原图加载完成
                    imageLoaded = true;
                    // 显示原图
                    showOriginalElement();
                    // 更新图像信息
                    const w = originalImage.naturalWidth;
                    const h = originalImage.naturalHeight;
                    originalInfo.textContent = `${w} × ${h}`;
                    // 重置黑白区域
                    showBWPlaceholder();
                    bwInfo.textContent = '—';
                    bwGenerated = false;
                    bwDataUrl = '';
                    convertBtn.disabled = false;
                    downloadBtn.disabled = true;
                    statusMessage.textContent = `✅ 已加载: ${file.name} (${w}×${h}) · 点击「转换为黑白」`;
                };
                originalImage.onerror = () => {
                    statusMessage.textContent = '⚠️ 图片加载失败,请重试';
                    showOriginalPlaceholder();
                    resetStates(false);
                };
                originalImage.src = dataURL;
            };
            reader.onerror = () => {
                statusMessage.textContent = '⚠️ 文件读取失败';
            };
            reader.readAsDataURL(file);
        }
        // ---------- 转换核心: 彩色 -> 黑白 (带强度混合) ----------
        function convertToBlackWhite() {
            if (!imageLoaded || !originalImage.complete || originalImage.naturalWidth === 0) {
                statusMessage.textContent = '⚠️ 原图尚未加载完成,请等待';
                return;
            }
            const img = originalImage;
            const w = img.naturalWidth;
            const h = img.naturalHeight;
            // 设置原画布尺寸 (备用,但不一定显示)
            originalCanvas.width = w;
            originalCanvas.height = h;
            const ctxOrig = originalCanvas.getContext('2d');
            ctxOrig.drawImage(img, 0, 0);
            // 设置黑白画布
            bwCanvas.width = w;
            bwCanvas.height = h;
            const ctxBw = bwCanvas.getContext('2d');
            // 先把原图画到黑白画布上 (作为基础)
            ctxBw.drawImage(img, 0, 0);
            // 获取像素数据
            const imageData = ctxBw.getImageData(0, 0, w, h);
            const data = imageData.data;
            const strength = parseInt(strengthSlider.value, 10) / 100;  // 0 ~ 1
            // 如果没有强度 (strength=0) 直接就是原彩,但这种情况一般没必要,但仍处理
            if (strength === 0) {
                // 什么都不做,就是原图
            } else {
                // 遍历像素,应用灰度 + 混合
                for (let i = 0; i < data.length; i += 4) {
                    const r = data[i];
                    const g = data[i + 1];
                    const b = data[i + 2];
                    // 标准灰度 luminosity 权重
                    const gray = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
                    if (strength === 1) {
                        // 完全黑白
                        data[i]     = gray;   // R
                        data[i + 1] = gray;   // G
                        data[i + 2] = gray;   // B
                    } else {
                        // 混合:  strength 控制黑白比例, (1-strength) 保留原色
                        const mixR = Math.round(gray * strength + r * (1 - strength));
                        const mixG = Math.round(gray * strength + g * (1 - strength));
                        const mixB = Math.round(gray * strength + b * (1 - strength));
                        data[i]     = mixR;
                        data[i + 1] = mixG;
                        data[i + 2] = mixB;
                    }
                    // alpha 不变
                }
            }
            // 将处理后的数据放回
            ctxBw.putImageData(imageData, 0, 0);
            // 显示黑白画布
            showBWCanvas();
            bwInfo.textContent = `${w} × ${h}`;
            bwGenerated = true;
            bwDataUrl = bwCanvas.toDataURL('image/png');
            downloadBtn.disabled = false;
            statusMessage.textContent = `🎯 黑白转换完成 (强度: ${strengthSlider.value}%)`;
        }
        // ---------- 下载黑白图片 ----------
        function downloadBW() {
            if (!bwGenerated || !bwDataUrl) {
                statusMessage.textContent = '⚠️ 还没有可下载的黑白图片,请先转换';
                return;
            }
            const link = document.createElement('a');
            link.download = `黑白_${currentFile ? currentFile.name.replace(/\.[^.]+$/, '') : 'image'}.png`;
            link.href = bwDataUrl;
            link.click();
            statusMessage.textContent = `⬇️ 下载已开始 (PNG 格式)`;
        }
        // ---------- 事件绑定 ----------
        // 1. 上传按钮 / 拖拽
        dropZone.addEventListener('click', () => fileInput.click());
        fileInput.addEventListener('change', (e) => {
            if (e.target.files && e.target.files.length > 0) {
                loadImageFile(e.target.files[0]);
            }
            fileInput.value = ''; // 允许重复选择相同文件
        });
        // 拖拽事件
        dropZone.addEventListener('dragover', (e) => {
            e.preventDefault();
            dropZone.classList.add('dragover');
        });
        dropZone.addEventListener('dragleave', () => {
            dropZone.classList.remove('dragover');
        });
        dropZone.addEventListener('drop', (e) => {
            e.preventDefault();
            dropZone.classList.remove('dragover');
            if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
                loadImageFile(e.dataTransfer.files[0]);
            }
        });
        // 2. 转换按钮
        convertBtn.addEventListener('click', convertToBlackWhite);
        // 3. 下载按钮
        downloadBtn.addEventListener('click', downloadBW);
        // 4. 滑块实时更新数值 + 自动重转换 (如果已经生成过黑白)
        strengthSlider.addEventListener('input', function() {
            strengthValue.textContent = `${this.value}%`;
            if (imageLoaded && bwGenerated) {
                // 如果已经有黑白图,重新转换以应用新的强度
                convertToBlackWhite();
            } else if (imageLoaded) {
                // 有图但还没转黑白:什么都不做,或者显示提示
                // 但为了友好,可以自动转换?这里选择如果图片已加载,点击转换才执行;但滑块不自动转(除非已转换过)
                // 更合理:如果图片加载了且没有黑白,不动;但如果图片加载了,显示提示可以转换
                if (!bwGenerated) {
                    statusMessage.textContent = '💡 拖动强度后,点击「转换为黑白」生效';
                }
            }
        });
        // 额外: 如果图片加载后用户没按转换,但拖动滑块,显示提示
        strengthSlider.addEventListener('mouseup', function() {
            if (imageLoaded && !bwGenerated) {
                statusMessage.textContent = '👆 点击「转换为黑白」应用当前强度';
            }
        });
        // 5. 快捷键 & 初始化占位
        showOriginalPlaceholder();
        showBWPlaceholder();
        resetStates(false);
        statusMessage.textContent = '💡 请上传一张图片开始';
        // 如果用户点击原图或黑白占位,不做特殊处理
        console.log('🖼 图片黑白转换脚本已启动');
    })();
</script>
</body>
</html>

核心功能与操作流程

您可以通过上传图片并调节强度,轻松获得理想的黑白效果,其核心转换逻辑基于像素级的灰度算法,并提供了直观的控制选项。

  • 图片上传:您可以通过点击上传区域或直接拖拽图片文件(支持 JPG、PNG、WebP 格式)来加载需要处理的彩色图片。
  • 黑白转换与强度调节:点击“转换为黑白”按钮即可应用效果,您还可以通过“强度”滑块,在纯黑白与原图色彩之间进行混合调节,获得丰富的灰度过渡效果。
  • 结果预览与下载:页面会并排显示原图与转换后的黑白效果,确认效果后,点击“下载黑白图”按钮即可将结果保存为 PNG 格式的图片。

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