From e5806507d4bbe7b0c60e8bb7cf5247e9c0bca01a Mon Sep 17 00:00:00 2001 From: Steven Date: Fri, 20 Aug 2021 15:11:14 -0400 Subject: [PATCH] Remove Node.js API surface in libsquoosh --- cli/src/index.js | 10 ++++++---- libsquoosh/README.md | 8 +++++--- libsquoosh/src/index.ts | 30 +++++++----------------------- 3 files changed, 18 insertions(+), 30 deletions(-) diff --git a/cli/src/index.js b/cli/src/index.js index 331d31b7..16971208 100755 --- a/cli/src/index.js +++ b/cli/src/index.js @@ -75,7 +75,9 @@ async function getInputFiles(paths) { for (const inputPath of paths) { const files = (await fsp.lstat(inputPath)).isDirectory() - ? (await fsp.readdir(inputPath, {withFileTypes: true})).filter(dirent => dirent.isFile()).map(dirent => path.join(inputPath, dirent.name)) + ? (await fsp.readdir(inputPath, { withFileTypes: true })) + .filter((dirent) => dirent.isFile()) + .map((dirent) => path.join(inputPath, dirent.name)) : [inputPath]; for (const file of files) { try { @@ -101,7 +103,7 @@ async function getInputFiles(paths) { async function processFiles(files) { files = await getInputFiles(files); - const imagePool = new ImagePool(); + const imagePool = new ImagePool(cpus().length); const results = new Map(); const progress = progressTracker(results); @@ -116,7 +118,7 @@ async function processFiles(files) { let decoded = 0; let decodedFiles = await Promise.all( files.map(async (file) => { - const image = imagePool.ingestImage(file); + const image = imagePool.ingestImage(fsp.readFile(file)); await image.decoded; results.set(image, { file, @@ -178,7 +180,7 @@ async function processFiles(files) { const outputPath = path.join( program.opts().outputDir, path.basename(originalFile, path.extname(originalFile)) + - program.opts().suffix + program.opts().suffix, ); for (const output of Object.values(image.encodedWith)) { const outputFile = `${outputPath}.${(await output).extension}`; diff --git a/libsquoosh/README.md b/libsquoosh/README.md index 80217af5..f3c84563 100644 --- a/libsquoosh/README.md +++ b/libsquoosh/README.md @@ -16,7 +16,8 @@ You can start using the libSquoosh by adding these lines to the top of your JS p ```js import { ImagePool } from '@squoosh/lib'; -const imagePool = new ImagePool((url) => fs.readFile(url)); +import { cpus } from 'os'; +const imagePool = new ImagePool(cpus().length); ``` This will create an image pool with an underlying processing pipeline that you can use to ingest and encode images. The ImagePool constructor takes one argument that defines how many parallel operations it is allowed to run at any given time. By default, this number is set to the amount of CPU cores available in the system it is running on. @@ -26,11 +27,12 @@ This will create an image pool with an underlying processing pipeline that you c You can ingest a new image like so: ```js -const imagePath = 'file://path/to/image.png'; +import fs from 'fs/promises'; +const file = await fs.readFile('./path/to/image.png'); const image = imagePool.ingestImage(imagePath); ``` -The `ingestImage` function will accept a URL path and call the `loadFile()` function defined in the `ImagePool`. +The `ingestImage` function can accept any [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) whether that is from `readFile()` or `fetch()`. The returned `image` object is a representation of the original image, that you can now preprocess, encode, and extract information about. diff --git a/libsquoosh/src/index.ts b/libsquoosh/src/index.ts index 93041c2c..21620829 100644 --- a/libsquoosh/src/index.ts +++ b/libsquoosh/src/index.ts @@ -1,5 +1,4 @@ import { isMainThread } from 'worker_threads'; -import { promises as fsp } from 'fs'; import { codecs as encoders, preprocessors } from './codecs.js'; import WorkerPool from './worker_pool.js'; @@ -9,26 +8,15 @@ import type ImageData from './image_data'; export { ImagePool, encoders, preprocessors }; type EncoderKey = keyof typeof encoders; type PreprocessorKey = keyof typeof preprocessors; -type FileLike = Buffer | ArrayBuffer | string | ArrayBufferView; async function decodeFile({ file, }: { - file: FileLike; + file: ArrayBuffer; }): Promise<{ bitmap: ImageData; size: number }> { - let buffer; - if (ArrayBuffer.isView(file)) { - buffer = Buffer.from(file.buffer); - file = 'Binary blob'; - } else if (file instanceof ArrayBuffer) { + let buffer: Buffer; + if (file instanceof ArrayBuffer) { buffer = Buffer.from(file); - file = 'Binary blob'; - } else if ((file as unknown) instanceof Buffer) { - // TODO: Check why we need type assertions here. - buffer = (file as unknown) as Buffer; - file = 'Binary blob'; - } else if (typeof file === 'string') { - buffer = await fsp.readFile(file); } else { throw Error('Unexpected input type'); } @@ -40,7 +28,7 @@ async function decodeFile({ detectors.some((detector) => detector.exec(firstChunkString)), )?.[0] as EncoderKey | undefined; if (!key) { - throw Error(`${file} has an unsupported format`); + throw Error(`File has an unsupported format`); } const encoder = encoders[key]; const mod = await encoder.dec(); @@ -250,25 +238,21 @@ class Image { */ class ImagePool { public workerPool: WorkerPool; - public loadFile: (path: URL) => Promise; /** * Create a new pool. - * @param {(path: URL) => Promise} [loadFile] - A function that loads a file from a URL. * @param {number} [threads] - Number of concurrent image processes to run in the pool. */ - constructor(loadFile: (path: URL) => Promise, threads: number) { - this.loadFile = loadFile; + constructor(threads: number) { this.workerPool = new WorkerPool(threads, __filename); } /** * Ingest an image into the image pool. - * @param {URL} url - The URL path to the image that should be ingested and decoded. + * @param {ArrayBuffer} file - The image that should be ingested and decoded. * @returns {Image} - A custom class reference to the decoded image. */ - ingestImage(url: URL): Image { - const file = await this.loadFile(url); + ingestImage(file: ArrayBuffer): Image { return new Image(this.workerPool, file); }