code icon Code

Process Image

Resize, convert, and manipulate images

Source Code

import fs from "fs";
import path from "path";
import sharp from "sharp";

const [inputPath, outputPath, operationsJson] = process.argv.slice(2);

if (!inputPath || !outputPath || !operationsJson) {
  console.error("Usage: inputPath outputPath operationsJson");
  process.exit(1);
}

try {
  console.log(`Processing image: ${inputPath}...`);

  let ops;
  try {
    ops = JSON.parse(operationsJson);
  } catch {
    console.error("Invalid operations JSON:", operationsJson);
    process.exit(1);
  }

  let image = sharp(inputPath);

  // Get original metadata
  const metadata = await image.metadata();
  console.log(`  Original: ${metadata.width}x${metadata.height} ${metadata.format}`);

  // Apply resize if specified
  if (ops.resize) {
    const [width, height] = ops.resize;
    image = image.resize(width || null, height || null, {
      fit: ops.fit || "inside",
      withoutEnlargement: ops.withoutEnlargement !== false,
    });
    console.log(`  Resize: ${width || "auto"}x${height || "auto"}`);
  }

  // Apply rotation if specified
  if (ops.rotate) {
    image = image.rotate(ops.rotate);
    console.log(`  Rotate: ${ops.rotate}°`);
  }

  // Apply flip/flop if specified
  if (ops.flip) {
    image = image.flip();
    console.log(`  Flip: vertical`);
  }
  if (ops.flop) {
    image = image.flop();
    console.log(`  Flop: horizontal`);
  }

  // Apply grayscale if specified
  if (ops.grayscale || ops.greyscale) {
    image = image.grayscale();
    console.log(`  Grayscale: true`);
  }

  // Apply blur if specified
  if (ops.blur) {
    image = image.blur(ops.blur);
    console.log(`  Blur: ${ops.blur}`);
  }

  // Apply sharpen if specified
  if (ops.sharpen) {
    image = image.sharpen();
    console.log(`  Sharpen: true`);
  }

  // Set output format and quality
  const format = ops.format || path.extname(outputPath).slice(1) || "jpeg";
  const quality = ops.quality || 80;

  switch (format) {
    case "jpeg":
    case "jpg":
      image = image.jpeg({ quality });
      break;
    case "png":
      image = image.png({ quality });
      break;
    case "webp":
      image = image.webp({ quality });
      break;
    case "avif":
      image = image.avif({ quality });
      break;
    case "tiff":
      image = image.tiff({ quality });
      break;
    default:
      image = image.toFormat(format);
  }

  console.log(`  Format: ${format}, Quality: ${quality}`);

  // Ensure output directory exists
  const dir = path.dirname(outputPath);
  if (dir && dir !== ".") {
    fs.mkdirSync(dir, { recursive: true });
  }

  const info = await image.toFile(outputPath);

  console.log(`\n✓ Processed image`);
  console.log(`  Output: ${info.width}x${info.height} ${info.format}`);
  console.log(`  Size: ${(info.size / 1024).toFixed(1)} KB`);
  console.log(`  Written to: ${outputPath}`);

  console.log(
    JSON.stringify({
      success: true,
      inputPath,
      outputPath,
      original: {
        width: metadata.width,
        height: metadata.height,
        format: metadata.format,
      },
      output: {
        width: info.width,
        height: info.height,
        format: info.format,
        size: info.size,
      },
    })
  );
} catch (error) {
  console.error("Error:", error.message);
  process.exit(1);
}