图片压缩
canvas(H5、APP能用)
html
<canvas
canvas-id="compressCanvas"
style="position: fixed; left: -9999px; top: -9999px; width:300px;height:300px"
/>js
export default {
methods: {
/**
* 利用html5+api压缩图片
* @param {String} src 图片地址
* @returns {Promise}
* @description 压缩图片,返回压缩后的图片路径
*/
compressImage(url: string) {
return new Promise((resolve, reject) => {
const ctx = uni.createCanvasContext("canvas");
uni.getImageInfo({
src: url,
success: (imgInfo) => {
const maxWidth = 400;
const ratio = imgInfo.width / imgInfo.height;
const targetWidth = Math.min(imgInfo.width, maxWidth);
const targetHeight = targetWidth / ratio;
ctx.drawImage(url, 0, 0, targetWidth, targetHeight);
ctx.draw(false, () => {
uni.canvasToTempFilePath({
canvasId: "canvas",
destWidth: targetWidth,
destHeight: targetHeight,
quality: 0.5,
success: (res) => {
resolve(res.tempFilePath);
},
fail: reject,
});
});
},
fail: reject,
});
});
},
},
};HTML5 plus API(仅用于APP端)
js
export default {
methods: {
/**
* 利用html5+api压缩图片
* @param {String} src 图片地址
* @returns {Promise}
* @description 压缩图片,返回压缩后的图片路径,如需上传,需要在上传成功之后删除保存在本地的图片
*/
compressImage(src) {
return new Promise((resolve, reject) => {
plus.zip.compressImage(
{
src, // 原图路径
dst: `_doc/${Date.now()}-compressed.jpg`, // 保存到 _doc 目录
quality: 30, // 压缩质量
width: "40%", // 宽度缩小到原图的 40%
overwrite: true, // 允许覆盖已有文件
rotate: undefined, // 不旋转
},
(res) => resolve(res.target),
(err) => reject(err)
);
});
},
},
};uni.compressImage (小程序、H5、APP都能用)
js
export default {
methods: {
/**
* 利用html5+api压缩图片
* @param {String} src 图片地址
* @returns {Promise}
* @description 压缩图片,返回压缩后的图片路径
*/
compressImage(src) {
return new Promise((resolve, reject) => {
uni.compressImage({
src: url,
quantity: 20,
compressedWidth: 500,
compressedHeight: 500,
success: (res) => resolve(res.tempFilePath),
fail: (err) => reject(err),
});
});
},
},
};服务端压缩
js
const fs = require("fs").promises;
const path = require("path");
const sharp = require("sharp");
class ImageCompressor {
/**
* 压缩图片
* @param {String} inputPath 压缩的图片路径
* @param {String} outputPath 压缩后存放的图片路径
* @returns {Promise}
*/
async compressImage(inputPath, outputPath) {
try {
const ext = path.extname(inputPath).toLowerCase();
// 检查文件大小,只压缩大于50KB的文件
const originalStats = await fs.stat(inputPath);
const originalSize = originalStats.size;
const fileSizeKB = originalSize / 1024;
if (originalSize < 50 * 1024) {
console.log(
`文件小于50KB,跳过压缩: ${path.basename(
inputPath
)} (${fileSizeKB.toFixed(2)}KB)`
);
await fs.copyFile(inputPath, outputPath);
return {
originalSize,
compressedSize: originalSize,
compressionRatio: 0,
skipped: true,
};
}
let sharpInstance = sharp(inputPath);
// 获取图片信息
const metadata = await sharpInstance.metadata();
console.log(
`处理图片: ${path.basename(inputPath)} (${metadata.width}x${
metadata.height
}, ${fileSizeKB.toFixed(2)}KB)`
);
// 调整尺寸(如果超过最大尺寸)
if (metadata.width > this.maxWidth || metadata.height > this.maxHeight) {
sharpInstance = sharpInstance.resize(this.maxWidth, this.maxHeight, {
fit: "inside",
withoutEnlargement: true,
});
}
// 根据文件格式进行压缩
switch (ext) {
case ".jpg":
case ".jpeg":
await sharpInstance
.jpeg({ quality: this.quality, progressive: true })
.toFile(outputPath);
break;
case ".png":
await sharpInstance
.png({ quality: this.quality, compressionLevel: 9 })
.toFile(outputPath);
break;
case ".webp":
await sharpInstance
.webp({ quality: this.quality })
.toFile(outputPath);
break;
default:
throw new Error(`不支持的图片格式: ${ext}`);
}
// 获取压缩后的文件大小
const compressedStats = await fs.stat(outputPath);
const compressedSize = compressedStats.size;
// 如果压缩后文件更大或压缩效果不明显,使用原文件
if (compressedSize >= originalSize * 0.95) {
console.log(`压缩效果不佳,使用原文件: ${path.basename(inputPath)}`);
await fs.copyFile(inputPath, outputPath);
return {
originalSize,
compressedSize: originalSize,
compressionRatio: 0,
usedOriginal: true,
};
}
const compressionRatio = (
((originalSize - compressedSize) / originalSize) *
100
).toFixed(2);
console.log(
`压缩完成: ${path.basename(inputPath)} (减少 ${compressionRatio}%)`
);
return {
originalSize,
compressedSize,
compressionRatio: parseFloat(compressionRatio),
};
} catch (error) {
console.error(`压缩失败 ${inputPath}:`, error.message);
throw error;
}
}
}
module.exports = ImageCompressor;