When a large image is processed in tiles, a job can return the expected number of files even though one grid cell is missing and another appears twice. A manifest check can catch that handoff error before you allocate the output canvas or start stitching.
This Node.js example checks a regular, nonoverlapping grid. It verifies that each cell appears once and that its placement and dimensions match the canvas.
1. Define the placement coordinates
Use zero-based rows and columns with the origin at the top left of the output canvas. Each tile entry gives the destination x and y and the width and height of the usable tile region in pixels.
If a processing step adds padding around tiles, trim that padding before recording the usable bounds. A pipeline that intentionally blends overlapping tiles needs a separate contract for overlap and placement.
2. Build a fixture with clipped edges
Save the following synthetic manifest as grid.json. The canvas is 2,300 by 1,300 pixels and the nominal tile is 1,200 by 800 pixels.
{
"width": 2300,
"height": 1300,
"tileWidth": 1200,
"tileHeight": 800,
"tiles": [
{
"row": 0,
"column": 0,
"x": 0,
"y": 0,
"width": 1200,
"height": 800
},
{
"row": 0,
"column": 1,
"x": 1200,
"y": 0,
"width": 1100,
"height": 800
},
{
"row": 1,
"column": 0,
"x": 0,
"y": 800,
"width": 1200,
"height": 500
},
{
"row": 1,
"column": 1,
"x": 1200,
"y": 800,
"width": 1100,
"height": 500
}
]
}
Columns and rows round up from the canvas size divided by the nominal tile size. The final column is 1,100 pixels wide and the final row is 500 pixels high. Their intersection is a 1,100 by 500 pixel corner tile.
3. Check each cell and then look for gaps
Compute the expected x and y from the column and row. Clip the tile size against the remaining canvas extent. A tile shifted left by one pixel fails the bounds check even if its width and height look right.
Track occupied cells by row and column. Report repeated cells, out-of-grid entries, and any missing cells. Here an incorrect bounds entry still occupies its declared cell so the report can distinguish a placement error from an absent entry.
4. Implement the validator
Save this as tile-grid.mjs and run it with Node.js 24.20.0. The example bounds each integer input to at most one million and the grid to 10,000 cells. The number check also rejects strings and fractions. ECMAScript Number.isSafeInteger specification.
import { readFileSync } from "node:fs";
function integer(value, field, minimum = 0) {
if (!Number.isSafeInteger(value) || value < minimum || value > 1_000_000) {
throw new Error(field + " must be an integer from " + minimum + " to 1000000");
}
return value;
}
export function checkGrid(manifest) {
const width = integer(manifest?.width, "width", 1);
const height = integer(manifest?.height, "height", 1);
const tileWidth = integer(manifest?.tileWidth, "tileWidth", 1);
const tileHeight = integer(manifest?.tileHeight, "tileHeight", 1);
const columns = Math.ceil(width / tileWidth);
const rows = Math.ceil(height / tileHeight);
if (columns * rows > 10_000) throw new Error("grid exceeds 10000 cells");
if (!Array.isArray(manifest.tiles)) throw new Error("tiles must be an array");
const seen = new Set();
const issues = [];
for (const [index, tile] of manifest.tiles.entries()) {
const row = integer(tile?.row, "row");
const column = integer(tile?.column, "column");
const actual = {
x: integer(tile?.x, "x"),
y: integer(tile?.y, "y"),
width: integer(tile?.width, "tile width", 1),
height: integer(tile?.height, "tile height", 1),
};
if (row >= rows || column >= columns) {
issues.push({ kind: "outside-grid", index, row, column });
continue;
}
const key = row * columns + column;
if (seen.has(key)) issues.push({ kind: "duplicate", index, row, column });
seen.add(key);
const x = column * tileWidth;
const y = row * tileHeight;
const expected = {
x, y,
width: Math.min(tileWidth, width - x),
height: Math.min(tileHeight, height - y),
};
if (Object.keys(expected).some((field) => expected[field] !== actual[field])) {
issues.push({ kind: "bounds", index, row, column, expected, actual });
}
}
for (let row = 0; row < rows; row += 1) {
for (let column = 0; column < columns; column += 1) {
if (!seen.has(row * columns + column)) {
issues.push({ kind: "missing", row, column });
}
}
}
return { ok: issues.length === 0, rows, columns, issues };
}
if (import.meta.main) {
try {
if (process.argv.length !== 3) throw new Error("Usage: node tile-grid.mjs grid.json");
const manifest = JSON.parse(readFileSync(process.argv[2], "utf8"));
const report = checkGrid(manifest);
console.log(JSON.stringify(report, null, 2));
process.exitCode = report.ok ? 0 : 1;
} catch (error) {
console.error(error.message);
process.exitCode = 2;
}
}
The validator accepts tile entries in any order. The index in an issue points to the zero-based position in the input array. A missing cell has no input index.
5. Test a complete grid and a duplicate
Copy grid.json to broken.json and replace the last tile with a copy of the first. The file still has four entries, but the first cell repeats and the corner is absent.
node tile-grid.mjs grid.json
node tile-grid.mjs broken.json
node tile-grid.mjs
The complete fixture exits 0. The broken fixture exits 1 and produces this report. The third command exits 2 because it has no input path.
{
"ok": false,
"rows": 2,
"columns": 2,
"issues": [
{
"kind": "duplicate",
"index": 3,
"row": 0,
"column": 0
},
{
"kind": "missing",
"row": 1,
"column": 1
}
]
}
6. Use the report before assembling pixels
Pass the manifest to the stitcher only after validation succeeds. For an actual render, obtain the usable dimensions from trusted metadata or from the decoder and compare them with each recorded tile. Keep the original file or asset ID beside each manifest row for that follow-up.
This check verifies placement geometry. Image decoding, edge appearance, and whether a worker returned the right image content belong to the subsequent inspection.
AI-assisted writing and code drafting. Tests used synthetic JSON and integer coordinates on Node.js 24.20.0. No image was generated, decoded, tiled, or stitched.
This independent post-processing example follows the large-image workflow discussed in the PixMind source. Nano Banana Pro complete guide.
About the author
- The PixMind team shares practical AI image and video workflows. PixMind brings text-to-image, reference-based creation, editing, and video tools into one workspace. Website: https://www.pixmind.io/
Comments
Join the discussionNo comments yet. Be the first to comment.