convert_and_resize
Convert images to different formats and resize them simultaneously for web optimization or specific platform requirements.
Instructions
Convert an image to a new format and resize it in a single operation.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| input_path | Yes | Absolute path to the source image file | |
| output_format | Yes | Target format | |
| quality | No | JPEG/WebP quality (1-100, default 90) | |
| width | No | Target width in pixels | |
| height | No | Target height in pixels | |
| preset | No | Named size preset (overrides width/height) | |
| lock_aspect_ratio | No | Keep aspect ratio (default true) | |
| output_path | No | Where to save the output |
Implementation Reference
- index.js:173-225 (handler)The registration and handler implementation of the 'convert_and_resize' tool.
server.tool( "convert_and_resize", "Convert an image to a new format and resize it in a single operation.", { input_path: z.string().describe("Absolute path to the source image file"), output_format: z.enum(["png", "jpeg", "gif", "webp", "ico"]).describe("Target format"), quality: z.number().int().min(1).max(100).optional().describe("JPEG/WebP quality (1-100, default 90)"), width: z.number().int().positive().optional().describe("Target width in pixels"), height: z.number().int().positive().optional().describe("Target height in pixels"), preset: z.enum([ "instagram-square", "instagram-portrait", "instagram-landscape", "twitter-post", "twitter-header", "full-hd", "4k", "youtube-thumbnail", "favicon", ]).optional().describe("Named size preset (overrides width/height)"), lock_aspect_ratio: z.boolean().optional().default(true).describe("Keep aspect ratio (default true)"), output_path: z.string().optional().describe("Where to save the output"), }, async ({ input_path, output_format, quality = 90, width, height, preset, lock_aspect_ratio = true, output_path }) => { try { await fs.access(input_path); let targetW = width; let targetH = height; if (preset) { targetW = PRESETS[preset].width; targetH = PRESETS[preset].height; } const outExt = output_format === "jpeg" ? "jpg" : output_format; const outPath = resolveOutputPath(input_path, outExt, output_path); if (output_format === "ico") { // For ICO, resize to 32x32 via encodeIco (which already resizes) const icoBuffer = await encodeIco(input_path); await fs.writeFile(outPath, icoBuffer); } else { let pipeline = sharp(input_path); if (targetW || targetH) { const fit = lock_aspect_ratio ? "inside" : "fill"; pipeline = pipeline.resize(targetW, targetH, { fit }); } pipeline = pipeline.toFormat(output_format, { quality }); await pipeline.toFile(outPath); } const stat = await fs.stat(outPath); const meta = await sharp(outPath).metadata(); return { content: [{ type: "text", text: JSON.stringify({ success: true, output_path: outPath, width: meta.width, height: meta.height, size_bytes: stat.size }) }], }; } catch (err) { return { isError: true, content: [{ type: "text", text: `Error: ${err.message}` }] }; } } );