文章目录
- 一、阅读须知
- 二、解决的问题
- 三、知识储备
- 四、解决方案
- 五、核心代码
- 六、参考资料
- 七、FileReader()对象
- 八、Exif库使用
- 九、Canvas画布
- 十、动态创建标签并添加绑定事件
- 十一、utils方法
- 十二、vue中图片预览
- 十三、工具网站
一、阅读须知
小帅爆肝整理的这篇文章,内容比较多,帅帅的你值得看一看,有解决方案的核心代码,放到项目中可以直接使用
最近还会更新关于“图片横向合并、纵向合并、图片编辑”的另一篇文章,敬请期待!
二、解决的问题
- 使用canvas处理图片旋转、导入问题
- 目前来看,在前端对图片文件进行处理,再传到服务端,性能上是可以的,不必要图片处理逻辑在服务端实现
三、知识储备
- 使用
<input type="file">
标签得到的File文件格式对象如下
- 图片Base64编码的格式(可以直接使用
<img>
<el-image>
标签进行渲染)
四、解决方案
如果使用canvas实现对图片的旋转目前有两种方案
- 利用canvas的
translate()平移函数
+rotate()旋转函数
+drawImage()函数
实现,这种方式存在更复杂的数学计算问题 - 利用canvas的
rotate()旋转函数
+drawImage()函数
实现(本篇使用的解决方案),下文提供代码案例
五、核心代码
- 解决方案2对应的核心代码,解决将图片顺时针旋转90°、180°、270°问题
- 如下代码
drawImage()
函数中的img
参数为new Image()对象,或者其它符合函数要求的参数类型
// 创建canvas
const selfCanvas = document.createElement('canvas')
const selfCtx = selfCanvas.getContext('2d')
if (angle == '90') { // 顺时针旋转90度
selfCanvas.width = img.height
selfCanvas.height = img.width
selfCtx.rotate(90 * Math.PI / 180);
selfCtx.drawImage(img, 0, 0, img.width, -img.height)
} else if (angle == '180') { // 顺时针旋转180度
selfCanvas.width = img.width
selfCanvas.height = img.height
selfCtx.rotate(180 * Math.PI / 180)
selfCtx.drawImage(img, -img.width, -img.height, img.width, img.height)
} else if (angle == '270') { // 顺时针旋转270度
selfCanvas.width = img.height
selfCanvas.height = img.width
selfCtx.rotate(270 * Math.PI / 180)
selfCtx.drawImage(img, -img.width, 0, img.width, img.height)
} else { // 不进行任何旋转
selfCanvas.width = img.width
selfCanvas.height = img.height
selfCtx.drawImage(img, 0, 0, img.width, img.height)
}
六、参考资料
- 得到图片文件File的URL
img.src = URL.createObjectURL(imgFile)
- 相关api函数方法
- createObjectURL(obj):返回一个URL 对象表示指定的 File 对象(生成blob:http://www.xxxx.com/xx的链接,可以直接在网页上打开File内容)或 Blob 对象(用于下载),obj为 File 对象、Blob 对象或者 MediaSource 对象
- revokeObjectURL(objURL):在每次调用 createObjectURL() 方法时,都会创建一个新的 URL 对象,即使你已经用相同的对象作为参数创建过。当不再需要这些 URL 对象时,每个对象必须通过调用 URL.revokeObjectURL() 方法来释放,objURL为URL.createObjectURL(obj) 返回的对象
- arr = new Uint8Array(length):返回一个长度为length的8位无符号整型数组(存储大小为0~256,负数会自动加256转为整数,超出-256),创建时内容被初始化为0
- new Blob(arr,options):返回一个blob对象(可理解为二进制的数据对象),常用用于文件下载
- canvas.toBlob(callback, type, quality):创造 Blob 对象,用以展示 canvas 上的图片;这个图片文件可以被缓存或保存到本地,具体参数:
- allback:回调函数,可获得一个单独的 Blob 对象参数。如果图像未被成功创建,可能会获得 null 值
- type:指定图片格式,默认格式(未指定或不支持)为 image/png
- quality:值在 0 与 1 之间,当请求图片格式为 image/jpeg 或者 image/webp 时用来指定图片展示质量。如果这个参数的值不在指定类型与范围之内
- 在h5中,使用input的type="file"和capture="camera"这两个属性就可以调用摄像头
- 如果使用document.createElement()动态创建的元素,通过如下的方法得到输入的值
// 创建一个input元素
var inputElem = document.createElement("input");
// 获取input的值
var inputValue = inputElem.value;
// 如果input标签type="file"
// 得到文件对象File
var file = inputElem.files
- 如果input标签不是动态创建的,是已经写好的html元素,则可以在change=“methodsName(e)”,通过
e.target.files
获得文件对象 - Vue中可以使用如下方式添加、移除事件
// 绑定事件 可以进行监听
addEventListener()
// 移除事件
removeEventListener()
- 关于
<input>
标签中的webkitdirectory属性参考:https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLInputElement/webkitdirectory
- 使用FormData对象上传文件
const formData = new FormData()
formData.append('file', File)
七、FileReader()对象
- FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。
- FileReader实例拥有4个方法,3个用来读取文件,一个用来中断读取
- abort 参数none 中断读取
- readAsBinaryString 参数file 将文件读取为二进制码
- readAsDataUrl 参数file 将文件读取为data:开头的字符串,实质就是Data URL 是将小文件(图像等)直接嵌入文档的方案,base64的方式由此来获得
- readAsText file,[encoding] 文本方式读取文件,读取结果是文本的内容
- 读取结果会存储在FileReader的result属性中,处理事件简介:
- onabort 中断时触发
- onerror 出错时触发
- onload 读取成功时触发
- onloadend 读取完成时触发 无论成功失败
- onloadstart 读取开始时触发
- onprogress 读取中
- 文件开始读取后无论成功失败都会填充result属性,读取失败result属性会赋值null,否则会填充读取结果
- onload读取成功之后,直接将base64赋值给img元素的src属性,就可以预览图片了
- 使用FileReader对象将File转成base64代码案例
// 图片file转base64方法(file文件,回调函数)
fileToBase64(file, callback) {
// 创建FileReader对象(不兼容IE)
let reader = new FileReader();
// 将file转为base64 (异步操作)
reader.readAsDataURL(file);
// 转换成功
reader.onload = () => {
const response = {
status: true,
data: reader.result
}
callback(response);
};
// 转换失败
reader.onerror = function () {
const response = {
status: false,
data: reader.error
}
callback(response);
};
}
// 调用方法
fileToBase64(imgFile, (res) => {
if(res.status) {
console.log('file转化成base64成功---',res.data)
} else {
console.log('file转化base64失败---',res.data)
}
})
八、Exif库使用
- 用Exif获取图像的原始数据,例如:拍照方向,拍摄事件,ISO感光度,GPS地理位置等数据
- vue中引入exif-js
npm install exif-js --save
- Exif提供的部分API方法
- Exif.getData(img,callback) 获取图像数据
- Exif.getTag(img,tag) 获取图像的某个数据
- Exif.getAllTags(img) 获取图像的全部数据
- Exif.pretty(img) 获取图像的全部数据,值以字符串的形式范围
- 其中Exif中
orientation
不同的值代表不同的方向
- Exif的npm仓库地址:
https://www.npmjs.com/package/exif-js
- Exif的GitHub地址:
https://github.com/exif-js/exif-js
上述两个地址里面有使用参考文档 - 前端开发工具箱:
http://code.ciaoca.com/
九、Canvas画布
- canvas是一个容器(画布),他的getContext()方法用来获取一个对象,这个对象提供了在画布上绘图的方法和属性
- 菜鸟教程中关于canvas资料:
https://www.runoob.com/tags/ref-canvas.html
- w3school中的canvas资料:
https://www.w3school.com.cn/jsref/dom_obj_canvas.asp
- 资料网站:
https://www.twle.cn/l/yufei/canvas/canvas-basic-index.html
十、动态创建标签并添加绑定事件
var input = document.createElement('input');
input.setAttribute('value', '');
input.setAttribute('type', 'text');
input.setAttribute('class', 'my-custom-input');
document.body.appendChild(input);
//Change event listener
input.addEventListener('change', function(e) {
console.log('I just changed');
}, false);
十一、utils方法
- 从base64代码中获取图片的宽高
var i = new Image(); //创建一个临时存储
i.onload = function(){ //定义加载图片后弹出显示
alert( i.width+", "+i.height );
};
i.src = imageData //将图片数据赋值即可
- base64转文件
dataURLtoFile(dataurl) {
var arr = dataurl.split(',')
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], 'image', {
type: 'image'
})
}
十二、vue中图片预览
- 使用远程的
<img>
标签 - 使用element-ui的
<el-image>
标签 - 使用element-ui的
<el-image-viewer>
<el-image-viewer v-if="imgViewerVisible" :on-close="closeImgViewer" :url-list="imgList" />
- 使用v-viewer库
十三、工具网站
- base64转图片:
http://www.atoolbox.net/Tool.php?Id=1024
- vue图片裁剪插件(vue-picture-cut 2.x):
https://gitee.com/light-year/vue-picture-cut