2D人体姿势生成器:一个简单而强大的Web工具

2D人体姿势生成器:一个简单而强大的Web工具

在数字艺术和动画领域,快速创建和调整人体姿势是一项常见而重要的任务。今天,我们将介绍一个简单但功能强大的工具:2D人体姿势生成器。这个基于Web的工具允许用户轻松创建、调整和导出2D人体姿势,非常适合艺术家、动画师或任何需要快速草绘人体姿势的人使用。

在这里插入图片描述

功能特点

  1. 交互式火柴人: 用户可以通过拖拽关节点来自由调整火柴人的姿势。
  2. 直观的头部控制: 通过移动头顶和颈部节点来调整头部的角度和位置。
  3. 完整的人体结构: 包括头部、躯干、手臂和腿部,共11个可调节的关节点。
  4. 图片导出: 一键将当前姿势导出为PNG格式的图片,背景为白色,便于进一步编辑或使用。
  5. 轻量级设计: 纯HTML、CSS和JavaScript实现,无需任何外部依赖。

技术实现

这个工具主要使用HTML5 Canvas来绘制火柴人,并通过JavaScript来处理用户交互。下面是一些关键代码片段及其解释:

1. 关节点定义

const joints = [
    {
    
    x: 200, y: 50, name: 'headTop'},     // 头顶
    {
    
    x: 200, y: 100, name: 'neck'},       // 颈部
    {
    
    x: 200, y: 200, name: 'hip'},        // 臀部
    // ... 其他关节点
];

这个数组定义了火柴人的所有关节点,包括它们的初始位置和名称。

2. 绘制函数

function drawStickman(fillBackground = false) {
    
    
    // ... 绘制代码
}

这个函数负责在Canvas上绘制火柴人。它可以选择是否填充白色背景(用于导出图片时)。

3. 用户交互

canvas.addEventListener('mousedown', (e) => {
    
    
    // ... 鼠标按下事件处理
});

canvas.addEventListener('mousemove', (e) => {
    
    
    // ... 鼠标移动事件处理
});

canvas.addEventListener('mouseup', () => {
    
    
    // ... 鼠标松开事件处理
});

这些事件监听器处理用户的鼠标交互,允许用户拖动和调整关节点的位置。

4. 图片导出

downloadBtn.addEventListener('click', () => {
    
    
    drawStickman(true);  // 绘制带白色背景的图像
    const dataUrl = canvas.toDataURL('image/png');
    // ... 创建下载链接
});

这段代码处理图片导出功能,将Canvas内容转换为PNG格式的数据URL,并触发下载。

完整代码

以下是这个2D人体姿势生成器的完整HTML代码,包括HTML结构、CSS样式和JavaScript逻辑:

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>高级2D人体姿势生成器</title>
    <style>
        body {
      
      
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
            font-family: Arial, sans-serif;
        }
        #canvas {
      
      
            border: 1px solid #000;
            background-color: #fff;
            margin-bottom: 10px;
        }
        #downloadBtn {
      
      
            padding: 10px 20px;
            font-size: 16px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            transition: background-color 0.3s;
        }
        #downloadBtn:hover {
      
      
            background-color: #45a049;
        }
    </style>
</head>
<body>
    <canvas id="canvas" width="400" height="400"></canvas>
    <button id="downloadBtn">下载姿势图片</button>
    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        const downloadBtn = document.getElementById('downloadBtn');

        // 定义关节点
        const joints = [
            {
      
      x: 200, y: 50, name: 'headTop'},     // 头顶
            {
      
      x: 200, y: 100, name: 'neck'},       // 颈部
            {
      
      x: 200, y: 200, name: 'hip'},        // 臀部
            {
      
      x: 150, y: 150, name: 'leftElbow'},  // 左肘
            {
      
      x: 100, y: 200, name: 'leftHand'},   // 左手
            {
      
      x: 250, y: 150, name: 'rightElbow'}, // 右肘
            {
      
      x: 300, y: 200, name: 'rightHand'},  // 右手
            {
      
      x: 175, y: 300, name: 'leftKnee'},   // 左膝
            {
      
      x: 150, y: 380, name: 'leftFoot'},   // 左脚
            {
      
      x: 225, y: 300, name: 'rightKnee'},  // 右膝
            {
      
      x: 250, y: 380, name: 'rightFoot'}   // 右脚
        ];

        function drawStickman(fillBackground = false) {
      
      
            if (fillBackground) {
      
      
                // 如果需要填充背景,则填充白色
                ctx.fillStyle = 'white';
                ctx.fillRect(0, 0, canvas.width, canvas.height);
            } else {
      
      
                // 否则清除画布
                ctx.clearRect(0, 0, canvas.width, canvas.height);
            }
            
            ctx.strokeStyle = 'black';
            ctx.fillStyle = 'black';
            
            // 绘制身体
            ctx.beginPath();
            ctx.moveTo(joints[1].x, joints[1].y); // 从颈部开始
            ctx.lineTo(joints[2].x, joints[2].y); // 到臀部
            ctx.moveTo(joints[1].x, joints[1].y);
            ctx.lineTo(joints[3].x, joints[3].y); // 到左肘
            ctx.lineTo(joints[4].x, joints[4].y); // 到左手
            ctx.moveTo(joints[1].x, joints[1].y);
            ctx.lineTo(joints[5].x, joints[5].y); // 到右肘
            ctx.lineTo(joints[6].x, joints[6].y); // 到右手
            ctx.moveTo(joints[2].x, joints[2].y);
            ctx.lineTo(joints[7].x, joints[7].y); // 到左膝
            ctx.lineTo(joints[8].x, joints[8].y); // 到左脚
            ctx.moveTo(joints[2].x, joints[2].y);
            ctx.lineTo(joints[9].x, joints[9].y); // 到右膝
            ctx.lineTo(joints[10].x, joints[10].y); // 到右脚
            ctx.stroke();

            // 绘制头部
            const headAngle = Math.atan2(joints[0].y - joints[1].y, joints[0].x - joints[1].x);
            const headMidX = (joints[0].x + joints[1].x) / 2;
            const headMidY = (joints[0].y + joints[1].y) / 2;
            
            ctx.save();
            ctx.translate(headMidX, headMidY);
            ctx.rotate(headAngle + Math.PI / 2);
            ctx.beginPath();
            ctx.ellipse(0, 0, 15, 20, 0, 0, 2 * Math.PI);
            ctx.stroke();
            ctx.restore();

            // 绘制从颈部到头顶的线
            ctx.beginPath();
            ctx.moveTo(joints[1].x, joints[1].y);
            ctx.lineTo(joints[0].x, joints[0].y);
            ctx.stroke();

            // 绘制关节点
            joints.forEach(joint => {
      
      
                ctx.beginPath();
                ctx.arc(joint.x, joint.y, 5, 0, Math.PI * 2);
                ctx.fill();
            });
        }

        let dragging = false;
        let selectedJoint = null;

        // 鼠标按下事件
        canvas.addEventListener('mousedown', (e) => {
      
      
            const rect = canvas.getBoundingClientRect();
            const x = e.clientX - rect.left;
            const y = e.clientY - rect.top;
            
            joints.forEach(joint => {
      
      
                if (Math.abs(x - joint.x) < 10 && Math.abs(y - joint.y) < 10) {
      
      
                    dragging = true;
                    selectedJoint = joint;
                }
            });
        });

        // 鼠标移动事件
        canvas.addEventListener('mousemove', (e) => {
      
      
            if (dragging && selectedJoint) {
      
      
                const rect = canvas.getBoundingClientRect();
                selectedJoint.x = e.clientX - rect.left;
                selectedJoint.y = e.clientY - rect.top;
                drawStickman();
            }
        });

        // 鼠标松开事件
        canvas.addEventListener('mouseup', () => {
      
      
            dragging = false;
            selectedJoint = null;
        });

        // 下载按钮点击事件
        downloadBtn.addEventListener('click', () => {
      
      
            drawStickman(true);  // 绘制带白色背景的图像
            const dataUrl = canvas.toDataURL('image/png');
            const link = document.createElement('a');
            link.download = 'stick-figure-pose.png';
            link.href = dataUrl;
            link.click();
            drawStickman();  // 重新绘制不带背景的图像,以便继续编辑
        });

        // 初始绘制
        drawStickman();
    </script>
</body>
</html>

如何使用

  1. 调整姿势: 点击并拖动任意关节点来调整火柴人的姿势。头部可以通过移动头顶和颈部节点来调整角度和位置。
  2. 导出图片: 当你对姿势满意时,点击"下载姿势图片"按钮。你的浏览器会自动下载一个名为"stick-figure-pose.png"的PNG图片文件,其中包含当前的火柴人姿势,背景为白色。

如何运行

要运行这个2D人体姿势生成器,只需将上面的完整代码保存为一个HTML文件(例如pose-generator.html),然后用现代浏览器(如Chrome、Firefox、Safari或Edge)打开这个文件即可。

结论

这个2D人体姿势生成器虽然简单,但展示了Web技术在创意工具开发中的潜力。通过组合HTML5 Canvas和JavaScript,我们创建了一个直观、易用且功能强大的工具。无论你是数字艺术家、动画师,还是just for fun,希望这个工具能为你的创作过程带来便利和乐趣。

猜你喜欢

转载自blog.csdn.net/exlink2012/article/details/143116035