convert_image
Convert images between formats like PNG, JPG, WebP, GIF, BMP, TIFF, SVG, and ICO. Resize images while maintaining aspect ratio and adjust compression quality for supported formats.
Instructions
将图片转换为指定格式
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| input_path | No | 源图片文件路径(与input_data二选一) | |
| input_data | No | 图片数据(Buffer或base64字符串,与input_path二选一) | |
| input_filename | No | 原始文件名,用于确定格式(使用input_data时建议提供) | |
| output_format | Yes | 目标格式(png/jpg/jpeg/gif/bmp/tiff/webp/svg/ico等) | |
| quality | No | 压缩质量(1-100,仅适用于有损格式) | |
| width | No | 目标宽度(像素) | |
| height | No | 目标高度(像素) | |
| maintain_aspect_ratio | No | 保持宽高比 | |
| output_path | No | 输出文件路径(可选,默认自动生成) |
Implementation Reference
- src/index.ts:60-110 (registration)Registration of the 'convert_image' tool in the ListTools handler, defining name, description, and input schema.{ name: 'convert_image', description: '将图片转换为指定格式', inputSchema: { type: 'object', properties: { input_path: { type: 'string', description: '源图片文件路径(与input_data二选一)' }, input_data: { type: 'string', description: '图片数据(Buffer或base64字符串,与input_path二选一)' }, input_filename: { type: 'string', description: '原始文件名,用于确定格式(使用input_data时建议提供)' }, output_format: { type: 'string', description: '目标格式(png/jpg/jpeg/gif/bmp/tiff/webp/svg/ico等)' }, quality: { type: 'number', minimum: 1, maximum: 100, description: '压缩质量(1-100,仅适用于有损格式)' }, width: { type: 'number', minimum: 1, description: '目标宽度(像素)' }, height: { type: 'number', minimum: 1, description: '目标高度(像素)' }, maintain_aspect_ratio: { type: 'boolean', default: true, description: '保持宽高比' }, output_path: { type: 'string', description: '输出文件路径(可选,默认自动生成)' } }, required: ['output_format'] } },
- src/index.ts:13-23 (schema)Zod schema for validating arguments to the convert_image tool.const ConvertImageArgsSchema = z.object({ input_path: z.string().optional().describe('源图片文件路径'), input_data: z.string().optional().describe('图片数据(Buffer或base64字符串)'), input_filename: z.string().optional().describe('原始文件名,用于确定格式'), output_format: z.string().describe('目标格式(png/jpg/jpeg/gif/bmp/tiff/webp/svg/ico等)'), quality: z.number().min(1).max(100).optional().describe('压缩质量(1-100,仅适用于有损格式)'), width: z.number().positive().optional().describe('目标宽度(像素)'), height: z.number().positive().optional().describe('目标高度(像素)'), maintain_aspect_ratio: z.boolean().default(true).describe('保持宽高比'), output_path: z.string().optional().describe('输出文件路径(可选,默认自动生成)') });
- src/index.ts:208-219 (handler)MCP CallTool request handler case that validates args and delegates to ImageConverter.convertImage.case 'convert_image': { const validatedArgs = ConvertImageArgsSchema.parse(args); const result = await this.converter.convertImage(validatedArgs); return { content: [ { type: 'text', text: `图片转换成功!\n输出文件:${result.output_path}\n文件大小:${result.file_size} bytes\n图片尺寸:${result.dimensions.width}x${result.dimensions.height}\n格式:${result.format}` } ] }; }
- src/converter.ts:73-217 (handler)Primary handler function implementing the image conversion logic, supporting various input/output formats with resizing and quality options.async convertImage(options: ConvertImageOptions): Promise<ConvertResult> { const { input_path, input_data, input_filename, output_format, quality, width, height, maintain_aspect_ratio = true, output_path } = options; let inputBuffer: Buffer; let inputFormat: string; // 处理不同的输入方式 if (input_data) { // 处理上传的文件数据 if (typeof input_data === 'string') { // 处理base64数据 const base64Data = input_data.includes(',') ? input_data.split(',')[1] : input_data; inputBuffer = Buffer.from(base64Data, 'base64'); } else { // 处理Buffer数据 inputBuffer = input_data; } // 从文件名获取格式 if (input_filename) { inputFormat = this.getFileFormat(input_filename); } else { // 尝试从Buffer检测格式 inputFormat = await this.detectFormatFromBuffer(inputBuffer); } } else if (input_path) { // 处理文件路径 try { await fs.access(input_path); inputBuffer = await fs.readFile(input_path); inputFormat = this.getFileFormat(input_path); } catch { throw new Error(`输入文件不存在: ${input_path}`); } } else { throw new Error('必须提供input_path或input_data参数'); } // 验证输出格式 const normalizedFormat = output_format.toLowerCase().replace('.', ''); if (!this.supportedOutputFormats.includes(normalizedFormat)) { throw new Error(`不支持的输出格式: ${output_format}`); } // 生成输出路径 const finalOutputPath = output_path || this.generateOutputPath( input_path || input_filename || `uploaded_image.${inputFormat}`, normalizedFormat ); // 确保输出目录存在 const outputDir = path.dirname(finalOutputPath); await fs.mkdir(outputDir, { recursive: true }); // 验证输入格式是否支持 if (!this.supportedInputFormats.includes(inputFormat)) { throw new Error(`不支持的输入格式: ${inputFormat}`); } // 对于特殊格式的处理说明 if (inputFormat === 'heic' || inputFormat === 'heif') { try { // Sharp 0.32+ 支持HEIC,但需要libvips支持 await sharp(inputBuffer).metadata(); } catch { throw new Error(`HEIC/HEIF格式需要系统支持libvips,请先转换为JPG或PNG格式`); } } else if (inputFormat === 'psd') { throw new Error(`PSD格式暂不支持,请使用Photoshop导出为JPG或PNG格式`); } try { let sharpInstance = sharp(inputBuffer); // 调整尺寸 if (width || height) { const resizeOptions: sharp.ResizeOptions = { fit: maintain_aspect_ratio ? 'inside' : 'fill', withoutEnlargement: false }; if (width && height) { sharpInstance = sharpInstance.resize(width, height, resizeOptions); } else if (width) { sharpInstance = sharpInstance.resize(width, undefined, resizeOptions); } else if (height) { sharpInstance = sharpInstance.resize(undefined, height, resizeOptions); } } // 根据格式设置输出选项 switch (normalizedFormat) { case 'jpg': case 'jpeg': sharpInstance = sharpInstance.jpeg({ quality: quality || 90 }); break; case 'png': sharpInstance = sharpInstance.png({ quality: quality || 90 }); break; case 'webp': sharpInstance = sharpInstance.webp({ quality: quality || 90 }); break; case 'gif': // Sharp不直接支持GIF输出,使用Jimp return await this.convertWithJimp(inputBuffer, finalOutputPath, normalizedFormat, { width, height, quality }); case 'bmp': // 使用Jimp处理BMP return await this.convertWithJimp(inputBuffer, finalOutputPath, normalizedFormat, { width, height, quality }); case 'tiff': sharpInstance = sharpInstance.tiff({ quality: quality || 90 }); break; case 'avif': sharpInstance = sharpInstance.avif({ quality: quality || 90 }); break; case 'ico': // ICO格式需要特殊处理 return await this.convertToIco(inputBuffer, finalOutputPath, { width: width || 32, height: height || 32 }); case 'svg': // SVG格式转换 return await this.convertToSvg(inputBuffer, finalOutputPath, { width, height }); default: throw new Error(`暂不支持转换为格式: ${normalizedFormat}`); } // 执行转换 await sharpInstance.toFile(finalOutputPath); // 获取结果信息 const stats = await fs.stat(finalOutputPath); const metadata = await sharp(finalOutputPath).metadata(); return { output_path: finalOutputPath, file_size: stats.size, dimensions: { width: metadata.width || 0, height: metadata.height || 0 }, format: normalizedFormat }; } catch (error) { throw new Error(`图片转换失败: ${error instanceof Error ? error.message : String(error)}`); } }
- src/converter.ts:6-16 (schema)TypeScript interface defining the options for the convertImage function.export interface ConvertImageOptions { input_path?: string; input_data?: Buffer | string; // 支持Buffer数据或base64字符串 input_filename?: string; // 原始文件名,用于确定格式 output_format: string; quality?: number; width?: number; height?: number; maintain_aspect_ratio?: boolean; output_path?: string; }