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

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

前言

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

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

实现方案

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

ini 复制代码
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中

ini 复制代码
  imgData = ctx.getImageData(0, 0, img.width, img.height);

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

ini 复制代码
// 生成主体,逐个读取字符
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或字符串,根据灰度值的大小,拼接不同的字符串,来达到绘制出图案的效果。

javascript 复制代码
// 根据灰度转化字符,添加颜色
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打印纯字符串格式的,只需要将上面的方法略微修改即可

javascript 复制代码
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访问

ini 复制代码
<!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>

总结

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

相关推荐
Moment几秒前
小米不仅造车,还造模型?309B参数全开源,深度思考完胜DeepSeek 🐒🐒🐒
前端·人工智能·后端
苏打水com4 分钟前
第十六篇:Day46-48 前端安全进阶——从“漏洞防范”到“安全体系”(对标职场“攻防实战”需求)
前端·javascript·css·vue.js·html
5C246 分钟前
从思想到实践:前端工程化体系与 Webpack 构建架构深度解析
前端·前端工程化
咕噜企业分发小米12 分钟前
如何平衡服务器内存使用率和系统稳定性?
java·服务器·前端
前端无涯12 分钟前
react组件(2)---State 与生命周期
前端·react.js
GoldenPlayer13 分钟前
Web-Tech:CORS的触发机制
前端
AY呀14 分钟前
Vite:现代前端构建工具的革命与实战指南
前端·vue.js·vite
爬山算法14 分钟前
Netty(13)Netty中的事件和回调机制
java·前端·算法
前端无涯19 分钟前
react组件(3)---组件间的通信
前端·react.js
讯方洋哥1 小时前
应用冷启动优化
前端·harmonyos