h5: canvas操作图片并上传
canvas.drawImage()
作用:将图片绘制到canvas对象上,具体使用请参考 MDN文档
用法:
void ctx.drawImage(image, dx, dy); // 不缩放
void ctx.drawImage(image, dx, dy, dWidth, dHeight); // 设置缩放
void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); // 对源图片进行裁剪
canavs.toDataURL()
作用:canavs.toDataURL() 方法返回一个包含图片展示的 data URI 。可以使用 type 参数其类型,默认为 PNG 格式。图片的分辨率为96dpi。MDN文档
- 如果画布的高度或宽度是0,那么会返回字符串“data:,”。
- 如果传入的类型非“image/png”,但是返回的值以“data:image/png”开头,那么该传入的类型是不支持的。
- Chrome支持“image/webp”类型。
用法:
canvas.toDataURL(type, encoderOptions);
// 这个方法有意思的是参数encoderOptions。在指定图片格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,将会使用默认值 0.92。其他参数会被忽略。
朋友们一定要注意了,encoderOptions 千万不能设置为1,除非你对图片的质量要求真的非常高,不然得到的数据会非常大。这里我使用一个大小为88k的图片做了一个测试:
- 1.0 181k
- 0.9 57k
- 0.8 37k
- 0.7 30k
- 0.6 25k
图片内容绘制到canvas上
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,minimal-ui"><title></title><link rel="stylesheet" href="">
</head>
<body><img src="https://s1-1251010403.cosgz.myqcloud.com/20181227/images/wxacode_92d928a3eb8eb2b19e17ad16d86ab2bd.png">
</body>
<script>var body = document.body;
var img = document.querySelector('img');
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');canvas.width = 400;
canvas.height = 300;img.onload = function () {context.drawImage(img, 0, 0, 400, 300);console.log(canvas);body.appendChild(canvas);
}// 这里需要注意的是当图片没有触发 onload 时, canvas将会读取不到内容
</script>
</html>
上面的代码完成了将图片绘制到 canvas 上的功能。主要依赖于 HTML5 canvas drawImage()
方法。
canvas对象转为 dataURL
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,minimal-ui"><title></title><link rel="stylesheet" href="">
</head>
<body><img src="wxacode_92d928a3eb8eb2b19e17ad16d86ab2bd.png">
</body>
<script>var body = document.body;
var img = document.querySelector('img');
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');img.onload = function () {canvas.width = img.width;canvas.height = img.height;context.drawImage(img, 0, 0, canvas.width, canvas.height);var dataURL = canvas.toDataURL('image/jpeg');var nimg = new Image();nimg.src = dataURL;body.appendChild(nimg);
}
</script>
</html>
在这里我遇到了一个问题,canvas 绘制出来的图片背景颜色变成了黑色:
变成了
这是为什么呢?表面上是因为我将png格式图片转换为jpeg格式的dataURL,其本质原因我尚不知晓。
压缩图片大小
压缩方式有两个方向:
- 通过减少图片的尺寸,而减小图片所占的存储空间
- canvas.drawImage 设置 转换系数
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title><style>* {padding: 0;margin: 0;}</style>
</head><body><img class="bg" src="./01.jpg" onload="onImgLoad(this)">
</body>
<script>/*** 原图 750 * 380 88k* 处理后 375 * 190 22k* 由于图片的尺寸变小了,图片所占的存储空间也变小了*/ function onImgLoad (img) {var canvas = document.createElement('canvas');var context = canvas.getContext('2d');var width = img.widthvar height = img.heightcanvas.width = width / 2 // 宽度减半canvas.height = height / 2 // 高度减半context.drawImage(img, 0, 0, canvas.width, canvas.height);var dataURL = canvas.toDataURL('image/jpeg')var img = new Image()img.src = dataURLdocument.body.appendChild(img)}
</script>
</html>
上传图片到服务器
可以将 dataURL 数据转换为 File 文件格式进行异步上传。其中涉及到两个比较关键的技术。
(1)dataURLtoFile 实现
/*** base64 to File* @param {*} dataURL* @param {*} filename*/
export const dataURLtoFile = (dataurl, filename) => {var arr = dataurl.split(',');var mime = arr[0].match(/:(.*?);/)[1];var bstr = atob(arr[1]);var n = bstr.length;var u8arr = new Uint8Array(n);while (n--) {u8arr[n] = bstr.charCodeAt(n);}return new File([u8arr], filename, { type: mime });
};
(2)使用 FormData ajax 进行异步上传
const filename = `${uuid}_${stamp}.png`;
const file = dataURLtoFile(base64, filename);
const formData = new FormData();formData.append('filecontent', file);
formData.append('op', 'upload');
底层原理是使用 POST 请求,可以直接将 FormData 实例作为请求body:
xmlHttpInstanceRequest.send(formData);
如果您是使用第三方ajax库,比如axios,$.ajax 等。只需将 data参数 设置 为 formData 即可。
常见问题及错误
- 图片跨域问题:可以使用nginx设置一层代理(设置 CORS),或者代理到自己的服务器返回 base64 格式的数据。
- 背景色变为黑色:查看图片的格式是否正确。
- canvas生成的图片有白色的边框:查看canvas的尺寸大小是否和图片的大小一致,注意已定要等图片加载完成(onload 触发以后)之后再使用。
后续更新(2019-01-15): 服务器将第三方图片转换为base64时,遇到了严重的性能问题(后端PHP),故这个方法不可取。
后续更新(2019-01-16):通过查阅资料,图片转base64其实并不是那么消耗性能,导致性能的原因很可能是PHP在下载图片时使用 file_get_content 这个函数,它是没有缓存的。换成 curl 后就好了。
本文总结
以上就是使用canvas绘图并上传到服务器的所有关键点,若有错误支持,恳请指出;若有疑问之处,留言我会尽快回复。
转载于:https://www.cnblogs.com/gaollard/p/10186581.html
h5: canvas操作图片并上传相关推荐
- 微信公众号h5网站,图片裁剪上传成功案例分享
1.裁剪插件 cropper 2.微信公众号内,微信sdk cropper挺简单的,如下: <VueCropper ref="cropper" ...
- android h5 多图上传源码,JS移动端/H5同时选择多张图片上传并使用canvas压缩图片...
最近在做一个H5的项目,里边涉及到拍照上传图片的功能以及识别图片的功能,这里对识别图片的功能不做赘述,不属本文范畴.我在做完并上线项目后,同事跟我提了一个要求是可不可以同时选择多张图片上传,我做的时候 ...
- cropper.js 实现裁剪图片并上传(PC端)
博客地址:http://blog.mambaxin.com 由于之前做项目的时候有需求是需要实现裁剪图片来做头像并上传到服务器,所以上网查询了很多资料,也试用了许多案例,发现cropper插件裁剪是比 ...
- 前端图片压缩上传(纯js的质量压缩,非长宽压缩)
前端图片压缩上传(纯js的质量压缩,非长宽压缩) 此demo为大于1M对图片进行压缩上传 若小于1M则原图上传,可以根据自己实际需求更改. demo源码如下: <!DOCTYPE html> ...
- js 导出pdf上传至oss_前端上传图片到oss,压缩图片后上传至oss(补充图片文件旋转90度问题)...
上传图片如果过大,等待时间过长体验不好,于是使用js压缩图片再上传,无关图片清晰度. /** * 压缩图片 * @param file 图片文件 * @param callback 回调函数,压缩完要 ...
- web 前端图片优化之--图片压缩上传
移动前端-图片压缩上传实践 此前有同事跟我聊过关于移动端用canvas压缩图片后再上传的功能,最近有了点空闲时间,所以就实践了一下.demo效果链接在文章底部贴出. 在做移动端图片上传的时候,用户传 ...
- jquery实现截取pc图片_Cropper.js 实现裁剪图片并上传(PC端)
由于之前做项目的时候有需求是需要实现裁剪图片来做头像并上传到服务器,所以上网查询了很多资料,也试用了许多案例,发现cropper插件裁剪是比较完善的,所以结合之前的使用情况,编写了此案例.本案例是参考 ...
- JS前端图片压缩上传
JS前端图片压缩上传重点知识 最近在做一个手机端的图片上传,写了一个比较符合自己要求的方法,可供参考 在做这个功能模块时,我遇到了以下问题,都花费了大量时间: 1. 不知道怎么压缩图片,(代码和方法) ...
- uni-app实现图片的上传和裁剪
uni-app实现图片的上传和裁剪 uni-app 实现图片的上传和裁剪,插件市场上已经有作者提供了相关的插件.这里主要介绍下我在自己开发图片上传和裁剪过程中遇到的一些问题. 图片上传 图片上传功能比 ...
最新文章
- SDN控制器ONOS架构—Vecloud
- oracle数据库第八章答案,Oracle培训(三十)——Oracle 11g 第八章知识点小结——处理数据...
- 谷歌机器学习规则:机器学习工程的43条最佳实践经验
- Jquery 全选,反选
- poj 1250 解题(链表法)
- 释放变量所指向的内存_前端基础突破(二)内存回收与内存泄漏
- python判断数据是否在另一个集合中_python判断一个集合是否包含了另外一个集合中所有项的方法...
- java字符串替换的问题
- QCC3040---earbudUi module
- OA流程归档后,没有推送消息通知这样处理
- UI兼容性测试——一机多控之百度Hydra工具在移动端UI兼容性测试上的高效应用
- mysql skewed_Hive分区字段含中文报错问题解决方案
- 翡翠手链的起源和发展历史
- FTP服务器的搭建与连接
- 使用Dir函数遍历文件和目录
- linux内核 checksum,Linux内核分析 - 网络[十三]:校验和
- 靶机测试 Me and My Girlfriend1笔记
- 百度音乐2013 8.2.8 去广告VIP绿色版|zd423作品
- java 线程机制_Java线程机制学习
- JavaScript API方法