我们都知道在“寸土寸金”的互联网时代, 速度是第一竞争力, 虽然我们的5G发展已经摇摇领先, 但是也经不住用户在一个网页里传很多“巨无霸”图片, 最终导致的结果就是页面“龟速”打开......
那么作为技术人, 当然也有一堆的解决方案, 比如:
当然聪明的小伙伴也会将上面的方案组合, 设计更优秀的图片“提速”方案.
今天不会和大家把所有方案都介绍一遍, 因为网上也有很多实践, 接下来会从前端技术提升的角度, 分享一下如何用原生 javascript, 实现从图片上传到图片自定义压缩的完整方案. 大家可以把文章中介绍的方案直接用于自己的实际开发中, 或者基于它设计更棒的图片压缩方案.
前端实现图片压缩无非就是在用户上传图片文件后, 将file转换成image对象, 然后再利用canvas 及其 api 将图片压缩成指定体积. 如下流程:
首先我们先实现将file转换成image对象, 这里我们用到了FileReader API, 代码如下:
// 压缩前将file转换成img对象
function readImg(file:File) {
return new Promise((resolve, reject)=> {
const img=new Image()
const reader=new FileReader()
reader.onload=function(e:any) {
img.src=e.target.result
}
reader.onerror=function(e) {
reject(e)
}
reader.readAsDataURL(file)
img.onload=function() {
resolve(img)
}
img.onerror=function(e) {
reject(e)
}
})
}
这里使用 promise 来设计生成图片数据的方法, 接下来我们看看核心的图片压缩源码:
/**
* 压缩图片
* @param img 被压缩的img对象
* @param type 压缩后转换的文件类型
* @param mx 触发压缩的图片最大宽度限制
* @param mh 触发压缩的图片最大高度限制
* @param quality 图片质量
*/
function compressImg(img: any, type:string, mx: number, mh: number, quality:number=1) {
return new Promise((resolve, reject)=> {
const canvas=document.createElement('canvas')
const context=canvas.getContext('2d')
const { width: originWidth, height: originHeight }=img
// 最大尺寸限制
const maxWidth=mx
const maxHeight=mh
// 目标尺寸
let targetWidth=originWidth
let targetHeight=originHeight
if (originWidth > maxWidth || originHeight > maxHeight) {
if (originWidth / originHeight > 1) {
// 宽图片
targetWidth=maxWidth
targetHeight=Math.round(maxWidth * (originHeight / originWidth))
} else {
// 高图片
targetHeight=maxHeight
targetWidth=Math.round(maxHeight * (originWidth / originHeight))
}
}
canvas.width=targetWidth
canvas.height=targetHeight
context?.clearRect(0, 0, targetWidth, targetHeight)
// 图片绘制
context?.drawImage(img, 0, 0, targetWidth, targetHeight)
canvas.toBlob(function(blob) {
resolve(blob)
}, type || 'image/png', quality)
})
}
这里通过控制 canvas的宽高, 以及对 canvas 的 toBlob设置参数, 来实现自定义的图片压缩.
如果大家对代码有不理解的地方, 也可以在文末发表问题, 我会做出对应的解答.
的选择是做或不做,但不做就永远不会有机会。
监听剪切板粘贴事件,读取剪切板中的图片文件,转成base64通过img标签显示出来,此时可能会存在剪切板中图片过大,产生上传速度慢问题,接下来就跟大家分享下如何将base64图片进行压缩。先跟大家展示下最终实现的效果:
本篇文章主要讲解剪切板图片压缩的实现,效果图中如何将剪切板的图片插入可编辑div以及如何发送,请移步我的另一篇文章:Vue解析剪切板图片并实现发送功能
const that=this;
document.body.addEventListener('paste', function (event) {
that.$fullScreenLoading.show("读取图片中");
// 获取当前输入框内的文字
const oldText=that.$refs.msgInputContainer.textContent;
// 读取图片
let items=event.clipboardData && event.clipboardData.items;
let file=null;
if (items && items.length) {
// 检索剪切板items
for (let i=0; i < items.length; i++) {
if (items[i].type.indexOf('image') !==-1) {
file=items[i].getAsFile();
break;
}
}
}
// 预览图片
const reader=new FileReader();
reader.onload=function(event) {
// 图片内容
const imgContent=event.target.result;
// 创建img标签
let img=document.createElement('img');//创建一个img
// 获取当前base64图片信息,计算当前图片宽高以及压缩比例
let imgObj=new Image();
let imgWidth="";
let imgHeight="";
let scale=1;
imgObj.src=imgContent;
imgObj.onload=function() {
// 计算img宽高
if(this.width<400){
imgWidth=this.width;
imgHeight=this.height;
}else{
// 输入框图片显示缩小10倍
imgWidth=this.width/10;
imgHeight=this.height/10;
// 图片宽度大于1920,图片压缩5倍
if(this.width>1920){
// 真实比例缩小5倍
scale=5;
}
}
// 设置可编辑div中图片宽高
img.width=imgWidth;
img.height=imgHeight;
// 压缩图片,渲染页面
that.compressPic(imgContent,scale,function (newBlob,newBase) {
// 删除可编辑div中的图片名称
that.$refs.msgInputContainer.textContent=oldText;
img.src=newBase; //设置链接
// 图片渲染
that.$refs.msgInputContainer.append(img);
that.$fullScreenLoading.hide();
});
};
};
reader.readAsDataURL(file);
});
// 参数: base64地址,压缩比例,回调函数(返回压缩后图片的blob和base64)
compressPic:function(base64, scale, callback){
const that=this;
let _img=new Image();
_img.src=base64;
_img.onload=function() {
let _canvas=document.createElement("canvas");
let w=this.width / scale;
let h=this.height / scale;
_canvas.setAttribute("width", w);
_canvas.setAttribute("height", h);
_canvas.getContext("2d").drawImage(this, 0, 0, w, h);
let base64=_canvas.toDataURL("image/jpeg");
// 当canvas对象的原型中没有toBlob方法的时候,手动添加该方法
if (!HTMLCanvasElement.prototype.toBlob) {
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
value: function (callback, type, quality) {
let binStr=atob(this.toDataURL(type, quality).split(',')[1]),
len=binStr.length,
arr=new Uint8Array(len);
for (let i=0; i < len; i++) {
arr[i]=binStr.charCodeAt(i);
}
callback(new Blob([arr], {type: type || 'image/png'}));
}
});
}else{
_canvas.toBlob(function(blob) {
if(blob.size > 1024*1024){
that.compressPic(base64, scale, callback);
}else{
callback(blob, base64);
}
}, "image/jpeg");
}
}
}
github: https://github.com/likaia/chat-system/blob/master/src/components/message-display.vue
作者:神奇的程序员K
转发链接:https://mp.weixin.qq.com/s/hADXM37cactAGFf2vduQJw
实现 HTML 压缩,可以使用 JavaScript 中的正则表达式来去除 HTML 中的空格和注释。以下是一个简单的 HTML 压缩函数:
function compressHTML(html) {
// 去除注释
html=html.replace(/<!--[\s\S]*?-->/g, "");
// 去除多余空白
html=html.replace(/\s+/g, " ");
// 去除标签之间空格
html=html.replace(/>\s+</g, "><");
return html.trim();
}
该函数首先使用正则表达式去除 HTML 中的注释。然后,它使用另一个正则表达式去除 HTML 中的多余空格。最后,它使用另一个正则表达式去除标签之间的空格。
为了测试该函数,您可以创建一个 HTML 文件,并在其中添加一些冗余的空格和注释。例如:
<!DOCTYPE html>
<html>
<head>
<title>My Website</title>
</head>
<body>
<!-- This is a comment -->
<h1> Welcome to my website! </h1>
<p> This is some text. </p>
</body>
</html>
然后,您可以在Node.JS中使用以下代码将 HTML 文件加载为字符串并压缩它:
// 加载 HTML 文件
const fs=require("fs");
const html=fs.readFileSync("index.html", "utf8");
// 压缩 HTML
const compressedHtml=compressHTML(html);
console.log(compressedHtml);
输出是一个压缩后的 HTML 字符串,其中不包含注释或冗余空格。
或者直接在IE中测试,代码如下:
function compressHTML(html) {
// 去除注释
html=html.replace(/<!--[\s\S]*?-->/g, "");
// 去除多余空白
html=html.replace(/\s+/g, " ");
// 去除标签之间空格
html=html.replace(/>\s+</g, "><");
return html.trim();
}
var html=`
<!DOCTYPE html>
<html>
<head>
<title>My Website</title>
</head>
<body>
<!-- This is a comment -->
<h1> Welcome to my website! </h1>
<p> This is some text. </p>
</body>
</html>
`;
console.log(compressHTML(html));
运行效果:
*请认真填写需求信息,我们会在24小时内与您取得联系。