file-adapters

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

File Converter Adapters

文件转换器适配器

This skill provides comprehensive guidance for using
@rytass/file-converter
packages to process images with resizing, format conversion, watermarking, and pipeline processing.
本技能提供了使用
@rytass/file-converter
系列包进行图片处理的全面指南,包括图片缩放、格式转换、添加水印和管道处理等功能。

Overview

概述

All adapters implement the
FileConverter
interface from
@rytass/file-converter
, providing a unified API for image processing:
PackageFunctionBased On
@rytass/file-converter
Core interfaces and pipeline manager (核心介面與管道管理器)TypeScript interfaces
@rytass/file-converter-adapter-image-resizer
Image resizing (圖像縮放)Sharp ^0.34.5
@rytass/file-converter-adapter-image-transcoder
Format conversion (格式轉換)Sharp ^0.34.5, file-type ^21.1.1
@rytass/file-converter-adapter-image-watermark
Watermark overlay (浮水印疊加)Sharp ^0.34.5
所有适配器都实现了
@rytass/file-converter
中的
FileConverter
接口,为图片处理提供统一的API:
功能基于技术
@rytass/file-converter
核心接口与管道管理器TypeScript接口
@rytass/file-converter-adapter-image-resizer
图像缩放Sharp ^0.34.5
@rytass/file-converter-adapter-image-transcoder
格式转换Sharp ^0.34.5, file-type ^21.1.1
@rytass/file-converter-adapter-image-watermark
水印叠加Sharp ^0.34.5

Base Interface (@rytass/file-converter)

基础接口 (@rytass/file-converter)

All adapters share these core concepts:
FileConverter<O> - Main interface for file conversion
typescript
interface FileConverter<O = Record<string, unknown>> {
  convert<Buffer>(file: ConvertableFile): Promise<Buffer>;
  convert<Readable>(file: ConvertableFile): Promise<Readable>;
}
ConvertableFile - Supported input types
typescript
type ConvertableFile = Readable | Buffer;
ConverterManager - Pipeline processor for chaining conversions
typescript
class ConverterManager {
  constructor(converters: FileConverter[]);
  convert<Output>(file: ConvertableFile): Promise<Output>;
}
所有适配器共享以下核心概念:
FileConverter<O> - 文件转换主接口
typescript
interface FileConverter<O = Record<string, unknown>> {
  convert<Buffer>(file: ConvertableFile): Promise<Buffer>;
  convert<Readable>(file: ConvertableFile): Promise<Readable>;
}
ConvertableFile - 支持的输入类型
typescript
type ConvertableFile = Readable | Buffer;
ConverterManager - 用于链式转换的管道处理器
typescript
class ConverterManager {
  constructor(converters: FileConverter[]);
  convert<Output>(file: ConvertableFile): Promise<Output>;
}

Installation

安装

bash
undefined
bash
undefined

Install base package

安装基础包

npm install @rytass/file-converter
npm install @rytass/file-converter

Choose the adapters you need

选择需要的适配器

npm install @rytass/file-converter-adapter-image-resizer npm install @rytass/file-converter-adapter-image-transcoder npm install @rytass/file-converter-adapter-image-watermark
undefined
npm install @rytass/file-converter-adapter-image-resizer npm install @rytass/file-converter-adapter-image-transcoder npm install @rytass/file-converter-adapter-image-watermark
undefined

Quick Start

快速开始

ImageResizer (圖像縮放)

ImageResizer(图像缩放)

Resize images while maintaining or controlling aspect ratio:
typescript
import { ImageResizer } from '@rytass/file-converter-adapter-image-resizer';
import { readFileSync, writeFileSync } from 'fs';

// Resize to max 800x600, maintaining aspect ratio
const resizer = new ImageResizer({
  maxWidth: 800,
  maxHeight: 600,
  keepAspectRatio: true,
  concurrency: 4, // Optional: parallel processing
});

const originalImage = readFileSync('photo.jpg');
const resizedImage = await resizer.convert<Buffer>(originalImage);
writeFileSync('photo-resized.jpg', resizedImage);
在保持或控制宽高比的前提下调整图片大小:
typescript
import { ImageResizer } from '@rytass/file-converter-adapter-image-resizer';
import { readFileSync, writeFileSync } from 'fs';

// 调整至最大800x600,保持宽高比
const resizer = new ImageResizer({
  maxWidth: 800,
  maxHeight: 600,
  keepAspectRatio: true,
  concurrency: 4, // 可选:并行处理
});

const originalImage = readFileSync('photo.jpg');
const resizedImage = await resizer.convert<Buffer>(originalImage);
writeFileSync('photo-resized.jpg', resizedImage);

ImageTranscoder (格式轉換)

ImageTranscoder(格式转换)

Convert images between formats (JPEG, PNG, WebP, AVIF, etc.):
typescript
import { ImageTranscoder } from '@rytass/file-converter-adapter-image-transcoder';

// Convert to WebP format
const transcoder = new ImageTranscoder({
  targetFormat: 'webp',
  quality: 85,
  effort: 4,
});

const jpegBuffer = readFileSync('photo.jpg');
const webpBuffer = await transcoder.convert<Buffer>(jpegBuffer);
writeFileSync('photo.webp', webpBuffer);
在不同格式之间转换图片(JPEG、PNG、WebP、AVIF等):
typescript
import { ImageTranscoder } from '@rytass/file-converter-adapter-image-transcoder';

// 转换为WebP格式
const transcoder = new ImageTranscoder({
  targetFormat: 'webp',
  quality: 85,
  effort: 4,
});

const jpegBuffer = readFileSync('photo.jpg');
const webpBuffer = await transcoder.convert<Buffer>(jpegBuffer);
writeFileSync('photo.webp', webpBuffer);

ImageWatermark (浮水印)

ImageWatermark(添加水印)

Add watermarks to images:
typescript
import { ImageWatermark } from '@rytass/file-converter-adapter-image-watermark';
import { gravity } from 'sharp';

// Add watermark at bottom-right corner
const watermarker = new ImageWatermark({
  watermarks: [
    {
      image: readFileSync('logo.png'), // Can be Buffer or file path
      gravity: gravity.southeast, // Position: bottom-right
    },
  ],
});

const originalImage = readFileSync('photo.jpg');
const watermarkedImage = await watermarker.convert<Buffer>(originalImage);
writeFileSync('photo-watermarked.jpg', watermarkedImage);
为图片添加水印:
typescript
import { ImageWatermark } from '@rytass/file-converter-adapter-image-watermark';
import { gravity } from 'sharp';

// 在右下角添加水印
const watermarker = new ImageWatermark({
  watermarks: [
    {
      image: readFileSync('logo.png'), // 可以是Buffer或文件路径
      gravity: gravity.southeast, // 位置:右下角
    },
  ],
});

const originalImage = readFileSync('photo.jpg');
const watermarkedImage = await watermarker.convert<Buffer>(originalImage);
writeFileSync('photo-watermarked.jpg', watermarkedImage);

ConverterManager (管道處理)

ConverterManager(管道处理)

Chain multiple converters in a pipeline:
typescript
import { ConverterManager } from '@rytass/file-converter';
import { ImageResizer } from '@rytass/file-converter-adapter-image-resizer';
import { ImageWatermark } from '@rytass/file-converter-adapter-image-watermark';
import { ImageTranscoder } from '@rytass/file-converter-adapter-image-transcoder';
import { gravity } from 'sharp';

// Create processing pipeline: Resize → Watermark → Convert to WebP
const pipeline = new ConverterManager([
  new ImageResizer({
    maxWidth: 1200,
    maxHeight: 800,
    keepAspectRatio: true,
  }),
  new ImageWatermark({
    watermarks: [
      {
        image: './logo.png',
        gravity: gravity.southeast,
      },
    ],
  }),
  new ImageTranscoder({
    targetFormat: 'webp',
    quality: 85,
    effort: 4,
  }),
]);

const originalImage = readFileSync('photo.jpg');
const processedImage = await pipeline.convert<Buffer>(originalImage);
writeFileSync('processed.webp', processedImage);
将多个转换器串联成处理管道:
typescript
import { ConverterManager } from '@rytass/file-converter';
import { ImageResizer } from '@rytass/file-converter-adapter-image-resizer';
import { ImageWatermark } from '@rytass/file-converter-adapter-image-watermark';
import { ImageTranscoder } from '@rytass/file-converter-adapter-image-transcoder';
import { gravity } from 'sharp';

// 创建处理管道:缩放 → 添加水印 → 转换为WebP
const pipeline = new ConverterManager([
  new ImageResizer({
    maxWidth: 1200,
    maxHeight: 800,
    keepAspectRatio: true,
  }),
  new ImageWatermark({
    watermarks: [
      {
        image: './logo.png',
        gravity: gravity.southeast,
      },
    ],
  }),
  new ImageTranscoder({
    targetFormat: 'webp',
    quality: 85,
    effort: 4,
  }),
]);

const originalImage = readFileSync('photo.jpg');
const processedImage = await pipeline.convert<Buffer>(originalImage);
writeFileSync('processed.webp', processedImage);

Common Patterns

常见模式

Buffer vs Stream Processing

Buffer与Stream处理

Buffer - Use for small files (小檔案), faster, uses more memory:
typescript
const buffer = readFileSync('image.jpg');
const result = await converter.convert<Buffer>(buffer);
writeFileSync('output.jpg', result);
Stream (Readable) - Use for large files (大檔案), memory efficient:
typescript
import { createReadStream, createWriteStream } from 'fs';
import { Readable } from 'stream';

const stream = createReadStream('large-image.jpg');
const resultStream = await converter.convert<Readable>(stream);

// Pipe to output
resultStream.pipe(createWriteStream('output.jpg'));
Buffer - 适用于小文件,速度更快,但占用更多内存:
typescript
const buffer = readFileSync('image.jpg');
const result = await converter.convert<Buffer>(buffer);
writeFileSync('output.jpg', result);
Stream(Readable) - 适用于大文件,内存占用更高效:
typescript
import { createReadStream, createWriteStream } from 'fs';
import { Readable } from 'stream';

const stream = createReadStream('large-image.jpg');
const resultStream = await converter.convert<Readable>(stream);

// 输出到文件
resultStream.pipe(createWriteStream('output.jpg'));

Single Conversion

单一转换

Process one image with one converter:
typescript
// Resize only
const resizer = new ImageResizer({ maxWidth: 800 });
const resized = await resizer.convert<Buffer>(imageBuffer);

// Convert format only
const transcoder = new ImageTranscoder({ targetFormat: 'webp', quality: 90 });
const webp = await transcoder.convert<Buffer>(jpegBuffer);
使用单个转换器处理一张图片:
typescript
// 仅缩放
const resizer = new ImageResizer({ maxWidth: 800 });
const resized = await resizer.convert<Buffer>(imageBuffer);

// 仅转换格式
const transcoder = new ImageTranscoder({ targetFormat: 'webp', quality: 90 });
const webp = await transcoder.convert<Buffer>(jpegBuffer);

Pipeline Conversion

管道转换

Chain multiple operations:
typescript
// Three-step processing
const pipeline = new ConverterManager([
  new ImageResizer({ maxWidth: 1000, maxHeight: 750 }),
  new ImageWatermark({ watermarks: [{ image: 'logo.png' }] }),
  new ImageTranscoder({ targetFormat: 'webp', quality: 85 }),
]);

const result = await pipeline.convert<Buffer>(originalImage);
串联多个操作:
typescript
// 三步处理
const pipeline = new ConverterManager([
  new ImageResizer({ maxWidth: 1000, maxHeight: 750 }),
  new ImageWatermark({ watermarks: [{ image: 'logo.png' }] }),
  new ImageTranscoder({ targetFormat: 'webp', quality: 85 }),
]);

const result = await pipeline.convert<Buffer>(originalImage);

Batch Processing

批量处理

Process multiple images:
typescript
import { glob } from 'glob';
import { basename } from 'path';

const pipeline = new ConverterManager([
  new ImageResizer({ maxWidth: 800 }),
  new ImageTranscoder({ targetFormat: 'webp', quality: 85 }),
]);

// Find all JPEG files
const images = await glob('photos/*.jpg');

// Process all images
await Promise.all(
  images.map(async (imagePath) => {
    const buffer = readFileSync(imagePath);
    const result = await pipeline.convert<Buffer>(buffer);
    const outputName = basename(imagePath, '.jpg') + '.webp';
    writeFileSync(`output/${outputName}`, result);
  })
);
处理多张图片:
typescript
import { glob } from 'glob';
import { basename } from 'path';

const pipeline = new ConverterManager([
  new ImageResizer({ maxWidth: 800 }),
  new ImageTranscoder({ targetFormat: 'webp', quality: 85 }),
]);

// 查找所有JPEG文件
const images = await glob('photos/*.jpg');

// 处理所有图片
await Promise.all(
  images.map(async (imagePath) => {
    const buffer = readFileSync(imagePath);
    const result = await pipeline.convert<Buffer>(buffer);
    const outputName = basename(imagePath, '.jpg') + '.webp';
    writeFileSync(`output/${outputName}`, result);
  })
);

Feature Comparison

功能对比

FeatureImageResizerImageTranscoderImageWatermarkConverterManager
Resize Images (縮放圖片)YesNoNoVia pipeline
Convert Formats (轉換格式)NoYesNoVia pipeline
Add Watermarks (添加浮水印)NoNoYesVia pipeline
Maintain Aspect Ratio (保持縱橫比)YesN/AN/AN/A
Crop to Fit (裁剪適配)YesNoNoN/A
Buffer Support (緩衝支援)YesYesYesYes
Stream Support (串流支援)YesYesYesYes
Concurrency Control (並發控制)YesYesYesN/A
Multiple Watermarks (多浮水印)NoNoYesN/A
Pipeline Chaining (管道串聯)NoNoNoYes
功能ImageResizerImageTranscoderImageWatermarkConverterManager
图像缩放通过管道实现
格式转换通过管道实现
添加水印通过管道实现
保持宽高比不适用不适用不适用
裁剪适配不适用
Buffer支持
Stream支持
并发控制不适用
多水印支持不适用
管道串联

Supported Formats (ImageTranscoder)

支持的格式(ImageTranscoder)

Input FormatsOutput Formats
jpg, png, webp, gif, avif, tif, svgjpg/jpeg, png, webp, avif, heif, gif, tif/tiff
Note: Input formats are detected by
file-type
library. JPEG uses 'jpg' internally.
內部常數(未導出):
  • SupportSources
    - 支援的輸入格式陣列:
    ['jpg', 'png', 'webp', 'gif', 'avif', 'tif', 'svg']
  • UnsupportedSource
    - 當輸入格式不支援時拋出的錯誤類別
输入格式输出格式
jpg, png, webp, gif, avif, tif, svgjpg/jpeg, png, webp, avif, heif, gif, tif/tiff
注意: 输入格式由
file-type
库自动检测。JPEG在内部使用'jpg'标识。
内部常量(未导出):
  • SupportSources
    - 支持的输入格式数组:
    ['jpg', 'png', 'webp', 'gif', 'avif', 'tif', 'svg']
  • UnsupportedSource
    - 当输入格式不支持时抛出的错误类

ImageTranscoderOptions Types

ImageTranscoderOptions类型

每種輸出格式都有對應的 Sharp options:
typescript
import type { AvifOptions, GifOptions, HeifOptions, JpegOptions, PngOptions, TiffOptions, WebpOptions } from 'sharp';

type ImageTranscoderOptions =
  | { targetFormat: 'avif' } & AvifOptions
  | { targetFormat: 'heif' } & HeifOptions
  | { targetFormat: 'gif' } & GifOptions
  | { targetFormat: 'tif' | 'tiff' } & TiffOptions
  | { targetFormat: 'png' } & PngOptions
  | { targetFormat: 'webp' } & WebpOptions
  | { targetFormat: 'jpg' | 'jpeg' } & JpegOptions;

// Constructor 額外支援 concurrency 選項
new ImageTranscoder(options: ImageTranscoderOptions & { concurrency?: number });
每种输出格式都有对应的Sharp配置项:
typescript
import type { AvifOptions, GifOptions, HeifOptions, JpegOptions, PngOptions, TiffOptions, WebpOptions } from 'sharp';

type ImageTranscoderOptions =
  | { targetFormat: 'avif' } & AvifOptions
  | { targetFormat: 'heif' } & HeifOptions
  | { targetFormat: 'gif' } & GifOptions
  | { targetFormat: 'tif' | 'tiff' } & TiffOptions
  | { targetFormat: 'png' } & PngOptions
  | { targetFormat: 'webp' } & WebpOptions
  | { targetFormat: 'jpg' | 'jpeg' } & JpegOptions;

// 构造函数额外支持concurrency选项
new ImageTranscoder(options: ImageTranscoderOptions & { concurrency?: number });

ImageResizerOptions

ImageResizerOptions

typescript
interface ImageResizerOptions {
  maxWidth?: number;      // 最大寬度(至少需設定 maxWidth 或 maxHeight 其一)
  maxHeight?: number;     // 最大高度
  keepAspectRatio?: boolean;  // 保持縱橫比(預設 true,使用 'inside' fit)
  concurrency?: number;   // 並發數(預設 1)
}
Note: 使用
withoutEnlargement: true
確保不會放大小於目標尺寸的圖片。當
keepAspectRatio=false
時使用
fit: 'cover'
裁剪適配。
typescript
interface ImageResizerOptions {
  maxWidth?: number;      // 最大宽度(至少需设置maxWidth或maxHeight其中一个)
  maxHeight?: number;     // 最大高度
  keepAspectRatio?: boolean;  // 保持宽高比(默认true,使用'inside'适配方式)
  concurrency?: number;   // 并发数(默认1)
}
注意: 使用
withoutEnlargement: true
确保不会放大小于目标尺寸的图片。当
keepAspectRatio=false
时,使用
fit: 'cover'
进行裁剪适配。

ImageWatermarkOptions

ImageWatermarkOptions

typescript
interface Watermark {
  image: string | Buffer;  // 浮水印圖片(檔案路徑或 Buffer)
  gravity?: Gravity;       // 位置(預設 southeast)
}

interface ImageWatermarkOptions {
  watermarks: Watermark[];  // 浮水印陣列(支援多個浮水印)
  concurrency?: number;     // 並發數(預設 1)
}
typescript
interface Watermark {
  image: string | Buffer;  // 水印图片(文件路径或Buffer)
  gravity?: Gravity;       // 位置(默认southeast)
}

interface ImageWatermarkOptions {
  watermarks: Watermark[];  // 水印数组(支持多个水印)
  concurrency?: number;     // 并发数(默认1)
}

Watermark Positions (ImageWatermark)

水印位置(ImageWatermark)

PositionGravity ConstantDescription
Top-Left (左上)
gravity.northwest
Northwest corner
Top-Center (上中)
gravity.north
Top center
Top-Right (右上)
gravity.northeast
Northeast corner
Middle-Left (中左)
gravity.west
Middle left
Center (中央)
gravity.center
Center
Middle-Right (中右)
gravity.east
Middle right
Bottom-Left (左下)
gravity.southwest
Southwest corner
Bottom-Center (下中)
gravity.south
Bottom center
Bottom-Right (右下)
gravity.southeast
Southeast corner (default)
位置Gravity常量描述
左上
gravity.northwest
左上角
上中
gravity.north
顶部中央
右上
gravity.northeast
右上角
中左
gravity.west
左侧中间
中央
gravity.center
正中央
中右
gravity.east
右侧中间
左下
gravity.southwest
左下角
下中
gravity.south
底部中央
右下
gravity.southeast
右下角(默认)

Detailed Documentation

详细文档

For complete API reference and advanced usage:
  • ImageResizer Complete Reference - All options, methods, and use cases
  • ImageTranscoder Complete Reference - Format-specific options, error handling
  • ImageWatermark Complete Reference - Watermark configuration, positioning
如需完整的API参考和高级用法:
  • ImageResizer完整参考 - 所有配置项、方法和使用场景
  • ImageTranscoder完整参考 - 格式专属配置项、错误处理
  • ImageWatermark完整参考 - 水印配置、位置设置

Complete Examples

完整示例

E-commerce Product Images

电商产品图片处理

Process product photos: resize for web, add branding watermark, convert to modern format:
typescript
import { ConverterManager } from '@rytass/file-converter';
import { ImageResizer } from '@rytass/file-converter-adapter-image-resizer';
import { ImageWatermark } from '@rytass/file-converter-adapter-image-watermark';
import { ImageTranscoder } from '@rytass/file-converter-adapter-image-transcoder';
import { readFileSync, writeFileSync } from 'fs';
import { gravity } from 'sharp';

// Create product image processor
const productImageProcessor = new ConverterManager([
  // Step 1: Resize to 1200x1200 max
  new ImageResizer({
    maxWidth: 1200,
    maxHeight: 1200,
    keepAspectRatio: true,
    concurrency: 4,
  }),

  // Step 2: Add brand watermark at bottom-right
  new ImageWatermark({
    watermarks: [
      {
        image: readFileSync('brand-logo.png'),
        gravity: gravity.southeast,
      },
    ],
  }),

  // Step 3: Convert to WebP for smaller file size
  new ImageTranscoder({
    targetFormat: 'webp',
    quality: 85,
    effort: 4, // Higher effort = better compression
  }),
]);

// Process a product image
const originalPhoto = readFileSync('product-001-raw.jpg');
const processedPhoto = await productImageProcessor.convert<Buffer>(originalPhoto);
writeFileSync('product-001.webp', processedPhoto);
处理产品图片:调整网页适配尺寸、添加品牌水印、转换为现代格式:
typescript
import { ConverterManager } from '@rytass/file-converter';
import { ImageResizer } from '@rytass/file-converter-adapter-image-resizer';
import { ImageWatermark } from '@rytass/file-converter-adapter-image-watermark';
import { ImageTranscoder } from '@rytass/file-converter-adapter-image-transcoder';
import { readFileSync, writeFileSync } from 'fs';
import { gravity } from 'sharp';

// 创建产品图片处理器
const productImageProcessor = new ConverterManager([
  // 步骤1:调整至最大1200x1200
  new ImageResizer({
    maxWidth: 1200,
    maxHeight: 1200,
    keepAspectRatio: true,
    concurrency: 4,
  }),

  // 步骤2:在右下角添加品牌水印
  new ImageWatermark({
    watermarks: [
      {
        image: readFileSync('brand-logo.png'),
        gravity: gravity.southeast,
      },
    ],
  }),

  // 步骤3:转换为WebP格式以减小文件体积
  new ImageTranscoder({
    targetFormat: 'webp',
    quality: 85,
    effort: 4, // 更高的effort值对应更好的压缩效果
  }),
]);

// 处理产品图片
const originalPhoto = readFileSync('product-001-raw.jpg');
const processedPhoto = await productImageProcessor.convert<Buffer>(originalPhoto);
writeFileSync('product-001.webp', processedPhoto);

Large File Stream Processing

大文件流处理

Handle large files efficiently with streams to avoid memory issues:
typescript
import { createReadStream, createWriteStream } from 'fs';
import { ImageResizer } from '@rytass/file-converter-adapter-image-resizer';
import { Readable } from 'stream';

// Create resizer
const resizer = new ImageResizer({
  maxWidth: 1920,
  maxHeight: 1080,
  keepAspectRatio: true,
});

// Process large file using streams
const inputStream = createReadStream('large-photo.jpg');
const outputStream = await resizer.convert<Readable>(inputStream);

// Pipe to output file
outputStream.pipe(createWriteStream('large-photo-resized.jpg'));

// Wait for completion
await new Promise((resolve, reject) => {
  outputStream.on('finish', resolve);
  outputStream.on('error', reject);
});
使用流高效处理大文件,避免内存问题:
typescript
import { createReadStream, createWriteStream } from 'fs';
import { ImageResizer } from '@rytass/file-converter-adapter-image-resizer';
import { Readable } from 'stream';

// 创建缩放器
const resizer = new ImageResizer({
  maxWidth: 1920,
  maxHeight: 1080,
  keepAspectRatio: true,
});

// 使用流处理大文件
const inputStream = createReadStream('large-photo.jpg');
const outputStream = await resizer.convert<Readable>(inputStream);

// 输出到文件
outputStream.pipe(createWriteStream('large-photo-resized.jpg'));

// 等待处理完成
await new Promise((resolve, reject) => {
  outputStream.on('finish', resolve);
  outputStream.on('error', reject);
});

Batch Processing with Progress Tracking

带进度追踪的批量处理

Process multiple images with progress updates:
typescript
import { glob } from 'glob';
import { basename } from 'path';
import { ConverterManager } from '@rytass/file-converter';
import { ImageResizer } from '@rytass/file-converter-adapter-image-resizer';
import { ImageTranscoder } from '@rytass/file-converter-adapter-image-transcoder';

// Create pipeline
const pipeline = new ConverterManager([
  new ImageResizer({ maxWidth: 800, maxHeight: 600, keepAspectRatio: true }),
  new ImageTranscoder({ targetFormat: 'webp', quality: 80 }),
]);

// Find all images
const images = await glob('input-photos/*.{jpg,png,jpeg}');
const total = images.length;
let processed = 0;

console.log(`Found ${total} images to process`);

// Process with progress tracking
for (const imagePath of images) {
  const buffer = readFileSync(imagePath);
  const result = await pipeline.convert<Buffer>(buffer);

  const outputName = basename(imagePath).replace(/\.(jpg|png|jpeg)$/, '.webp');
  writeFileSync(`output/${outputName}`, result);

  processed++;
  console.log(`Progress: ${processed}/${total} (${Math.round((processed / total) * 100)}%)`);
}

console.log('All images processed successfully!');
处理多张图片并显示进度:
typescript
import { glob } from 'glob';
import { basename } from 'path';
import { ConverterManager } from '@rytass/file-converter';
import { ImageResizer } from '@rytass/file-converter-adapter-image-resizer';
import { ImageTranscoder } from '@rytass/file-converter-adapter-image-transcoder';

// 创建处理管道
const pipeline = new ConverterManager([
  new ImageResizer({ maxWidth: 800, maxHeight: 600, keepAspectRatio: true }),
  new ImageTranscoder({ targetFormat: 'webp', quality: 80 }),
]);

// 查找所有图片
const images = await glob('input-photos/*.{jpg,png,jpeg}');
const total = images.length;
let processed = 0;

console.log(`找到${total}张待处理图片`);

// 带进度追踪处理
for (const imagePath of images) {
  const buffer = readFileSync(imagePath);
  const result = await pipeline.convert<Buffer>(buffer);

  const outputName = basename(imagePath).replace(/\.(jpg|png|jpeg)$/, '.webp');
  writeFileSync(`output/${outputName}`, result);

  processed++;
  console.log(`进度:${processed}/${total}${Math.round((processed / total) * 100)}%)`);
}

console.log('所有图片处理完成!');

Conditional Processing

条件处理

Apply different processing based on image properties:
typescript
import sharp from 'sharp';
import { ImageResizer } from '@rytass/file-converter-adapter-image-resizer';
import { ImageTranscoder } from '@rytass/file-converter-adapter-image-transcoder';
import { ConverterManager } from '@rytass/file-converter';

async function processImage(inputBuffer: Buffer): Promise<Buffer> {
  // Get image metadata
  const metadata = await sharp(inputBuffer).metadata();

  if (!metadata.width || !metadata.height) {
    throw new Error('Unable to read image dimensions');
  }

  // For large images: resize first
  if (metadata.width > 2000 || metadata.height > 2000) {
    console.log('Large image detected, resizing...');
    const pipeline = new ConverterManager([
      new ImageResizer({ maxWidth: 1600, maxHeight: 1600, keepAspectRatio: true }),
      new ImageTranscoder({ targetFormat: 'webp', quality: 85 }),
    ]);
    return pipeline.convert<Buffer>(inputBuffer);
  }

  // For small images: just convert format
  console.log('Small image detected, converting format only...');
  const transcoder = new ImageTranscoder({ targetFormat: 'webp', quality: 90 });
  return transcoder.convert<Buffer>(inputBuffer);
}

// Usage
const imageBuffer = readFileSync('photo.jpg');
const result = await processImage(imageBuffer);
writeFileSync('output.webp', result);
根据图片属性应用不同的处理逻辑:
typescript
import sharp from 'sharp';
import { ImageResizer } from '@rytass/file-converter-adapter-image-resizer';
import { ImageTranscoder } from '@rytass/file-converter-adapter-image-transcoder';
import { ConverterManager } from '@rytass/file-converter';

async function processImage(inputBuffer: Buffer): Promise<Buffer> {
  // 获取图片元数据
  const metadata = await sharp(inputBuffer).metadata();

  if (!metadata.width || !metadata.height) {
    throw new Error('无法读取图片尺寸');
  }

  // 对于大图片:先缩放
  if (metadata.width > 2000 || metadata.height > 2000) {
    console.log('检测到大尺寸图片,正在缩放...');
    const pipeline = new ConverterManager([
      new ImageResizer({ maxWidth: 1600, maxHeight: 1600, keepAspectRatio: true }),
      new ImageTranscoder({ targetFormat: 'webp', quality: 85 }),
    ]);
    return pipeline.convert<Buffer>(inputBuffer);
  }

  // 对于小图片:仅转换格式
  console.log('检测到小尺寸图片,仅转换格式...');
  const transcoder = new ImageTranscoder({ targetFormat: 'webp', quality: 90 });
  return transcoder.convert<Buffer>(inputBuffer);
}

// 使用示例
const imageBuffer = readFileSync('photo.jpg');
const result = await processImage(imageBuffer);
writeFileSync('output.webp', result);

Troubleshooting

故障排除

Common Issues

常见问题

Memory Errors with Large Images
  • Solution: Use Stream processing instead of Buffer
typescript
// Instead of Buffer
const buffer = readFileSync('huge-image.jpg');
const result = await converter.convert<Buffer>(buffer);

// Use Stream
const stream = createReadStream('huge-image.jpg');
const resultStream = await converter.convert<Readable>(stream);
Sharp Cache Issues
  • Sharp automatically disables cache in all adapters with
    sharp.cache(false)
  • No action needed
Concurrency Performance
  • Adjust
    concurrency
    option based on your CPU cores
  • Default is 1 (single-threaded)
  • Try 4-8 for multi-core systems
typescript
const resizer = new ImageResizer({
  maxWidth: 800,
  concurrency: 8, // Adjust based on CPU cores
});
Unsupported Format Errors (ImageTranscoder)
  • Check input format is supported: JPEG, PNG, WebP, GIF, AVIF, TIFF, SVG
  • Error will throw
    UnsupportedSource
    exception (internal class, catch using
    instanceof Error
    and check
    message === 'UnsupportedSource'
    )
Output Quality Issues
  • Increase
    quality
    parameter (0-100)
  • For WebP/AVIF, increase
    effort
    (0-9) for better compression
typescript
const transcoder = new ImageTranscoder({
  targetFormat: 'webp',
  quality: 95, // Higher quality
  effort: 6,   // More compression effort
});
大图片处理时出现内存错误
  • 解决方案:使用Stream处理替代Buffer处理
typescript
// 避免使用Buffer
const buffer = readFileSync('huge-image.jpg');
const result = await converter.convert<Buffer>(buffer);

// 使用Stream
const stream = createReadStream('huge-image.jpg');
const resultStream = await converter.convert<Readable>(stream);
Sharp缓存问题
  • 所有适配器中已通过
    sharp.cache(false)
    自动禁用Sharp缓存
  • 无需额外操作
并发性能优化
  • 根据CPU核心数调整
    concurrency
    选项
  • 默认值为1(单线程)
  • 多核系统建议设置为4-8
typescript
const resizer = new ImageResizer({
  maxWidth: 800,
  concurrency: 8, // 根据CPU核心数调整
});
格式不支持错误(ImageTranscoder)
  • 检查输入格式是否在支持列表中:JPEG、PNG、WebP、GIF、AVIF、TIFF、SVG
  • 错误会抛出
    UnsupportedSource
    异常(内部类,可通过
    instanceof Error
    并检查
    message === 'UnsupportedSource'
    捕获)
输出质量问题
  • 提高
    quality
    参数值(范围0-100)
  • 对于WebP/AVIF格式,提高
    effort
    值(范围0-9)以获得更好的压缩效果
typescript
const transcoder = new ImageTranscoder({
  targetFormat: 'webp',
  quality: 95, // 更高质量
  effort: 6,   // 更高压缩耗时,更好效果
});