image-tiler
Version:
Create zoom tile pyramids from a large image
78 lines (73 loc) • 3.44 kB
JavaScript
;
var execFileSync = require('child_process').execFileSync;
var sizeOf = require('image-size');
var mkdirp = require('mkdirp-promise');
var rimraf = require('rimraf-then');
var fs = require('fs');
var path = require('path');
function tileLevel(inPath, outPath, zoom, tileSize, pattern, quality) {
var dotExtension = pattern.replace(/.*(\.[^.]+)$/, '$1');
var patternedFilename = pattern.replace(/\{z\}/, '' + zoom)
.replace(/\{x\}/, '%[fx:page.x/' + tileSize + ']')
.replace(/\{y\}/, '%[fx:page.y/' + tileSize + ']')
.replace(/\.[^.]+$/, '');
var patternedFilenameWithoutTheFilename = '';
if (pattern.indexOf(path.sep) > 0) {
patternedFilenameWithoutTheFilename = pattern.replace(new RegExp(path.sep + '[^' + path.sep + ']*$'), '')
.replace(/\{z\}/, '' + zoom);
}
return mkdirp(outPath + path.sep + patternedFilenameWithoutTheFilename)
.then(() => {
var args = [inPath,
'-crop', tileSize + 'x' + tileSize,
'-set', 'filename:tile', patternedFilename,
'-quality', quality, '+repage', '+adjoin',
outPath + '/%[filename:tile]' + dotExtension];
execFileSync('convert', args);
});
}
function imageBiggerThanTile(path, tileSize) {
var size = sizeOf(path);
return size.height > tileSize || size.width > tileSize;
}
function tileRec(inPath, outPath, zoom, tileSize, tempDir, pattern, zoomToDisplay, invertZoom, quality) {
var inPathMpc = tempDir + '/temp_level_' + zoom + '.mpc';
var inPathCache = tempDir + '/temp_level_' + zoom + '.cache';
execFileSync('convert', [inPath, inPathMpc]);
return tileLevel(inPathMpc, outPath, zoomToDisplay, tileSize, pattern, quality)
.then(function () {
if (imageBiggerThanTile(inPath, tileSize)) {
var newZoom = zoom + 1;
var newZoomToDisplay = zoomToDisplay + 1;
if (!invertZoom) {
newZoomToDisplay = zoomToDisplay - 1;
}
var newInPath = tempDir + '/temp_level_' + zoom + '.png';
execFileSync('convert', [inPathMpc, '-resize', '50%', '-quality', quality, newInPath]);
fs.unlinkSync(inPathMpc);
fs.unlinkSync(inPathCache);
return tileRec(newInPath, outPath, newZoom, tileSize, tempDir, pattern, newZoomToDisplay, invertZoom, quality);
} else {
fs.unlinkSync(inPathMpc);
fs.unlinkSync(inPathCache);
}
});
}
module.exports.tile = function (inPath, outPath, pattern, options) {
options = options || {};
var tileSize = options.tileSize || 256;
var tmpDir = options.tmpDir || process.env.TMPDIR || '/tmp';
var tempDir = tmpDir + '/image-tiler_' + process.pid;
var zoom = 0;
var zoomToDisplay = 0;
var quality = options.quality || 100;
if (!options.invertZoom) {
var size = sizeOf(inPath);
var halvingsWidth = Math.ceil(Math.log2(Math.ceil(size.width / tileSize)));
var halvingsheight = Math.ceil(Math.log2(Math.ceil(size.height / tileSize)));
zoomToDisplay = Math.max(halvingsWidth, halvingsheight);
}
return mkdirp(tempDir)
.then(() => tileRec(inPath, outPath, zoom, tileSize, tempDir, pattern, zoomToDisplay, options.invertZoom, quality))
.then(() => rimraf(tempDir));
};