观“你能不能用div给我画条龙”有感

2,375 阅读2分钟

前言

前几日,在掘金刷到一片文章,叫产品经理:你能不能用div给我画条龙?,写得很生动,很有趣,就想着自己也去跟着作者去实现一下,话不多说,直接撸起袖子开干吧。

环境

window10 + vscode

搭建项目

因为只是为了实现效果,所以没有讲究其他什么性能,命名问题,直接就新建了一个html文件,取名也是粗暴,就叫"你不能不能用div给我画条龙.html",并添加一个canvas标签,用来作绘图准备。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="Access-Control-Allow-Origin" content="*">
  <title>你能不能用div给我画条龙</title>
</head>
<body>
  <canvas id="canvas"></canvas>
</body>
</html>

找图片

打开百度,直接搜索“龙 剪影”,选一张自己喜欢的图片,放在自己的工具目录中,取名 southeast.jpg

创建canvas上下文

var canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d')

创建一个image实例

var image = new image
image.src = './imgs/southeast.jpg'
image.onload = function() {
    canvas.width = image.width
    canvas.height = image.height
    
    // 绘图
    ctx.drawImage(image, 0, 0)
}

现在显示的效果如下:

image.png

将图片像素化

要想实现图片像素化,可分为四步

1、获取像素

在canvas中有一个getImageData()的方法,可以获取图片的像素点

// 获取像素数据
var imageData = ctx.getImageData(0, 0, image.width, image.height)

2、点阵转换

imageData = convertPointArray(imageData)

 // 点阵转换
function convertPointArray(image) {
  for (var i=0; i<image.height; i=i+8) {
    for (var j=0; j<image.width; j=j+8) {
      var isCovered = isCover(image.data, image.width, i, j);
      if (isCovered) {
          image.data = drawPoints(image.data, image.width, i, j);
      } else {
          // 其他区域直接清空
          image.data = drawPoints(image.data, image.width, i, j, true);
      }
    }
  }
  return image;
}

这里用到了一个帮助函数isCover,用来判断是否覆盖

// 判断像素块是否空白or像素覆盖
function isCover(imageData, width, x, y) {
  var covered = 0
  // 像素块为 8*8
  for(var i = x; i < x + 8; i++) {
    for (var j = y; j < y + 8; j++) {
      var idx = i * 4 * width + 4 * j 
      // 阈值设为192
      var r = imageData[idx]
      var g = imageData[idx + 1]
      var b = imageData[idx + 2]
      if (r<192 || g<192 || b<192 ) {

        covered++;
      }
      // 覆盖面积超过 45/64
      if (covered > 45) {
          return true;
      }
    }
  }
  return false
}

还用到了一个画点函数drawPoint:

// 填充像素块
function drawPoints(imageData, width, x, y, clear = false) {
  for (var i = x; i < x + 8; i++) {
    for (var j = y; j < y + 8; j++) {
      var idx = i * 4 * width + 4 * j 
      if (i >=x+2 && i<x+6 && j>=y+2 && j<y+6 && !clear) {
          // 画小方块
          imageData[idx] = 168;
          imageData[idx+1] = 168;
          imageData[idx+2] = 168;
          imageData[idx+3] = 192;
      } else {
          // 置为空白
          imageData[idx] = 255;
          imageData[idx+1] = 255;
          imageData[idx+2] = 255;
          imageData[idx+3] = 0;
      }
    }
  }
  return imageData
}

3、删除原来的图片

// 擦除原来的图片
ctx.clearRect(0, 0, canvas.width, canvas.height)

4、重新绘图

// 重新绘图
ctx.putImageData(imageData, 0, 0)

最后得到:

image.png

到此,结束,喜欢的朋友,可以点个关注,点个赞!

参考:

产品经理:你能不能用div给我画条龙?

借助Canvas 实现图片转点阵图