龙年|切图仔在这给大家画条龙🐲

835 阅读4分钟

龙年|切图仔在这给大家画条龙🐲

截屏2024-01-19 14.45.38.png

前言

不知各位掘友是否有过这样的经历,在我初学编程时,当使用System.out.println("Hello World");一句代码在黑窗口输出了hello World的时候,脑海里就有了很多创意方案,于是乎用一指禅愣是一个字符一个字符的敲出类似下面这样的图案。

截屏2024-01-18 16.15.50.png

几年后回头再看,当时的做法确实有点傻,在这龙年到来之际,不由地又想到这个创意,不过这次当然不能再像当年那样再用手敲字符串的形式来绘制图案了。本文将使用JS将图片转化为字符图,有需要的小伙伴欢迎点赞收藏🙏🙏

实现方案

1、首先我们怎么获取到图片上的相关像素信息呢,此时就需要借助canvas了,我们首先将预先准备好的图片转为canvas

canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
const img = document.querySelector('#myImg');
ctx.clearRect(0, 0, canvas.width, canvas.height)
// 将图片绘制在canvas上
ctx.drawImage(img, 0, 0, img.width, img.height);

2、通过canvas我们能拿到每个像素点的信息,我们将数据存放到imgData中

  imgData = ctx.getImageData(0, 0, img.width, img.height);

3、为了控制绘制出来字符图的精度,在遍历横向和纵向时控制每次移动的像素点,最小为1

// 生成主体,逐个读取字符
let size = 1;
for (let i = 0; i < img.height; i = i + size) {
    for (let j = 0; j < img.width; j = j + size) {
        const curPoint = (i * img.width + j) * 4; // ×4是因为,1为r,2为g,3为b,4为a,四个是一组rgba值
        const [r, g, b] = imgData.data.slice(curPoint, curPoint + 3);
        const gray = r * 0.3 + g * 0.6 + b * 0.1; // 计算灰度值
        const color = `rgba(${r},${g},${b})`; // 保存像素点rgb值
        //生成html格式的
        toText(gray, color)
        //生成纯字符串
        toStr(gray)
    }
    imgText += "</br>";
    imgStr += "\n";
}

4、通过像素点返回的灰度值和color,生成对应的html或字符串,根据灰度值的大小,拼接不同的字符串,来达到绘制出图案的效果。

// 根据灰度转化字符,添加颜色
function toText(g, color) {
    if (color) imgText += `<span style='color:${color}'>`;
    if (g <= 40) imgText += "?";
    else if (g > 40 && g <= 80) imgText += "》";
    else if (g > 80 && g <= 120) imgText += "!";
    else if (g > 120 && g <= 160) imgText += ":";
    else if (g > 160 && g <= 200) imgText += "~";
    else if (g > 200 && g <= 240) imgText += ";";
    else imgText += "。";
    if (color) imgText += "</span>";
}

各个比重用的字符串可自行更改,能有不同的效果。

5、如果需要console打印纯字符串格式的,只需要将上面的方法略微修改即可

function toStr(g) {
    if (g <= 40) imgStr += "?";
    else if (g > 40 && g <= 80) imgStr += "》";
    else if (g > 80 && g <= 120) imgStr += "!";
    else if (g > 120 && g <= 160) imgStr += ":";
    else if (g > 160 && g <= 200) imgStr += "~";
    else if (g > 200 && g <= 240) imgStr += ";";
    else imgStr += "。";
}

6、最终得到了一个程序员风格的字符串图👍

源码

本文所用的测试源码,可以复制直接使用,注:vscode需要使用live server访问

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>图片转字符</title>
</head>

<body>
    <img id="myImg" src="./1.png" style="display: none;"></img>
    <div id="leftDiv">
        <canvas id="canvas" width="600" height="600" style="display: none;"></canvas>
    </div>

    <div id="rightDiv" style="line-height: 0.9;"></div>

    <script>
        let canvas;// canvas实例
        let ctx;// 画笔
        let imgText;// 生成的字符画
        let imgStr = '';// 生成的字符串
        const IMAGE_SIZE = 200;// 生成画规模
        // 加载canvas
        window.onload = () => {
            canvas = document.getElementById("canvas");
            ctx = canvas.getContext("2d");
            const img = document.querySelector('#myImg');
            toImg(img);
            console.log(imgStr)
            document.getElementById("rightDiv").innerHTML = imgText;
        };

        // 转换
        function toImg(img) {
            // 清空字符画
            imgText = "";
            // 先记录比率,如果宽,那么先缩放宽,再用比率算出长,反之同理,这里是保证不超过不超过设定规模
            let rate = img.width / img.height;
            if (rate > 1) {
                img.style.width = IMAGE_SIZE + 'px';
                img.style.height = IMAGE_SIZE / rate + 'px';
                img.width = IMAGE_SIZE;
                img.height = IMAGE_SIZE / rate;
            } else {
                img.style.height = IMAGE_SIZE + 'px';
                img.style.width = IMAGE_SIZE * rate + 'px';
                img.height = IMAGE_SIZE;
                img.width = IMAGE_SIZE * rate;
            }

            ctx.clearRect(0, 0, canvas.width, canvas.height)
            // 将图片绘制在canvas上
            ctx.drawImage(img, 0, 0, img.width, img.height);

            // 从canvas上获取像素信息
            let imgData;
            try {
                imgData = ctx.getImageData(0, 0, img.width, img.height);
            } catch {
                alert("图片加载失败,请重新选择图片或刷新页面。");
            }

            // 调整字符大小,追求更高精度就在这里调小
            let size = 1;
            // 设置zoom缩放
            document.querySelector("#rightDiv").style.zoom = size / 6;

            // 生成主体,逐个读取字符
            for (let i = 0; i < img.height; i = i + size) {
                for (let j = 0; j < img.width; j = j + size) {
                    const curPoint = (i * img.width + j) * 4; // ×4是因为,1为r,2为g,3为b,4为a,四个是一组rgba值
                    const [r, g, b] = imgData.data.slice(curPoint, curPoint + 3);
                    const gray = r * 0.3 + g * 0.6 + b * 0.1; // 计算灰度值
                    const color = `rgba(${r},${g},${b})`; // 保存像素点rgb值
                    toText(gray, color)
                    toStr(gray)
                }
                imgText += "</br>";
                imgStr += "\n";
            }
        }

        // 根据灰度转化字符,添加颜色
        function toText(g, color) {
            if (color) imgText += `<span style='color:${color}'>`;
            if (g <= 40) imgText += "?";
            else if (g > 40 && g <= 80) imgText += "》";
            else if (g > 80 && g <= 120) imgText += "!";
            else if (g > 120 && g <= 160) imgText += ":";
            else if (g > 160 && g <= 200) imgText += "~";
            else if (g > 200 && g <= 240) imgText += ";";
            else imgText += "。";
            if (color) imgText += "</span>";
        }
        function toStr(g) {
            if (g <= 40) imgStr += "?";
            else if (g > 40 && g <= 80) imgStr += "》";
            else if (g > 80 && g <= 120) imgStr += "!";
            else if (g > 120 && g <= 160) imgStr += ":";
            else if (g > 160 && g <= 200) imgStr += "~";
            else if (g > 200 && g <= 240) imgStr += ";";
            else imgStr += "。";
        }

    </script>
</body>

</html>

截屏2024-01-19 14.41.16.png

总结

有需要的小伙伴快拿去换上自己喜欢的图案试试吧,在这祝大家财源滚滚、身体健康、家庭幸福、工作顺利,新年快乐!🎉🎉🎉