纯前端js给表情包gif加文字,你就是“表情包大战”最靓的仔!

前言

表情包大家都用过,很多表情包上会有些辅助文字,来表达更多的内容含义。通过加文字特效,可能只用几个表情包,就能来场"表情包大战"。

有很多网站和工具可以操作gif,包括加文字、压缩、合成、制作表情包等等,但是大多需要登陆、看广告、甚至收费才能用,不如自己做一个。下面就介绍如何通过纯前端js来给gif表情包加文字。

思路是:先用第三方库把gif按帧分解为多个图片,然后再利用canvas插入图片再加文字,最后再利用第三方库把多个canvas合成一个gif文件。

用到的第三方库:

这些第三方库,有的有npm package,有的没有,没有的可以直接在github上下载js文件,比如 omggif.js,然后可以script引用,也可以import url方式引用。

gif 转换成多个 canvas

利用第三方库把gif文件分解为多个图片或canvas。

方案1:omggif

omggif:github.com/deanm/omggi...

omggif 可以逐帧解析gif,没有文档,可以看官方例子

逻辑:先读取gif buffer,然后通过omggif读取每个帧图片数据,然后画在canvas上,然后在每个canvas上添加文字,最后生成canvas list。

js 复制代码
async function gif2canvas(url) {
    var response = await fetch(url);
    var blob = await response.blob();
    var arrayBuffer = await blob.arrayBuffer();
    var intArray = new Uint8Array(arrayBuffer);
    var reader = new GifReader(intArray);
    var info = reader.frameInfo(0);

    return new Array(reader.numFrames()).fill(0).map((_, k) => {
        var image = new ImageData(info.width, info.height);
        reader.decodeAndBlitFrameRGBA(k, image.data);

        var canvas = document.createElement('canvas');
        canvas.width = info.width;
        canvas.height = info.height;
        var context = canvas.getContext('2d');
        context.putImageData(image, 0, 0);

        // draw text
        context.font = `normal 30px sans-serif`;
        context.fillStyle = 'white';
        context.textAlign = 'center';
        context.textBaseline = 'top';
        context.fillText('不错不错!', info.width / 2, info.height - 50);

        return canvas;
    });
}

方案2:libgif

libgif:github.com/buzzfeed/li...

libgif 也可以逐帧解析gif,然后读取每帧图像,可以获取canvas,也可以支持播放、暂停等功能。但是不太稳定,经测试相比omggif能解析成功的gif图片不多,大部分都会抛错

逻辑:跟方案1类似,只是它传入的参数是image dom对象。

js 复制代码
function gif2canvas2(image) {
    return new Promise(resolve => {
        image.setAttribute('rel:animated_src', image.src);
        image.setAttribute('rel:auto_play', '0');
        var rub = new SuperGif({ gif: image, max_width: image.width });
        rub.load(function () {
            var list = [];
            for (var i = 1; i <= rub.get_length(); i++) {
                rub.move_to(i);
                var canvas = rub.get_canvas();

                var newCanvas = document.createElement('canvas');
                newCanvas.width = image.width;
                newCanvas.height = image.height;
                var context = newCanvas.getContext('2d');
                context.drawImage(canvas, 0, 0);

                // draw text
                context.font = `normal 30px sans-serif`;
                context.fillStyle = 'white';
                context.textAlign = 'center';
                context.textBaseline = 'top';
                context.fillText('不错不错!', info.width / 2, info.height - 50);
                list.push(newCanvas);
            }
            resolve(list);
        });
    });
}

多个 canvas 合成 gif 文件

利用第三方库把多个图片或者canvas,合成一个gif文件。

方案1:gif.js

gif.js:github.com/jnordberg/g...

gif.js 可以把多个frame合并成一个gif,且利用web workers提高解析速度。注意还需要把gif.worker.js文件放在站点根路径下,或者用workerScript来自定义路径。

js 复制代码
function canvas2gif(canvasList, { width, height }) {
    return new Promise(resolve => {
        var gif = new GIF({
            workers: 2,
            quality: 10,
            width: width,
            height: height,
            workerScript: '/lib/gif.worker.js',
        });
        canvasList.forEach(canvas => gif.addFrame(canvas, { delay: 100 }));

        gif.on('finished', function (blob) {
            var url = URL.createObjectURL(blob);
            resolve(url);
        });
        gif.render();
    });
}

方案2:gifshot

gifshot:github.com/michael-ben...

gifshotgif.js类似,它还可以合成视频或者多个gif,而且本身还支持添加文字。

用gifshot只支持图片格式转gif,所以需要canvas先转image,再调用api。

js 复制代码
function canvas2gif2(canvasList, { width, height }) {
    return new Promise(resolve => {
        var loadImages = canvasList.map(canvas => {
            var src = canvas.toDataURL('image/jpeg');
            return loadImage(src);
        });

        Promise.all(loadImages).then(images => {
            gifshot.createGIF({
                images,
                width: width,
                height: height,
                gifWidth: width,
                gifHeight: height,
            }, result => {
                if (!result.error) {
                    resolve(result.image);
                }
            });
        });
    });
}
async function loadImage(src) {
    return new Promise((resolve, reject) => {
        var img = document.createElement('img');
        img.src = src;
        img.onload = function () {
            resolve(img);
        };
        img.onerror = function (e) {
            reject(e);
        };
    });
}

整合

html 复制代码
<button id="btn1">click1</button>
<img id="img1" src="/images/gif1.gif">
<div id="canvas-div"></div>
<img id="img-output1">
<img id="img-output2">
js 复制代码
var btn1 = document.getElementById('btn1');
var img1 = document.getElementById('img1');
var imgOutput1 = document.getElementById('img-output1');
var imgOutput2 = document.getElementById('img-output2');
var size = { width: img1.width, height: img1.height };

btn1.onclick = async () => {

    // solution1: omggif
    var canvasList = await gif2canvas(img1.src);

    // solution2: libgif
    // var canvasList = await gif2canvas2(img1);

    // solution1: gif.js
    var url1 = await canvas2gif(canvasList, size);
    imgOutput1.src = url1;

    // solution2: gifshot
    var url2 = await canvas2gif2(canvasList, size);
    imgOutput2.src = url2;
}

效果图:

gif.js方案输出的gif:

结论

本文介绍了如何纯前端给gif加文字,思路就是先转多个图片,然后再用canvas加文字,最后合成gif。

用到的第三方lib:

本文只是介绍了第三方相关库的使用,如果要做成Tools就能做成更多功能。比如在线播放gif,或者分解图片后展示在页面上,然后支持根据帧数来添加文字或特效,也就是支持gif里根据时间来显示或隐藏文字。

最后,毕竟客户端无论能力,还是性能、兼容性都有限,比如上面的库都只支持Web,不支持其它客户端例如小程序。尤其这种文件编码能力,其实在服务端能力更好,能用的库或者服务端的工具都很多,所以这种需求尽量还是放在后端实现。之后文章里也会介绍一些好用的nodejs第三方库,来实现更多图片处理需求。

源码:github.com/markz-demo/...

相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60615 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅6 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment6 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅7 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊7 小时前
jwt介绍
前端
爱敲代码的小鱼7 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax