heightmap-rgb-gen
Version:
Map generator from heightmap (comma separated numbers file). It process a heightmap as input and generates a png with a graduated color scale (customizable through the arguments)
103 lines (81 loc) • 3.46 kB
JavaScript
const path = require('path');
const fs = require('fs'),
PNG = require('pngjs').PNG;
const colorGradient = require("javascript-color-gradient");
console.log('order arguments: inputFile width height fromColor toColor midPoints outputFile verbose');
const args = process.argv.slice(2);
console.log('arguments passed:', args);
const procPath = process.cwd();
const inputFile = args[0] ? args[0] : 'heightmap';
let width = args[1];
let height = args[2];
const fromColor = args[3] ? args[3] : '#3F2CAF';
const toColor = args[4] ? args[4] : '#e9446a';
const midPoints = args[5] ? args[5] : 10;
const outputFile = args[6] ? args[6] : inputFile + '.png';
const verbose = args[7] ? args[7] : false;
// default alpha channel
const alphaChannelDefault = 'FF';
// files
const inputPath = path.join(procPath, inputFile);
const outputPath = path.join(procPath, outputFile);
if(!fs.existsSync(inputPath)) throw new Error(`input file ${inputPath} not found`);
// read heightmap
var buffer = fs.readFileSync(inputPath);
const heightmap = buffer.toString().split(',').map(x => Number(x));
// default width and height
const [min, max] = getMinMaxFromHeightmap(heightmap);
if(width == undefined || height == undefined) {
width = Math.floor(Math.sqrt(heightmap.length));
height = Math.floor(heightmap.length / width);
}
console.info(
`\tinputPath: ${inputPath}
\twidth: ${width}
\theight: ${height}
\tfromColor: ${fromColor}
\ttoColor: ${toColor}
\tmidPoints: ${midPoints}
\toutputPath: ${outputPath}
\tverbose: ${verbose}`);
if(!(heightmap.length > 0)) throw new Error('heightmap error');
if(width * height != heightmap.length) throw new Error(`heightmap size error: width: ${width} height: ${height} heightmap: ${heightmap.length}`);
var png = new PNG({
width: width,
height: height,
filterType: -1
});
for (var i = 0; i < png.height; i++) {
for (var j = 0; j < png.width; j++) {
var idx = (png.width * i + j) << 2;
const value = heightmap[i*width+j];
const color = mapColor(value, min, max, fromColor, toColor, midPoints);
if(verbose) console.log(`i: ${i} j: ${j} idx: ${idx} valueIn: ${value} index: ${color}`);
png.data.write(color.substring(1,3), idx, 'hex');
png.data.write(color.substring(3,5), idx+1, 'hex');
png.data.write(color.substring(5,7), idx+2, 'hex');
png.data.write(alphaChannelDefault, idx+3, 'hex');
}
}
png.pack().pipe(fs.createWriteStream(outputPath));
if(verbose) console.log(`successfully created heightmap ${outputPath}`);
// external functions -----------------------------
function mapRange(valueIn, min1, max1, min2, max2){
const tot1 = Math.abs(min1 - max1);
const delta1 = Math.abs(valueIn - min1)
const ratio1 = delta1 / tot1;
const tot2 = Math.abs(max2 - min2);
const valueOut = tot2 * ratio1;
return Math.floor(valueOut);
};
function mapColor(valueIn, min, max, fromColor, toColor, midPoints){
const gradientArray = colorGradient.setGradient(fromColor, toColor).setMidpoint(midPoints).getArray();
const index = mapRange(valueIn, min, max, 1, gradientArray.length);
return gradientArray[index];
}
function getMinMaxFromHeightmap(heightmap){
const max = Math.max(...heightmap);
const min = Math.min(...heightmap);
return [min, max];
}