添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《 阿里云开发者社区用户服务协议 》和 《 阿里云开发者社区知识产权保护指引 》。如果您发现本社区中有涉嫌抄袭的内容,填写 侵权投诉表单 进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
+关注继续查看

图片颜色识别的关键函数为: CanvasRenderingContext2D.getImageData(sx, sy, sw, sh) , 详情参考: MDN getImageData

本文实现的效果图如下:
1630918215(1).jpg
实现的功能点有:

1). 加载本地图片
2). 鼠标悬浮显示出相应的颜色
3). 按键盘快捷键复制代码
4). 额外小功能,图片支持拖曳加载

接下来详细介绍每一步的实现:

  1. 加载本地图片

    // 绘制图片到 canvas
    function drawImage() {
      if (canvasWidth != -1) {
        ctx.clearRect(0, 0, canvasWidth, canvasHeight); // 清除 canvas 内容
      // 获取图片宽高
      imageWidth = image.width;
      imageHeight = image.height;
      // 计算 canvas 宽高(需要预留提示框的位置)
      canvasWidth = imageWidth + toolTipWidth;
      if (imageWidth > canvasWidth) {
        canvasWidth = imageWidth;
      canvasHeight = imageWidth + toolTipHeight;
      if (imageHeight > canvasHeight) {
        canvasHeight = imageHeight;
      canvas.width = canvasWidth;
      canvas.height = canvasHeight;
      // 获取元素数据
      rect = canvas.getBoundingClientRect();
      ctx.drawImage(image, 0, 0); //  绘制图片
      // 通过 getImageData 获取图片的所有像素颜色数组(从左往右,从上往下)
      imageData = ctx.getImageData(0, 0, image.width, image.height).data;
     // for (let i = 0, len = imageData.length; i < len; i = i + 4) {
     //   let item = {
      //     x: ((i / 4) % imageWidth) + 1,
      //     y: Math.floor(i / 4 / imageWidth) + 1,
      //   };
    // 加载图像
    function loadImage(url) {
      image.src = url;
      image.onload = function () {
        drawImage(image);
    // 上传文件
    function uploadImage(img) {
      // 判断是否有选中文件
      if (!img) return;
      // 检测是否是图片类型
      if (img.type.indexOf('image') !== 0) {
        alert('只能选择图片');
        return;
      // 定义文件读取对象,用于读取文件
      var reader = new FileReader();
      reader.readAsDataURL(img); // 读取图片内容为 url 格式
      reader.onload = function () {
        loadImage(reader.result); // 加载图片
    // 定义选择图片
    imgSelector.addEventListener('change', function (e) {
      uploadImage(e.target.files[0]); // 选中的图片文件
    });

    看似是一步,实际这一步里面包含了很多步:监听 input-file change 事件 --> 通过 FileReader 读取本地文件 --> 将读取到的本地文件( reader.result )放置到 Image --> 将 image 绘制到 canvas --> 读取 getImageData 图片颜色。

  2. 鼠标悬浮显示颜色信息

    // 将图片的 r, g, b 分别转换为 16进制的颜色
    function colorItemHex(itemNumber) {
      let hex = itemNumber.toString(16);
      return (hex.length === 1 ? '0' + hex : hex).toUpperCase();
    // 添加鼠标滑动事件
    canvas.addEventListener('mousemove', function (evt) {
      clearTimeout(t);
      t = setTimeout(() => {
        if (imageData != null) {
                  getBoundingClient()中的[left, top] 获取元素距离视图左边和上边的距离
                  clientX 和 clientY 获取鼠标距离试图左边和上边的距离
          let x = evt.clientX - rect.left;
          let y = evt.clientY - rect.top;
          ctx.clearRect(0, 0, canvasWidth, canvasHeight); // 清除 canvas 内容
          // 重新绘制
          ctx.drawImage(image, 0, 0);
          // 根据坐标计算像素点位置,详情参考:desc.jpg
          var i = ((y - 1) * imageWidth + x - 1) * 4;
          if (x >= imageWidth || y >= imageHeight) {
            return;
          var tsPointX = x,
            tsPointY = y; // 提示框的位置
          if (x + toolTipWidth > canvasWidth) {
            // 右边无法绘制出提示框, 左边绘制
            tsPointX = x - toolTipWidth;
          if (y + toolTipHeight > canvasHeight) {
            // 下边无法绘制出提示框,上边绘制
            tsPointY = y - toolTipHeight;
          // 重新绘制新的提示框
          ctx.fillStyle = 'rgba(255, 255, 255, 0.8)'; // 矩形填充颜色
          ctx.fillRect(tsPointX, tsPointY, toolTipWidth, toolTipHeight); // 绘制矩形
          ctx.strokeStyle = 'blue'; // 边框颜色
          ctx.strokeRect(tsPointX, tsPointY, toolTipWidth, toolTipHeight); // 绘制矩形边框
          // rgb 模式为颜色值的十进制数模式
          let red = imageData[i];
          let green = imageData[i + 1];
          let blue = imageData[i + 2];
          let alpha = imageData[i + 3];
          let hex =
            '#' +
            colorItemHex(red) +
            colorItemHex(green) +
            colorItemHex(blue);
          currHTML = hex;
          // 设置文本样式
          ctx.font = '16px sans-serif';
          ctx.fillStyle = 'black';
          if (alpha === 255) {
            currRGB = `(${red}, ${green}, ${blue})`;
            // 255 为完全不透明, 0 - 完全透明
            ctx.fillText(
              `RGB: ${currRGB}`,
              tsPointX + 7,
              tsPointY + 20 // 40 = 20 + 16(字体大小) + 5
          } else {
            // 颜色值的 alpha 是 0~255,而 css rgba() 函数的 alpha 为 0~1
            let cssAlpha = Number((alpha / 255).toFixed(2));
            currRGB = `(${red}, ${green}, ${blue}, ${cssAlpha})`;
            ctx.fillText(
              `RGBA: ${currRGB}`,
              tsPointX + 7,
              tsPointY + 20 // 40 = 20 + 16 * 2(字体大小) + 5
          // hex 为颜色值的16进制模式
          // 关于进制之间的手动转换可以参考:https://www.cnblogs.com/ysocean/p/7513061.html
          ctx.fillText('HTML: ' + hex, tsPointX + 7, tsPointY + 40);
          ctx.fillText('按 C 复制 HTML 代码', tsPointX + 7, tsPointY + 60);
          ctx.fillText('按 V 复制 RGB 代码', tsPointX + 7, tsPointY + 80);
      }, 150);
    // 添加鼠标移出事件
    canvas.addEventListener('mouseout', function () {
      clearTimeout(t);
      ctx.clearRect(0, 0, canvasWidth, canvasHeight); // 清除 canvas 内容
      // 重新绘制
      ctx.drawImage(image, 0, 0);
      currHTML = currRGB = null;
    });

    这一步也是有很多步的:添加鼠标滑动事件 --> 根据鼠标坐标点获取在 ImageData 数组中的位置 --> 获取到图片 RGBA --> 通过 canvas 绘制提示框

    注意要点:

    1. 要在鼠标移出的时候,清除之前的提示框
    2. 如何根据坐标计算在图片颜色集中的位置,详细解释,会在下面放图说明
    3. 获取到的 RGBA 是十进制式的数据,如果需要 HTML 代码,则还需要转换为十六进制, 进制间的相互转换
    4. 加入 setTimeout 避免滑动过快频繁触发

    desc.jpg

  3. 按键盘快捷键复制代码

    // 复制内容到剪贴板
    function copy(copyValue) {
      var $tmpCopyNode = document.createElement('input');
      $tmpCopyNode.type = 'text';
      $tmpCopyNode.className = 'copy-node';
      $tmpCopyNode.value = copyValue;
      document.body.append($tmpCopyNode);
      $tmpCopyNode.select();
      document.execCommand('copy');
      document.body.removeChild($tmpCopyNode);
    // 监听键盘事件
    document.addEventListener('keydown', function (e) {
      if (e.keyCode === 67) {
        // 按下了 C 键,复制 HTML 代码
        if (currHTML != null) {
          copy(currHTML);
      } else if (e.keyCode === 86) {
        // 按下了 V 键,复制 RGB 代码
        if (currRGB != null) {
          copy(currRGB);
    });

    这里的难点就在于 复制 功能的实现,这里的复制是通过 input 实现的,所以需要让 input 透明并且不能显示在屏幕上,这个就需要 CSS 的配合:

    /* 一个用于复制内容的输入框的样式 */
    .copy-node {
      /* 将位置放到屏幕外 */
      position: fixed;
      top: -100px;
      left: -100px;
      /* 将背景和颜色设置为透明, 避免显现 */
      border: none;
      outline: none;
      background-color: transparent;
      color: transparent;
    }
  4. 拖曳加载图片

    /* 要实现拖曳上传的功能,以下2个事件必须监听 */
    // 监听当被拖动元素在目的地元素内时触发, 取消浏览器的默认行为,要不然浏览器会默认打开新的标签页预览图片
    $imgSelectorBtn.addEventListener('dragover', function (e) {
      e.stopPropagation();
      e.preventDefault();
    // 当被拖动元素在目的地元素里放下时触发, 一般需要取消浏览器的默认行为
    $imgSelectorBtn.addEventListener('drop', function (e) {
      e.stopPropagation();
      e.preventDefault();
      uploadImage(e.dataTransfer.files[0]); // 上传文件
    });

下面补上两段代码:

  1. 按钮的 CSS 代码
/* 定义文件选择按钮 */
.img-selector {
  display: none;
.file {
  position: absolute;
  width: 100%;
  font-size: 90px;
.img-selector-btn {
  color: #ffffff;
  background: #06980e;
  text-align: center;
  cursor: pointer;
  border: 1px solid #cccccc;
  padding: 7px 10px;
  display: inline-block;
  box-sizing: border-box;
.img-selector-btn:hover {
  background: #04bc0d;
}
  1. 所有的 HTML 标签
<canvas id="canvas"></canvas>
  <input
    type="file"
    class="img-selector"
    id="imgSelector"
    accept="image/*"
  <label
    id="imgSelectorBtn"
    class="img-selector-btn"
    for="imgSelector"
    title="JPG,GIF,PNG"
  </label>
</div>
  1. 所有声明的变量及说明:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var posColors = []; // 保存所有位置的像素信息
var rect = null; // canvas 元素矩阵数据
var t = -1; // 定时器,避免频繁触发鼠标悬浮事件
var imageData = null; // 图片像素点颜色数组
var imageWidth = -1,
  imageHeight; // 图片宽度,高度
var canvasWidth = -1,
  canvasHeight = -1; // canvas 宽度和高度
var toolTipWidth = 175,
  toolTipHeight = 90; // tooltip 提示框的宽度和高度
var currRGB = null,
  currHTML = null;
var $copyNode = document.getElementById('copyNode'); // 用于复制操作的编辑框
var $imgSelectorBtn = document.getElementById('imgSelectorBtn'); // 图片选择按钮
var image = new Image(); // 构造图片

关于 canvas 的内容可参考菜鸟教程相关专题: HTML5 Canvas 学习 HTML5 Canvas 这一篇文章就够了