@visualizevalue/img-grid 0.1.2 → 0.1.3
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 +4 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +8 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,6 +30,8 @@ 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', // Background and letterbox color
|
|
34
|
+
pixelated: true, // Nearest-neighbour resize — keeps pixel art crisp
|
|
33
35
|
format: 'webp', // Output as png (default), jpeg, or webp
|
|
34
36
|
quality: 80, // Quality for jpeg/webp
|
|
35
37
|
onError: (img, err) => console.warn(`failed: ${img.url}`, err),
|
|
@@ -43,6 +45,7 @@ writeFileSync('grid.png', buffer)
|
|
|
43
45
|
|
|
44
46
|
- Packs images into a compact, near-square grid
|
|
45
47
|
- Supports highlighting specific images (makes them 2×2)
|
|
48
|
+
- Optional nearest-neighbour scaling to keep pixel art crisp (`pixelated`)
|
|
46
49
|
- Downloads images concurrently (with a configurable limit)
|
|
47
50
|
- Leaves a blank cell for failed downloads instead of failing the grid
|
|
48
51
|
- Output as PNG, JPEG, or WebP
|
|
@@ -56,6 +59,7 @@ writeFileSync('grid.png', buffer)
|
|
|
56
59
|
| `maxWidth` | `1920` | Maximum width of output image in pixels |
|
|
57
60
|
| `concurrency` | `10` | Maximum concurrent image downloads |
|
|
58
61
|
| `background` | `'#000'` | Background and letterbox color (any sharp color) |
|
|
62
|
+
| `pixelated` | `false` | Nearest-neighbour resize; keeps pixel art crisp |
|
|
59
63
|
| `format` | `'png'` | Output format: `'png'`, `'jpeg'`, or `'webp'` |
|
|
60
64
|
| `quality` | sharp's | Quality (1–100) for `jpeg`/`webp`; ignored for png |
|
|
61
65
|
| `onError` | `undefined` | `(img, error) => void` called when an image fails |
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,12 @@ export interface GridOptions {
|
|
|
12
12
|
concurrency?: number;
|
|
13
13
|
/** Background and letterbox color (any sharp-compatible color). */
|
|
14
14
|
background?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Resize with nearest-neighbour instead of the default smooth (lanczos)
|
|
17
|
+
* kernel. Keeps pixel art (e.g. NFTs) crisp instead of blurring it when
|
|
18
|
+
* scaled up. Like CSS `image-rendering: pixelated`.
|
|
19
|
+
*/
|
|
20
|
+
pixelated?: boolean;
|
|
15
21
|
/** Output image format. */
|
|
16
22
|
format?: ImageFormat;
|
|
17
23
|
/** Quality (1–100) for lossy formats (`jpeg`, `webp`); ignored for `png`. */
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ const HIGHLIGHT_SPAN = 2;
|
|
|
19
19
|
* `onError`) instead of failing the whole grid.
|
|
20
20
|
*/
|
|
21
21
|
async function grid(images, opts = {}) {
|
|
22
|
-
const { highlight = [], maxWidth = DEFAULT_MAX_WIDTH, concurrency = DEFAULT_CONCURRENCY, background = DEFAULT_BACKGROUND, format = DEFAULT_FORMAT, quality, onError, } = opts;
|
|
22
|
+
const { highlight = [], maxWidth = DEFAULT_MAX_WIDTH, concurrency = DEFAULT_CONCURRENCY, background = DEFAULT_BACKGROUND, pixelated = false, format = DEFAULT_FORMAT, quality, onError, } = opts;
|
|
23
23
|
const highlightIds = new Set(highlight);
|
|
24
24
|
const isHighlighted = (img) => img.id !== undefined && highlightIds.has(img.id);
|
|
25
25
|
const highlighted = images.filter(isHighlighted);
|
|
@@ -31,7 +31,7 @@ async function grid(images, opts = {}) {
|
|
|
31
31
|
const cellSize = Math.max(1, Math.floor(maxWidth / columns));
|
|
32
32
|
const layers = await mapWithConcurrency(placements, concurrency, async (placement) => {
|
|
33
33
|
const size = cellSize * placement.span;
|
|
34
|
-
const cell = await renderCell(placement.img, size, background, onError);
|
|
34
|
+
const cell = await renderCell(placement.img, size, background, pixelated, onError);
|
|
35
35
|
return {
|
|
36
36
|
input: cell,
|
|
37
37
|
left: placement.col * cellSize,
|
|
@@ -117,7 +117,7 @@ function pack(highlighted, normal, columns) {
|
|
|
117
117
|
return { placements, rows: occupied.length };
|
|
118
118
|
}
|
|
119
119
|
/** Fetch and resize a single image; fall back to a blank cell on any failure. */
|
|
120
|
-
async function renderCell(img, size, background, onError) {
|
|
120
|
+
async function renderCell(img, size, background, pixelated, onError) {
|
|
121
121
|
try {
|
|
122
122
|
const response = await fetch(img.url, {
|
|
123
123
|
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
@@ -127,7 +127,11 @@ async function renderCell(img, size, background, onError) {
|
|
|
127
127
|
throw new Error(`HTTP ${response.status} for ${img.url}`);
|
|
128
128
|
const data = Buffer.from(await response.arrayBuffer());
|
|
129
129
|
return await (0, sharp_1.default)(data)
|
|
130
|
-
.resize(size, size, {
|
|
130
|
+
.resize(size, size, {
|
|
131
|
+
fit: 'contain',
|
|
132
|
+
background,
|
|
133
|
+
...(pixelated ? { kernel: 'nearest' } : {}),
|
|
134
|
+
})
|
|
131
135
|
.png()
|
|
132
136
|
.toBuffer();
|
|
133
137
|
}
|