示例
本页面提供了 Sharp 的各种使用示例,从基本操作到高级技巧。
基本示例
图像调整大小
javascript
import sharp from 'sharp';
// 调整到固定尺寸
await sharp('input.jpg')
.resize(300, 200)
.toFile('resized.jpg');
// 保持宽高比
await sharp('input.jpg')
.resize(300, null)
.toFile('resized.jpg');
// 使用不同的适配模式
await sharp('input.jpg')
.resize(300, 200, {
fit: 'cover', // 裁剪以适应
position: 'center' // 居中裁剪
})
.toFile('cover.jpg');
格式转换
javascript
// JPEG 转 PNG
await sharp('input.jpg')
.png()
.toFile('output.png');
// PNG 转 WebP
await sharp('input.png')
.webp({ quality: 80 })
.toFile('output.webp');
// 转换为 AVIF
await sharp('input.jpg')
.avif({ quality: 80 })
.toFile('output.avif');
创建缩略图
javascript
// 创建正方形缩略图
await sharp('input.jpg')
.resize(150, 150, { fit: 'cover' })
.jpeg({ quality: 90 })
.toFile('thumbnail.jpg');
// 创建不同尺寸的缩略图
const sizes = [150, 300, 600];
const promises = sizes.map(size =>
sharp('input.jpg')
.resize(size, size, { fit: 'cover' })
.jpeg({ quality: 85 })
.toFile(`thumbnail-${size}.jpg`)
);
await Promise.all(promises);
高级示例
图像合成
javascript
// 在图像上添加水印
await sharp('input.jpg')
.composite([{
input: 'watermark.png',
top: 10,
left: 10
}])
.jpeg()
.toFile('with-watermark.jpg');
// 创建图像网格
const grid = await sharp({
create: {
width: 600,
height: 400,
channels: 4,
background: { r: 255, g: 255, b: 255, alpha: 1 }
}
})
.composite([
{ input: 'image1.jpg', top: 0, left: 0 },
{ input: 'image2.jpg', top: 0, left: 300 },
{ input: 'image3.jpg', top: 200, left: 0 },
{ input: 'image4.jpg', top: 200, left: 300 }
])
.jpeg()
.toFile('grid.jpg');
滤镜效果
javascript
// 应用多种滤镜
await sharp('input.jpg')
.blur(3) // 模糊
.sharpen() // 锐化
.modulate({ // 色彩调整
brightness: 1.1,
saturation: 0.8
})
.jpeg({ quality: 85 })
.toFile('filtered.jpg');
// 创建复古效果
await sharp('input.jpg')
.modulate({
brightness: 0.9,
saturation: 0.7,
hue: 30
})
.tint({ r: 255, g: 200, b: 150 })
.jpeg({ quality: 80 })
.toFile('vintage.jpg');
批量处理
javascript
import fs from 'fs';
import path from 'path';
async function processDirectory(inputDir, outputDir) {
const files = fs.readdirSync(inputDir);
const imageFiles = files.filter(file =>
/\.(jpg|jpeg|png|webp)$/i.test(file)
);
const promises = imageFiles.map(async file => {
const inputPath = path.join(inputDir, file);
const outputPath = path.join(outputDir, `processed-${file}`);
await sharp(inputPath)
.resize(800, 600, { fit: 'inside' })
.jpeg({ quality: 80 })
.toFile(outputPath);
console.log(`处理完成: ${file}`);
});
await Promise.all(promises);
console.log('所有文件处理完成!');
}
processDirectory('./input', './output');
响应式图像
javascript
// 生成响应式图像
const sizes = [
{ width: 320, suffix: 'sm' },
{ width: 640, suffix: 'md' },
{ width: 1024, suffix: 'lg' },
{ width: 1920, suffix: 'xl' }
];
const formats = ['jpeg', 'webp', 'avif'];
async function generateResponsiveImages(inputFile) {
const promises = [];
for (const size of sizes) {
for (const format of formats) {
const outputFile = `output-${size.suffix}.${format}`;
let pipeline = sharp(inputFile)
.resize(size.width, null, { fit: 'inside' });
switch (format) {
case 'jpeg':
pipeline = pipeline.jpeg({ quality: 80 });
break;
case 'webp':
pipeline = pipeline.webp({ quality: 80 });
break;
case 'avif':
pipeline = pipeline.avif({ quality: 80 });
break;
}
promises.push(pipeline.toFile(outputFile));
}
}
await Promise.all(promises);
console.log('响应式图像生成完成!');
}
generateResponsiveImages('input.jpg');
性能优化示例
流式处理
javascript
import fs from 'fs';
// 处理大文件
const pipeline = sharp()
.resize(800, 600)
.jpeg({ quality: 80 });
fs.createReadStream('large-input.jpg')
.pipe(pipeline)
.pipe(fs.createWriteStream('output.jpg'));
// 处理多个文件
const processFile = (inputFile, outputFile) => {
return new Promise((resolve, reject) => {
sharp(inputFile)
.resize(300, 200)
.jpeg({ quality: 80 })
.pipe(fs.createWriteStream(outputFile))
.on('finish', resolve)
.on('error', reject);
});
};
const files = ['file1.jpg', 'file2.jpg', 'file3.jpg'];
const promises = files.map((file, index) =>
processFile(file, `output-${index}.jpg`)
);
await Promise.all(promises);
内存优化
javascript
// 使用 Buffer 处理小文件
const buffer = await sharp('input.jpg')
.resize(300, 200)
.jpeg({ quality: 80 })
.toBuffer();
// 使用流处理大文件
const stream = sharp('large-input.jpg')
.resize(800, 600)
.jpeg({ quality: 80 });
// 分块处理
const chunkSize = 1024 * 1024; // 1MB
const chunks = [];
stream.on('data', chunk => {
chunks.push(chunk);
});
stream.on('end', () => {
const buffer = Buffer.concat(chunks);
fs.writeFileSync('output.jpg', buffer);
});
并发控制
javascript
// 限制并发数量
async function processWithConcurrency(files, concurrency = 3) {
const results = [];
for (let i = 0; i < files.length; i += concurrency) {
const batch = files.slice(i, i + concurrency);
const batchPromises = batch.map(file =>
sharp(file)
.resize(300, 200)
.jpeg({ quality: 80 })
.toFile(`processed-${file}`)
);
const batchResults = await Promise.all(batchPromises);
results.push(...batchResults);
}
return results;
}
const files = ['file1.jpg', 'file2.jpg', 'file3.jpg', 'file4.jpg'];
await processWithConcurrency(files, 2);
实用工具示例
图像信息提取
javascript
async function getImageInfo(file) {
const metadata = await sharp(file).metadata();
const stats = await sharp(file).stats();
return {
filename: file,
format: metadata.format,
width: metadata.width,
height: metadata.height,
size: metadata.size,
channels: metadata.channels,
isOpaque: stats.isOpaque,
dominantColor: stats.dominant
};
}
const info = await getImageInfo('input.jpg');
console.log('图像信息:', info);
图像比较
javascript
async function compareImages(file1, file2) {
const [stats1, stats2] = await Promise.all([
sharp(file1).stats(),
sharp(file2).stats()
]);
return {
file1: stats1,
file2: stats2,
dominantDiff: {
r: Math.abs(stats1.dominant.r - stats2.dominant.r),
g: Math.abs(stats1.dominant.g - stats2.dominant.g),
b: Math.abs(stats1.dominant.b - stats2.dominant.b)
}
};
}
const comparison = await compareImages('image1.jpg', 'image2.jpg');
console.log('图像比较结果:', comparison);
图像验证
javascript
async function validateImage(file) {
try {
const metadata = await sharp(file).metadata();
const validation = {
isValid: true,
format: metadata.format,
width: metadata.width,
height: metadata.height,
size: metadata.size,
errors: []
};
// 检查尺寸
if (metadata.width > 5000 || metadata.height > 5000) {
validation.errors.push('图像尺寸过大');
}
// 检查文件大小
if (metadata.size > 10 * 1024 * 1024) { // 10MB
validation.errors.push('文件大小过大');
}
// 检查格式
const allowedFormats = ['jpeg', 'png', 'webp'];
if (!allowedFormats.includes(metadata.format)) {
validation.errors.push('不支持的格式');
}
if (validation.errors.length > 0) {
validation.isValid = false;
}
return validation;
} catch (error) {
return {
isValid: false,
errors: [error.message]
};
}
}
const validation = await validateImage('input.jpg');
console.log('验证结果:', validation);
完整应用示例
javascript
import sharp from 'sharp';
import fs from 'fs';
import path from 'path';
class ImageProcessor {
constructor(options = {}) {
this.options = {
quality: 80,
maxWidth: 1920,
maxHeight: 1080,
...options
};
}
async processImage(inputPath, outputPath, options = {}) {
try {
const metadata = await sharp(inputPath).metadata();
// 计算调整尺寸
const { width, height } = this.calculateDimensions(
metadata.width,
metadata.height,
options
);
// 处理图像
await sharp(inputPath)
.resize(width, height, { fit: 'inside' })
.jpeg({ quality: this.options.quality })
.toFile(outputPath);
return {
success: true,
originalSize: { width: metadata.width, height: metadata.height },
newSize: { width, height },
outputPath
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
calculateDimensions(originalWidth, originalHeight, options = {}) {
const { maxWidth = this.options.maxWidth, maxHeight = this.options.maxHeight } = options;
let width = originalWidth;
let height = originalHeight;
if (width > maxWidth) {
height = (height * maxWidth) / width;
width = maxWidth;
}
if (height > maxHeight) {
width = (width * maxHeight) / height;
height = maxHeight;
}
return { width: Math.round(width), height: Math.round(height) };
}
async batchProcess(inputDir, outputDir) {
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
const files = fs.readdirSync(inputDir);
const imageFiles = files.filter(file =>
/\.(jpg|jpeg|png|webp)$/i.test(file)
);
const results = [];
for (const file of imageFiles) {
const inputPath = path.join(inputDir, file);
const outputPath = path.join(outputDir, `processed-${file}`);
const result = await this.processImage(inputPath, outputPath);
results.push({ file, ...result });
}
return results;
}
}
// 使用示例
const processor = new ImageProcessor({ quality: 85 });
// 处理单个文件
const result = await processor.processImage('input.jpg', 'output.jpg');
// 批量处理
const results = await processor.batchProcess('./input', './output');
console.log('处理结果:', results);