UNPKG

tinify-client

Version:

A CLI to compress your images not only intelligently but also to the EXTREME!

138 lines (137 loc) 5.47 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.summarize = exports.compress = exports.DELTA = void 0; const path_1 = require("path"); const image_to_base64_1 = require("@legend80s/image-to-base64"); const colors_1 = require("../constants/colors"); const image_1 = require("../utils/image"); const lite_fs_1 = require("../utils/lite-fs"); // import { timeToReadable } from '../utils/lite-lodash'; const number_1 = require("../utils/number"); const lite_lodash_1 = require("../utils/lite-lodash"); const i18n_1 = require("../i18n"); const dictionary = i18n_1.i18n(); exports.DELTA = 1; async function compress(src, { tinify, output, verbose, inPlace, maxCount, dryRun, }) { const startAt = Date.now(); if (!output) { output = await resolveOutput(src, { verbose, inPlace }); } else if (lite_fs_1.isDirectory(output)) { let filename = path_1.basename(src); if (image_to_base64_1.isRemoteFile(src)) { const ext = await image_to_base64_1.resolveExtFromRemote(src); if (ext) { filename = `${filename}.${ext}`; } } output = path_1.join(output, filename); // console.log('isDirectory output:', output); } // return; // const tmpFiles = []; const sizes = []; let tmpSrc = src; if (dryRun) { return { sizes: new Array(maxCount).fill([0, 0]), dest: output, hasCompressedToExtreme: false, costs: Date.now() - startAt }; } for (let i = 0; i < maxCount; ++i) { // const tmpOutput = output.replace(/(-\d)*.png/, `-${idx+1}.png`); const { sizeBefore, sizeAfter } = await minify(tmpSrc, { dest: output, verbose, tinify }); const diff = sizeBefore - sizeAfter; tmpSrc = output; sizes.push([sizeBefore, sizeAfter]); if (diff <= exports.DELTA) { if (verbose) { console.log(colors_1.GREEN, `${diff} Bytes reduced in the last turn and it is less than the delta ${exports.DELTA} Bytes. Compressing is ready to abort.`, colors_1.EOS); } return { sizes, dest: output, hasCompressedToExtreme: true, costs: Date.now() - startAt }; } } return { sizes, dest: output, hasCompressedToExtreme: false, costs: Date.now() - startAt }; } exports.compress = compress; async function minify(src, { dest, verbose = false, tinify }) { verbose && console.time(colors_1.GREEN + ' compress ' + src + ' costs' + colors_1.EOS); const sizeBefore = await image_1.getImageSize(src); try { await (image_to_base64_1.isRemoteFile(src) ? tinify.fromUrl(src) : tinify.fromFile(src)).toFile(dest); } catch (error) { console.error(colors_1.RED, 'tinify failed:', error); console.log(colors_1.EOS); throw error; } finally { verbose && console.timeEnd(colors_1.GREEN + ' compress ' + src + ' costs' + colors_1.EOS); } // console.log(GREEN, 'compressed successfully'); // console.log('', src, 'has been optimized to', dest); // console.log(EOS); // console.time(' getImageSize costs') try { const sizeAfter = await image_1.getImageSize(dest); const diff = sizeBefore - sizeAfter; const percentage = `${number_1.getPercentageOff(sizeBefore, sizeAfter)}%`; verbose && console.log(colors_1.GREEN, `Images compressed successfully: before ${sizeBefore} Bytes after ${sizeAfter} Bytes, ${diff} Bytes (${percentage}) off.`, colors_1.EOS); // console.timeEnd(' getImageSize costs') return { sizeBefore, sizeAfter }; } catch (error) { console.error(colors_1.RED, 'getImageSize failed:', error, colors_1.EOS); throw error; } } /** * @param {string} endpoint local image path or */ async function resolveOutput(endpoint, { verbose = false, inPlace = false } = {}) { const label = colors_1.GREEN + `no output resolve filename from url ` + endpoint + ' costs' + colors_1.EOS; verbose && console.time(label); let filename = ''; try { filename = await resolveFilenameFromEndpoint(endpoint, { inPlace }); } finally { verbose && console.timeEnd(label); } const output = filename; verbose && console.log('output after resolved:', output); return output; } /** * @param {string} endpoint * @returns {Promise<string>} */ async function resolveFilenameFromEndpoint(endpoint, { inPlace = false } = {}) { var _a; if (!image_to_base64_1.isRemoteFile(endpoint)) { return inPlace ? endpoint : // a => a-compressed // a.png => a-compressed.png endpoint.replace(/(\.\w+)?$/, (_m, $1) => `-compressed${$1 || ''}`); } const filename = ((_a = endpoint.split('/').pop()) === null || _a === void 0 ? void 0 : _a.replace(/\?.*/, '')) || endpoint; if (/\.\w+$/.test(filename)) { return filename; } const ext = await image_to_base64_1.resolveExtFromRemote(endpoint); if (ext) { return `${filename}.${ext}`; } return filename; } function summarize({ dest, sizes, costs }) { const firstTurn = sizes[0]; const lastTurn = lite_lodash_1.last(sizes); return dictionary.summarize({ dest, beforeSizeInByte: firstTurn[0], afterSizeInByte: lastTurn[1], nTurns: sizes.length, lastTurnDelta: lastTurn[0] - lastTurn[1], costs, }); } exports.summarize = summarize;