UNPKG

@gld5000-cli/image-scripts

Version:

A useful collection of image processing scripts

130 lines (125 loc) 3.75 kB
import path from "path"; import { exec } from "child_process"; import webp from "webp-converter"; import { getImageDimensions, getEvenImageDimensions, copyFileToSubFolder, cropInputFrame, } from "../imageProcessing/imageEditing.mjs"; import ffmpeg from "@ffmpeg-installer/ffmpeg"; import { webpmux_animateLocal } from "../../webp/webpConverterLocal.mjs"; import { isImageFile } from "../general/fileTypeTests.mjs"; import { getTargetPath, getPathParts } from "../general/fileOperations.mjs"; import sharp from "sharp"; /** * Loop through list of files with name and path * Create webp frames in new directory * Mux frames to animated webp * Return animated webp path string * @param {string[]} fileListFullPath * @returns {Promise<{newFileList: string[], backupList: string[]}>} */ export async function createWebPAnimation(fileListFullPath) { // Validate inputs if (!Array.isArray(fileListFullPath) || fileListFullPath.length === 0) { throw new Error("Input files must be a non-empty array"); } const webpFrames = await makeWebpFrames(fileListFullPath); await makeWebpAnimation(webpFrames); makeMp4Animation(fileListFullPath); } /** * * @param {string} fileListFullPath * @returns {void} */ async function makeMp4Animation(fileListFullPath) { const { extension, dirName } = getPathParts(fileListFullPath[0]); const { width, height } = await getImageDimensions(fileListFullPath[0]); // -stream_loop -1 const ffmpegCommand = `"${ffmpeg.path}" -framerate 1 -i "${path.join( dirName, `%d${extension}` )}" -c:v libx264 -pix_fmt yuv420p -y "${path.join( dirName, "processed", "animation", `output-mp_${width}_${height}.mp4` )}"`; console.log(ffmpegCommand); exec(ffmpegCommand, (error, stdout, stderr) => { if (error) { console.error(`Error: ${error}`); return; } if (stdout) { console.log("stdout", stdout); } if (stderr) { console.log(`FFmpeg output: ${stderr}`); } }); } /** * * @param {string} outputArray * @returns {void} */ async function makeWebpAnimation(outputArray) { const outputFrames = outputArray.map((outputPath) => { return { path: outputPath, offset: "+1000" }; }); try { const { width, height } = await getImageDimensions(outputArray[0]); const animationPath = await getTargetPath(outputArray[0], { fileName: "output-webp", folders:['animation'], suffix: `_${width}_${height}`, }); await webpmux_animateLocal( outputFrames, animationPath, "0", "255,255,255,255" ); console.log("Created webpmux_animate:", animationPath); } catch (error) { console.log("Error with webpmux_animate", error); } } /** * * @param {string} fileListFullPath * @returns {string[]} */ async function makeWebpFrames(fileListFullPath) { const outputArray = []; const { width, height, shouldCrop } = await getEvenImageDimensions( fileListFullPath[0] ); for (const file of fileListFullPath) { const isImage = isImageFile(file); if (isImage) { shouldCrop && (await cropInputFrame(file, width, height)); // Crop as needed outputArray.push(await makeWebpFrame(file)); } } return outputArray; } /** * * @param {string} file * @param {string[]} outputArray * @returns */ async function makeWebpFrame(file) { try { const outputPath = await getTargetPath(file, { folders: ["processed"] }); await webp.cwebp(file, outputPath); console.log("Created webp:", outputPath); return outputPath; } catch (error) { console.log("Error with cwebp", error); } }