From f0eb79f2f11ee8663a7cd4114f3aaa8266f9e2f5 Mon Sep 17 00:00:00 2001 From: Surma Date: Wed, 9 Sep 2020 15:22:39 +0100 Subject: [PATCH] Use all the codecs --- cli/index.js | 191 +++++++++++++++++++++++++++++++++--------- cli/package-lock.json | 13 +++ cli/package.json | 3 +- 3 files changed, 167 insertions(+), 40 deletions(-) diff --git a/cli/index.js b/cli/index.js index 7fa64ac5..e11c86d5 100644 --- a/cli/index.js +++ b/cli/index.js @@ -1,16 +1,108 @@ -const mozjpeg_dec = require("../codecs/mozjpeg/dec/mozjpeg_dec.js"); -const mozjpeg_enc = require("../codecs/mozjpeg/enc/mozjpeg_enc.js"); -const webp_enc = require("../codecs/webp/enc/webp_enc.js"); +const { program } = require("commander"); +const JSON5 = require("json5"); +//const { Worker, isMainThread, parentPort } = require('worker_threads'); +//const {cpus} = require("os"); +const path = require("path"); +const fsp = require("fs").promises; + const visdifModule = require("../codecs/visdif/visdif.js"); // Our decoders currently rely on this. globalThis.ImageData = require("./image_data.js"); -const fsp = require("fs").promises; - +const supportedFormats = { + mozjpeg: { + name: "MozJPEG", + extension: "jpg", + detectors: [/^\xFF\xD8\xFF/], + dec: require("../codecs/mozjpeg/dec/mozjpeg_dec.js"), + enc: require("../codecs/mozjpeg/enc/mozjpeg_enc.js"), + defaultEncoderOptions: { + quality: 75, + baseline: false, + arithmetic: false, + progressive: true, + optimize_coding: true, + smoothing: 0, + color_space: 3 /*YCbCr*/, + quant_table: 3, + trellis_multipass: false, + trellis_opt_zero: false, + trellis_opt_table: false, + trellis_loops: 1, + auto_subsample: true, + chroma_subsample: 2, + separate_chroma_quality: false, + chroma_quality: 75 + } + }, + webp: { + name: "WebP", + extension: "webp", + detectors: [/^RIFF....WEBPVP8[LX ]/], + dec: require("../codecs/webp/dec/webp_dec.js"), + enc: require("../codecs/webp/enc/webp_enc.js"), + defaultEncoderOptions: { + quality: 75, + target_size: 0, + target_PSNR: 0, + method: 4, + sns_strength: 50, + filter_strength: 60, + filter_sharpness: 0, + filter_type: 1, + partitions: 0, + segments: 4, + pass: 1, + show_compressed: 0, + preprocessing: 0, + autofilter: 0, + partition_limit: 0, + alpha_compression: 1, + alpha_filtering: 1, + alpha_quality: 100, + lossless: 0, + exact: 0, + image_hint: 0, + emulate_jpeg_size: 0, + thread_level: 0, + low_memory: 0, + near_lossless: 100, + use_delta_palette: 0, + use_sharp_yuv: 0 + } + }, + avif: { + name: "AVIF", + extension: "avif", + detectors: [/^\x00\x00\x00 ftypavif\x00\x00\x00\x00/], + dec: require("../codecs/avif/dec/avif_dec.js"), + enc: require("../codecs/avif/enc/avif_enc.js"), + defaultEncoderOptions: { + minQuantizer: 16, + maxQuantizer: 16, + tileColsLog2: 0, + tileRowsLog2: 0, + speed: 10, + subsample: 0 + } + } +}; async function decodeFile(file) { const buffer = await fsp.readFile(file); - const rgba = (await mozjpeg_dec()).decode(new Uint8Array(buffer)); + const firstChunk = buffer.slice(0, 16); + const firstChunkString = Array.from(firstChunk) + .map(v => String.fromCodePoint(v)) + .join(""); + const key = Object.entries(supportedFormats).find(([name, { detectors }]) => + detectors.some(detector => detector.exec(firstChunkString)) + )?.[0]; + if (!key) { + throw Error(`${file} has an unsupported format`); + } + const rgba = (await supportedFormats[key].dec()).decode( + new Uint8Array(buffer) + ); return rgba; } @@ -63,40 +155,61 @@ async function optimize(bitmapIn, encode, decode) { }; } -async function main() { - const [, , inFile, outFile] = process.argv; - const bitmapIn = await decodeFile(inFile); +//if(isMainThread) { +program + .version(require("./package.json").version) + .arguments("") + .option("-d, --output-dir ", "Output directory", "."); - const jpegEncModule = await mozjpeg_enc(); - const jpegEnc = async (bitmap, quality) => - jpegEncModule.encode(bitmap.data.buffer, bitmap.width, bitmap.height, { - quality, - baseline: false, - arithmetic: false, - progressive: true, - optimize_coding: true, - smoothing: 0, - color_space: 3 /*YCbCr*/, - quant_table: 3, - trellis_multipass: false, - trellis_opt_zero: false, - trellis_opt_table: false, - trellis_loops: 1, - auto_subsample: true, - chroma_subsample: 2, - separate_chroma_quality: false, - chroma_quality: 75 - }); - const jpegDecModule = await mozjpeg_dec(); - const jpegDec = async binary => jpegDecModule.decode(binary); - const jpegOut = await optimize(bitmapIn, jpegEnc, jpegDec); - await fsp.writeFile("out.jpg", jpegOut.binary); - //await webp_enc(); - //console.log(bitmapIn); +// Create a CLI option for each supported encoder +for (const [key, value] of Object.entries(supportedFormats)) { + program.option( + `--${key} [config]`, + `Use ${value.name} to generate a .${value.extension} file with the given configuration` + ); } -main().catch(err => { - console.error("Something went wrong"); - console.error(err); - process.exit(1); +program.action(async files => { + // Create output directory + await fsp.mkdir(program.outputDir, { recursive: true }); + //const pool = Array.from({length: cpus().length}, () => new Worker(process.argv[1])); + let i = 0; + for (const file of files) { + const ext = path.extname(file); + const base = path.basename(file, ext); + const bitmapIn = await decodeFile(file); + + for (const [key, value] of Object.entries(supportedFormats)) { + if (!program[key]) { + continue; + } + const encConfig = Object.assign( + {}, + value.defaultEncoderOptions, + JSON5.parse(program[key]) + ); + const encoder = await value.enc(); + const out = encoder.encode( + bitmapIn.data.buffer, + bitmapIn.width, + bitmapIn.height, + encConfig + ); + const outputFile = path.join( + program.outputDir, + `${base}.${value.extension}` + ); + await fsp.writeFile(outputFile, out); + } + // pool[i].postMessage({ + // inFile: file, + // outFile: path.join(program.outputDir, base,kkkkk + // }) + } }); + +program.parse(process.argv); +//} else { +// parentPort.on("message", async ({inFile, outFile, encoder, config}) => { +// }); +//} diff --git a/cli/package-lock.json b/cli/package-lock.json index e84d7743..72557c87 100644 --- a/cli/package-lock.json +++ b/cli/package-lock.json @@ -8,6 +8,19 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/commander/-/commander-6.0.0.tgz", "integrity": "sha512-s7EA+hDtTYNhuXkTlhqew4txMZVdszBmKWSPEMxGr8ru8JXR7bLUFIAtPhcSuFdJQ0ILMxnJi8GkQL0yvDy/YA==" + }, + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "requires": { + "minimist": "^1.2.5" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" } } } diff --git a/cli/package.json b/cli/package.json index f11643a7..b2ab8641 100644 --- a/cli/package.json +++ b/cli/package.json @@ -10,6 +10,7 @@ "author": "Surma ", "license": "Apache-2.0", "dependencies": { - "commander": "^6.0.0" + "commander": "^6.0.0", + "json5": "^2.1.3" } }