canvas实现头像+二维码+背景图合成

83 阅读4分钟

有个项目需求是生成带二维码的邀请卡片,效果图如下:

image.png

思路

先说下实现思路:

  1. 使用canvas的drawImage、fillText进行图片、文字的合成
  2. 使用html2canva插件实现对DOM的截图,前提是有这个邀请卡片的HTML

思路1实现

先实现一个简单的Demo,需要以下物料:

image.png

头像和二维码先用静态的做演示。。。有需要可以使用qrcode生成二维码。

步骤:

  1. 新建canvas标签
  2. 获取canvas上下文 canvas.getContext('2d')
  3. new Image() ctx.drawImage 绘制背景图
  4. 绘制头像
  5. ctx.fillText绘制用户名
  6. 绘制二维码
  7. 将图像的src改为对应的物料
  8. 使用canvas.toDataURL得到base64

代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Canvas合成名片</title>
    <style>
        #previewContainer {
            margin-top: 20px;
            text-align: center;
            display: none;
        }
        #previewImage {
            max-width: 100%;
            max-height: 80vh;
            border: 1px solid #ddd;
            box-shadow: 0 0 10px rgba(0,0,0,0.1);
        }
    </style>
</head>
<body>
    <button id="generateBtn">生成邀请名片</button>
    <button id="previewBtn">预览邀请名片</button>
    <canvas id="canvas" style="display:none;"></canvas>
    
    <div id="previewContainer">
        <h3>预览效果</h3>
        <img id="previewImage" alt="邀请名片预览">
        <br><br>
        <button id="downloadBtn">下载名片</button>
    </div>

    <script>
        // 存储合成的图片数据
        let generatedImageData = null;
        
        // 预览按钮事件
        document.getElementById('previewBtn').addEventListener('click', function() {
            generateCard(true); // 生成并显示预览
        });
        
        // 生成按钮事件
        document.getElementById('generateBtn').addEventListener('click', function() {
            generateCard(false); // 生成并直接下载
        });
        
        // 下载按钮事件
        document.getElementById('downloadBtn').addEventListener('click', function() {
            if (generatedImageData) {
                downloadImageFromData(generatedImageData);
            }
        });
        
        // 生成名片主函数
        function generateCard(isPreview) {
            // 创建canvas元素
            const canvas = document.getElementById('canvas');
            const ctx = canvas.getContext('2d');
            
            // 设置画布尺寸
            canvas.width = 1170;
            canvas.height = 3558;
            
            // 创建背景图
            const background = new Image();
            background.onload = function() {
                // 绘制背景图
                ctx.drawImage(background, 0, 0, canvas.width, canvas.height);
                
                // 加载头像
                const avatar = new Image();
                avatar.onload = function() {
                    // 设置头像位置和尺寸
                    const avatarWidth = 240;
                    const avatarHeight = 240;
                    const avatarX = (canvas.width - avatarWidth) / 2; // 居中
                    const avatarY = 1300; // 距离顶部1460px
                    
                    // 绘制头像
                    ctx.drawImage(avatar, avatarX, avatarY, avatarWidth, avatarHeight);
                    
                    // 在头像旁边添加文字
                    ctx.fillStyle = '#FFF'; // 文字颜色
                    ctx.font = 'bold 48px Arial'; // 字体样式
                    ctx.textAlign = 'center'; // 文字对齐方式
                    ctx.fillText('陈*文', canvas.width/2, avatarY + avatarHeight + 70); // 用户名
                    
                    // 加载二维码
                    const qrcode = new Image();
                    qrcode.onload = function() {
                        // 设置二维码位置和尺寸
                        const qrWidth = 400;
                        const qrHeight = 400;
                        const qrX = (canvas.width - qrWidth) / 2; // 居中
                        const qrY = 1840; // 距离顶部1840px
                        
                        // 绘制二维码
                        ctx.drawImage(qrcode, qrX, qrY, qrWidth, qrHeight);
                        
                        // 合成完成后的处理
                        if (isPreview) {
                            // 显示预览
                            showPreview(canvas);
                        } else {
                            // 直接下载
                            downloadImage(canvas);
                        }
                    };
                    qrcode.src = './assets/qr.png'; // 替换为您的二维码图片路径
                };
                avatar.src = './assets/avatar.png';
            };
            background.src = './assets/bg.png';
        }
        
        // 显示预览
        function showPreview(canvas) {
            const previewImage = document.getElementById('previewImage');
            const previewContainer = document.getElementById('previewContainer');
            
            // 保存图像数据供下载使用
            generatedImageData = canvas.toDataURL('image/png');
            
            // 设置预览图像
            previewImage.src = generatedImageData;
            
            // 显示预览容器
            previewContainer.style.display = 'block';
        }
        
        // 下载合成图片
        function downloadImage(canvas) {
            const link = document.createElement('a');
            link.download = 'invitation-card.png';
            link.href = canvas.toDataURL('image/png');
            link.click();
        }
        
        // 从数据URL下载图片
        function downloadImageFromData(dataURL) {
            const link = document.createElement('a');
            link.download = 'invitation-card.png';
            link.href = dataURL;
            link.click();
        }
    </script>
</body>
</html>

使用qrcode

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Canvas合成名片</title>
    <!-- 引入qrcode.js库 -->
    <script src="https://cdn.jsdelivr.net/npm/qrcode/build/qrcode.min.js"></script>
    <style>
        #previewContainer {
            margin-top: 20px;
            text-align: center;
            display: none;
        }
        #previewImage {
            max-width: 100%;
            max-height: 80vh;
            border: 1px solid #ddd;
            box-shadow: 0 0 10px rgba(0,0,0,0.1);
        }
    </style>
</head>
<body>
    <button id="generateBtn">生成邀请名片</button>
    <button id="previewBtn">预览邀请名片</button>
    <canvas id="canvas" style="display:none;"></canvas>
    
    <div id="previewContainer">
        <h3>预览效果</h3>
        <img id="previewImage" alt="邀请名片预览">
        <br><br>
        <button id="downloadBtn">下载名片</button>
    </div>

    <script>
        // 存储合成的图片数据
        let generatedImageData = null;
        
        // 预览按钮事件
        document.getElementById('previewBtn').addEventListener('click', function() {
            generateCard(true); // 生成并显示预览
        });
        
        // 生成按钮事件
        document.getElementById('generateBtn').addEventListener('click', function() {
            generateCard(false); // 生成并直接下载
        });
        
        // 下载按钮事件
        document.getElementById('downloadBtn').addEventListener('click', function() {
            if (generatedImageData) {
                downloadImageFromData(generatedImageData);
            }
        });
        
        // 生成名片主函数
        function generateCard(isPreview) {
            // 创建canvas元素
            const canvas = document.getElementById('canvas');
            const ctx = canvas.getContext('2d');
            
            // 设置画布尺寸
            canvas.width = 1170;
            canvas.height = 3558;
            
            // 创建背景图
            const background = new Image();
            background.onload = function() {
                // 绘制背景图
                ctx.drawImage(background, 0, 0, canvas.width, canvas.height);
                
                // 加载头像
                const avatar = new Image();
                avatar.onload = function() {
                    // 设置头像位置和尺寸
                    const avatarWidth = 240;
                    const avatarHeight = 240;
                    const avatarX = (canvas.width - avatarWidth) / 2; // 居中
                    const avatarY = 1300; // 距离顶部1460px
                    
                    // 绘制头像
                    ctx.drawImage(avatar, avatarX, avatarY, avatarWidth, avatarHeight);
                    
                    // 在头像旁边添加文字
                    ctx.fillStyle = '#FFF'; // 文字颜色
                    ctx.font = 'bold 48px Arial'; // 字体样式
                    ctx.textAlign = 'center'; // 文字对齐方式
                    ctx.fillText('陈*文', canvas.width/2, avatarY + avatarHeight + 70); // 用户名
                    
                    // 使用qrcode插件生成二维码
                    generateQRCode(function(qrCanvas) {
                        // 设置二维码位置和尺寸
                        const qrWidth = 400;
                        const qrHeight = 400;
                        const qrX = (canvas.width - qrWidth) / 2; // 居中
                        const qrY = 1840; // 距离顶部1840px
                        
                        // 绘制二维码
                        ctx.drawImage(qrCanvas, qrX, qrY, qrWidth, qrHeight);
                        
                        // 合成完成后的处理
                        if (isPreview) {
                            // 显示预览
                            showPreview(canvas);
                        } else {
                            // 直接下载
                            downloadImage(canvas);
                        }
                    });
                };
                avatar.src = './assets/avatar.png';
            };
            background.src = './assets/bg.png';
        }
        
        // 使用qrcode.js生成二维码
        function generateQRCode(callback) {
            // 创建临时canvas用于生成二维码
            const tempCanvas = document.createElement('canvas');
            
            // 使用qrcode库生成二维码
            QRCode.toCanvas(tempCanvas, 'https://opening.wlbank.tech/zh_hk/biz/mgm?Ref_no=0000006327', {
                width: 400,
                height: 400,
                margin: 2,
                color: {
                    dark: '#000000',
                    light: '#ffffff'
                }
            }, function (error) {
                if (error) {
                    console.error('生成二维码失败:', error);
                    return;
                }
                // 生成成功后回调
                callback(tempCanvas);
            });
        }
        
        // 显示预览
        function showPreview(canvas) {
            const previewImage = document.getElementById('previewImage');
            const previewContainer = document.getElementById('previewContainer');
            
            // 保存图像数据供下载使用
            generatedImageData = canvas.toDataURL('image/png');
            
            // 设置预览图像
            previewImage.src = generatedImageData;
            
            // 显示预览容器
            previewContainer.style.display = 'block';
        }
        
        // 下载合成图片
        function downloadImage(canvas) {
            const link = document.createElement('a');
            link.download = 'invitation-card.png';
            link.href = canvas.toDataURL('image/png');
            link.click();
        }
        
        // 从数据URL下载图片
        function downloadImageFromData(dataURL) {
            const link = document.createElement('a');
            link.download = 'invitation-card.png';
            link.href = dataURL;
            link.click();
        }
    </script>
</body>
</html>

物料

物料在这里,感兴趣的伙伴可以试试!

avatar.png

qr.png

bg.png