解决问题:1、图片上传成功后,由于图片过大,页面上没有及时显示;2、压缩图片后添加水印随着图片一起降低品质了
本文实现:以上问题均在本文中解决。1、使用canvas进行压缩后再进行上传,可以自行调整encoderOptions(图片品质)和压缩后图片的宽高来控制图片的清晰度和图片显示的速度;2、给压缩后的图片添加水印
本文压缩文件功能代码出自迷途小码农零零发
uniapp页面调用代码
import imgCompress from "shared/utils/imgCompress"
choseImage () {
const WaterMarkContent = {
font: "24px 宋体",
fillStyle: "white",
textAlign: 'right',
fillText: [
{
text: `水印1`
}
]
}
uni.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success: chooseImageRes => {
const token = uni.getStorageSync('token')
const url = `${apiUrl.api.protocol}://${apiUrl.api.host}:${apiUrl.api.port === '' ? '' : apiUrl.api.port === '80' ? '' : apiUrl.api.port}`
const method = api.upload
const formData = new ActionAxios(method, JSON.stringify({})).setData()
uni.showLoading({title: '正在上传头像'})
imgCompress(chooseImageRes.tempFiles[0], WaterMarkContent).then(res => {
uni.uploadFile({
url,
filePath: res,
name: 'fileName',
header: { Authorization: token },
formData,
// timeout: 5000,
success: (res) => {
const data = JSON.parse(res.data).xxx_response
if (data.code !== '10000') {
uni.showLoading({title: '上传失败', icon: 'none'})
} else {
this.baseList[0].msg = data.url
uni.showLoading({title: '上传成功', icon: 'none'})
}
setTimeout(() => {
uni.hideLoading()
}, 1000)
},
fail: err => {
console.log('err', err);
}
})
})
}
})
},
功能代码(压缩&水印)
// 这是图片上传压缩的核心所在,我们先使用CanvasRenderingContext2D.drawImage()方法将上传的图片文件在画布上绘制出来;
// 再使用Canvas.toDataURL()将画布上的图片信息转换成base64(DataURL)格式的数据。
const imgCompress = function (file, WaterMarkContent) {
const Radio = file.size / (1024 * 1024 * 2) // 默认到2m以下
let encoderOptions = Radio > 1 ? (1 / Math.ceil(Radio)) : 1 // encoderOptions图片质量取值0-1
return new Promise(function (resolve, reject) {
let fileType = file.type
let imgResult = ''
let reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = function () {
let img = new Image() //先创建图片对象
img.src = this.result
let canvas = document.createElement('canvas')
let ctx = canvas.getContext('2d')
img.onload = function () { //图片加载完后
// 做适配
let width = 800
if (img.width < 800) {
width = img.width
}
canvas.width = width
canvas.height = (img.height / img.width) * width
ctx.drawImage(img, 0, 0, canvas.width, canvas.height) //绘制图像;把大图片画在一张小画布上,压缩就这么实现了
imgResult = canvas.toDataURL(fileType, encoderOptions)
// 设置文字水印
if (WaterMarkContent) imgResult = setWaterMark(file, WaterMarkContent, imgResult)
// 返回base64
// encoderOptions表示导出的图片质量,只要导出为jpg和webp格式的时候此参数才有效果
resolve(imgResult)
// 这时可能后端要求我们传文件格式图片 base64转Blob
// const blobImg = that.converrVase64UrlToBlob(imgResult , fileType)
// resolve(blobImg)
}
}
reader.onerror = function (error) {
reject(error)
}
})
}
// dataURL转File
function dataURLtoFile(dataURL, filename) {
const arr = dataURL.split(',')
const mime = arr[0].match(/:(.*?);/)[1]
const bstr = atob(arr[1])
let n = bstr.length
const u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], filename, { type: mime })
}
// 设置水印
function setWaterMark (file, WaterMarkContent, imgResult) {
const FileNew = dataURLtoFile(imgResult, file.name)
let reader = new FileReader()
return new Promise(function (resolve, reject) {
reader.readAsDataURL(FileNew)
reader.onload = function () {
let img = new Image()
img.src = this.result
let canvas = document.createElement('canvas')
let ctx = canvas.getContext('2d')
img.onload = function () {
canvas.width = img.width
canvas.height = img.height
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
// 设置填充字号和字体,样式
WaterMarkContent.font && (ctx.font = WaterMarkContent.font)
WaterMarkContent.fillStyle && (ctx.fillStyle = WaterMarkContent.fillStyle)
WaterMarkContent.textAlign && (ctx.textAlign = WaterMarkContent.textAlign)
const FillTextArr = WaterMarkContent.fillText || []
FillTextArr.forEach((element, index) => {
const X = element.x || (canvas.width - 20)
const Y = element.y || (canvas.height - 30 * (FillTextArr.length - index))
ctx.fillText(element.text, X, Y)
});
resolve(canvas.toDataURL(file.type, 1))
}
}
reader.onerror = function (error) {
reject(error)
}
})
}
// base64转Blob
const converrVase64UrlToBlob = function (base64, mimeType) {
// mimeType 图片类型,例如 mimeType='image/png'
const bytes = window.atob(base64.split(',')[1]) // atob方法用于解码base64
// 创建一个长度为 bytes.length 的 buffer(一个二进制文件), 它会分配一个 16 字节(byte)的连续内存空间,并用 0 进行预填充。
const ab = new ArrayBuffer(bytes.length)
// Uint8Array —— 将 ArrayBuffer 中的每个字节视为 0 到 255 之间的单个数字(每个字节是 8 位)。这称为 “8 位无符号整数”。
const ia = new Uint8Array(ab)
for (let i = 0; i < bytes.length; i++) {
// 更改里面的初始化内容
ia[i] = bytes.charCodeAt(i)
}
// 创建blob格式数据,并传入二进制文件和文件原本类型
return new Blob([ia], { type: mimeType })
}
export default imgCompress