JS获取剪贴板图片之后的格式选择与压缩问题
前言
某年某月的某一天,突然发现博客服务器上上传的图片都比较大,一些很小的截图都有几百kb,本来服务器带宽就慢,不优化一下说不过去。
问题细述
特别说明:本文代码因为只是用于我自己后台写markdown上传图片,运行环境只考虑PC,所以没有考虑任何兼容性,推荐Chrome下使用。
以下面一张图片为例:

原始图片为85kb,jpg格式的,上传之后就变成png格式了,而且变成了560kb!实在是说不过去!
我的代码大致如下:
// $('.editor')为markdown编辑区
$('.editor').bind('paste', function(event)
{
var e = event.originalEvent;
var items = e.clipboardData.items;
for(var i = 0; i < items.length; ++i)
{
// 如果剪贴板中的内容类型是图片文件
if (items[i].kind == 'file' && items[i].type.indexOf('image/') >= 0)
{
e.preventDefault();
var blob = items[i].getAsFile();
ajaxUpload(blob); // 拿到blob之后直接上传,这里省略上传代码
};
};
});
我原本以为图片原始是多大,上传之后就应该是多大的,因为是“复制粘贴”嘛,可见实际情况并非如此,问题出在哪个环节呢?
我将相同图片采用复制粘贴的方式粘贴到word里面去,然后另存为html格式,发现保存下来的图片更大了,有将近900kb。
虽然如此,直到现在依然不能确定,图片的转换是在当我们打开图片按下Ctrl+C放到剪贴板的时候就已经执行了,还是在js中items[i].getAsFile()中转换了,有知道的朋友欢迎指正。
问题解决
既然图片变大了,那就压缩嘛,压缩一般习惯在前端进行,这样可以降低上传带宽。
处理过程:先从剪贴板获取图片,拿到的是blob对象,然后转换成base64格式的dataURL,再然后以Image形式画到canvas上,再把canvas转换成dataURL,这个转换的过程可以设置质量,最后再将dataURL转换成blob,然后上传。
直接上代码:
/**
* 改变blob图片的质量,为考虑兼容性
* @param blob 图片对象
* @param callback 转换成功回调,接收一个新的blob对象作为参数
* @param format 目标格式,mime格式
* @param quality 介于0-1之间的数字,用于控制输出图片质量,仅当格式为jpg和webp时才支持质量,png时quality参数无效
*/
function changeBlobImageQuality(blob, callback, format, quality)
{
format = format || 'image/jpeg';
quality = quality || 0.9; // 经测试0.9最合适
var fr = new FileReader();
fr.onload = function(e)
{
var dataURL = e.target.result;
var img = new Image();
img.onload = function()
{
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
var newDataURL = canvas.toDataURL(format, quality);
if(callback) callback(dataURLtoBlob(newDataURL));
canvas = null;
};
img.src = dataURL;
};
fr.readAsDataURL(blob); // blob 转 dataURL
function dataURLtoBlob(dataurl)
{
var arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
len = bstr.length,
u8arr = new Uint8Array(len);
while (len--) u8arr[len] = bstr.charCodeAt(len);
return new Blob([u8arr], {type: mime});
}
}
修改之后的上传代码就是这样了:
if (items[i].kind == 'file' && items[i].type.indexOf('image/') >= 0)
{
e.preventDefault();
var blob = items[i].getAsFile();
changeBlobImageQuality(blob, function(newBlob)
{
ajaxUpload(newBlob); // 拿到blob之后直接上传,这里省略上传代码
});
};
关于dataURL转blob,有一个考虑的兼容性的代码片段如下:
function convertDataURLToBlob(dataURL)
{
var arr = dataURL.split(',');
var code = window.atob(arr[1]);
var aBuffer = new window.ArrayBuffer(code.length);
var uBuffer = new window.Uint8Array(aBuffer);
for(var i = 0; i < code.length; i++)
{
uBuffer[i] = code.charCodeAt(i);
}
var Builder = window.WebKitBlobBuilder || window.MozBlobBuilder;
if(Builder)
{
var builder = new Builder;
builder.append(buffer);
return builder.getBlob(format);
}
else
{
return new window.Blob([ buffer ], {type: arr[0].match(/:(.*?);/)[1]});
}
}
问题还没完全解决
有一个问题,对于GIF格式的图片,复制粘贴之后只会复制第一帧(不知高手是否有解决方案)。
还有一个问题,虽然我要解决的问题是图片上传之后变大,但是有时候本地本来就是一张压缩的比较厉害的jpg格式图片,上传之后虽然通过调整质量可以控制大小,但是有时候经过前端这么一折腾,体积虽然变化不大,但是图片质量下降的很厉害,特别是对于截图又添加文字的图片,比如下面这个:
这是png格式效果,上传之后28kb:

这是jpg效果,上传之后37kb,反而比png格式还要大,而且质量大打折扣:

发现貌似是在上传一些底色为纯色的图片时,png比jpg更好,在上传传统的类似风景图片时,jpg格式更好,不知道说的有没有错。
还有很多时候我是希望图片没有任何转换,直接原样上传,所以简单增加了个拖拽上传的功能,直接把事件绑定在body上面:
function initDrag()
{
var obj = $('body')[0];
obj.ondragenter = function(ev)
{
ev.dataTransfer.dropEffect = 'copy';
};
obj.ondragover = function(ev)
{
ev.preventDefault(); //防止默认事件拖入图片 放开的时候打开图片了
ev.dataTransfer.dropEffect = 'copy';
};
obj.ondrop = function(ev)
{
ev.preventDefault();
var files = ev.dataTransfer.files;
for(var i=0; i<files.length; i++)
{
if(files[i].type.indexOf('image') >= 0)
{
ajaxUpload(files[i]);
}
}
};
}
这样我就可以根据实际需要选择不同方式上传图片了:
- 普通的白底黑字截图的话就上传png格式;
- 普通复杂背景图片就上传jpg格式;
- 一些gif格式还有一些本来就比较小的图片,就采用拖拽上传的方式;
JS获取剪贴板图片之后的格式选择与压缩问题的更多相关文章
- 为什么不能用 JS 获取剪贴板上的内容?
为什么不能用 JS 获取剪贴板上的内容? 为什么不能用 JS 获取剪贴板上的内容? 发一串口令给朋友朋友复制这串口令,然后访问你的网站你在网站上用 JS 读取朋友剪贴板上的口令根据不同的口令,显示不同 ...
- js获取当地时间并且拼接时间格式的三种方式
js获取当地时间并且拼接时间格式,在stackoverflow上有人在问,查了资料,各种方法将时间格式改成任意自己想要的样式. 1. var date = new Date(+new Date()+8 ...
- js获取当前时间,并格式化为"yyyy-MM-dd HH:mm:ss"
/** * Created by Administrator on 2019/11/15. *指尖敲打着世界 ----一个阳光而又不失帅气的少年!!!. */ // js获取当前时间,并格式化为&qu ...
- JS获取IMG图片高宽
前段时间在LJW写的touchslider.js轮播代码里添加自适应屏幕大小的功能时,遇到一个问题.不管用什么样的方法都无法获取到IMG标签的高宽,最后只有给图片定一个高宽的比例值:趁今天有空我就写了 ...
- CEF JS实现获取剪贴板图片的DataURL
转载:https://www.deanhan.cn/js-paste-upload.html 转载:https://segmentfault.com/a/1190000002915597 转载:htt ...
- js 获取div 图片高度
使用jquery获取网页中图片的高度其实很简单,有两种常用的方法都可以打到我们的目的 $("img").whith();(返回纯数字) $("img").css ...
- 使用Javascript获取剪贴板图片的DataURL
最近写博客需要插入一些截图,想着用DataURL会方便点,于是需要一个把图片转成DataURL的工具.搜索一番后发现这个功能用HTML就能实现,通过paste事件. 先尝试在Chrome上实现,Chr ...
- js获取当前的日期时间 格式“yyyy-MM-dd HH:MM:SS”
function getNowFormatDate() { var date = new Date(); var seperator1 = "-"; var seperator2 ...
- js获取当前日期方法(YYYY-MM-DD格式)
var myDate = new Date(); var time = myDate.toLocaleDateString().split('/').join('-');将1970/08/08转化 ...
随机推荐
- Codeforces Round #382 Div. 2【数论】
C. Tennis Championship(递推,斐波那契) 题意:n个人比赛,淘汰制,要求进行比赛双方的胜场数之差小于等于1.问冠军最多能打多少场比赛.题解:因为n太大,感觉是个构造.写写小数据, ...
- LD算法获取字符串相似度
一个如何识别相似语句的问题,于是上网找了找,一个叫Levenshtein Distance的算法比较简单,就写了段代码实现了一下,效果还不错. 这个算法是一个俄国人Lvenshtein提出的,用于计算 ...
- mysql 字符串 日期互转
一.字符串转日期 下面将讲述如何在MySQL中把一个字符串转换成日期: 背景:rq字段信息为:20100901 1.无需转换的: SELECT * FROM tairlist_day WHERE rq ...
- 域名解析服务查询工具dnstracer
域名解析服务查询工具dnstracer 在访问网站过程中,当用户输入网址后,通常是先解析域名,获取该网站的IP地址.然后,根据IP地址访问对应的网站服务器.所以,域名解析服务器保证域名指向正确的网 ...
- iOS 图片文件格式判断、圆角图片
1.圆角图片 // 设置圆形图片(放到分类中使用) - (UIImage *)cutCircleImage { UIGraphicsBeginImageContextWithOptions(self. ...
- BZOJ2763 [JLOI2011]飞行路线(SPFA + DP)
题目 Source http://www.lydsy.com/JudgeOnline/problem.php?id=2763 Description Alice和Bob现在要乘飞机旅行,他们选择了一家 ...
- matlab 求解线性方程组之LU分解
线性代数中的一个核心思想就是矩阵分解,既将一个复杂的矩阵分解为更简单的矩阵的乘积.常见的有如下分解: LU分解:A=LU,A是m×n矩阵,L是m×m下三角矩阵,U是m×n阶梯形矩阵 QR分解: 秩分解 ...
- [译]App Framework 2.1 (2)之 About
英文原文在此:http://app-framework-software.intel.com/documentation.php#App Framework/af_about App Framewor ...
- VS2015 调试时 编辑并继续不可用
最近在项目中遇到一次调试时 编辑并继续不可用.结合网上说的工具->设置->调试->常规下的一些操作,到后来还是不可用,最后把项目的解决方案平台改成Mixed Platform ,之后 ...
- centos7 解决ftp和apache运行目录权限冲突问题
1.将ftp用户加入到apache用户组 usermod -a -G apache ftpadmin ftpadmin 为ftp用户 2.设置网站根目录/var/www的所有组为apache chow ...