Skip to content

Commit 2130152

Browse files
authored
Merge pull request #2 from thinknathan/v2
v2.0.0
2 parents 7d56621 + 92d4b2f commit 2130152

File tree

12 files changed

+654
-146
lines changed

12 files changed

+654
-146
lines changed

@types/types.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
declare type Options = {
2+
filename?: string;
3+
folderPath?: string;
4+
width: number;
5+
height?: number;
6+
};

README.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# node-image-slice
22

3-
Command-line utility that slices an input image into segments according to specified width and height, and outputs those segments into a folder.
3+
Command-line utility that slices input images into segments according to specified width and height, and outputs those segments into a folder.
44

55
## Install
66

@@ -16,18 +16,17 @@ Command-line utility that slices an input image into segments according to speci
1616

1717
## Usage
1818

19-
`node slice.cjs <filename> <width> [height]`
19+
`node slice.cjs`
2020

21-
- If `filename` does not include an extension, `.png` will be guessed
22-
- If `height` is not specified, `width` will be used as `height`
23-
24-
## Supported formats
21+
```
22+
-f, --filename Input image filename [string]
23+
-i, --folderPath Input folder [string]
24+
-w, --width Output image width [number] [required]
25+
-h, --height Output image height [number]
26+
```
2527

26-
- jpeg
27-
- png
28-
- bmp
29-
- tiff
30-
- gif
28+
- If `filename` does not include an extension, `.png`, `.gif`, `.jpg` and `.jpeg` will be guessed
29+
- If `height` is not specified, `width` will be used as `height`
3130

3231
## Background
3332

package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "node-image-slice",
3-
"version": "1.0.0",
3+
"version": "2.0.0",
44
"description": "Slices an input image into segments according to specified width and height",
55
"repository": {
66
"type": "git",
@@ -11,19 +11,22 @@
1111
"type": "commonjs",
1212
"main": "slice.cjs",
1313
"files": [
14-
"slice.cjs"
14+
"slice.cjs",
15+
"utils"
1516
],
1617
"scripts": {
1718
"build": "tsc && npm run renameCjs && npm run prettier",
1819
"renameCjs": "node -e \"require('fs').renameSync('slice.js', 'slice.cjs')\"",
1920
"prettier": "prettier \"./**/*.{ts,d.ts,cjs,md,json}\" --write"
2021
},
2122
"devDependencies": {
23+
"@types/yargs": "^17.0.32",
2224
"prettier": "^3.1.1",
2325
"tsc": "^2.0.4",
2426
"typescript": "~5.2.2"
2527
},
2628
"dependencies": {
27-
"jimp": "~0.22.10"
29+
"jimp": "~0.22.10",
30+
"yargs": "^17.7.2"
2831
}
2932
}

slice.cjs

Lines changed: 52 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,56 @@
11
"use strict";
22
Object.defineProperty(exports, "__esModule", { value: true });
3-
const Jimp = require("jimp");
4-
const fs = require("fs");
5-
const path = require("path");
6-
const outputFolder = "output";
7-
function sliceImage(filename, width, height) {
8-
Jimp.read(filename, (err, image) => {
9-
if (err) {
10-
// Try again by appending '.png' to the filename
11-
const pngFilename = `${filename}.png`;
12-
Jimp.read(pngFilename, (pngErr, pngImage) => {
13-
if (pngErr) {
14-
console.error("Error reading the image:", pngErr);
15-
return;
16-
}
17-
continueSlicing(pngImage, width, height, filename);
18-
});
19-
} else {
20-
continueSlicing(image, width, height, filename);
21-
}
22-
});
23-
}
24-
function continueSlicing(image, width, height, inputFilename) {
25-
// If height is not specified, use width as height
26-
height = height || width;
27-
const imageWidth = image.getWidth();
28-
const imageHeight = image.getHeight();
29-
// Calculate the number of slices in both dimensions
30-
const horizontalSlices = Math.ceil(imageWidth / width);
31-
const verticalSlices = Math.ceil(imageHeight / height);
32-
// Create a folder for output if it doesn't exist
33-
if (!fs.existsSync(outputFolder)) {
34-
fs.mkdirSync(outputFolder);
35-
}
36-
// Slice the image and save each segment
37-
for (let y = 0; y < verticalSlices; y++) {
38-
for (let x = 0; x < horizontalSlices; x++) {
39-
const startX = x * width;
40-
const startY = y * height;
41-
const sliceWidth = Math.min(width, imageWidth - startX);
42-
const sliceHeight = Math.min(height, imageHeight - startY);
43-
const slice = image.clone().crop(startX, startY, sliceWidth, sliceHeight);
44-
// Incorporate the input filename into the output filename
45-
const baseFilename = path.basename(
46-
inputFilename,
47-
path.extname(inputFilename),
48-
);
49-
const outputFilename = `${outputFolder}/${baseFilename}_${x}_${y}.png`;
50-
slice.write(outputFilename);
51-
console.log(`Slice saved: ${outputFilename}`);
52-
}
3+
const yargs = require("yargs");
4+
const os = require("os");
5+
const processImage_1 = require("./utils/processImage");
6+
const processPath_1 = require("./utils/processPath");
7+
// Parse command line arguments
8+
const options = yargs
9+
.option("f", {
10+
alias: "filename",
11+
describe: "Input image filename",
12+
type: "string",
13+
})
14+
.option("i", {
15+
alias: "folderPath",
16+
describe: "Input folder",
17+
type: "string",
18+
})
19+
.option("w", {
20+
alias: "width",
21+
describe: "Output image width",
22+
type: "number",
23+
demandOption: true,
24+
coerce: (value) => {
25+
if (value < 1) {
26+
throw new Error("width should not be lower than 1");
27+
}
28+
return Math.round(value);
29+
},
30+
})
31+
.option("h", {
32+
alias: "height",
33+
describe: "Output image height",
34+
type: "number",
35+
coerce: (value) => {
36+
if (value !== undefined && value < 1) {
37+
throw new Error("height should not be lower than 1");
38+
}
39+
return Math.round(value);
40+
},
41+
}).argv;
42+
if (options.filename) {
43+
// Process a single image
44+
const { filename, width, height } = options;
45+
(0, processImage_1.sliceImage)(filename, width, height);
46+
} else if (options.folderPath) {
47+
// Process all images in a folder, splitting the task into threads
48+
let numCores = 2;
49+
try {
50+
numCores = os.cpus().length;
51+
} catch (err) {
52+
console.error(err);
5353
}
54-
}
55-
// Get input from the command line arguments
56-
const [filename, width, height] = process.argv.slice(2);
57-
if (!filename || !width) {
58-
console.log("Usage: node slice.cjs <filename> <width> [height]");
59-
} else {
60-
sliceImage(filename, parseInt(width), parseInt(height));
54+
numCores = Math.max(numCores - 1, 1);
55+
(0, processPath_1.processPath)(options.folderPath, options, numCores);
6156
}

src/slice.ts

Lines changed: 55 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,57 @@
1-
import * as Jimp from "jimp";
2-
import * as fs from "fs";
3-
import * as path from "path";
4-
5-
const outputFolder = "output";
6-
7-
function sliceImage(filename: string, width: number, height?: number): void {
8-
Jimp.read(filename, (err, image) => {
9-
if (err) {
10-
// Try again by appending '.png' to the filename
11-
const pngFilename = `${filename}.png`;
12-
Jimp.read(pngFilename, (pngErr, pngImage) => {
13-
if (pngErr) {
14-
console.error("Error reading the image:", pngErr);
15-
return;
16-
}
17-
continueSlicing(pngImage, width, height, filename);
18-
});
19-
} else {
20-
continueSlicing(image, width, height, filename);
21-
}
22-
});
23-
}
24-
25-
function continueSlicing(
26-
image: Jimp,
27-
width: number,
28-
height: number | undefined,
29-
inputFilename: string,
30-
): void {
31-
// If height is not specified, use width as height
32-
height = height || width;
33-
34-
const imageWidth = image.getWidth();
35-
const imageHeight = image.getHeight();
36-
37-
// Calculate the number of slices in both dimensions
38-
const horizontalSlices = Math.ceil(imageWidth / width);
39-
const verticalSlices = Math.ceil(imageHeight / height);
40-
41-
// Create a folder for output if it doesn't exist
42-
if (!fs.existsSync(outputFolder)) {
43-
fs.mkdirSync(outputFolder);
44-
}
45-
46-
// Slice the image and save each segment
47-
for (let y = 0; y < verticalSlices; y++) {
48-
for (let x = 0; x < horizontalSlices; x++) {
49-
const startX = x * width;
50-
const startY = y * height;
51-
52-
const sliceWidth = Math.min(width, imageWidth - startX);
53-
const sliceHeight = Math.min(height, imageHeight - startY);
54-
55-
const slice = image.clone().crop(startX, startY, sliceWidth, sliceHeight);
56-
57-
// Incorporate the input filename into the output filename
58-
const baseFilename = path.basename(
59-
inputFilename,
60-
path.extname(inputFilename),
61-
);
62-
const outputFilename = `${outputFolder}/${baseFilename}_${x}_${y}.png`;
63-
64-
slice.write(outputFilename);
65-
console.log(`Slice saved: ${outputFilename}`);
66-
}
1+
import * as yargs from "yargs";
2+
import * as os from "os";
3+
4+
import { sliceImage } from "./utils/processImage";
5+
import { processPath } from "./utils/processPath";
6+
7+
// Parse command line arguments
8+
const options = yargs
9+
.option("f", {
10+
alias: "filename",
11+
describe: "Input image filename",
12+
type: "string",
13+
})
14+
.option("i", {
15+
alias: "folderPath",
16+
describe: "Input folder",
17+
type: "string",
18+
})
19+
.option("w", {
20+
alias: "width",
21+
describe: "Output image width",
22+
type: "number",
23+
demandOption: true,
24+
coerce: (value) => {
25+
if (value < 1) {
26+
throw new Error("width should not be lower than 1");
27+
}
28+
return Math.round(value);
29+
},
30+
})
31+
.option("h", {
32+
alias: "height",
33+
describe: "Output image height",
34+
type: "number",
35+
coerce: (value) => {
36+
if (value !== undefined && value < 1) {
37+
throw new Error("height should not be lower than 1");
38+
}
39+
return Math.round(value);
40+
},
41+
}).argv as unknown as Options;
42+
43+
if (options.filename) {
44+
// Process a single image
45+
const { filename, width, height } = options;
46+
sliceImage(filename, width, height);
47+
} else if (options.folderPath) {
48+
// Process all images in a folder, splitting the task into threads
49+
let numCores = 2;
50+
try {
51+
numCores = os.cpus().length;
52+
} catch (err) {
53+
console.error(err);
6754
}
68-
}
69-
70-
// Get input from the command line arguments
71-
const [filename, width, height] = process.argv.slice(2);
72-
73-
if (!filename || !width) {
74-
console.log("Usage: node slice.cjs <filename> <width> [height]");
75-
} else {
76-
sliceImage(filename, parseInt(width), parseInt(height));
55+
numCores = Math.max(numCores - 1, 1);
56+
processPath(options.folderPath, options, numCores);
7757
}

0 commit comments

Comments
 (0)