diff --git a/admin/scripts/resizeImage.js b/admin/scripts/resizeImage.js new file mode 100644 index 000000000..82a2a4785 --- /dev/null +++ b/admin/scripts/resizeImage.js @@ -0,0 +1,92 @@ +import fs from 'fs-extra'; +import path from 'path'; +import {fileURLToPath} from 'url'; +import {program} from 'commander'; +import logger from '@docusaurus/logger'; +import sharp from 'sharp'; +import imageSize from 'image-size'; + +// You can use it as: +// +// # Resize all images in showcase (which is most likely) +// node admin/scripts/resizeImage.js +// +// # Resize specified images / all images in a folder +// # This does not read folders recursively as of now +// node admin/scripts/resizeImage.js image1.png some-folder ... +// +// By default, showcase images are resized to 640×320; everything else is +// resized to width 1000. You can explicitly give a width/height as arguments. +// node admin/scripts/resizeImage.js --width 640 --height 320 image1.png + +function maybeParseInt(n) { + const res = Number.parseInt(n, 10); + if (Number.isNaN(res)) { + return undefined; + } + return res; +} + +const showcasePath = 'src/data/showcase'; + +program + .arguments('[imagePaths...]') + .option('-w, --width ', 'Image width', maybeParseInt) + .option('-h, --height ', 'Image height', maybeParseInt) + .action(async (imagePaths, options) => { + if (imagePaths.length === 0) { + imagePaths.push(showcasePath); + } + const rootDir = fileURLToPath(new URL('../..', import.meta.url)); + const images = ( + await Promise.all( + imagePaths.map(async (p) => + path.extname(p) + ? [path.resolve(rootDir, p)] + : (await fs.readdir(p)).map((f) => path.resolve(rootDir, p, f)), + ), + ) + ) + .flat() + .filter((p) => ['.png', 'jpg', '.jpeg'].includes(path.extname(p))); + + const stats = { + skipped: 0, + resized: 0, + }; + + await Promise.all( + images.map(async (imgPath) => { + const {width, height} = imageSize(imgPath); + const targetWidth = + options.width ?? (imgPath.includes(showcasePath) ? 640 : 1000); + const targetHeight = + options.height ?? (imgPath.includes(showcasePath) ? 320 : undefined); + if ( + width <= targetWidth && + (!targetHeight || height <= targetHeight) && + imgPath.endsWith('.png') + ) { + // Do not emit if not resized. Important because we can't guarantee + // idempotency during resize -> optimization + stats.skipped += 1; + return; + } + logger.info`Resized path=${imgPath}: before number=${width}×number=${height}; now number=${targetWidth}×number=${ + targetHeight ?? Math.floor((height / width) * targetWidth) + }`; + const data = await sharp(imgPath) + .resize(targetWidth, targetHeight, {fit: 'cover', position: 'top'}) + .png() + .toBuffer(); + await fs.writeFile(imgPath.replace(/jpe?g/, 'png'), data); + stats.resized += 1; + }), + ); + + logger.info`Images resizing complete. + resized: number=${stats.resized} + skipped: number=${stats.skipped}`; + }); + +program.parse(process.argv); \ No newline at end of file diff --git a/src/data/showcase/3d-0scrolling-animation.png b/src/data/showcase/3d-0scrolling-animation.png index 988d5bef4..6717fdaaf 100644 Binary files a/src/data/showcase/3d-0scrolling-animation.png and b/src/data/showcase/3d-0scrolling-animation.png differ diff --git a/src/data/showcase/8-puzzle.png b/src/data/showcase/8-puzzle.png index 7918a835e..4f70cd408 100644 Binary files a/src/data/showcase/8-puzzle.png and b/src/data/showcase/8-puzzle.png differ diff --git a/src/data/showcase/BMI-calculator.png b/src/data/showcase/BMI-calculator.png index 2010653bf..6e5c6d79e 100644 Binary files a/src/data/showcase/BMI-calculator.png and b/src/data/showcase/BMI-calculator.png differ diff --git a/src/data/showcase/Dictonary.png b/src/data/showcase/Dictonary.png index a7cb8a6c2..ab52e4f2b 100644 Binary files a/src/data/showcase/Dictonary.png and b/src/data/showcase/Dictonary.png differ diff --git a/src/data/showcase/Smart-tv.png b/src/data/showcase/Smart-tv.png index 3aa919677..2269613ac 100644 Binary files a/src/data/showcase/Smart-tv.png and b/src/data/showcase/Smart-tv.png differ diff --git a/src/data/showcase/URLShortner.png b/src/data/showcase/URLShortner.png index e0bd31363..c84631695 100644 Binary files a/src/data/showcase/URLShortner.png and b/src/data/showcase/URLShortner.png differ diff --git a/src/data/showcase/activitar.png b/src/data/showcase/activitar.png index 84d860737..91728f85f 100644 Binary files a/src/data/showcase/activitar.png and b/src/data/showcase/activitar.png differ diff --git a/src/data/showcase/age-calculator-ss.png b/src/data/showcase/age-calculator-ss.png index 4a58a425c..a22043584 100644 Binary files a/src/data/showcase/age-calculator-ss.png and b/src/data/showcase/age-calculator-ss.png differ diff --git a/src/data/showcase/anime.png b/src/data/showcase/anime.png index 663444762..702bb9809 100644 Binary files a/src/data/showcase/anime.png and b/src/data/showcase/anime.png differ diff --git a/src/data/showcase/array-explorer.png b/src/data/showcase/array-explorer.png index e36591726..f01bd3b52 100644 Binary files a/src/data/showcase/array-explorer.png and b/src/data/showcase/array-explorer.png differ diff --git a/src/data/showcase/budget.png b/src/data/showcase/budget.png index 30e9ff3d5..46d6a3240 100644 Binary files a/src/data/showcase/budget.png and b/src/data/showcase/budget.png differ diff --git a/src/data/showcase/captcha-code.png b/src/data/showcase/captcha-code.png index e2fb3cc1c..6cefdf1ee 100644 Binary files a/src/data/showcase/captcha-code.png and b/src/data/showcase/captcha-code.png differ diff --git a/src/data/showcase/chatbot.png b/src/data/showcase/chatbot.png index fbbe055b9..e55e4dd06 100644 Binary files a/src/data/showcase/chatbot.png and b/src/data/showcase/chatbot.png differ diff --git a/src/data/showcase/crossfits.png b/src/data/showcase/crossfits.png index ec2983aeb..37245ec9c 100644 Binary files a/src/data/showcase/crossfits.png and b/src/data/showcase/crossfits.png differ diff --git a/src/data/showcase/currency.png b/src/data/showcase/currency.png index b073304be..9b9f12bd8 100644 Binary files a/src/data/showcase/currency.png and b/src/data/showcase/currency.png differ diff --git a/src/data/showcase/flappy_game.png b/src/data/showcase/flappy_game.png index 0e42c2206..339939a0d 100644 Binary files a/src/data/showcase/flappy_game.png and b/src/data/showcase/flappy_game.png differ diff --git a/src/data/showcase/gemini-ai-chatbot.png b/src/data/showcase/gemini-ai-chatbot.png index 667bc52fb..8fdb41de9 100644 Binary files a/src/data/showcase/gemini-ai-chatbot.png and b/src/data/showcase/gemini-ai-chatbot.png differ diff --git a/src/data/showcase/guessnumber-ss.png b/src/data/showcase/guessnumber-ss.png index 9da5a203c..ff278530e 100644 Binary files a/src/data/showcase/guessnumber-ss.png and b/src/data/showcase/guessnumber-ss.png differ diff --git a/src/data/showcase/meme.png b/src/data/showcase/meme.png index 29638ffff..3833ff200 100644 Binary files a/src/data/showcase/meme.png and b/src/data/showcase/meme.png differ diff --git a/src/data/showcase/movie_recommender.png b/src/data/showcase/movie_recommender.png index 5e2057369..b0ab5f559 100644 Binary files a/src/data/showcase/movie_recommender.png and b/src/data/showcase/movie_recommender.png differ diff --git a/src/data/showcase/number-guess.png b/src/data/showcase/number-guess.png index c2f1bdb8a..8f2b6d3a2 100644 Binary files a/src/data/showcase/number-guess.png and b/src/data/showcase/number-guess.png differ diff --git a/src/data/showcase/portfolio.png b/src/data/showcase/portfolio.png index f8d6c3a6d..37053b6ea 100644 Binary files a/src/data/showcase/portfolio.png and b/src/data/showcase/portfolio.png differ diff --git a/src/data/showcase/pull.png b/src/data/showcase/pull.png index 05a94b9ae..398ae3f57 100644 Binary files a/src/data/showcase/pull.png and b/src/data/showcase/pull.png differ diff --git a/src/data/showcase/qr_generator-ss.png b/src/data/showcase/qr_generator-ss.png index 0bbaed954..a98cb3f39 100644 Binary files a/src/data/showcase/qr_generator-ss.png and b/src/data/showcase/qr_generator-ss.png differ diff --git a/src/data/showcase/ridhi-portfolio.png b/src/data/showcase/ridhi-portfolio.png index cff46bb10..1913c1f4e 100644 Binary files a/src/data/showcase/ridhi-portfolio.png and b/src/data/showcase/ridhi-portfolio.png differ diff --git a/src/data/showcase/to-do-js-app.png b/src/data/showcase/to-do-js-app.png index ea25441cb..7acf21ced 100644 Binary files a/src/data/showcase/to-do-js-app.png and b/src/data/showcase/to-do-js-app.png differ diff --git a/src/data/showcase/todo-list.png b/src/data/showcase/todo-list.png index c3d312bf2..058f7ba6d 100644 Binary files a/src/data/showcase/todo-list.png and b/src/data/showcase/todo-list.png differ diff --git a/src/data/showcase/todolist.png b/src/data/showcase/todolist.png index fdeb41ed2..3aa2bd56e 100644 Binary files a/src/data/showcase/todolist.png and b/src/data/showcase/todolist.png differ diff --git a/src/data/showcase/video-game-portal.png b/src/data/showcase/video-game-portal.png index 5e1d134c6..ccad91934 100644 Binary files a/src/data/showcase/video-game-portal.png and b/src/data/showcase/video-game-portal.png differ