Skip to content

Instantly share code, notes, and snippets.

@josephrocca
Last active November 5, 2023 16:06
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save josephrocca/b4d0a13b0e679f85506d46c33c5481f5 to your computer and use it in GitHub Desktop.
Save josephrocca/b4d0a13b0e679f85506d46c33c5481f5 to your computer and use it in GitHub Desktop.
Generate map tiles from a large image with nodejs
// Given a large input image, this script generates map tiles of 256*256px
// at power-of-2 zoom levels. It's not super efficient or anything, just a
// quickly hacked together script.
//Use the tiles in leaflet.js like this:
/*
<div id='map' style='height:100%;'></div>
<script>
var map = L.map('map', {
attributionControl: false
}).setView([0, 0], 1);
var layer_url = './images/{z}-{x}-{y}.png';
L.tileLayer(layer_url, {
maxZoom: 20, // <-- change to suit
noWrap: true
}).addTo(map);
</script>
*/
// Instructions:
// 1. create a new directory
// 2. run `npm init -y`
// 3. run `npm install sharp --save`
// 4. copy your image into the directory and call it `input.png`
// 5. make a folder called `output`
// 6. run this script with `node generate.js`
(async function() {
let input = 'input.png'; // <-- this is your input image
let sharp = require('sharp');
let metadata = await sharp(input).metadata();
let fullPixelSize = Math.max(metadata.width, metadata.height);
await sharp(input)
.resize(fullPixelSize, fullPixelSize)
.background({r: 0, g: 0, b: 0, alpha: 0})
.embed()
.toFile("squarified.png");
console.log("squarified ✓");
//sharp.cache(false);
let zoom = 0;
while(true) {
// double size for each consecutive zoom level, starting at 256px:
let pixelSize = 256 * 2**zoom;
if(pixelSize > fullPixelSize) {
zoom--;
break;
}
console.log(`Processing zoom level ${zoom}...`);
await sharp("squarified.png")
.resize(pixelSize, pixelSize)
.toFile(`resized-${zoom}.png`);
let rows = 2**zoom;
let cols = 2**zoom;
for(let row = 0; row < rows; row++) {
for(let col = 0; col < cols; col++) {
await sharp(`resized-${zoom}.png`)
.extract({ left: col*256, top: row*256, width: 256, height: 256 })
.toFile(`./output/${zoom}-${col}-${row}.png`);
}
}
zoom++;
}
if(zoom < 0) {
console.error(`Seems that you've input an image that's less than 256 pixels`);
} else {
console.log(`Finished at zoom=${zoom}`);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment