gifshot.js:可以从媒体流、视频或图像创建动画 GIF 的 JavaScript 库。
https://github.com/yahoo/gifshot
经测试:
text配置项:
生成的GIF每一帧所覆盖的文本;
images配置项(数组):
首个设置的图片会一直显示;
如设置text,则优先级最高,当前(帧)图片覆盖文本替换text配置项全局文本;
demo:多张图片合成GIF图片;VIDEO生成的GIF;
demo资源下载
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>gifshot.js合成GIF</title>
<style type="text/css">
body{ background-color: #ddd;}
</style>
</head>
<body>
<div class="">
<p>gifshot.js:可以从媒体流、视频或图像创建动画 GIF 的 JavaScript 库。</p>
<p><a href="https://github.com/yahoo/gifshot">https://github.com/yahoo/gifshot</a></p>
<p>经测试:</p>
<p>text配置项:<br>生成的GIF每一帧所覆盖的文本;</p>
<p>images配置项(数组):<br>首个设置的图片会一直显示;<br>如设置text,则优先级最高,当前(帧)图片覆盖文本替换text配置项全局文本;</p>
<p>demo:多张图片合成GIF图片;VIDEO生成的GIF;</p>
</div>
<div style="text-align: center;display: flex; justify-content: center; align-items: flex-start;">
<div id="img1" style="width: 30%;">
<p>所有图片PNG生成的GIF <span></span></p>
</div>
<div id="img2" style="width: 30%;">
<p>所有图片JPG生成的GIF <span></span></p>
</div>
<div id="img3" style="width: 30%;">
<p>VIDEO生成的GIF <span></span></p>
</div>
</div>
<!-- <script src="gifshot.js"></script> -->
<script src="gifshot.min.js"></script>
<!-- 所有图片PNG生成的GIF -->
<script type="text/javascript">
gifshot.createGIF({
// 图片的宽度
'gifWidth' : 300,
// 图片的高度
'gifHeight' : 300,
// 如果使用此选项,则将使用这些图片创建 GIF
// 注意:确保这些图像资源启用了 CORS 以防止任何跨域 JavaScript 错误
// 注意:您还可以传递页面上现有图像元素的 NodeList
'images' : [
{ src:'img/png/base.png',text:'我是第 1 张图片(所有图片PNG)'},
{ src:'img/png/1.png',text:'第 2 张'},
{ src:'img/png/2.png',text:'第 3 张'},
{ src:'img/png/3.png',text:'第 4 张'},
{ src:'img/png/4.png',text:'第 5 张'},
{ src:'img/png/5.png',text:'第 6 张'},
{ src:'img/png/6.png',text:'第 7 张'},
{ src:'img/png/7.png',text:'第 8 张'},
{ src:'img/png/8.png',text:'第 9 张'},
],
// 如果使用此选项,则将使用适当的视频创建 gif
// 您想从中创建动画 GIF 的 HTML5 视频
// 注意:已检查浏览器对某些视频编解码器的支持,并选择了适当的视频
// 注意:您还可以传递页面上现有视频元素的 NodeList
// 例如 'video': ['example.mp4', 'example.ogv'],
'video' : null,
// 你可以传递一个现有的 video 元素用于网络摄像头 GIF 创建过程,
// 和这个视频元素不会被隐藏(与 keepCameraOn 选项一起使用时很有用)
// 专业提示:将视频元素的高度和宽度设置为与您未来的 GIF 相同的值
// 另一个专业提示:如果您使用此选项,视频不会被暂停,对象 url 不会被撤销,并且
// 视频不会从 DOM 中删除。您需要自己处理。
'webcamVideoElement' : null,
// 您是否希望在创建 GIF 后用户的相机保持开启
// 注意:cameraStream Media 对象在 createGIF() 回调函数中传回给您
'keepCameraOn' : false,
// 需要一个 cameraStream 媒体对象
// 注意:如果您不使用 SSL
// 传递现有的相机流将允许您创建另一个 GIF 和/或快照,而无需请求用户再次访问相机的权限
'cameraStream':null,
// 将应用于图像的 CSS 过滤器(例如 blur(5px))
'filter' : '',
// 每帧捕获之间等待的时间(以秒为单位)
'interval' : 0.1,
//开始捕获 GIF 的时间(以秒为单位)(仅适用于 HTML5 视频)
'offset' : null,
// 用于创建动画 GIF 的帧数
// 注意:每帧每 100 毫秒捕获一次现有图像的视频和每毫秒
'numFrames' : 10, //视频中捕获的生成GIF的帧数
// 每帧停留的时间 (10 = 1s)
'frameDuration' : 1,
// 覆盖动画 GIF的文本
'text' : '生成的GIF每一帧所覆盖的文本',
// 覆盖动画 GIF 的文本的字体粗细
'fontWeight' : 'normal',
// 覆盖动画 GIF 的文本的字体大小
'fontSize' : '16px',
// 覆盖动画 GIF 的文本的最小字体大小
// 注意:该选项仅在正在应用的文本被截断时应用
'minFontSize' : '10px',
// 是否动画 GIF 文本是否会调整大小以适应 GIF 容器
'resizeFont' : false,
// 覆盖动画 GIF 的文本的字体系列
'fontFamily' : 'sans-serif',
// 覆盖动画 GIF 的文本的字体颜色
// 'fontColor' : '#dd0000',
'fontColor' : 'green',
// 水平文本覆盖动画 GIF的文本对齐方式
'textAlign' : 'center',
// 覆盖动画 GIF 的文本的垂直文本对齐方式
'textBaseline' : 'bottom',
// 文本的 X(水平)坐标涵盖动画 GIF(仅在默认 textAlign 和 textBaseline 选项不适合您时使用)
'textXCoordinate':null,
// 覆盖动画 GIF 的文本的 Y(垂直)坐标(仅在默认的 textAlign 和 textBaseline 选项不适合您时使用)
'textYCoordinate' : null,
// 提供当前进度的回调函数当前图像的
'progressCallback' : function (captureProgress){
// console.log(captureProgress);
document.getElementById('img1').getElementsByTagName('span')[0].innerHTML = parseInt(captureProgress * 100) + '%';
},
// 当前图像完成时调用的回调函数
'completeCallback' : function (){
console.log('当前图像完成时调用的回调函数')
},
// 创建调色板时要跳过多少像素。默认值为 10。越少越好,但更慢。
// 注意:通过调整采样间隔,既可以慢慢产生极高质量的图像,也可以在合理的时间内产生好的图像。
// sampleInterval 为 1,整个图像用于学习阶段,而间隔为 10,
// 1/10 像素的伪随机子集用于学习阶段。10 的采样因子给出了
// 显着的加速,但质量损失很小。
'sampleInterval' : 10,
// 使用多少网络工作者来处理动画 GIF 帧。默认为 2。
'numWorkers' : 2,
// 您是否希望从创建的 GIF 中保存所有画布图像二进制数据
// 注意:当您想重新使用 GIF 将文本添加到以后的
'saveRenderingContexts':false,
// 需要一个画布图像数据数组
// 注意:如果您将 saveRenderingContexts 选项设置为 true,然后在 createGIF 回调函数'savedRenderingContexts'中获得
"savedRenderingContexts": [],
// 当请求使用现有图像或视频时,我们在请求上设置 CORS 属性。
// 选项是 'Anonymous'、'use-credentials' 或虚假值(如 '')以不设置 CORS 属性。
'showFrameText':true,
// 如果图像数组提供了特定于框架的文本,则可以通过将此选项设置为“false”来强制不显示特定于框架的文本。
'crossOrigin' : 'Anonymous',
// 水印图像 如果这里给出了图像,它将被标记在 GIF 帧的顶部
"waterMark" : null,
// 水印图像 的高度
"waterMarkHeight" : null,
// 水印图像 的宽度
"waterMarkWidth" : null,
// 水印图像的 X(水平)坐标
"waterMarkXCoordinate" : 1,
//水印图像的Y(垂直)坐标
"waterMarkYCoordinate" : 1
},function(obj) {
if(!obj.error) {
var image = obj.image,
animatedImage = document.createElement('img');
animatedImage.src = image;
// document.body.appendChild(animatedImage);
document.getElementById('img1').appendChild(animatedImage);
}
});
</script>
<!-- 所有图片JPG生成的GIF -->
<script type="text/javascript">
gifshot.createGIF({
// 图片的宽度
'gifWidth' : 300,
// 图片的高度
'gifHeight' : 300,
// 如果使用此选项,则将使用这些图片创建 GIF
// 注意:确保这些图像资源启用了 CORS 以防止任何跨域 JavaScript 错误
// 注意:您还可以传递页面上现有图像元素的 NodeList
'images' : [
{ src:'img/jpg/base.jpg',text:'我是第 1 张图片(所有图片JPG)'},
{ src:'img/jpg/1.jpg',text:'第 2 张'},
{ src:'img/jpg/2.jpg',text:'第 3 张'},
{ src:'img/jpg/3.jpg',text:'第 4 张'},
{ src:'img/jpg/4.jpg',text:'第 5 张'},
{ src:'img/jpg/5.jpg',text:'第 6 张'},
{ src:'img/jpg/6.jpg',text:'第 7 张'},
{ src:'img/jpg/7.jpg',text:'第 8 张'},
{ src:'img/jpg/8.jpg',text:'第 9 张'},
],
// 如果使用此选项,则将使用适当的视频创建 gif
// 您想从中创建动画 GIF 的 HTML5 视频
// 注意:已检查浏览器对某些视频编解码器的支持,并选择了适当的视频
// 注意:您还可以传递页面上现有视频元素的 NodeList
// 例如 'video': ['example.mp4', 'example.ogv'],
'video' : null,
// 你可以传递一个现有的 video 元素用于网络摄像头 GIF 创建过程,
// 和这个视频元素不会被隐藏(与 keepCameraOn 选项一起使用时很有用)
// 专业提示:将视频元素的高度和宽度设置为与您未来的 GIF 相同的值
// 另一个专业提示:如果您使用此选项,视频不会被暂停,对象 url 不会被撤销,并且
// 视频不会从 DOM 中删除。您需要自己处理。
'webcamVideoElement' : null,
// 您是否希望在创建 GIF 后用户的相机保持开启
// 注意:cameraStream Media 对象在 createGIF() 回调函数中传回给您
'keepCameraOn' : false,
// 需要一个 cameraStream 媒体对象
// 注意:如果您不使用 SSL
// 传递现有的相机流将允许您创建另一个 GIF 和/或快照,而无需请求用户再次访问相机的权限
'cameraStream':null,
// 将应用于图像的 CSS 过滤器(例如 blur(5px))
'filter' : '',
// 每帧捕获之间等待的时间(以秒为单位)
'interval' : 0.1,
//开始捕获 GIF 的时间(以秒为单位)(仅适用于 HTML5 视频)
'offset' : null,
// 用于创建动画 GIF 的帧数
// 注意:每帧每 100 毫秒捕获一次现有图像的视频和每毫秒
'numFrames' : 10, //视频中捕获的生成GIF的帧数
// 每帧停留的时间 (10 = 1s)
'frameDuration' : 1,
// 覆盖动画 GIF的文本
'text' : '生成的GIF每一帧所覆盖的文本',
// 覆盖动画 GIF 的文本的字体粗细
'fontWeight' : 'normal',
// 覆盖动画 GIF 的文本的字体大小
'fontSize' : '16px',
// 覆盖动画 GIF 的文本的最小字体大小
// 注意:该选项仅在正在应用的文本被截断时应用
'minFontSize' : '10px',
// 是否动画 GIF 文本是否会调整大小以适应 GIF 容器
'resizeFont' : false,
// 覆盖动画 GIF 的文本的字体系列
'fontFamily' : 'sans-serif',
// 覆盖动画 GIF 的文本的字体颜色
// 'fontColor' : '#dd0000',
'fontColor' : 'green',
// 水平文本覆盖动画 GIF的文本对齐方式
'textAlign' : 'center',
// 覆盖动画 GIF 的文本的垂直文本对齐方式
'textBaseline' : 'bottom',
// 文本的 X(水平)坐标涵盖动画 GIF(仅在默认 textAlign 和 textBaseline 选项不适合您时使用)
'textXCoordinate':null,
// 覆盖动画 GIF 的文本的 Y(垂直)坐标(仅在默认的 textAlign 和 textBaseline 选项不适合您时使用)
'textYCoordinate' : null,
// 提供当前进度的回调函数当前图像的
'progressCallback' : function (captureProgress){
// console.log(captureProgress);
document.getElementById('img2').getElementsByTagName('span')[0].innerHTML = parseInt(captureProgress * 100) + '%';
},
// 当前图像完成时调用的回调函数
'completeCallback' : function (){
console.log('当前图像完成时调用的回调函数')
},
// 创建调色板时要跳过多少像素。默认值为 10。越少越好,但更慢。
// 注意:通过调整采样间隔,既可以慢慢产生极高质量的图像,也可以在合理的时间内产生好的图像。
// sampleInterval 为 1,整个图像用于学习阶段,而间隔为 10,
// 1/10 像素的伪随机子集用于学习阶段。10 的采样因子给出了
// 显着的加速,但质量损失很小。
'sampleInterval' : 10,
// 使用多少网络工作者来处理动画 GIF 帧。默认为 2。
'numWorkers' : 2,
// 您是否希望从创建的 GIF 中保存所有画布图像二进制数据
// 注意:当您想重新使用 GIF 将文本添加到以后的
'saveRenderingContexts':false,
// 需要一个画布图像数据数组
// 注意:如果您将 saveRenderingContexts 选项设置为 true,然后在 createGIF 回调函数'savedRenderingContexts'中获得
"savedRenderingContexts": [],
// 当请求使用现有图像或视频时,我们在请求上设置 CORS 属性。
// 选项是 'Anonymous'、'use-credentials' 或虚假值(如 '')以不设置 CORS 属性。
'showFrameText':true,
// 如果图像数组提供了特定于框架的文本,则可以通过将此选项设置为“false”来强制不显示特定于框架的文本。
'crossOrigin' : 'Anonymous',
// 水印图像 如果这里给出了图像,它将被标记在 GIF 帧的顶部
"waterMark" : null,
// 水印图像 的高度
"waterMarkHeight" : null,
// 水印图像 的宽度
"waterMarkWidth" : null,
// 水印图像的 X(水平)坐标
"waterMarkXCoordinate" : 1,
//水印图像的Y(垂直)坐标
"waterMarkYCoordinate" : 1
},function(obj) {
if(!obj.error) {
var image = obj.image,
animatedImage = document.createElement('img');
animatedImage.src = image;
// document.body.appendChild(animatedImage);
document.getElementById('img2').appendChild(animatedImage);
}
});
</script>
<!-- VIDEO生成的GIF -->
<script type="text/javascript">
gifshot.createGIF({
// 图片的宽度
'gifWidth' : 300,
// 图片的高度
'gifHeight' : 300,
// 如果使用此选项,则将使用这些图片创建 GIF
// 注意:确保这些图像资源启用了 CORS 以防止任何跨域 JavaScript 错误
// 注意:您还可以传递页面上现有图像元素的 NodeList
// 'images' : ,
// 如果使用此选项,则将使用适当的视频创建 gif
// 您想从中创建动画 GIF 的 HTML5 视频
// 注意:已检查浏览器对某些视频编解码器的支持,并选择了适当的视频
// 注意:您还可以传递页面上现有视频元素的 NodeList
// 例如 'video': ['example.mp4', 'example.ogv'],
'video' : ['img/video.mp4'],
// 你可以传递一个现有的 video 元素用于网络摄像头 GIF 创建过程,
// 和这个视频元素不会被隐藏(与 keepCameraOn 选项一起使用时很有用)
// 专业提示:将视频元素的高度和宽度设置为与您未来的 GIF 相同的值
// 另一个专业提示:如果您使用此选项,视频不会被暂停,对象 url 不会被撤销,并且
// 视频不会从 DOM 中删除。您需要自己处理。
'webcamVideoElement' : null,
// 您是否希望在创建 GIF 后用户的相机保持开启
// 注意:cameraStream Media 对象在 createGIF() 回调函数中传回给您
'keepCameraOn' : false,
// 需要一个 cameraStream 媒体对象
// 注意:如果您不使用 SSL
// 传递现有的相机流将允许您创建另一个 GIF 和/或快照,而无需请求用户再次访问相机的权限
'cameraStream':null,
// 将应用于图像的 CSS 过滤器(例如 blur(5px))
'filter' : '',
// 每帧捕获之间等待的时间(以秒为单位)
'interval' : 0.1,
//开始捕获 GIF 的时间(以秒为单位)(仅适用于 HTML5 视频)
'offset' : null,
// 用于创建动画 GIF 的帧数
// 注意:每帧每 100 毫秒捕获一次现有图像的视频和每毫秒
'numFrames' : 50, //视频中捕获的生成GIF的帧数
// 每帧停留的时间 (10 = 1s)
'frameDuration' : 1,
// 覆盖动画 GIF的文本
'text' : '生成的GIF每一帧所覆盖的文本(VIDEO生成的GIF)',
// 覆盖动画 GIF 的文本的字体粗细
'fontWeight' : 'normal',
// 覆盖动画 GIF 的文本的字体大小
'fontSize' : '12px',
// 覆盖动画 GIF 的文本的最小字体大小
// 注意:该选项仅在正在应用的文本被截断时应用
'minFontSize' : '10px',
// 是否动画 GIF 文本是否会调整大小以适应 GIF 容器
'resizeFont' : false,
// 覆盖动画 GIF 的文本的字体系列
'fontFamily' : 'sans-serif',
// 覆盖动画 GIF 的文本的字体颜色
// 'fontColor' : '#dd0000',
'fontColor' : 'white',
// 水平文本覆盖动画 GIF的文本对齐方式
'textAlign' : 'center',
// 覆盖动画 GIF 的文本的垂直文本对齐方式
'textBaseline' : 'bottom',
// 文本的 X(水平)坐标涵盖动画 GIF(仅在默认 textAlign 和 textBaseline 选项不适合您时使用)
'textXCoordinate':null,
// 覆盖动画 GIF 的文本的 Y(垂直)坐标(仅在默认的 textAlign 和 textBaseline 选项不适合您时使用)
'textYCoordinate' : null,
// 提供当前进度的回调函数当前图像的
'progressCallback' : function (captureProgress){
// console.log(captureProgress);
document.getElementById('img3').getElementsByTagName('span')[0].innerHTML = parseInt(captureProgress * 100) + '%';
},
// 当前图像完成时调用的回调函数
'completeCallback' : function (){
console.log('当前图像完成时调用的回调函数')
},
// 创建调色板时要跳过多少像素。默认值为 10。越少越好,但更慢。
// 注意:通过调整采样间隔,既可以慢慢产生极高质量的图像,也可以在合理的时间内产生好的图像。
// sampleInterval 为 1,整个图像用于学习阶段,而间隔为 10,
// 1/10 像素的伪随机子集用于学习阶段。10 的采样因子给出了
// 显着的加速,但质量损失很小。
'sampleInterval' : 10,
// 使用多少网络工作者来处理动画 GIF 帧。默认为 2。
'numWorkers' : 2,
// 您是否希望从创建的 GIF 中保存所有画布图像二进制数据
// 注意:当您想重新使用 GIF 将文本添加到以后的
'saveRenderingContexts':false,
// 需要一个画布图像数据数组
// 注意:如果您将 saveRenderingContexts 选项设置为 true,然后在 createGIF 回调函数'savedRenderingContexts'中获得
"savedRenderingContexts": [],
// 当请求使用现有图像或视频时,我们在请求上设置 CORS 属性。
// 选项是 'Anonymous'、'use-credentials' 或虚假值(如 '')以不设置 CORS 属性。
'showFrameText':true,
// 如果图像数组提供了特定于框架的文本,则可以通过将此选项设置为“false”来强制不显示特定于框架的文本。
'crossOrigin' : 'Anonymous',
// 水印图像 如果这里给出了图像,它将被标记在 GIF 帧的顶部
"waterMark" : null,
// 水印图像 的高度
"waterMarkHeight" : null,
// 水印图像 的宽度
"waterMarkWidth" : null,
// 水印图像的 X(水平)坐标
"waterMarkXCoordinate" : 1,
//水印图像的Y(垂直)坐标
"waterMarkYCoordinate" : 1
},function(obj) {
if(!obj.error) {
var image = obj.image,
animatedImage = document.createElement('img');
animatedImage.src = image;
// document.body.appendChild(animatedImage);
document.getElementById('img3').appendChild(animatedImage);
}
});
</script>
</body>
</html>