78 lines
2.3 KiB
JavaScript
78 lines
2.3 KiB
JavaScript
|
|
function isImageFile(file) {
|
||
|
|
return file && file.type && file.type.indexOf('image/') === 0
|
||
|
|
}
|
||
|
|
|
||
|
|
function canvasToBlob(canvas, type, quality) {
|
||
|
|
return new Promise(resolve => {
|
||
|
|
if (!canvas.toBlob) {
|
||
|
|
resolve(null)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
canvas.toBlob(blob => resolve(blob), type, quality)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
function loadImage(file) {
|
||
|
|
return new Promise((resolve, reject) => {
|
||
|
|
const reader = new FileReader()
|
||
|
|
reader.onload = event => {
|
||
|
|
const image = new Image()
|
||
|
|
image.onload = () => resolve(image)
|
||
|
|
image.onerror = reject
|
||
|
|
image.src = event.target.result
|
||
|
|
}
|
||
|
|
reader.onerror = reject
|
||
|
|
reader.readAsDataURL(file)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function compressImageForUpload(file, options = {}) {
|
||
|
|
const maxSize = options.maxSize || 3 * 1024 * 1024
|
||
|
|
const maxWidth = options.maxWidth || 1600
|
||
|
|
const maxHeight = options.maxHeight || 1600
|
||
|
|
const outputType = options.outputType || 'image/jpeg'
|
||
|
|
const minQuality = options.minQuality || 0.55
|
||
|
|
|
||
|
|
if (!isImageFile(file) || typeof FileReader === 'undefined' || typeof document === 'undefined') {
|
||
|
|
return file
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
const image = await loadImage(file)
|
||
|
|
let scale = Math.min(maxWidth / image.width, maxHeight / image.height, 1)
|
||
|
|
let quality = options.quality || 0.82
|
||
|
|
let bestBlob = null
|
||
|
|
|
||
|
|
for (let i = 0; i < 7; i++) {
|
||
|
|
const width = Math.max(1, Math.round(image.width * scale))
|
||
|
|
const height = Math.max(1, Math.round(image.height * scale))
|
||
|
|
const canvas = document.createElement('canvas')
|
||
|
|
canvas.width = width
|
||
|
|
canvas.height = height
|
||
|
|
const context = canvas.getContext('2d')
|
||
|
|
context.fillStyle = '#ffffff'
|
||
|
|
context.fillRect(0, 0, width, height)
|
||
|
|
context.drawImage(image, 0, 0, width, height)
|
||
|
|
|
||
|
|
const blob = await canvasToBlob(canvas, outputType, quality)
|
||
|
|
if (!blob) {
|
||
|
|
return file
|
||
|
|
}
|
||
|
|
bestBlob = blob
|
||
|
|
if (blob.size <= maxSize) {
|
||
|
|
break
|
||
|
|
}
|
||
|
|
scale = scale * 0.82
|
||
|
|
quality = Math.max(minQuality, quality - 0.08)
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!bestBlob || bestBlob.size >= file.size) {
|
||
|
|
return file
|
||
|
|
}
|
||
|
|
const fileName = file.name ? file.name.replace(/\.[^.]+$/, '.jpg') : 'upload.jpg'
|
||
|
|
return new File([bestBlob], fileName, { type: outputType, lastModified: Date.now() })
|
||
|
|
} catch (error) {
|
||
|
|
return file
|
||
|
|
}
|
||
|
|
}
|