canvas将图片转成点阵

前言

最近在掘金里看到了这篇文章:产品经理:你能不能用div给我画条龙? ,很有意思,通过canvas提取图片的像素,然后将图片转成点阵图。

按照文章,尝试了好多次,都没有成功。最后只能研究一下原理,自己写一个demo。

参考文章: canvas小练习-图片点阵化demo

需要了解的知识点:

canvas drawImage() 方法:在画布上绘制图像、画布或视频。

canvas getImageData() 方法:复制画布上指定矩形的像素数据

canvas putImageData() 方法:将图像数据放回画布

示例

以下示例基于vue

效果
canvas将图片转成点阵_第1张图片
代码

<template>
    <div style="height:2000px;">
        <canvas
            id="myCanvas"
            style="border: 1px solid #d3d3d3">
        </canvas>
        <el-button type="primary" @click="copy">复制</el-button>
    </div>
</template>

<script>
export default {
    data() {
        return {
            // 上下文对象
            ctx: undefined,
            // 要绘制图片的大小
            w: 200,
            h: 200
        };
    },
    mounted() {
        // 获取canvas对象
        let c = document.getElementById('myCanvas');
        // 获取canvas上下文
        this.ctx = c.getContext('2d');
        // 加载图片,不要直接写字符串
        let src = require('./imgs/a.png');
        // 创建image对象
        let image = new Image();
        image.src = src;
        let that = this;
        // 图片加载
        image.onload = function() {
            // 设置canvas对象的宽高(不一定要等于图像大小)
            c.width = image.width;
            c.height = image.height;
            // 绘制图像,图像,偏移量,宽高(可以跟图片一样大,也可以自定义)
            that.ctx.drawImage(image,0,0,that.w,that.h);
        };
    },
    methods: {
        copy() {
            // 获取图片的像素值
            var imageData = this.ctx.getImageData(0, 0, this.w, this.h);

            // 计算有多少个rgb值
            let sum = this.w * this.h * 4 ;
            for(let i = 0;i < sum;i += 4) {
                if(imageData.data[i] != 255 && imageData.data[i + 1] != 255 && imageData.data[i + 2] != 255) {
                    if(i % 12 != 0) {
                    // 黑
                        imageData.data[i] = 255;
                        imageData.data[i + 1] = 255;
                        imageData.data[i + 2] = 255;
                    }else{
                    // 白
                        imageData.data[i] = 0;
                        imageData.data[i + 1] = 0;
                        imageData.data[i + 2] = 0;
                    }
                }
            }
            // 对象,偏移量
            this.ctx.putImageData(imageData, 0,200);
        }
    }
};
</script>

<style scoped lang="scss">
</style>

注意点

注意点,或者说某些地方为什么要这么做

// 加载图片,不要直接写字符串。否则在vue中不能显示出图片
let src = require('./imgs/a.png');
// 获取图片的像素值
var imageData = this.ctx.getImageData(0, 0, this.w, this.h);

getImageData:这个函数会返回一个对象,里面有一个data属性,是一个数组。数组中的元素,4个一组,表示该像素点的rgba

// 计算有多少个rgb值
let sum = this.w * this.h * 4 ;

像素点就是宽乘以高,例如宽高都是10px的矩形,像素点就是100,但是一个像素点由4个值组成(rgba),所以要乘以4,否则会丢失一些东西。

核心

核心其实就是如何处理像素点。要想点阵显示的内容多,关键在于如何处理。
以当前这个例子来说:

 for(let i = 0;i < sum;i += 4) {

因为一个像素点是4个值,所以要加4,4个数一组进行处理。

if(imageData.data[i] != 255 && imageData.data[i + 1] != 255 && imageData.data[i + 2] != 255) {
    if(i % 12 != 0) {
    // 黑
        imageData.data[i] = 255;
        imageData.data[i + 1] = 255;
        imageData.data[i + 2] = 255;
    }else{
    // 白
        imageData.data[i] = 0;
        imageData.data[i + 1] = 0;
        imageData.data[i + 2] = 0;
    }
}

这个福字图片,字是红色的,周围是白色的。我们要显示的点阵是这个字,是让这个字以点的形式显示;不能让周围的白色也变成点。所以如果是白色就不处理,而白色的rgb是(255,255,255)

为啥要取余12呢?因为必须黑色和白色间隔显示才能显示点阵,不能所有颜色一样。一个像素是4个值,所以必须是4的倍数。值越小,越密集。值越大越松缓,这里取12是显示的效果比较好。

局限

局限还是如何处理像素点。比如福字周围不是白色,而是有多种颜色,那就要想办法不处理这些颜色。

你可能感兴趣的:(可视化,javascript,前端,vue.js)