场景:
实现选择一张图片后,进行转换格式然后压缩裁剪上传
问题描述
网页中实现选择上传头像时,需将图片转换为jpg格式,并且符合图片大小为500k
代码如下:
<template>
<el-upload
ref="avatarUpload"
action
:show-file-list="false"
:on-change="fileChange"
:auto-upload="false"
:multiple="false"
accept=""
>
<el-button type="primary">上传</el-button>
</el-upload>
<el-dialog
title="图片裁剪"
ref="dialog"
width="35%"
:visible.sync="dialogVisible"
:close-on-click-modal="false"
>
<div class="cropper-w">
<div class="cropper" :style="{ width: '100%', height: '280px' }">
<vueCropper
ref="cropper"
:img="option.img"
:outputSize="option.size"
:outputType="option.outputType"
:info="option.info"
:full="option.full"
:canMove="option.canMove"
:canMoveBox="option.canMoveBox"
:original="option.original"
:autoCrop="option.autoCrop"
:autoCropWidth="option.autoCropWidth"
:autoCropHeight="option.autoCropHeight"
:fixedBox="option.fixedBox"
:centerBox="option.centerBox"
>
</vueCropper>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"
>{{ $t("common.cancel") }}</el-button
>
<el-button type="primary" @click="handleConfirm"
>{{ $t("common.confirm") }}</el-button
>
</div>
</el-dialog>
</template>
<script>
data(){
return{
option: {
img: "", // 裁剪图片的地址
info: true, // 裁剪框的大小信息
outputSize: 0.8, // 裁剪生成图片的质量
outputType: "jpeg", // 裁剪生成图片的格式
canScale: false, // 图片是否允许滚轮缩放
autoCrop: true, // 是否默认生成截图框
autoCropWidth: 400, // 默认生成截图框宽度
autoCropHeight: 300, // 默认生成截图框高度
fixedBox: false, // 固定截图框大小 不允许改变
fixed: false, // 是否开启截图框宽高固定比例
// fixedNumber: [7, 5], // 截图框的宽高比例
full: true, // 是否输出原图比例的截图
canMoveBox: true, // 截图框能否拖动
original: true, // 上传图片按照原始比例渲染
centerBox: false, // 截图框是否被限制在图片里面
infoTrue: false, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
},
}
},
methods:{
handleConfirm() {
// vue-cropper获取截取后的图片信息,此处data为blob格式
this.$refs.cropper.getCropBlob((data) => {
// URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。
// 这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。
let blob = window.URL.createObjectURL(data);
// // 处理缩放 转格式
var img = new Image();
img.src = blob;
var _that = this;
img.onload = function () {
var that = this;
//生成比例
let w = that.width;
let h = that.height;
let scale = w / h;
h = w / scale;
//生成canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = w;
canvas.height = h;
ctx.drawImage(that, 0, 0, w, h);
// 生成base64
// canvas的toDataURL()方法是返回一个包含图片展示的 数据URL。可以使用 type 参数其类型,默认为 PNG 格式。图片的分辨率为96dpi。 数字越小约不清晰
_that.cropperPic = canvas.toDataURL("image/jpeg", 0.8);
let files = _that.transformToFiles(_that.cropperPic, _that.filename);
_that.dialogVisible = false;
if (files.size / 1024 > 100 && files.size / 1024 < 500) {
_that.yaSuo(files);
} else {
_that.formData.picture = files;
_that.pictureUrl = window.URL.createObjectURL(files);
}
};
});
},
// base64转成files
transformToFiles(dataurl, filename) {
let arr = dataurl.split(",");
let mime = arr[0].match(/:(.*?);/)[1];
let suffix = mime.split("/")[1];
let bstr = atob(arr[1]);
let n = bstr.length;
let u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], `file.${suffix}`, { type: "image/jpeg" });
},
fileChange(file) {
let min = 1024 * 1024 * 0.1;
let max = 1024 * 1024 * 0.5;
let fileSuffixList = ["jpg", "jpeg", "png", "webp", "bmp"];
let fileName = file.name.substring(file.name.lastIndexOf(".") + 1);
var self = this;
if (
fileSuffixList.indexOf(fileName) > -1 ||
fileName.substring(0, 4) == "webp"
) {
let isJpgOrPng = fileName === "jpeg";
if (isJpgOrPng) {
// 文件大于100小于500需要压缩
if (file.size < min && file.size > max) {
this.yaSuo(file);
} else if (file.size > max) {
// 文件大于500 先裁剪在压缩
this.openCropper(file, fileName);
} else {
}
} else {
var imgFile = new FileReader();
try {
imgFile.onload = function (e) {
var image = new Image();
image.src = e.target.result; //base64数据
image.onload = function () {
self.imgToCanvas(image);
};
};
imgFile.readAsDataURL(file.raw);
} catch (e) {
console.log("请上传图片!" + e);
}
}
var reader = new FileReader();
reader.onload = function (e) {
self.formData.picture = e.target.result;
self.pictureUrl = e.target.result;
};
//选择图片文件后即时预览图片
reader.readAsDataURL(file.raw);
} else {
this.$message.warning(
this.$t("common.selectImg") +
"('*.jpg', '*.jpeg', '*.png', '*.webp', '*.bmp')"
);
}
},
async yaSuo(file) {
// 压缩到100KB,这里的100就是要压缩的大小,可自定义
await imageConversion.compressAccurately(file, 100).then((res) => {
// 把blob转换为文件
let a = new File([res], `${file.name}`, { type: res.type });
let blob = new Blob([res], { type: "image/jpeg" });
// this.ada = window.URL.createObjectURL(blob);
this.formData.picture = blob;
this.pictureUrl = window.URL.createObjectURL(blob); // this.pictureUrl =
});
},
// 把image 转换为 canvas对象
imgToCanvas(image) {
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
canvas.getContext("2d").drawImage(image, 0, 0);
this.canvasToImg(canvas);
// return canvas;
},
//canvas转换为image
canvasToImg(canvas) {
//这个src是图片的base64流数据 一定要经过转换以后再转为文件 否则的话传给后端会出错
var src = canvas.toDataURL("image/jpeg");
this.ada = src;
let arr = src.split(",");
let mime = arr[0].match(/:(.*?);/)[1]; //设置file文件流的type名称
let suffix = mime.split("/")[1]; //设置file文件流的name名称
let filename;
// atob 对经过 base-64 编码的字符串进行解码
let bstr = window.atob(arr[1]);
// n 是解码后的长度
let n = bstr.length;
// Uint8Array 数组类型表示一个 8 位无符号整型数组 初始值都是 数子0
let u8arr = new Uint8Array(n);
// charCodeAt() 方法可返回指定位置的字符的 Unicode 编码。这个返回值是 0 - 65535 之间的整数
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
// new File返回File对象 第一个参数是 ArraryBuffer 或 Bolb 或Arrary 第二个参数是文件名
// 第三个参数是 要放到文件中的内容的 MIME 类型
let file = new File([u8arr], `${filename}.${suffix}`, {
type: "image/jpeg",
});
let min = 1024 * 1024 * 0.1;
let max = 1024 * 1024 * 0.5;
if (file.size > min && file.size < max) {
this.yaSuo(file);
} else if (file.size > max) {
this.openCropper(file, "jpeg");
} else {
this.formData.picture = file;
this.pictureUrl = window.URL.createObjectURL(file); // this.pictureUrl = file;
}
// this.yaSuo(file);
// return src;
},
}
</script>