@visualizevalue/img-grid 0.1.3 → 0.1.4
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 +7 -2
- package/dist/index.d.ts +8 -1
- package/dist/index.js +22 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,7 +30,9 @@ const highlightedBuffer = await grid(images, {
|
|
|
30
30
|
highlight: ['img2', 'img3'], // Images with these IDs will be 2×2
|
|
31
31
|
maxWidth: 1920, // Maximum width of output image
|
|
32
32
|
concurrency: 10, // Maximum concurrent downloads
|
|
33
|
-
background: '#000', //
|
|
33
|
+
background: '#000', // Fills background, padding, gutters, and letterboxing
|
|
34
|
+
padding: 16, // Space around the whole grid, in pixels
|
|
35
|
+
gutter: 8, // Gap between cells (rows and columns), in pixels
|
|
34
36
|
pixelated: true, // Nearest-neighbour resize — keeps pixel art crisp
|
|
35
37
|
format: 'webp', // Output as png (default), jpeg, or webp
|
|
36
38
|
quality: 80, // Quality for jpeg/webp
|
|
@@ -45,6 +47,7 @@ writeFileSync('grid.png', buffer)
|
|
|
45
47
|
|
|
46
48
|
- Packs images into a compact, near-square grid
|
|
47
49
|
- Supports highlighting specific images (makes them 2×2)
|
|
50
|
+
- Configurable `background` color, `padding` around the grid, and `gutter` between cells
|
|
48
51
|
- Optional nearest-neighbour scaling to keep pixel art crisp (`pixelated`)
|
|
49
52
|
- Downloads images concurrently (with a configurable limit)
|
|
50
53
|
- Leaves a blank cell for failed downloads instead of failing the grid
|
|
@@ -58,7 +61,9 @@ writeFileSync('grid.png', buffer)
|
|
|
58
61
|
| `highlight` | `[]` | Array of image IDs to highlight (make 2×2) |
|
|
59
62
|
| `maxWidth` | `1920` | Maximum width of output image in pixels |
|
|
60
63
|
| `concurrency` | `10` | Maximum concurrent image downloads |
|
|
61
|
-
| `background` | `'#000'` |
|
|
64
|
+
| `background` | `'#000'` | Fills background, padding, gutters, letterboxing |
|
|
65
|
+
| `padding` | `0` | Space around the whole grid, in pixels |
|
|
66
|
+
| `gutter` | `0` | Gap between cells (rows and columns), in pixels |
|
|
62
67
|
| `pixelated` | `false` | Nearest-neighbour resize; keeps pixel art crisp |
|
|
63
68
|
| `format` | `'png'` | Output format: `'png'`, `'jpeg'`, or `'webp'` |
|
|
64
69
|
| `quality` | sharp's | Quality (1–100) for `jpeg`/`webp`; ignored for png |
|
package/dist/index.d.ts
CHANGED
|
@@ -10,8 +10,15 @@ export interface GridOptions {
|
|
|
10
10
|
maxWidth?: number;
|
|
11
11
|
/** Maximum number of images downloaded at once. */
|
|
12
12
|
concurrency?: number;
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* Color filling the background, padding, gutters, and image letterboxing
|
|
15
|
+
* (any sharp-compatible color).
|
|
16
|
+
*/
|
|
14
17
|
background?: string;
|
|
18
|
+
/** Space around the whole grid, in pixels. Filled with `background`. */
|
|
19
|
+
padding?: number;
|
|
20
|
+
/** Gap between cells (rows and columns), in pixels. Filled with `background`. */
|
|
21
|
+
gutter?: number;
|
|
15
22
|
/**
|
|
16
23
|
* Resize with nearest-neighbour instead of the default smooth (lanczos)
|
|
17
24
|
* kernel. Keeps pixel art (e.g. NFTs) crisp instead of blurring it when
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,8 @@ const sharp_1 = __importDefault(require("sharp"));
|
|
|
8
8
|
const DEFAULT_MAX_WIDTH = 1920;
|
|
9
9
|
const DEFAULT_CONCURRENCY = 10;
|
|
10
10
|
const DEFAULT_BACKGROUND = '#000';
|
|
11
|
+
const DEFAULT_PADDING = 0;
|
|
12
|
+
const DEFAULT_GUTTER = 0;
|
|
11
13
|
const DEFAULT_FORMAT = 'png';
|
|
12
14
|
const FETCH_TIMEOUT_MS = 15_000;
|
|
13
15
|
const HIGHLIGHT_SPAN = 2;
|
|
@@ -20,25 +22,38 @@ const HIGHLIGHT_SPAN = 2;
|
|
|
20
22
|
*/
|
|
21
23
|
async function grid(images, opts = {}) {
|
|
22
24
|
const { highlight = [], maxWidth = DEFAULT_MAX_WIDTH, concurrency = DEFAULT_CONCURRENCY, background = DEFAULT_BACKGROUND, pixelated = false, format = DEFAULT_FORMAT, quality, onError, } = opts;
|
|
25
|
+
const padding = Math.max(0, Math.floor(opts.padding ?? DEFAULT_PADDING));
|
|
26
|
+
const gutter = Math.max(0, Math.floor(opts.gutter ?? DEFAULT_GUTTER));
|
|
23
27
|
const highlightIds = new Set(highlight);
|
|
24
28
|
const isHighlighted = (img) => img.id !== undefined && highlightIds.has(img.id);
|
|
25
29
|
const highlighted = images.filter(isHighlighted);
|
|
26
30
|
const normal = images.filter((img) => !isHighlighted(img));
|
|
27
31
|
const totalCells = normal.length + highlighted.length * HIGHLIGHT_SPAN ** 2;
|
|
28
|
-
if (totalCells === 0)
|
|
29
|
-
|
|
32
|
+
if (totalCells === 0) {
|
|
33
|
+
const side = Math.max(1, 2 * padding);
|
|
34
|
+
return encode(blankCanvas(side, side, background), format, quality);
|
|
35
|
+
}
|
|
30
36
|
const { columns, rows, placements } = chooseLayout(highlighted, normal);
|
|
31
|
-
|
|
37
|
+
// Carve padding and inter-column gutters out of the width budget before
|
|
38
|
+
// dividing what's left among the columns, so the output never exceeds maxWidth.
|
|
39
|
+
const available = maxWidth - 2 * padding - (columns - 1) * gutter;
|
|
40
|
+
const cellSize = Math.max(1, Math.floor(available / columns));
|
|
41
|
+
// Top-left pixel of cell (col, row); a span-N block also covers the N−1
|
|
42
|
+
// gutters between the cells it spans, so it reads as one solid larger tile.
|
|
43
|
+
const offset = (index) => padding + index * (cellSize + gutter);
|
|
44
|
+
const spanSize = (span) => span * cellSize + (span - 1) * gutter;
|
|
32
45
|
const layers = await mapWithConcurrency(placements, concurrency, async (placement) => {
|
|
33
|
-
const size =
|
|
46
|
+
const size = spanSize(placement.span);
|
|
34
47
|
const cell = await renderCell(placement.img, size, background, pixelated, onError);
|
|
35
48
|
return {
|
|
36
49
|
input: cell,
|
|
37
|
-
left: placement.col
|
|
38
|
-
top: placement.row
|
|
50
|
+
left: offset(placement.col),
|
|
51
|
+
top: offset(placement.row),
|
|
39
52
|
};
|
|
40
53
|
});
|
|
41
|
-
const
|
|
54
|
+
const width = 2 * padding + columns * cellSize + (columns - 1) * gutter;
|
|
55
|
+
const height = 2 * padding + rows * cellSize + (rows - 1) * gutter;
|
|
56
|
+
const canvas = blankCanvas(width, height, background).composite(layers);
|
|
42
57
|
return encode(canvas, format, quality);
|
|
43
58
|
}
|
|
44
59
|
/**
|