From 66fea49c646d8506b118a06e35bbe74dff66550e Mon Sep 17 00:00:00 2001 From: thinknathan Date: Wed, 20 Dec 2023 21:25:23 -0800 Subject: [PATCH 1/4] Update description of args --- slice.cjs | 4 ++-- src/slice.ts | 4 ++-- utils/processImage.js | 4 ++-- utils/workerPool.js | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/slice.cjs b/slice.cjs index 6dcd2e1..e20793c 100644 --- a/slice.cjs +++ b/slice.cjs @@ -19,7 +19,7 @@ const options = yargs }) .option('w', { alias: 'width', - describe: 'Output image width', + describe: 'Width of each slice', type: 'number', demandOption: true, coerce: (value) => { @@ -31,7 +31,7 @@ const options = yargs }) .option('h', { alias: 'height', - describe: 'Output image height', + describe: 'Height of each slice', type: 'number', coerce: (value) => { if (value !== undefined && value < 1) { diff --git a/src/slice.ts b/src/slice.ts index 563ddc7..0a29063 100644 --- a/src/slice.ts +++ b/src/slice.ts @@ -20,7 +20,7 @@ const options = yargs }) .option('w', { alias: 'width', - describe: 'Output image width', + describe: 'Width of each slice', type: 'number', demandOption: true, coerce: (value) => { @@ -32,7 +32,7 @@ const options = yargs }) .option('h', { alias: 'height', - describe: 'Output image height', + describe: 'Height of each slice', type: 'number', coerce: (value) => { if (value !== undefined && value < 1) { diff --git a/utils/processImage.js b/utils/processImage.js index 9a77eef..212b5ba 100644 --- a/utils/processImage.js +++ b/utils/processImage.js @@ -5,7 +5,7 @@ const Jimp = require("jimp"); const fs = require("fs"); const path = require("path"); const worker_threads_1 = require("worker_threads"); -const outputFolder = "output"; +const outputFolder = 'output'; /** * Function to slice an image into smaller segments */ @@ -26,7 +26,7 @@ function sliceImage(filename, width, height, skipExtCheck) { return; } // Check for supported image formats if skipExtCheck is false - const supportedFormats = [".png", ".gif", ".jpg", ".jpeg"]; + const supportedFormats = ['.png', '.gif', '.jpg', '.jpeg']; let foundImage = false; // Attempt to read the image with different extensions supportedFormats.forEach((ext) => { diff --git a/utils/workerPool.js b/utils/workerPool.js index ad1416f..508f5f0 100644 --- a/utils/workerPool.js +++ b/utils/workerPool.js @@ -24,15 +24,15 @@ class WorkerPool { * @param options - Image processing options for the file. */ createWorker(filePath, options) { - const worker = new worker_threads_1.Worker(path.join(__dirname, "processImage.js"), { + const worker = new worker_threads_1.Worker(path.join(__dirname, 'processImage.js'), { workerData: { filePath, options }, }); // Listen for messages and errors from the worker - worker.on("message", (message) => { + worker.on('message', (message) => { console.log(message); this.processNextTask(); }); - worker.on("error", (err) => { + worker.on('error', (err) => { console.error(`Error in worker for file ${filePath}:`, err); this.processNextTask(); }); @@ -66,7 +66,7 @@ class WorkerPool { */ waitForCompletion() { this.workers.forEach((worker) => { - worker.on("exit", () => { + worker.on('exit', () => { this.processNextTask(); }); }); From 699a10ead2a24ec43c9134a65802d06d4a87de1e Mon Sep 17 00:00:00 2001 From: thinknathan Date: Wed, 20 Dec 2023 21:36:03 -0800 Subject: [PATCH 2/4] Add new arguments --- @types/types.d.ts | 2 ++ slice.cjs | 20 ++++++++++++++++++-- src/slice.ts | 14 ++++++++++++-- src/utils/processImage.ts | 26 ++++++++++++++++++++++---- utils/processImage.js | 12 ++++++------ 5 files changed, 60 insertions(+), 14 deletions(-) diff --git a/@types/types.d.ts b/@types/types.d.ts index 0dcba8c..ba5a4e1 100644 --- a/@types/types.d.ts +++ b/@types/types.d.ts @@ -3,4 +3,6 @@ declare type Options = { folderPath?: string; width: number; height?: number; + canvasWidth?: number; + canvasHeight?: number; }; diff --git a/slice.cjs b/slice.cjs index e20793c..13ddbb4 100644 --- a/slice.cjs +++ b/slice.cjs @@ -39,11 +39,27 @@ const options = yargs } return Math.round(value); }, + }) + .option('d', { + alias: 'canvasWidth', + describe: 'Width of the canvas', + type: 'number', + }) + .option('g', { + alias: 'canvasHeight', + describe: 'Height of the canvas', + type: 'number', }).argv; if (options.filename) { // Process a single image - const { filename, width, height } = options; - (0, processImage_1.sliceImage)(filename, width, height); + const { filename, width, height, canvasWidth, canvasHeight } = options; + (0, processImage_1.sliceImage)( + filename, + width, + height, + canvasWidth, + canvasHeight, + ); } else if (options.folderPath) { // Process all images in a folder, splitting the task into threads let numCores = 2; diff --git a/src/slice.ts b/src/slice.ts index 0a29063..fe05010 100644 --- a/src/slice.ts +++ b/src/slice.ts @@ -40,12 +40,22 @@ const options = yargs } return Math.round(value); }, + }) + .option('d', { + alias: 'canvasWidth', + describe: 'Width of canvas for final output', + type: 'number', + }) + .option('g', { + alias: 'canvasHeight', + describe: 'Height of canvas for final output', + type: 'number', }).argv as unknown as Options; if (options.filename) { // Process a single image - const { filename, width, height } = options; - sliceImage(filename, width, height); + const { filename, width, height, canvasWidth, canvasHeight } = options; + sliceImage(filename, width, height, canvasWidth, canvasHeight); } else if (options.folderPath) { // Process all images in a folder, splitting the task into threads let numCores = 2; diff --git a/src/utils/processImage.ts b/src/utils/processImage.ts index 39d60cd..0284cf4 100644 --- a/src/utils/processImage.ts +++ b/src/utils/processImage.ts @@ -12,6 +12,8 @@ export function sliceImage( filename: string, width: number, height?: number, + canvasWidth?: number, + canvasHeight?: number, skipExtCheck?: boolean, ): void { Jimp.read(filename, (err, image) => { @@ -20,7 +22,14 @@ export function sliceImage( } else { // Continue slicing if image is successfully read if (image) { - continueSlicing(image, width, height, filename); + continueSlicing( + image, + width, + height, + canvasWidth, + canvasHeight, + filename, + ); return; } } @@ -41,7 +50,14 @@ export function sliceImage( Jimp.read(fullFilename, (err, image) => { if (!foundImage && !err) { foundImage = true; - continueSlicing(image, width, height, fullFilename); + continueSlicing( + image, + width, + height, + canvasWidth, + canvasHeight, + fullFilename, + ); } }); } @@ -55,6 +71,8 @@ function continueSlicing( image: Jimp, width: number, height: number | undefined, + canvasWidth: number | undefined, + canvasHeight: number | undefined, inputFilename: string, ): void { // If height is not specified, use width as height @@ -100,6 +118,6 @@ function continueSlicing( if (!isMainThread) { const { filePath, options } = workerData; options.filename = filePath; - const { filename, width, height } = options; - sliceImage(filename, width, height, true); + const { filename, width, height, canvasWidth, canvasHeight } = options; + sliceImage(filename, width, height, canvasWidth, canvasHeight, true); } diff --git a/utils/processImage.js b/utils/processImage.js index 212b5ba..3e926d9 100644 --- a/utils/processImage.js +++ b/utils/processImage.js @@ -9,7 +9,7 @@ const outputFolder = 'output'; /** * Function to slice an image into smaller segments */ -function sliceImage(filename, width, height, skipExtCheck) { +function sliceImage(filename, width, height, canvasWidth, canvasHeight, skipExtCheck) { Jimp.read(filename, (err, image) => { if (err && skipExtCheck) { console.error(err); @@ -17,7 +17,7 @@ function sliceImage(filename, width, height, skipExtCheck) { else { // Continue slicing if image is successfully read if (image) { - continueSlicing(image, width, height, filename); + continueSlicing(image, width, height, canvasWidth, canvasHeight, filename); return; } } @@ -35,7 +35,7 @@ function sliceImage(filename, width, height, skipExtCheck) { Jimp.read(fullFilename, (err, image) => { if (!foundImage && !err) { foundImage = true; - continueSlicing(image, width, height, fullFilename); + continueSlicing(image, width, height, canvasWidth, canvasHeight, fullFilename); } }); } @@ -45,7 +45,7 @@ exports.sliceImage = sliceImage; /** * Continue slicing the image into smaller segments */ -function continueSlicing(image, width, height, inputFilename) { +function continueSlicing(image, width, height, canvasWidth, canvasHeight, inputFilename) { // If height is not specified, use width as height height = height || width; const imageWidth = image.getWidth(); @@ -77,6 +77,6 @@ function continueSlicing(image, width, height, inputFilename) { if (!worker_threads_1.isMainThread) { const { filePath, options } = worker_threads_1.workerData; options.filename = filePath; - const { filename, width, height } = options; - sliceImage(filename, width, height, true); + const { filename, width, height, canvasWidth, canvasHeight } = options; + sliceImage(filename, width, height, canvasWidth, canvasHeight, true); } From 784316b3c98f9936facc1c005ae4f9e1c53076c8 Mon Sep 17 00:00:00 2001 From: thinknathan Date: Wed, 20 Dec 2023 21:55:05 -0800 Subject: [PATCH 3/4] Implement final canvas sizing --- README.md | 10 ++++++---- slice.cjs | 4 ++-- src/utils/processImage.ts | 22 +++++++++++++++++++++- utils/processImage.js | 16 +++++++++++++++- 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 9c702c1..8d508fe 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,12 @@ Command-line utility that slices input images into segments according to specifi `node slice.cjs` ``` --f, --filename Input image filename [string] --i, --folderPath Input folder [string] --w, --width Output image width [number] [required] --h, --height Output image height [number] +-f, --filename Input image filename [string] +-i, --folderPath Input folder [string] +-w, --width Width of each slice [number] [required] +-h, --height Height of each slice [number] +-d, --canvasWidth Width of canvas for final output [number] +-g, --canvasHeight Height of canvas for final output [number] ``` - If `filename` does not include an extension, `.png`, `.gif`, `.jpg` and `.jpeg` will be guessed diff --git a/slice.cjs b/slice.cjs index 13ddbb4..4989d45 100644 --- a/slice.cjs +++ b/slice.cjs @@ -42,12 +42,12 @@ const options = yargs }) .option('d', { alias: 'canvasWidth', - describe: 'Width of the canvas', + describe: 'Width of canvas for final output', type: 'number', }) .option('g', { alias: 'canvasHeight', - describe: 'Height of the canvas', + describe: 'Height of canvas for final output', type: 'number', }).argv; if (options.filename) { diff --git a/src/utils/processImage.ts b/src/utils/processImage.ts index 0284cf4..2c5f6f0 100644 --- a/src/utils/processImage.ts +++ b/src/utils/processImage.ts @@ -108,7 +108,27 @@ function continueSlicing( ); const outputFilename = `${outputFolder}/${baseFilename}_${x}_${y}.png`; - slice.write(outputFilename); + if (canvasWidth || canvasHeight) { + // Calculate canvas dimensions + const finalCanvasWidth = canvasWidth || width; + const finalCanvasHeight = (canvasHeight || canvasWidth) ?? height; + + // Create a new canvas with transparent background + const canvas = new Jimp( + finalCanvasWidth, + finalCanvasHeight, + 0x00000000, + ); + + // Composite the image in the middle of the canvas + const startX2 = Math.floor((finalCanvasWidth - sliceWidth) / 2); + const startY2 = Math.floor((finalCanvasHeight - sliceHeight) / 2); + canvas.composite(slice, startX2, startY2); + canvas.write(outputFilename); + } else { + slice.write(outputFilename); + } + console.log(`Slice saved: ${outputFilename}`); } } diff --git a/utils/processImage.js b/utils/processImage.js index 3e926d9..7354826 100644 --- a/utils/processImage.js +++ b/utils/processImage.js @@ -68,7 +68,21 @@ function continueSlicing(image, width, height, canvasWidth, canvasHeight, inputF // Incorporate the input filename into the output filename const baseFilename = path.basename(inputFilename, path.extname(inputFilename)); const outputFilename = `${outputFolder}/${baseFilename}_${x}_${y}.png`; - slice.write(outputFilename); + if (canvasWidth || canvasHeight) { + // Calculate canvas dimensions + const finalCanvasWidth = canvasWidth || width; + const finalCanvasHeight = (canvasHeight || canvasWidth) ?? height; + // Create a new canvas with transparent background + const canvas = new Jimp(finalCanvasWidth, finalCanvasHeight, 0x00000000); + // Composite the image in the middle of the canvas + const startX2 = Math.floor((finalCanvasWidth - sliceWidth) / 2); + const startY2 = Math.floor((finalCanvasHeight - sliceHeight) / 2); + canvas.composite(slice, startX2, startY2); + canvas.write(outputFilename); + } + else { + slice.write(outputFilename); + } console.log(`Slice saved: ${outputFilename}`); } } From 72d57ae98fdb8f098ea087014b0be45641bf2ec7 Mon Sep 17 00:00:00 2001 From: thinknathan Date: Wed, 20 Dec 2023 22:01:48 -0800 Subject: [PATCH 4/4] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4b2469e..167e9d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-image-slice", - "version": "2.0.0", + "version": "2.1.0", "description": "Slices an input image into segments according to specified width and height", "repository": { "type": "git",