当代码邂逅艺术:用 HTML5 Canvas 绘制数字蒙娜丽莎

在大众印象中,代码是理性的符号,艺术是感性的表达,二者仿佛分属两个截然不同的世界。然而,随着数字技术的发展,代码逐渐成为艺术家手中的 “画笔”,创造出跨越传统边界的视觉奇迹。本文将以一段 HTML5 Canvas 代码为例,探索代码如何复刻经典艺术名作《蒙娜丽莎》,揭开数字艺术创作背后的技术逻辑与美学思考。

20250919173223727-image

 

从 ASCII 到 Canvas:数字蒙娜丽莎的 “进化史”

这段代码的创意起点,源于互联网早期流行的 ASCII 艺术。ASCII 艺术以文本字符为 “像素”,通过不同密度的符号排列模拟图像明暗,代码中引用的monaLisa字符串数组,正是经典的 ASCII 版《蒙娜丽莎》—— 用#“@”Z等符号勾勒出画作的轮廓与层次,这是数字时代对经典艺术最朴素的致敬方式。
但代码并未止步于 ASCII 的 “文本美学”,而是借助 HTML5 Canvas 技术完成了一次 “升级”。Canvas 作为网页端的绘图 API,赋予代码更灵活的图形绘制能力:它可以创建像素级的图像控制、实现动态渲染效果,让静态的 ASCII 字符转化为富有光影变化的视觉作品,这也让 “用代码画蒙娜丽莎” 从简单的字符排列,升华为真正的数字艺术创作。

拆解代码:数字画笔的 “作画逻辑”

要理解代码如何 “画” 出蒙娜丽莎,我们需要深入其核心技术模块,看看每一段代码如何承担 “画笔”“颜料”“画布” 的角色。

1. 画布搭建:为艺术创造 “数字画框”

代码首先通过canvas标签创建绘图容器,并通过 JavaScript 设置画布尺寸:
const c = document.querySelector('#c');
const ctx = c.getContext('2d');
const ratio = window.innerHeight / window.innerWidth;
c.height = Math.max(900, window.innerHeight);
c.width = c.height / ratio;
这段代码的核心是 “适配”—— 它根据浏览器窗口的宽高比,自动调整画布尺寸,确保蒙娜丽莎的图像不会因窗口大小变化而变形,就像艺术家在动笔前,精心挑选并裁剪适合画作的画布。同时,getContext('2d')获取 2D 绘图上下文,相当于为代码配备了一套 “绘图工具包”,后续的线条、圆形、色彩填充,都依赖这个工具包实现。

2. 色彩体系:为画作调配 “数字颜料”

经典的《蒙娜丽莎》以柔和的棕色调为主,而这段代码则大胆采用了 “动态色彩方案”,通过 HSL 颜色模式(色相、饱和度、亮度)赋予画作更丰富的视觉层次:
const colors = [65, 85, 105, 125, 145, 165];
const e = Math.cos((x + time / 10000) * 10) + Math.sin((y + time / 10000) * 10);
const deg = 220 + colors[Math.floor(e * colors.length)];
ctx.fillStyle = `hsl(${deg}deg, 60%, ${20 + level * 40}%)`;
这里的色彩并非固定不变:time参数让色相(deg)随时间缓慢变化,呈现出细微的色彩流动感;而level参数(由 ASCII 字符在symbols数组中的位置决定)则控制亮度 —— 密度高的字符(如#)对应更高的亮度,密度低的字符(如空格)对应更低的亮度,完美复刻了蒙娜丽莎的明暗对比,让人物的面部轮廓、背景的空间感通过色彩差异呈现出来。

3. 图像渲染:用 “像素点” 勾勒经典轮廓

代码没有直接绘制线条,而是用无数个小圆点 “堆砌” 出蒙娜丽莎的形象,这正是数字图像 “像素化” 的核心逻辑:
const letter = monaLisa[y][x] ?? ' ';
const level = 1.256 - symbols.indexOf(letter) / symbols.length;
ctx.arc(padding + x * 10, y * 20, level * 5, 0, Math.PI * 2);
它的工作原理像 “点彩画”:首先读取 ASCII 数组中每个位置的字符(letter),再根据字符在symbols(符号密度表)中的位置计算出 “亮度等级”(level),最后以arc方法绘制圆形 —— 亮度高的位置,圆形半径更大、颜色更亮;亮度低的位置,圆形半径更小、颜色更深。无数个这样的小圆点按 ASCII 图像的布局排列,最终拼接出蒙娜丽莎的完整形象,既保留了经典画作的神韵,又带有数字艺术特有的 “颗粒感”。

4. 动态效果:让经典画作 “活” 起来

不同于静态的传统绘画,这段代码通过requestAnimationFrame实现了动态渲染:
const animate = (time) => {
  requestAnimationFrame(animate);
  ctx.fillStyle = 'black';
  ctx.fillRect(0, 0, c.width, c.height);
  // 图像绘制逻辑...
};
animate(0);
requestAnimationFrame会以浏览器的刷新率(通常 60 帧 / 秒)不断重绘画布,每次重绘时,色彩、位置会随time参数细微变化,让蒙娜丽莎的图像呈现出柔和的 “呼吸感”—— 这种动态效果不是对经典的破坏,而是数字艺术对传统的补充:它让静态的名作拥有了时间维度的生命力,仿佛达芬奇笔下的蒙娜丽莎在数字世界中轻轻 “动” 了起来。
 
全部代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>代码生成蒙娜丽莎</title>
    <style>
      html,
      body {
        margin: 0;
        padding: 0;
        overflow: hidden;
      }
    </style>
  </head>
  <body>
    <canvas id="c" />
    <script>
      const c = document.querySelector('#c');
      const ctx = c.getContext('2d');

      const ratio = window.innerHeight / window.innerWidth;
      const width = window.innerWidth;
      const height = window.innerHeight;

      c.height = Math.max(900, window.innerHeight);
      c.width = c.height / ratio;

      c.style.width = '100vw';
      c.style.height = '100vh';

      function pseudoRandom(seed) {
        return Math.sin(seed) * 10000 - Math.floor(Math.sin(seed) * 10000);
      }

      function noise(x, y) {
        const seed = x * 137 + y * 149;
        return pseudoRandom(seed) % 1;
      }

      const stepAngle = (Math.PI * 2) / 3;

      const getThread = (i) => {
        return {
          lastPoint: {
            x: c.width / 2 + Math.cos((Math.PI / 10) * i) * i * 3,
            y: c.height / 2 + Math.sin((Math.PI / 10) * i) * i * 3,
          },
          angle: Math.PI / 3 + stepAngle * i,
        };
      };

      const threads = [];

      for (let i = 0; i < 256; i++) {
        threads.push(getThread(i));
      }

      const palette = [
        // '#001219',
        '#80FFDB',
        '#72EFDD',
        '#64DFDF',
        '#56CFE1',
        '#48BFE3',
        '#4EA8DE',
        '#5390D9',
        '#5E60CE',
        '#6930C3',
        '#7400B8',
      ];

      // https://www.asciiart.eu/art-and-design/mona-lisa
      const monaLisa = `
                                  _______
                           _,,ad8888888888bba,_
                        ,ad88888I888888888888888ba,
                      ,88888888I88888888888888888888a,
                    ,d888888888I8888888888888888888888b,
                   d88888PP"""" ""YY88888888888888888888b,
                 ,d88"'__,,--------,,,,.;ZZZY8888888888888,
                ,8IIl'"                ;;l"ZZZIII8888888888,
               ,I88l;'                  ;lZZZZZ888III8888888,
             ,II88Zl;.                  ;llZZZZZ888888I888888,
            ,II888Zl;.                .;;;;;lllZZZ888888I8888b
           ,II8888Z;;                 ';;;;;''llZZ8888888I8888,
           II88888Z;'                        .;lZZZ8888888I888b
           II88888Z; _,aaa,      .,aaaaa,__.l;llZZZ88888888I888
           II88888IZZZZZZZZZ,  .ZZZZZZZZZZZZZZ;llZZ88888888I888,
           II88888IZZ<'(@@>Z|  |ZZZ<'(@@>ZZZZ;;llZZ888888888I88I
          ,II88888;   '""" ;|  |ZZ; '"""     ;;llZ8888888888I888
          II888888l            ';;          .;llZZ8888888888I888,
         ,II888888Z;           ;;;        .;;llZZZ8888888888I888I
         III888888Zl;    ..,   ';;       ,;;lllZZZ88888888888I888
         II88888888Z;;...;(_    _)      ,;;;llZZZZ88888888888I888,
         II88888888Zl;;;;;' '--'Z;.   .,;;;;llZZZZ88888888888I888b
         ]I888888888Z;;;;'   ";llllll;..;;;lllZZZZ88888888888I8888,
         II888888888Zl.;;"Y88bd888P";;,..;lllZZZZZ88888888888I8888I
         II8888888888Zl;.; '"PPP";;;,..;lllZZZZZZZ88888888888I88888
         II888888888888Zl;;. ';;;l;;;;lllZZZZZZZZW88888888888I88888
         'II8888888888888Zl;.    ,;;lllZZZZZZZZWMZ88888888888I88888
          II8888888888888888ZbaalllZZZZZZZZZWWMZZZ8888888888I888888,
          'II88888888888888888b"WWZZZZZWWWMMZZZZZZI888888888I888888b
           'II88888888888888888;ZZMMMMMMZZZZZZZZllI888888888I8888888
            'II8888888888888888 ';lZZZZZZZZZZZlllll888888888I8888888,
             II8888888888888888, ';lllZZZZllllll;;.Y88888888I8888888b,
            ,II8888888888888888b   .;;lllllll;;;.;..88888888I88888888b,
            II888888888888888PZI;.  .';;;.;;;..; ...88888888I8888888888,
            II888888888888PZ;;';;.   ;. .;.  .;. .. Y8888888I88888888888b,
           ,II888888888PZ;;'                        '8888888I8888888888888b,
           II888888888'                              888888I8888888888888888b
          ,II888888888                              ,888888I88888888888888888
         ,d88888888888                              d888888I8888888888ZZZZZZZ
      ,ad888888888888I                              8888888I8888ZZZZZZZZZZZZZ
    ,d888888888888888'                              888888IZZZZZZZZZZZZZZZZZZ
  ,d888888888888P'8P'                               Y888ZZZZZZZZZZZZZZZZZZZZZ
 ,8888888888888,  "                                 ,ZZZZZZZZZZZZZZZZZZZZZZZZ
d888888888888888,                                ,ZZZZZZZZZZZZZZZZZZZZZZZZZZZ
888888888888888888a,      _                    ,ZZZZZZZZZZZZZZZZZZZZ888888888
888888888888888888888ba,_d'                  ,ZZZZZZZZZZZZZZZZZ88888888888888
8888888888888888888888888888bbbaaa,,,______,ZZZZZZZZZZZZZZZ888888888888888888
88888888888888888888888888888888888888888ZZZZZZZZZZZZZZZ888888888888888888888
8888888888888888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888888888
888888888888888888888888888888888888888ZZZZZZZZZZZZZZ888888888888888888888888
8888888888888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888888888888
88888888888888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888888888
8888888888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888888888888888
88888888888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888888888888
8888888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888888888888888888
`
        .split('\n')
        .slice(1);

      const symbols = ` .-'":_,^=;><+!rc*/z?sLTv)J7(|Fi{C}fI31tlu[neoZ5Yxjya]2ESwqkP6h9d4VpPOGbUAKXHm8RD#$Bg0MNWQ%&@`;

      ctx.fillStyle = 'rgba(0, 0, 0, 1)';
      ctx.fillRect(0, 0, c.width, c.height);

      const animate = (time) => {
        requestAnimationFrame(animate);

        ctx.fillStyle = 'black';
        ctx.fillRect(0, 0, c.width, c.height);

        ctx.lineWidth = 1;

        // exit
        let prevColor = '#000000';
        for (let y = 1; y < monaLisa.length; y++) {
          for (let x = 0; x < 76; x++) {
            const padding = (c.width - 760) / 2;
            const letter = monaLisa[y][x] ?? ' ';
            const level = 1.256 - symbols.indexOf(letter) / symbols.length;
            const size = 20;

            ctx.beginPath();

            const colors = [65, 85, 105, 125, 145, 165];

            const e =
              Math.cos((x + time / 10000) * 10) +
              Math.sin((y + time / 10000) * 10);
            const deg = 220 + colors[Math.floor(e * colors.length)];

            ctx.arc(padding + x * 10, y * 20, level * 5, 0, Math.PI * 2);

            ctx.fillStyle = `hsl(${deg}deg, 60%, ${20 + level * 40}%)`;
            ctx.fill();

            prevColor = ctx.fillStyle;
          }
        }
      };

      animate(0);
    </script>
  </body>
</html>

 

 

代码与艺术的共生:数字时代的创作新可能

这段 “代码蒙娜丽莎” 的意义,远不止于技术层面的实现 —— 它更像一座桥梁,连接了理性的编程思维与感性的艺术表达,让我们看到数字时代创作的无限可能。
从技术角度看,它是 HTML5 Canvas、JavaScript 数学计算、色彩理论的结合体:Math.cosMath.sin计算色彩流动的规律,HSL模式实现精准的色彩控制,ASCII映射完成图像的 “数字化转译”—— 每一行代码都是一次 “技术决策”,而这些决策最终服务于艺术表达。
从艺术角度看,它是对经典的 “再创作”:既保留了《蒙娜丽莎》的核心构图与明暗关系,又用数字特有的 “像素感”“动态感” 赋予其新的美学特质。这种创作不是对传统艺术的替代,而是以新的媒介延续经典的生命力 —— 就像文艺复兴时期,艺术家们用油画替代蛋彩画,拓展了艺术的表达边界,如今,代码也成为了新一代艺术家的 “新画笔”。

结语:每个人都可以是 “数字达芬奇”

这段绘制蒙娜丽莎的代码,最动人的地方在于它的 “可及性”—— 它没有复杂的框架依赖,仅用基础的 HTML 和 JavaScript 就能实现,任何掌握基础编程知识的人,都可以修改其中的参数:调整colors数组改变画作的色调,修改level的计算逻辑调整图像的清晰度,甚至替换monaLisa的 ASCII 数组,让代码绘制出梵高的《星空》、莫奈的《睡莲》。
这正是数字艺术的魅力:它打破了传统艺术对 “专业工具”“专业技能” 的门槛限制,让代码成为人人可及的创作媒介。当我们用代码勾勒出经典画作的轮廓时,我们不仅在学习编程技术,更在以一种全新的方式与艺术对话 —— 或许,在未来的数字世界里,每个人都能成为用代码创作的 “达芬奇”,让理性与感性在屏幕上碰撞出更多精彩的火花。
🎀 🌸

📜 重要提示:
如有解压密码:看下载页、看下载页、看下载页。
源码工具资源类具有可复制性: 建议具有一定思考和动手能力的用户购买。
请谨慎考虑: 小白用户和缺乏思考动手能力者不建议赞助。
虚拟商品购买须知: 虚拟类商品,一经打赏赞助,不支持退款。请谅解,谢谢合作!
邻兔跃官网:lt.lintuyue.com(如有解压密码看下载页说明)。

文章版权声明 1、本网站名称:邻兔跃lT
2、本站永久网址:https://lt.lintuyue.com/
3、本站内容主要来源于互联网优质资源整合、网友积极投稿以及部分原创内容,仅供内部学习研究软件设计思想和原理使用,学习研究后请自觉删除,请勿传播,因未及时删除所造成的任何后果责任自负,如有侵权,请联系站长进行删除处理。
4、本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
5、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
6、本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。
© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容