nodejs-sprite-gen 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +178 -0
- package/bin/cli.js +72 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +194 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# nodejs-sprite-gen
|
|
2
|
+
|
|
3
|
+
A fast, modern CLI tool for generating image sprites and CSS stylesheets. Combine multiple images into a single optimized sprite sheet to reduce HTTP requests and improve page load times.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🚀 Fast image processing with Sharp
|
|
8
|
+
- 📦 Supports multiple input formats (JPG, PNG, WebP, GIF, BMP)
|
|
9
|
+
- 🎨 Generates clean CSS, SCSS, or LESS stylesheets
|
|
10
|
+
- 📐 Resize images on-the-fly
|
|
11
|
+
- 🔄 Grid, horizontal or vertical layouts
|
|
12
|
+
- ⚙️ Configurable padding between images
|
|
13
|
+
- 🌟 Zero configuration defaults
|
|
14
|
+
- 💻 Can be used as CLI or programmatically
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Global installation
|
|
20
|
+
npm install -g nodejs-sprite-gen
|
|
21
|
+
|
|
22
|
+
# Or use with npx (no installation needed)
|
|
23
|
+
npx nodejs-sprite-gen --input ./images
|
|
24
|
+
|
|
25
|
+
# Local installation for project
|
|
26
|
+
npm install --save-dev nodejs-sprite-gen
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
### Basic Usage
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
nodejs-sprite-gen --input ./images
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
This will:
|
|
38
|
+
- Read all images from `./images` directory
|
|
39
|
+
- Generate `sprite.png` and `sprite.css` in `./sprites` directory
|
|
40
|
+
|
|
41
|
+
### Advanced Usage
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
nodejs-sprite-gen \
|
|
45
|
+
--input ./flags \
|
|
46
|
+
--output ./dist/sprites \
|
|
47
|
+
--name country-flags \
|
|
48
|
+
--size 25x25 \
|
|
49
|
+
--layout horizontal \
|
|
50
|
+
--padding 10 \
|
|
51
|
+
--css-format scss \
|
|
52
|
+
--prefix some_name_for_css_classes
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Options
|
|
56
|
+
|
|
57
|
+
| Option | Alias | Description | Default |
|
|
58
|
+
|--------|-------|-------------|---------|
|
|
59
|
+
| `--input <path>` | `-i` | Input directory containing images (required) | - |
|
|
60
|
+
| `--output <path>` | `-o` | Output directory | `./sprites` |
|
|
61
|
+
| `--name <name>` | `-n` | Output filename (without extension) | `sprite` |
|
|
62
|
+
| `--layout <type>` | `-l` | Layout: `horizontal` or `vertical` | `vertical` |
|
|
63
|
+
| `--padding <pixels>` | `-p` | Padding between images | `0` |
|
|
64
|
+
| `--size <WxH>` | `-s` | Resize images (e.g., `25x25`) | original size |
|
|
65
|
+
| `--css-format <format>` | - | CSS format: `css`, `scss`, or `less` | `css` |
|
|
66
|
+
| `--prefix` | - | The CSS class name prefix | sprite |
|
|
67
|
+
| `--no-css` | - | Skip CSS generation | generates CSS |
|
|
68
|
+
|
|
69
|
+
### Using in npm scripts
|
|
70
|
+
|
|
71
|
+
Add to your `package.json`:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"scripts": {
|
|
76
|
+
"build:sprites": "nodejs-sprite-gen --input ./assets/icons --size 32x32"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Run with:
|
|
82
|
+
```bash
|
|
83
|
+
npm run build:sprites
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Programmatic Usage
|
|
87
|
+
|
|
88
|
+
You can also use nodejs-sprite-gen programmatically in your Node.js projects:
|
|
89
|
+
|
|
90
|
+
```javascript
|
|
91
|
+
const { generateSprite } = require('nodejs-sprite-gen');
|
|
92
|
+
|
|
93
|
+
async function buildSprites() {
|
|
94
|
+
const result = await generateSprite({
|
|
95
|
+
inputDir: './images',
|
|
96
|
+
outputDir: './sprites',
|
|
97
|
+
spriteName: 'sprite',
|
|
98
|
+
layout: 'vertical',
|
|
99
|
+
padding: 0,
|
|
100
|
+
resize: { width: 25, height: 25 }, // optional
|
|
101
|
+
generateCSS: true,
|
|
102
|
+
cssFormat: 'css',
|
|
103
|
+
prefix: 'icon'
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
console.log(`Generated: ${result.imagePath}`);
|
|
107
|
+
console.log(`CSS: ${result.cssPath}`);
|
|
108
|
+
console.log(`Images: ${result.imageCount}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
buildSprites();
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Output
|
|
115
|
+
|
|
116
|
+
### Generated PNG Sprite
|
|
117
|
+
A single optimized PNG file with transparency, containing all your images.
|
|
118
|
+
|
|
119
|
+
### Generated CSS
|
|
120
|
+
```css
|
|
121
|
+
.sprite {
|
|
122
|
+
display: inline-block;
|
|
123
|
+
background-image: url('sprite.png');
|
|
124
|
+
background-repeat: no-repeat;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.sprite-icon-home {
|
|
128
|
+
width: 32px;
|
|
129
|
+
height: 32px;
|
|
130
|
+
background-position: -0px -0px;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.sprite-icon-settings {
|
|
134
|
+
width: 32px;
|
|
135
|
+
height: 32px;
|
|
136
|
+
background-position: -0px -32px;
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Using the Sprite in HTML
|
|
141
|
+
```html
|
|
142
|
+
<div class="sprite sprite-icon-home"></div>
|
|
143
|
+
<div class="sprite sprite-icon-settings"></div>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Examples
|
|
147
|
+
|
|
148
|
+
### Icon Sprites
|
|
149
|
+
```bash
|
|
150
|
+
nodejs-sprite-gen --input ./icons --size 32x32 --padding 2
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Flag Sprites
|
|
154
|
+
```bash
|
|
155
|
+
nodejs-sprite-gen --input ./temp_images --output ./out --size 250x100 --prefix icon --layout grid
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### SCSS Output
|
|
159
|
+
```bash
|
|
160
|
+
nodejs-sprite-gen --input ./images --css-format scss
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Requirements
|
|
164
|
+
|
|
165
|
+
- Node.js >= 16.0.0
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT
|
|
170
|
+
|
|
171
|
+
## Author
|
|
172
|
+
|
|
173
|
+
Gidon Handler
|
|
174
|
+
Gidon.handler@gmail.com
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
Made with ❤️ for better web performance
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { Command } = require('commander');
|
|
4
|
+
const { generateSprite } = require('../dist/index.js');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const program = new Command();
|
|
8
|
+
|
|
9
|
+
program
|
|
10
|
+
.name('nodejs-sprite-gen')
|
|
11
|
+
.description('Generate image sprites and attached CSS stylesheets from a directory of images')
|
|
12
|
+
.version('1.0.0')
|
|
13
|
+
.requiredOption('-i, --input <path>', 'input directory containing images')
|
|
14
|
+
.option('-o, --output <path>', 'output directory', './sprites')
|
|
15
|
+
.option('-n, --name <name>', 'output filename (without extension)', 'sprite')
|
|
16
|
+
.option('-l, --layout <type>', 'layout direction: horizontal, vertical, or grid', 'grid')
|
|
17
|
+
.option('-p, --padding <pixels>', 'padding between images in pixels', '0')
|
|
18
|
+
.option('-s, --size <dimensions>', 'resize images to WxH (e.g., 25x25)')
|
|
19
|
+
.option('--css-format <format>', 'CSS output format: css, scss, less', 'css')
|
|
20
|
+
.option('--prefix <prefix>', 'CSS class prefix', 'sprite')
|
|
21
|
+
.option('--no-css', 'skip CSS generation')
|
|
22
|
+
.parse(process.argv);
|
|
23
|
+
|
|
24
|
+
const options = program.opts();
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
const config = {
|
|
28
|
+
inputDir: path.resolve(options.input),
|
|
29
|
+
outputDir: path.resolve(options.output),
|
|
30
|
+
spriteName: options.name,
|
|
31
|
+
layout: ['horizontal', 'vertical', 'grid'].includes(options.layout) ? options.layout : 'grid',
|
|
32
|
+
padding: parseInt(options.padding, 10),
|
|
33
|
+
generateCSS: options.css !== false,
|
|
34
|
+
cssFormat: options.cssFormat,
|
|
35
|
+
cssPrefix: options.prefix,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Parse size option if provided
|
|
39
|
+
if (options.size) {
|
|
40
|
+
const match = options.size.match(/^(\d+)x(\d+)$/i);
|
|
41
|
+
if (!match) {
|
|
42
|
+
console.error('Error: --size must be in format WxH (e.g., 25x25)');
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
config.resize = {
|
|
46
|
+
width: parseInt(match[1], 10),
|
|
47
|
+
height: parseInt(match[2], 10)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Run the sprite generator
|
|
52
|
+
console.log('🎨 Generating sprite...');
|
|
53
|
+
console.log(` Input: ${config.inputDir}`);
|
|
54
|
+
console.log(` Output: ${config.outputDir}`);
|
|
55
|
+
if (config.resize) {
|
|
56
|
+
console.log(` Size: ${config.resize.width}x${config.resize.height}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
generateSprite(config)
|
|
60
|
+
.then(result => {
|
|
61
|
+
console.log('✅ Sprite generated successfully!');
|
|
62
|
+
console.log(` Image: ${result.imagePath}`);
|
|
63
|
+
if (result.cssPath) {
|
|
64
|
+
console.log(` CSS: ${result.cssPath}`);
|
|
65
|
+
}
|
|
66
|
+
console.log(` Images processed: ${result.imageCount}`);
|
|
67
|
+
console.log(` Sprite dimensions: ${result.spriteWidth}x${result.spriteHeight}px`);
|
|
68
|
+
})
|
|
69
|
+
.catch(err => {
|
|
70
|
+
console.error('❌ Error generating sprite:', err.message);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface SpriteConfig {
|
|
2
|
+
inputDir: string;
|
|
3
|
+
outputDir: string;
|
|
4
|
+
spriteName: string;
|
|
5
|
+
layout?: 'horizontal' | 'vertical' | 'grid';
|
|
6
|
+
padding: number;
|
|
7
|
+
resize?: {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
};
|
|
11
|
+
/** Number of columns for grid layout. If not specified, auto-calculates a square-ish grid */
|
|
12
|
+
gridColumns?: number;
|
|
13
|
+
generateCSS: boolean;
|
|
14
|
+
cssFormat: 'css' | 'scss' | 'less';
|
|
15
|
+
cssPrefix?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface SpriteResult {
|
|
18
|
+
imagePath: string;
|
|
19
|
+
cssPath: string | null;
|
|
20
|
+
imageCount: number;
|
|
21
|
+
spriteWidth: number;
|
|
22
|
+
spriteHeight: number;
|
|
23
|
+
}
|
|
24
|
+
export declare function generateSprite(config: SpriteConfig): Promise<SpriteResult>;
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,YAAY,GAAG,UAAU,GAAG,MAAM,CAAC;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,6FAA6F;IAC7F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAaD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CA6FhF"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.generateSprite = generateSprite;
|
|
40
|
+
const fs = __importStar(require("fs/promises"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const sharp_1 = __importDefault(require("sharp"));
|
|
43
|
+
async function generateSprite(config) {
|
|
44
|
+
// Ensure output directory exists
|
|
45
|
+
await fs.mkdir(config.outputDir, { recursive: true });
|
|
46
|
+
// Read all image files from input directory
|
|
47
|
+
const files = await fs.readdir(config.inputDir);
|
|
48
|
+
const imageFiles = files.filter(file => /\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(file));
|
|
49
|
+
if (imageFiles.length === 0) {
|
|
50
|
+
throw new Error(`No image files found in ${config.inputDir}`);
|
|
51
|
+
}
|
|
52
|
+
// Load and process images
|
|
53
|
+
const images = [];
|
|
54
|
+
for (const filename of imageFiles) {
|
|
55
|
+
const filePath = path.join(config.inputDir, filename);
|
|
56
|
+
let image = (0, sharp_1.default)(filePath);
|
|
57
|
+
// Get metadata
|
|
58
|
+
const metadata = await image.metadata();
|
|
59
|
+
let width = metadata.width;
|
|
60
|
+
let height = metadata.height;
|
|
61
|
+
// Resize if specified
|
|
62
|
+
if (config.resize) {
|
|
63
|
+
image = image.resize(config.resize.width, config.resize.height, {
|
|
64
|
+
fit: 'contain',
|
|
65
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
|
66
|
+
});
|
|
67
|
+
width = config.resize.width;
|
|
68
|
+
height = config.resize.height;
|
|
69
|
+
}
|
|
70
|
+
const buffer = await image.png().toBuffer();
|
|
71
|
+
images.push({
|
|
72
|
+
filename,
|
|
73
|
+
path: filePath,
|
|
74
|
+
buffer,
|
|
75
|
+
width,
|
|
76
|
+
height,
|
|
77
|
+
x: 0,
|
|
78
|
+
y: 0,
|
|
79
|
+
className: sanitizeClassName(filename)
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// Calculate positions and sprite dimensions
|
|
83
|
+
const { spriteWidth, spriteHeight } = calculateLayout(images, config);
|
|
84
|
+
// Create the sprite
|
|
85
|
+
const compositeOperations = images.map(img => ({
|
|
86
|
+
input: img.buffer,
|
|
87
|
+
top: img.y,
|
|
88
|
+
left: img.x
|
|
89
|
+
}));
|
|
90
|
+
const spriteBuffer = await (0, sharp_1.default)({
|
|
91
|
+
create: {
|
|
92
|
+
width: spriteWidth,
|
|
93
|
+
height: spriteHeight,
|
|
94
|
+
channels: 4,
|
|
95
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
.composite(compositeOperations)
|
|
99
|
+
.png()
|
|
100
|
+
.toBuffer();
|
|
101
|
+
// Save sprite image
|
|
102
|
+
const imagePath = path.join(config.outputDir, `${config.spriteName}.png`);
|
|
103
|
+
await fs.writeFile(imagePath, spriteBuffer);
|
|
104
|
+
// Generate CSS if enabled
|
|
105
|
+
let cssPath = null;
|
|
106
|
+
if (config.generateCSS) {
|
|
107
|
+
const css = generateCSS(images, config.spriteName, config.cssFormat, config.cssPrefix ?? 'sprite');
|
|
108
|
+
const extension = config.cssFormat === 'scss' ? 'scss' :
|
|
109
|
+
config.cssFormat === 'less' ? 'less' : 'css';
|
|
110
|
+
cssPath = path.join(config.outputDir, `${config.spriteName}.${extension}`);
|
|
111
|
+
await fs.writeFile(cssPath, css);
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
imagePath,
|
|
115
|
+
cssPath,
|
|
116
|
+
imageCount: images.length,
|
|
117
|
+
spriteWidth,
|
|
118
|
+
spriteHeight
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function calculateLayout(images, config) {
|
|
122
|
+
let spriteWidth = 0;
|
|
123
|
+
let spriteHeight = 0;
|
|
124
|
+
const layout = config.layout ?? 'grid';
|
|
125
|
+
if (layout === 'horizontal') {
|
|
126
|
+
let currentX = 0;
|
|
127
|
+
for (const img of images) {
|
|
128
|
+
img.x = currentX;
|
|
129
|
+
img.y = 0;
|
|
130
|
+
currentX += img.width + config.padding;
|
|
131
|
+
spriteHeight = Math.max(spriteHeight, img.height);
|
|
132
|
+
}
|
|
133
|
+
spriteWidth = currentX - config.padding;
|
|
134
|
+
}
|
|
135
|
+
else if (layout === 'vertical') {
|
|
136
|
+
let currentY = 0;
|
|
137
|
+
for (const img of images) {
|
|
138
|
+
img.x = 0;
|
|
139
|
+
img.y = currentY;
|
|
140
|
+
currentY += img.height + config.padding;
|
|
141
|
+
spriteWidth = Math.max(spriteWidth, img.width);
|
|
142
|
+
}
|
|
143
|
+
spriteHeight = currentY - config.padding;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
const columns = config.gridColumns ?? Math.ceil(Math.sqrt(images.length));
|
|
147
|
+
const maxCellWidth = Math.max(...images.map(img => img.width));
|
|
148
|
+
const maxCellHeight = Math.max(...images.map(img => img.height));
|
|
149
|
+
for (let i = 0; i < images.length; i++) {
|
|
150
|
+
const col = i % columns;
|
|
151
|
+
const row = Math.floor(i / columns);
|
|
152
|
+
images[i].x = col * (maxCellWidth + config.padding);
|
|
153
|
+
images[i].y = row * (maxCellHeight + config.padding);
|
|
154
|
+
}
|
|
155
|
+
const rows = Math.ceil(images.length / columns);
|
|
156
|
+
spriteWidth = columns * maxCellWidth + (columns - 1) * config.padding;
|
|
157
|
+
spriteHeight = rows * maxCellHeight + (rows - 1) * config.padding;
|
|
158
|
+
}
|
|
159
|
+
return { spriteWidth, spriteHeight };
|
|
160
|
+
}
|
|
161
|
+
function sanitizeClassName(filename) {
|
|
162
|
+
return filename
|
|
163
|
+
.replace(/\.[^/.]+$/, '') // Remove extension
|
|
164
|
+
.replace(/[^a-z0-9]/gi, '-') // Replace non-alphanumeric with dash
|
|
165
|
+
.replace(/^-+|-+$/g, '') // Remove leading/trailing dashes
|
|
166
|
+
.toLowerCase();
|
|
167
|
+
}
|
|
168
|
+
function generateCSS(images, spriteName, format, prefix) {
|
|
169
|
+
const variable = format === 'scss' ? '$' : format === 'less' ? '@' : '';
|
|
170
|
+
const spriteUrl = `${spriteName}.png`;
|
|
171
|
+
let css = `/* Generated by nodejs-sprite-gen */\n\n`;
|
|
172
|
+
if (format === 'scss' || format === 'less') {
|
|
173
|
+
css += `${variable}${prefix}-image: '${spriteUrl}';\n\n`;
|
|
174
|
+
}
|
|
175
|
+
css += `.${prefix} {\n`;
|
|
176
|
+
css += ` display: inline-block;\n`;
|
|
177
|
+
if (format === 'scss' || format === 'less') {
|
|
178
|
+
css += ` background-image: url(${variable}${prefix}-image);\n`;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
css += ` background-image: url('${spriteUrl}');\n`;
|
|
182
|
+
}
|
|
183
|
+
css += ` background-repeat: no-repeat;\n`;
|
|
184
|
+
css += `}\n\n`;
|
|
185
|
+
for (const img of images) {
|
|
186
|
+
css += `.${prefix}-${img.className} {\n`;
|
|
187
|
+
css += ` width: ${img.width}px;\n`;
|
|
188
|
+
css += ` height: ${img.height}px;\n`;
|
|
189
|
+
css += ` background-position: -${img.x}px -${img.y}px;\n`;
|
|
190
|
+
css += `}\n\n`;
|
|
191
|
+
}
|
|
192
|
+
return css;
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nodejs-sprite-gen",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A fast, modern CLI tool for generating image sprites and corresponding CSS stylesheets",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"nodejs-sprite-gen": "bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"prepublishOnly": "npm run build",
|
|
13
|
+
"test": "node bin/cli.js --help"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"sprite",
|
|
17
|
+
"spritesheet",
|
|
18
|
+
"css-sprite",
|
|
19
|
+
"image-sprite",
|
|
20
|
+
"sprite-generator",
|
|
21
|
+
"image-optimization",
|
|
22
|
+
"cli-sprite-generator"
|
|
23
|
+
],
|
|
24
|
+
"author": "Gidon Handler",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"commander": "^11.1.0",
|
|
28
|
+
"sharp": "^0.33.1"
|
|
29
|
+
},
|
|
30
|
+
"files": ["bin", "dist", "README.md"],
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^20.10.6",
|
|
33
|
+
"typescript": "^5.3.3"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=16.0.0"
|
|
37
|
+
}
|
|
38
|
+
}
|