js -- html2canvas 海报截图功能
浏览器海报实现
下载 npm i html2canvas or html2canvas.js 和 canvas2image.js
开发中遇到的一些问题:
-
box-shadow 阴影属性截图后不生效,可以使用阴影图片代替
-
如果图片是 background 布局,截图出来图片是虚的,只能写 img 布局
-
options 配置中,添加的 scale 参数(可通过下面 getPixelRatio 方法获取设备的像素密度,注意默认不要太小或者固定写 >=2 以防止截图后图片虚)
-
当要生成的 html 代码中包含 img 标签,并且设置了 object-fit:cover 属性后,通过 html2canvas 生成的图片object-fit:cover 属性没有生效,导致生成的图片与通过样式设置的不一样。需要更改如下源码,当然你需要将此源码单独取出放在 js 中引入到项目中
CanvasRenderer.prototype.renderReplacedElement = function (container, curves, image) {
// if (image && container.intrinsicWidth > 0 && container.intrinsicHeight > 0) {
// var box = contentBox(container);
// var path = calculatePaddingBoxPath(curves);
// this.path(path);
// this.ctx.save();
// this.ctx.clip();
// this.ctx.drawImage(image, 0, 0, container.intrinsicWidth, container.intrinsicHeight, box.left, box.top, box.width, box.height);
// this.ctx.restore();
// }
// 上面注释的原来的代码,下面是我们自己修改后的
// Start Custom Code
if (image && container.intrinsicWidth > 0 && container.intrinsicHeight > 0) {
var box = contentBox(container);
var path = calculatePaddingBoxPath(curves);
this.path(path);
this.ctx.save();
this.ctx.clip();
let newWidth;
let newHeight;
let newX = box.left;
let newY = box.top;
if(container.intrinsicWidth / box.width < container.intrinsicHeight / box.height) {
newWidth = box.width;
newHeight = container.intrinsicHeight * (box.width / container.intrinsicWidth);
newY = box.top + (box.height - newHeight) / 2;
} else {
newWidth = container.intrinsicWidth * (box.height / container.intrinsicHeight);
newHeight = box.height;
newX = box.left + (box.width - newWidth) / 2;
}
this.ctx.drawImage(image, 0, 0, container.intrinsicWidth, container.intrinsicHeight, newX, newY, newWidth, newHeight);
this.ctx.restore();
}
// End Custom Code
};
<img :src="`${item.cover}?${new Date().getTime()}`" alt="" class="full-object-cover" crossOrigin="anonymous">
<a v-show="download" :href="imgUri" download="图片名称">下载图片</a>
同步写法
// 获取像素密度
function getPixelRatio(context) {
var backingStore = context.backingStorePixelRatio ||
context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio || 1
if ((window.devicePixelRatio || 1) / backingStore < 1.9) {
return 2 // 这里最好限制2倍或以上,防止截图后图片太虚
} else {
return (window.devicePixelRatio || 1) / backingStore
}
}
function save_html_as_png(filename = 'image') {
const eleContent = document.getElementById('overlay-img') // 显示图片的位置
const posterTemplate = document.getElementsByClassName('poster-template')[0] // 海报模板
if (eleContent.childNodes.length) return false
var width = posterTemplate.offsetWidth // 获取(原生)dom 宽度
var height = posterTemplate.offsetHeight // 获取(原生)dom 高
// var offsetTop = shareContent.offsetTop; // 元素距离顶部的偏移量
var canvas = document.createElement('canvas') // 创建canvas 对象
var scaleBy = getPixelRatio(context) // 获取像素密度的方法 (也可以采用自定义缩放比例)
var context = canvas.getContext('2d')
canvas.width = width * scaleBy // 这里 由于绘制的dom 为固定宽度,居中,所以没有偏移
// canvas.height = (height + offsetTop) * scaleBy; // 注意高度问题,由于顶部有个距离所以要加上顶部的距离,解决图像高度偏移问题
canvas.height = height * scaleBy // 注意高度问题,由于顶部有个距离所以要加上顶部的距离,解决图像高度偏移问题
context.scale(scaleBy, scaleBy)
context.translate(0, 0)
var opts = {
useCORS: true, // 【重要】开启跨域配置,true 允许加载跨域的图片,默认 false
scale: scaleBy, // 添加的 scale 参数
// canvas: canvas, //自定义 canvas
backgroundColor: null, // 此句可使转出的图没有白边
width: width, //dom 原始宽度
height: height,
logging: false, // 日志开关,便于查看 html2canvas 的内部执行流程
};
html2canvas($('body')[0], opts).then(canvas => {
// 【重要】关闭抗锯齿
var context = canvas.getContext('2d')
context.mozImageSmoothingEnabled = false
context.webkitImageSmoothingEnabled = false
context.msImageSmoothingEnabled = false
context.imageSmoothingEnabled = false
// 调用Canvas2Image插件
var img = Canvas2Image.convertToImage(canvas, canvas.width, canvas.height);
// 调用Canvas2Image插件
// Canvas2Image.saveAsImage(canvas, canvas.width, canvas.height, 'png', filename);
that.imgUri = image.src // 显示在页面中
eleContent.appendChild(image)
that.download = true // 编译过程中不能下载
posterTemplate.classList.add('hidden') // 隐藏 html 布局
});
}
异步写法
async function async_save_html_as_png(filename="image") {
...
var canvas = await html2canvas($('body')[0], opts);
...
}
需要注意的点:
-
allowTaint: true 和 useCORS: true 都是解决跨域问题的方式,不同的是使用 allowTaint 会对 canvas 造成污染,导致无法使用 canvas.toDataURL 方法,所以这里不能使用 allowTaint: true;
-
在跨域的图片里设置 crossOrigin="anonymous" 并且在给图片 img 标签中 src 属性传图片地址的时候,需要在图片地址后面拼接上一个随机字符串;
-
canvas.toDataURL('image/jpg') 是将 canvas 转成 base64 图片格式;
-
如果是用的阿里云或者其他云平台的 oss 对象存储,还需要在对应的平台上设置一下跨域(这里视情况看是否需要配置)。
其它:
-
html2canvas 传入的是 dom 对象。这是一个异步函数。可以截图指定元素区域。
-
Canvas2Image.convertToImage 是同步函数。可以指定图片区域大小。类型可以是 jpeg/png/bmp 等(不区分大小写)。文件名不需要后缀。Canvas2Image.convertToImage 只会下载图片文件。无法存放到指定路径。
QRCode 生成二维码功能
function getQrCode() {
var url = window.location.href
QRCode.toCanvas(document.getElementById('code'), url,
{
width: 72, // 太小容易识别不灵敏
height: 72,
colorDark: '#000000',
colorLight: '#ffffff',
typeNumber: 4,
correctLevel: 'Q', // H
logging: process.env.NODE_ENV === 'production'? false: true // 日志开关
},
error => {
if (error) console.error(error)
...
save_html_as_png()
})
},