在系统开发与维护中,经常需要调整图像中的特定颜色。然而,对于非设计人员而言,打开专业图像软件往往意味着高昂的学习成本和漫长的摸索时间。一款轻量化的在线换色工具,让开发者、产品经理或运营人员无需任何设计基础,即可通过简单的点选操作自助完成图标色彩调整,即时预览效果并直接投入使用,彻底摆脱对外部资源的依赖,实现视觉迭代的完全自主可控。本文将介绍如何使用 HTML、CSS 和 JavaScript 实现一个图片换色工具。效果演示
这个图片换色工具具有直观的用户界面和流畅的交互体验。用户首先通过“上传图片”按钮导入待处理的图像,随后可以在左侧原图区域点击任意位置来选取颜色作为源颜色,系统会自动生成一个新的颜色替换规则。在右侧的控制面板中,用户可以添加多个颜色替换规则,每个规则都包含源颜色、目标颜色以及颜色容差设置。当用户调整颜色值或容差参数时,处理后的图像会实时显示在右侧画布上,与原始图像形成对比。用户还可以通过缩放控件放大缩小图像查看细节,并最终下载处理后的图片。
页面结构
工具栏区域
顶部工具栏提供基本操作功能,包括上传、重置和下载按钮。<div class="toolbar"> <button id="uploadBtn" class="tool-btn primary">上传图片</button> <input type="file" id="imageUpload" accept="image/*">
<div class="tool-group"> <button id="resetBtn" class="tool-btn danger">重置</button> <button id="downloadBtn" class="tool-btn success">下载</button> </div></div>
图像展示区域
图像展示区域包含原始图像和处理后图像的对比展示,支持缩放功能。<div class="image-area"> <div class="image-comparison"> <div class="image-pair"> <div class="canvas-container"> <canvas id="sourceCanvas">您的浏览器不支持Canvas,请使用现代浏览器。</canvas> </div> <div class="image-label">原图</div> </div> <div class="image-pair"> <div class="canvas-container"> <canvas id="processedCanvas">您的浏览器不支持Canvas,请使用现代浏览器。</canvas> </div> <div class="image-label">处理后</div> </div> </div> <div class="zoom-controls" style="display: none;"> <button class="zoom-btn" id="zoomOutBtn">-</button> <div class="zoom-display" id="zoomDisplay">100%</div> <button class="zoom-btn" id="zoomInBtn">+</button> </div></div>
控制面板区域
右侧控制面板用于管理颜色替换规则,支持添加、删除和修改规则。<div class="controls-panel"> <h2 class="section-title">颜色替换规则 <button id="addAnotherRuleBtn">添加</button> </h2> <div class="color-rules-container" id="colorRulesContainer"></div></div>
核心功能实现
图像加载与初始化
loadImage 函数负责读取用户选择的文件,并将其绘制到Canvas上。函数首先使用 FileReader 读取文件,然后创建 Image 对象加载图像数据。计算合适的显示尺寸以适应容器大小,并将原始图像数据存储在 currentImageData 变量中供后续处理使用。function loadImage(file) { const reader = new FileReader();
reader.onload = function(e) { const img = new Image(); img.onload = function() { originalImage = img; isImageLoaded = true;
const container = document.querySelector('.image-area'); const maxWidth = container.clientWidth / 2 - 30; const maxHeight = container.clientHeight - 40;
let width = img.width; let height = img.height;
if (width > maxWidth) { height = (maxWidth / width) * height; width = maxWidth; }
if (height > maxHeight) { width = (maxHeight / height) * width; height = maxHeight; }
processedCanvas.width = width; processedCanvas.height = height; sourceCanvas.width = width; sourceCanvas.height = height;
sourceCtx.clearRect(0, 0, sourceCanvas.width, sourceCanvas.height); sourceCtx.drawImage(img, 0, 0, width, height);
const tempCanvas = document.createElement('canvas'); const tempCtx = tempCanvas.getContext('2d'); tempCanvas.width = width; tempCanvas.height = height; tempCtx.drawImage(img, 0, 0, width, height); currentImageData = tempCtx.getImageData(0, 0, width, height);
applyColorAdjustments();
resetAdjustments();
zoomControls.style.display = 'flex'; }; img.src = e.target.result; };
reader.readAsDataURL(file);}
颜色替换算法
applyColorAdjustments 函数遍历图像的每个像素,检查是否符合任何颜色替换规则。对于每个像素,函数计算其与源颜色的差异值,如果差异小于容差阈值,则将该像素的颜色替换为目标颜色。
colorDistance 函数使用加权欧几里得距离算法来计算颜色差异,这种方式更符合人眼对颜色差异的感知。
function applyColorAdjustments() { if (!isImageLoaded || !currentImageData) return;
const imageData = new ImageData( new Uint8ClampedArray(currentImageData.data), currentImageData.width, currentImageData.height ); const data = imageData.data;
const rules = colorRules .filter(rule => rule.enabled) .map(rule => { const sourceRgb = hexToRgb(rule.sourceColor); const targetRgb = hexToRgb(rule.targetColor); const tolerance = rule.tolerance / 100 * 255;
return {...rule, sourceRgb, targetRgb, tolerance}; });
for (let i = 0; i < data.length; i += 4) { let r = data[i]; let g = data[i + 1]; let b = data[i + 2];
for (const rule of rules) { const colorDiff = Math.sqrt( Math.pow(r - rule.sourceRgb.r, 2) + Math.pow(g - rule.sourceRgb.g, 2) + Math.pow(b - rule.sourceRgb.b, 2) );
if (colorDiff <= rule.tolerance) { r = rule.targetRgb.r; g = rule.targetRgb.g; b = rule.targetRgb.b; break; } }
data[i] = r; data[i + 1] = g; data[i + 2] = b; }
drawImage(imageData);}
function colorDistance(color1, color2) { const dr = color1.r - color2.r; const dg = color1.g - color2.g; const db = color1.b - color2.b;
return Math.sqrt(0.299 * dr * dr + 0.587 * dg * dg + 0.114 * db * db);}
颜色规则管理
addColorRule 函数负责创建新的颜色替换规则,默认情况下会生成随机颜色作为源颜色,绿色作为目标颜色。
createColorRuleElement 函数生成每个规则的HTML结构,包括颜色选择器、容差滑块和删除按钮。
bindRuleEvents 函数为所有规则元素绑定事件监听器,确保用户交互能够实时更新处理结果。
function addColorRule(sourceColor = null) { ruleCounter++;
if (!sourceColor) { sourceColor = rgbToHex( Math.floor(Math.random() * 256), Math.floor(Math.random() * 256), Math.floor(Math.random() * 256) ); }
const newRule = { id: ruleCounter, sourceColor: sourceColor, targetColor: '#00FF00', tolerance: 30, enabled: true };
colorRules.push(newRule); renderColorRules(); applyColorAdjustments();
return newRule.id;}
function createColorRuleElement(rule) { const ruleElement = document.createElement('div'); ruleElement.className = 'color-rule'; ruleElement.dataset.id = rule.id;
let targetColor = rule.targetColor; if (!targetColor) { targetColor = '#00FF00'; }
ruleElement.innerHTML = `<div class="color-rule-header"> <div class="rule-title">颜色规则 ${rule.id}</div> <button class="delete-rule-btn" data-id="${rule.id}">×</button> </div> <div class="color-rule-controls"> <div class="color-input-group"> <div class="color-label">原色:</div> <div class="color-input-row"> <input type="color" class="source-color" value="${rule.sourceColor}" data-id="${rule.id}"> <span class="color-value source-color-value" data-id="${rule.id}">${rule.sourceColor}</span> </div> </div> <div class="color-input-group"> <div class="color-label">目标色:</div> <div class="color-input-row"> <input type="color" class="target-color" value="${targetColor}" data-id="${rule.id}"> <span class="color-value target-color-value" data-id="${rule.id}">${targetColor}</span> </div> </div> </div> <div class="tolerance-label"> <span>颜色容差:</span> <span class="tolerance-value" data-id="${rule.id}">${rule.tolerance}%</span> </div> <input type="range" class="tolerance-slider" min="0" max="100" value="${rule.tolerance}" data-id="${rule.id}">`;
return ruleElement;}
function bindRuleEvents() { document.querySelectorAll('input[type="color"]').forEach(input => { input.removeEventListener('input', handleColorInputChange); input.addEventListener('input', handleColorInputChange); });
document.querySelectorAll('.tolerance-slider').forEach(slider => { slider.removeEventListener('input', handleToleranceChange); slider.addEventListener('input', handleToleranceChange); });
document.querySelectorAll('.delete-rule-btn').forEach(button => { button.removeEventListener('click', handleDeleteRule); button.addEventListener('click', handleDeleteRule); });}
图像缩放功能
syncUpdateZoom 函数同步更新两个画布的缩放级别,确保原图和处理后图片保持一致的视图比例。
function syncUpdateZoom(level) { const sourceContainer = document.querySelector('#sourceCanvas').parentElement; const processedContainer = document.querySelector('#processedCanvas').parentElement;
updateZoomLevel(sourceCanvas, sourceContainer, level); updateZoomLevel(processedCanvas, processedContainer, level);}
function updateZoomLevel(canvas, container, level) { const originalWidth = canvas.width; const originalHeight = canvas.height;
const newWidth = originalWidth * level; const newHeight = originalHeight * level;
canvas.style.width = newWidth + 'px'; canvas.style.height = newHeight + 'px';}
源码地址
git地址:https://gitee.com/ironpro/hjdemo/blob/master/image-color/index.html
阅读原文:原文链接
该文章在 2026/1/29 10:13:42 编辑过