Test/node_modules/pica/lib/tiler.js
2026-04-09 22:54:00 +07:00

95 lines
2.8 KiB
JavaScript

// Split original image into multiple 1024x1024 chunks to reduce memory usage
// (images have to be unpacked into typed arrays for resizing) and allow
// parallel processing of multiple tiles at a time.
//
'use strict';
/*
* pixelFloor and pixelCeil are modified versions of Math.floor and Math.ceil
* functions which take into account floating point arithmetic errors.
* Those errors can cause undesired increments/decrements of sizes and offsets:
* Math.ceil(36 / (36 / 500)) = 501
* pixelCeil(36 / (36 / 500)) = 500
*/
var PIXEL_EPSILON = 1e-5;
function pixelFloor(x) {
var nearest = Math.round(x);
if (Math.abs(x - nearest) < PIXEL_EPSILON) { return nearest; }
return Math.floor(x);
}
function pixelCeil(x) {
var nearest = Math.round(x);
if (Math.abs(x - nearest) < PIXEL_EPSILON) { return nearest; }
return Math.ceil(x);
}
module.exports = function createRegions(options) {
var scaleX = options.toWidth / options.width;
var scaleY = options.toHeight / options.height;
var innerTileWidth = pixelFloor(options.srcTileSize * scaleX) - 2 * options.destTileBorder;
var innerTileHeight = pixelFloor(options.srcTileSize * scaleY) - 2 * options.destTileBorder;
// prevent infinite loop, this should never happen
if (innerTileWidth < 1 || innerTileHeight < 1) {
throw new Error('Internal error in pica: target tile width/height is too small.');
}
var x, y;
var innerX, innerY, toTileWidth, toTileHeight;
var tiles = [];
var tile;
// we go top-to-down instead of left-to-right to make image displayed from top to
// doesn in the browser
for (innerY = 0; innerY < options.toHeight; innerY += innerTileHeight) {
for (innerX = 0; innerX < options.toWidth; innerX += innerTileWidth) {
x = innerX - options.destTileBorder;
if (x < 0) { x = 0; }
toTileWidth = innerX + innerTileWidth + options.destTileBorder - x;
if (x + toTileWidth >= options.toWidth) {
toTileWidth = options.toWidth - x;
}
y = innerY - options.destTileBorder;
if (y < 0) { y = 0; }
toTileHeight = innerY + innerTileHeight + options.destTileBorder - y;
if (y + toTileHeight >= options.toHeight) {
toTileHeight = options.toHeight - y;
}
tile = {
toX: x,
toY: y,
toWidth: toTileWidth,
toHeight: toTileHeight,
toInnerX: innerX,
toInnerY: innerY,
toInnerWidth: innerTileWidth,
toInnerHeight: innerTileHeight,
offsetX: x / scaleX - pixelFloor(x / scaleX),
offsetY: y / scaleY - pixelFloor(y / scaleY),
scaleX: scaleX,
scaleY: scaleY,
x: pixelFloor(x / scaleX),
y: pixelFloor(y / scaleY),
width: pixelCeil(toTileWidth / scaleX),
height: pixelCeil(toTileHeight / scaleY)
};
tiles.push(tile);
}
}
return tiles;
};