The core steps of color recognition are as follows: 1. After selecting the image, use FileReader API to convert the image into base64 format 2. Create an IMG tag and assign the contents of Base64 to the SRC attribute 3 of the IMG tag. Call the Canvas drawImage() method to make the Canvas draw the image 4. Call the Canvas getImageData() method to get the color value 5 for a pixel. Display the color value in RGB and hexadecimal format
Running effect
The initial page consists of a display box and a button to select an image. After selecting an image, move the mouse pointer to the image and the color value of the image will be displayed.
The source code:
<! doctypehtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width =device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Image color recognition</title>
<style>
body {
display: flex;
justify-content: center;
/*align-items: center; * /
background: white;
margin-top: 20px;
}
#color {
height: 30px;
line-height: 30px;
text-align: center;
}
#canvas {
border: 1px dashed # 000;
}
.tooltip {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
min-width: 150px;
min-height: 80px;
margin: 10px;
padding: 10px 20px;
border: 1px solid #b3c9ce;
border-radius: 4px;
color: #eee;
font-size: 16px;
box-shadow: 3px 3px 3px rgba(0.0.0.3);
z-index: 9999999999999999999999;
}
.fileWrap {
margin-left: 200px;
}
</style>
</head>
<body>
<div class="wrapper">
<canvas id="canvas" width="600" height="400"></canvas>
<br>
<br>
<div class="fileWrap">
<input type="file" onchange="selectImg(this)">
</div>
<br>
<div id="color"></div>
<br>
</div>
<script>
var canvas = document.getElementById('canvas');
var canvasW = canvas.width;
var canvasH = canvas.height;
var ctx = canvas.getContext('2d');
var isSelectImg = false;
function selectImg(that) {
isSelectImg = true;
// console.log("that: ", that);
var file = that.files[0];
// console.log(file);
var reader = new FileReader();
// console.log("reader: ", reader);
reader.readAsDataURL(file);
reader.onload = (e) = > {
var img = new Image();
img.src = reader.result;
img.onload = () = > {
// console.log("img.width, img.height: ", img.width, img.height);
ctx.clearRect(0.0, canvasW, canvasH);
if (img.width < canvasW && img.height < canvasH) {
canvas.height = canvasH;
ctx.drawImage(img, 0.0, img.width, img.height);
} else {
canvas.height = canvasW * img.height / img.width; // Keep the image in shape
ctx.drawImage(img, 0.0, canvasW, canvas.height); }}}}// RGB to Hex
function colorRGBtoHex(rgb_color) {
if (/(^(*(RGB)\((*\d{1,3} *,){2} *\d{1,3} *\)) *$)/.test(rgb_color)) {
var rgb = rgb_color.split(', ');
var r = parseInt(rgb[0].split('(') [1]);
var g = parseInt(rgb[1]);
var b = parseInt(rgb[2].split(') ') [0]);
var hex = "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
return hex;
}
return rgb_color;
}
// Follow the mouse movement of the tooltip
function toolTip() {
let tooltipElem, timer;
let color = document.getElementById('color');
document.onmouseover = function(e) {
var target = e.target;
if(! isSelectImg)return;
if(target.tagName ! = ='CANVAS') {
return;
}
tooltipElem = document.createElement('div');
tooltipElem.className = "tooltip";
document.body.append(tooltipElem);
document.onmousemove = function(e) {
tooltipElem.style.left = e.clientX + 'px';
tooltipElem.style.top = e.clientY + 'px';
var x = e.layerX;
var y = e.layerY;
var pixel = ctx.getImageData(x, y, 1.1);
// console.log("pixel: ", pixel);
var data = pixel.data;
var rgb =
'rgb(' + data[0] +
', ' + data[1] +
', ' + data[2] +
// ',' + (data[3] / 255) + // rgba changed to RGB
') ';
// function throttling
clearInterval(timer);
timer = setTimeout(function() {
// Display color values
color.style.background = rgb;
color.textContent = rgb;
tooltipElem.innerText = colorRGBtoHex(rgb);
tooltipElem.style.background = rgb;
}, 15)}};document.onmouseout = function() {
if (tooltipElem) {
tooltipElem.remove();
tooltipElem = null;
}
document.onmousemove = null;
clearInterval(timer)
}
}
toolTip();
</script>
</body>
</html>
Copy the code
Image color recognition upgrade version
Upgrade function: 1. Add a color and save it to the database 2. If the color in the picture is consistent with the existing color in the database, the color name is displayed
Running effect after the upgrade
The initial interfaceSelect an image (the image I chose is a screenshot from the color control)
To add a color, enter a color name and a color value, then click Save:
Refresh the page and you can see the new color at the end of the comparison:
Upgraded source code
Back-end Node.js startup file (using Express + MySQL):
let my_mysql = require('mysql');
let express = require('express');
let path = require('path');
let conn = my_mysql.createConnection({
host : 'localhost'.user : 'root'.password : '123456'.database : 'color'
});
conn.connect();
var app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.json());// The data type is JSON
app.use(bodyParser.urlencoded({ extended: false }));// Parse post request data
app.use(express.static(path.join(__dirname, 'public')));
app.get('/getAllColor'.async function (req, res) {
getAllColor(req, res);
})
app.post('/insertColor'.async function (req, res) {
insertColor(req, res)
})
function getAllColor(req, res) {
conn.query(`SELECT * FROM color`.function (err, result) {
if (err) {
res.send({code: 1.msg: 'Database query error'});
console.log('[SELECT ERROR] - ', err.message);
return;
}
// console.log("result: ", result);
res.send(result)
})
}
function insertColor(req, res) {
console.log(req.body.name, req.body.value);
var name = req.body.name;
var value = req.body.value;
if (name && name.length > 20) return false;
if (value && value.length > 30) return false;
let sql = "INSERT INTO color(name, value) VALUES(? ,?) ";
let sqlVal = [name, value];
console.log("sqlVal: ", sqlVal);
conn.query(sql, sqlVal, function (err, result) {
if (err) {
console.log("err: ", err);
res.send('Add failed')
return false;
} else {
// console.log("result: ", result);
res.send('Added successfully')
return true; }})}var port = 4006;
console.log("Server startup time:".new Date().toLocaleString());
console.log("Open your browser and visit: http://localhost:"+port);
app.listen(port);
Copy the code
Database table design:
Vue + jQuery + Layer
<! doctypehtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="Width =device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Color identification</title>
<style>
body {
display: flex;
justify-content: center;
/*align-items: center; * /
background: white;
margin-top: 20px;
}
#color {
height: 30px;
line-height: 30px;
text-align: center;
}
#canvas {
border: 1px dashed # 000;
}
.tooltip {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
min-width: 150px;
min-height: 80px;
margin: 10px;
padding: 10px 20px;
border: 1px solid #b3c9ce;
border-radius: 4px;
color: #eee;
font-size: 16px;
box-shadow: 3px 3px 3px rgba(0.0.0.3);
z-index: 9999999999999999999999;
}
.fileWrap {
margin-left: 200px;
}
form input {
height: 25px;
width: 250px;
}
form div {
text-align: center;
margin-top: 5px;
line-height: 25px;
height: 25px;
}
.left {}
#colorList {
width: 350px;
height: 500px;
overflow: auto;
margin-left: 20px;
}
#colorList .name.#colorList .value.#colorList .colors {
display: inline-block;
width: 100px;
height: 30px;
overflow: hidden;
box-sizing: border-box;
}
</style>
<script src="lib/vue.js"></script>
<script src="lib/jq.js"></script>
<script src="layer/layer.js"></script>
</head>
<body>
<div class="left">
<canvas id="canvas" width="600" height="400"></canvas>
<br>
<br>
<div class="fileWrap">
<input type="file" onchange="selectImg(this)">
</div>
<br>
<div id="color"></div>
<br>
<form id="form">
<input type="text" id="name" placeholder="Color name" autocomplete="off">
<input type="text" id="value" oninput="realTimeShowColor(this.value)" placeholder="Color value (RGB and hexadecimal can be used)" autocomplete="off">
<button type="button" onclick="insertColor()">Save color value</button>
<div id="realTimeShowColorId"></div>
</form>
</div>
<div class="right">
<div id="colorList">
<h2>Color contrast (click on color value to copy)</h2>
<div>
<span class="name">Color name</span>
<span class="value">Color value</span>
<span class="colors">Color effect</span>
</div>
<div v-for="color in colors">
<span class="name" @click="copyColorValue">{{color.name}}</span>
<span class="value" @click="copyColorValue">{{color.value}}</span>
<span :style="'background:'+ color.value" class="colors"></span>
</div>
</div>
</div>
<script>
var alert = layer.msg; // Override the browser's own alert
var canvas = document.getElementById('canvas');
var realTimeShowColorId = document.getElementById('realTimeShowColorId')
var canvasW = canvas.width;
var canvasH = canvas.height;
var ctx = canvas.getContext('2d');
var isSelectImg = false;
// Match RGB or hexadecimal, RGB color values greater than 255 will be treated as 255, so more specific matching or judgment will not be done for the time being
var regExp = / (^ (RGB \ [(\ d {1, 3}, {2} {1, 3} \ \ d)) $) | (^ (# [0-9 a - fA - F] {6}) $) | (^ (# [0-9 a - fA - F] {3}) $) /;
function selectImg(that) {
isSelectImg = true;
// console.log("that: ", that);
var file = that.files[0];
// console.log(file);
var reader = new FileReader();
console.log("reader: ", reader);
reader.readAsDataURL(file);
reader.onload = (e) = > {
var img = new Image();
img.src = reader.result;
img.onload = () = > {
// console.log("img.width, img.height: ", img.width, img.height);
ctx.clearRect(0.0, canvasW, canvasH);
if (img.width < canvasW && img.height < canvasH) {
canvas.height = canvasH;
ctx.drawImage(img, 0.0, img.width, img.height);
} else {
canvas.height = canvasW * img.height / img.width; // Keep the image in shape
ctx.drawImage(img, 0.0, canvasW, canvas.height); }}}}function insertColor() {
var name = document.getElementById('name').value
var value = document.getElementById('value').value
if(! name) { alert('Color name cannot be empty')
return;
}
value = value.replace(/\s/g.' '); // Remove whitespace
if(! regExp.test(value)) { alert('Incorrect color input')
return;
}
$.ajax({
type: 'post'.url: '/insertColor'.data: {
name: name,
value: value
},
success(d) {
// console.log("d: ", d);
getAllColor();
document.forms[0].reset();
alert('Added successfully')}}}var vm = new Vue({
el: '#colorList'.data: {
colors: []},methods: {
copyColorValue(e) {
console.log("that: ", e.target.textContent);
var input = document.createElement('input');
input.value = e.target.textContent;
document.body.appendChild(input)
input.select();
document.execCommand("copy");
input.remove();
alert('Copy successful ~')}},created() {
// document.addEventListener('mousemove', function (e) {
// console.log("e: ", e);
// })}})function getAllColor() {
$.ajax({
url: '/getAllColor'.success(d) {
// console.log("getAllColor: ", d);
vm.colors = d;
}
})
}
getAllColor();
// RGB to Hex
function colorRGBtoHex(color) {
if (/(^(*(RGB)\((*\d{1,3} *,){2} *\d{1,3} *\)) *$)/.test(color)) {
var rgb = color.split(', ');
var r = parseInt(rgb[0].split('(') [1]);
var g = parseInt(rgb[1]);
var b = parseInt(rgb[2].split(') ') [0]);
var hex = "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
return hex;
}
return color;
}
function toolTip() {
let tooltipElem, timer;
let color = document.getElementById('color');
document.onmouseover = function(e) {
var target = e.target;
if(! isSelectImg)return;
if(target.tagName ! = ='CANVAS') {
return;
}
tooltipElem = document.createElement('div');
tooltipElem.className = "tooltip";
document.body.append(tooltipElem);
document.onmousemove = function(e) {
tooltipElem.style.left = e.clientX + 'px';
tooltipElem.style.top = e.clientY + 'px';
var x = e.layerX;
var y = e.layerY;
var pixel = ctx.getImageData(x, y, 1.1);
// console.log("pixel: ", pixel);
var data = pixel.data;
var rgb =
'rgb(' + data[0] +
', ' + data[1] +
', ' + data[2] +
// ',' + (data[3] / 255) + // rgba changed to RGB
') ';
color.style.background = rgb;
color.textContent = rgb;
tooltipElem.innerHTML = rgb;
tooltipElem.style.background = rgb;
// console.log("rgb: ", rgb);
// console.log(vm.colors);
let currentElemColor = colorRGBtoHex(rgb);
let colors = vm.colors;
clearInterval(timer);
timer = setTimeout(function() {
for (let i = 0; i < colors.length; i++) {
var hex = colorRGBtoHex(colors[i].value)
// console.log("hex: ", hex);
// console.log("colorRGBtoHex(rgb): ", colorRGBtoHex(rgb));
if (hex === currentElemColor) {
color.textContent = colors[i].name;
tooltipElem.innerHTML = colors[i].name;
break; }}},100)}};document.onmouseout = function() {
if (tooltipElem) {
tooltipElem.remove();
tooltipElem = null;
}
document.onmousemove = null;
clearInterval(timer)
}
}
toolTip();
function realTimeShowColor(value) {
// console.log("value: ", value);
value = value.replace(/\s/g.' '); // Remove whitespace
if(! value) { realTimeShowColorId.style.background ='transparent'
realTimeShowColorId.textContent = ' '
return;
}
if (regExp.test(value)) {
realTimeShowColorId.style.background = value
realTimeShowColorId.textContent = 'Color effects'
} else {
realTimeShowColorId.style.background = 'transparent'
realTimeShowColorId.textContent = 'Incorrect color value'}}</script>
</body>
</html>
Copy the code