import * as fs from 'fs'
import * as path from 'path'
import tinify from 'tinify'
import { isSupportedImageFile } from './fileUtils.js'
import type { ResizeMethod } from './types.js'
/**
* Resize an image using TinyPNG resize API.
*
* @param imagePath Path to the input image file.
* @param width Target width in pixels.
* @param height Target height in pixels.
* @param method Resize method ('fit', 'scale', 'cover', 'thumb').
* @param outputPath Optional output path. If not provided, will overwrite the original file.
* @returns Promise that resolves when resize is complete.
*/
export async function resizeImage(
imagePath: string,
width: number,
height: number,
method: ResizeMethod,
outputPath?: string,
): Promise<void> {
/* Validate input file exists */
if (!fs.existsSync(imagePath)) {
throw new Error(`Input file does not exist: ${imagePath}`)
}
/* Validate file is supported image format */
if (!isSupportedImageFile(imagePath)) {
throw new Error(`Unsupported image format: ${path.extname(imagePath)}`)
}
/* Validate dimensions */
if (width <= 0 || height <= 0) {
throw new Error('Width and height must be positive numbers')
}
const finalOutputPath = outputPath ?? imagePath
/* Ensure output directory exists */
const outputDir = path.dirname(finalOutputPath)
if (!fs.existsSync(outputDir)) {
await fs.promises.mkdir(outputDir, { recursive: true })
}
return new Promise((resolve, reject) => {
try {
const source = tinify.fromFile(imagePath)
/* Apply resize with the specified method */
const resized = source.resize({
method,
width,
height,
})
resized.toFile(finalOutputPath, (err: any) => {
if (err) {
reject(new Error(`Failed to resize image: ${err.message}`))
} else {
resolve()
}
})
} catch (error) {
reject(new Error(`Failed to process image: ${error instanceof Error ? error.message : 'Unknown error'}`))
}
})
}