2021-11-04

h5 canvas 实现海报图片效果

前几天想用纯前端实现一下海报的效果,做出一张海报图出来不需要使用ps这些工具,能给用户下载的一张图,忙着赶项目,代码写得比较杂乱,望大佬指导,话不多说直接上代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .poster {
            width: 400px;
            border: solid 1px black;
        }
    </style>
</head>

<body>
<div class="poster">
</div>
<canvas class="qrcode"></canvas>
</script>
<script src="qrcode.js"></script>
<script src="index.js"></script>
</body>
</html>
这里使用了自适应海报的宽度会随着poster的实际宽度来定义,然后二维码模块使用了qrcode这个库

var posterContent = {
    /**
     * 海报的封面
     * url为海报图片的链接地址
     * text为内部文字的属性,context:内容,x:当前内容的x,y为当前内容的y,size:为字体大小,color:字体颜色
     * text为数组可以有多个字体
     * 下面的同上
     */
    titlePage: {
        url: 'https://book-upload-1251142715.file.myqcloud.com/6c1ab843-cd80-48d8-923b-e838f06fefeb/1.jpg',
        text: [{
            context: '海报封面',
            x: 10,
            y: 100,
            size: 10,
            color: '#aaa'
        }]
    },
    /**
     * 只针对title可以设置他的初始位置和缩放倍率
     * @type {startX:初始x,startY:初始y,imgPower:title的放大倍率默认为 0~1}
     * center是否水平居中
     */
    title: {
        url: 'https://baige-static-1251142715.file.myqcloud.com/book.baige.me/images/baige_100_100.png',
        imgPower: 0.3,
        startX: 0,
        startY: 10,
        center: true,
        text: [{
            context: 'logo文字',
            x: 10,
            y: 10,
            size: 20,
            color: '#ccc'
        }]
    },
    urlcode: {
        /**
         * url链接的地址
         * imgPower二维码的缩放倍率
         * startX二维码默认的开始位置;不设置的话默认上下左右居中,也可以自己微微调试
         * startY二维码默认开始的y位置
         */
        url: 'http://you.baige.me/view/Xho',
        imgPower: 0.8,
        startX: 0,
        startY: 0,
        text: [{
            context: '二维码',
            x: 10,
            y: 10,
            size: 30,
            color: 'black'
        }]
    },
    option: {
        /**
         * color为分割线的颜色
         * top分割线离上封面的距离
         * bottom分割线离下的距离
         * slitLineSize分割线的长度,默认为宽度的一半,不建议修改
         * 挂载元素
         */
        color: "#ccc",
        top: 20,
        bottom: 20,
        splitLineSize: 100,
        el: ".poster"
    }

}

//调用此函数传入数据模板
drawPoster(posterContent);

function drawPoster(posterContent) {
    if (document.querySelector(posterContent.option.el) == null) {
        console.log("跳出执行")
        return;
    }
    getImgSize(posterContent, function (img) {
        drawImage(posterContent, img, function (data) {
            var imgDom = document.createElement('img');
            imgDom.src = data;
            document.querySelector(posterContent.option.el).appendChild(imgDom);
        });
    })

    /**
     * 获取图片的宽高
     * @param url 图片的路径
     */
    function getImgSize(posterContent, callback) {
        if (Object.keys(posterContent).length != 4) {

            console.log("传入图片不符合格式")

            return;
        }
        var images = {
            titlePage: {width: 0, height: 0},
            title: {width: 0, height: 0}
        };
        var sum = 0;
        Object.keys(posterContent).forEach(function (key, index) {
            if (index >= 2) return;

            var image = new Image();

            image.src = posterContent[key].url;
            // 图片先加载完,才可以得到图片宽度和高度
            image.onload = function () {

                let width = image.width;

                let height = image.height;
                sum++;
                if (index == 0) {
                    images.titlePage.width = parseInt(width);

                    images.titlePage.height = parseInt(height);
                    if (sum == 2) {
                        callback(images);
                    }

                }
                if (index == 1) {
                    images.title.width = parseInt(width);

                    images.title.height = parseInt(height);
                    if (sum == 2) {
                        callback(images);
                    }
                }
            }
        })


    }

    /**
     * 合并图片
     * @param images 图片路径数组
     * @param callback
     */
    function drawImage(contentItems, img, callback) {

        var posterWidth = document.querySelector(contentItems.option.el).clientWidth,

            canvas = document.createElement('canvas'), // 创建canvas元素

            titlePageProPortion = img.titlePage.width / img.titlePage.height,

            titleProPortion = img.title.width / img.title.height;

        canvas.width = posterWidth; // canvas宽度

        var splictH = posterWidth / 2;

        if (contentItems.option.splitLineSize != null) {
            splictH = contentItems.option.splitLineSize
        }
        canvas.height = posterWidth / titlePageProPortion + splictH + contentItems.option.top + contentItems.option.bottom; // canvas的高度

        var context = canvas.getContext('2d'); // 创建渲染

        // 设置背景为白色
        context.fillStyle = '#fff';

        context.fillRect(0, 0, canvas.width, canvas.height);

        var posterW, posterH;

        var imageItem_1 = new Image();

        imageItem_1.src = contentItems.titlePage.url;
        // 跨域
        imageItem_1.crossOrigin = 'Anonymous';

        var xAxis_1 = 0;

        var yAxis_1 = 0;

        var istitleOk = false;
        // 图片加载成功,绘制图片
        imageItem_1.onload = function () {

            posterW = posterWidth;


            posterH = posterWidth / titlePageProPortion;

            context.drawImage(imageItem_1, xAxis_1, yAxis_1, posterW, posterH);


            var imageItem_2 = new Image();

            if (contentItems.titlePage.text.length > 0) {

                contentItems.titlePage.text.forEach(function (item, index) {

                    //console.log("这里开始添加了文字", item.color, item.size, item.context)
                    context.fillStyle = item.color;

                    context.font = 'bold ' + item.size + 'px Arial';

                    context.fillText(item.context, xAxis_1 + item.x, yAxis_1 + item.y);

                })

            }
            imageItem_2.src = contentItems.title.url;
            // 跨域
            imageItem_2.crossOrigin = 'Anonymous';
            var xAxis_2 = 0;

            var yAxis_2 = posterH + 20;

            if (contentItems.title.center) {
                xAxis_2 = posterWidth / 4 - posterWidth / 2 * contentItems.title.imgPower / 2;
            }
            context.moveTo(posterW / 2, posterH + contentItems.option.top);
            //设置起点状态
            var splitLineSize = posterWidth / 2;

            if (contentItems.option.splitLineSize != null) {

                splitLineSize = contentItems.option.splitLineSize;
            }
            context.lineTo(posterW / 2, posterH + splitLineSize + contentItems.option.top);
            //设置末端状态
            context.lineWidth = 1;
            //设置线宽状态
            context.strokeStyle = contentItems.color;
            //设置线的颜色状态
            context.stroke();
            //进行绘制
            // 图片加载成功,绘制图片
            imageItem_2.onload = function () {
                istitleOk = true;
                context.drawImage(imageItem_2, xAxis_2 + contentItems.title.startX, yAxis_2 + contentItems.title.startY, posterWidth / 2 * contentItems.title.imgPower, (posterWidth / 2) / titleProPortion * contentItems.title.imgPower);
                if (contentItems.title.text.length > 0) {
                    contentItems.title.text.forEach(function (item, index) {

                        context.fillStyle = item.color;
                        context.font = 'bold ' + item.size + 'px Arial';
                        context.fillText(item.context, xAxis_2 + item.x, yAxis_2 + item.y);

                    })

                }
            }
            imageItem_2.onerror = function () {
                console.log("第二张图片解析失败")
            }
            //二维码生成的地方

            var qrcodeDom = document.createElement('canvas');// 创建canvas元素
            document.querySelector("body").appendChild(qrcodeDom);
            var qrcode = new QRCode(qrcodeDom, {
                text: contentItems.urlcode.url,
                width: 128,
                height: 128,
                colorDark: "#000000",
                colorLight: "#ffffff",
                correctLevel: QRCode.CorrectLevel.H
            });
            var qrcodeUrl = '';
            var time = setInterval(function () {
                qrcodeUrl = qrcodeDom.childNodes[1].src;
                if (qrcodeUrl != '' && istitleOk) {
                    clearInterval(time)
                    var imageItem_3 = new Image();
                    imageItem_3.src = qrcodeUrl;
                    // 跨域
                    imageItem_3.crossOrigin = 'Anonymous';
                    var splitLineS = posterW / 4;
                    if (contentItems.option.splitLineSize != null) {
                        splitLineS = contentItems.option.splitLineSize / 2
                    }
                    var xAxis_3 = posterW / 2 + 50 + contentItems.urlcode.startX;
                    var yAxis_3 = posterH + 20 + splitLineS - (100 * contentItems.urlcode.imgPower) / 2 + contentItems.urlcode.startY;
                    // 图片加载成功,绘制图片
                    imageItem_3.onload = function () {
                        context.drawImage(imageItem_3, xAxis_3, yAxis_3, 100 * contentItems.urlcode.imgPower, 100 * contentItems.urlcode.imgPower);
                        if (contentItems.urlcode.text.length > 0) {
                            contentItems.urlcode.text.forEach(function (item, index) {

                                context.fillStyle = item.color;
                                context.font = 'bold ' + item.size + 'px Arial';
                                context.fillText(item.context, xAxis_3 + item.x, yAxis_3 + item.y);

                            })

                        }
                        callback(canvas.toDataURL('image/jpeg', 1))
                    }
                    imageItem_3.onerror = function () {
                        console.log("第二张图片解析失败")
                    }
                }
            }, 50)


            //二维码的数据

        }
        imageItem_1.onerror = function () {
            console.log("第一张图片路径解析失败")
        }
       
    }
}

这里封装了一个drawPoster的方法,我们需要提前定义一个对象进去对象的格式在最前面,大家可以看一下,由于时间关系所以并没有完善其他功能,最后给大家看一下效果图
在这里插入图片描述
这里所形成的海报图片文字这些就是一整张图片了,大家有兴趣可以试一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值