|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- import yargs from 'yargs';
- import { hideBin } from 'yargs/helpers';
- import { project, ProjectBounds } from '@theoryofnekomata/orbis-core';
- import { writeFile } from 'fs/promises';
- import { basename, dirname, resolve } from 'path';
-
- type ProjectArgs = {
- input: string,
- projection: string,
- output?: string,
- bounds: ProjectBounds,
- width?: number,
- height?: number,
- padding: [number, number],
- country?: string,
- };
-
- const coerceNumber = (n?: string) => {
- if (typeof n === 'undefined') {
- return undefined;
- }
- const tryWidth = Number(n);
- if (Number.isFinite(tryWidth)) {
- return tryWidth;
- }
- return undefined;
- };
-
- const coercePadding = (n?: string) => {
- if (typeof n !== 'string') {
- return [0, 0];
- }
- const [paddingXString = '0', paddingYString = paddingXString] = n.split(';');
- return [
- Number(paddingXString),
- Number(paddingYString),
- ];
- };
-
- const coerceBounds = (n?: string): ProjectBounds => {
- if (typeof n !== 'string') {
- return {
- type: 'geojson',
- value: {
- type: 'Sphere',
- },
- };
- }
-
- const [boundsType, etcBounds] = n.split(':');
-
- if (boundsType === 'geojson') {
- const [geometryType, etcArgs] = etcBounds.split(';');
-
- if (geometryType === 'Sphere') {
- return {
- type: boundsType,
- value: {
- type: geometryType,
- },
- };
- }
-
- if (geometryType === 'Polygon' || geometryType === 'MultiPolygon') {
- return {
- type: boundsType,
- value: {
- type: geometryType,
- coordinates: JSON.parse(etcArgs),
- },
- };
- }
-
- return {
- type: 'geojson',
- value: {
- type: 'Sphere',
- },
- };
- }
-
- if (boundsType === 'country') {
- const [country] = etcBounds.split(';');
- return {
- type: boundsType,
- value: country,
- };
- }
-
- return {
- type: 'geojson',
- value: {
- type: 'Sphere',
- },
- };
- };
-
- const main = async (argv: string | readonly string[]) => {
- await yargs
- .option('interactive', {
- alias: 'i',
- })
- .command({
- command: 'project <input> <projection>',
- aliases: 'p',
- describe: 'Project an equirectangular PNG image to another projection.',
- builder: (y) => y
- .option('output', {
- alias: 'o',
- })
- .coerce('output', (output) => {
- if (!output) {
- return null;
- }
- if (typeof output !== 'string') {
- return null;
- }
- return output;
- })
- .option('width', {
- alias: 'w',
- })
- .coerce('width', coerceNumber)
- .option('height', {
- alias: 'h',
- })
- .coerce('height', coerceNumber)
- .option('padding', {
- alias: 'p',
- default: '0;0',
- })
- .coerce('padding', coercePadding)
- .option('bounds', {
- alias: 'b',
- default: 'geojson:Sphere',
- })
- .option('country', {
- alias: 'c',
- })
- .coerce('bounds', coerceBounds),
- handler: async (projectArgvRaw) => {
- const projectArgv = projectArgvRaw as unknown as ProjectArgs;
- const outputPng = await project(projectArgv.input, [projectArgv.projection], {
- bounds: projectArgv.bounds,
- wrapAround: false,
- outputSize: {
- width: projectArgv.width,
- height: projectArgv.height,
- },
- outputPadding: {
- x: projectArgv.padding[0],
- y: projectArgv.padding[1],
- },
- });
- if (!outputPng) {
- process.stdout.write('No output created.\n');
- return;
- }
- const outputFilename = projectArgv.output ?? `${basename(projectArgv.input, '.png')}.out.png`;
- const outputPath = resolve(
- dirname(projectArgv.input),
- outputFilename.endsWith('.png') ? outputFilename : `${outputFilename}.png`,
- );
- await writeFile(outputPath, outputPng);
- process.stdout.write(`Created output file: ${outputPath}\n`);
- },
- })
- .demandCommand(1, 'Please specify a command')
- .help()
- .parse(
- hideBin((Array.isArray(argv) ? argv : [argv]) as string[]),
- );
- };
-
- void main(process.argv);
|