Skip to content

Instantly share code, notes, and snippets.

@kadamwhite
Last active September 12, 2016 19:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kadamwhite/9271ef31debc25bb35e30cdde471bfed to your computer and use it in GitHub Desktop.
Save kadamwhite/9271ef31debc25bb35e30cdde471bfed to your computer and use it in GitHub Desktop.
Take an input image, break it into tiles, then recompose the tiles into a new image (requires "convert" from image magick)
var spawn = require( 'child_process' ).spawn;
var exec = require( 'child_process' ).exec;
var path = require( 'path' );
var fs = require( 'fs' );
/**
* Get the list of files in a directory, either as a list of file and subdir
* names or a list of absolute file system paths
*
* @private
* @param {string} inputDir The file system path to the directory to read
* @returns {Promise} A promise to the string array of file names
*/
const ls = ( inputDir, absolute ) => {
return new Promise( ( resolve, reject ) => {
fs.readdir( inputDir, ( err, list ) => {
if ( err ) {
return reject( err );
}
resolve( list );
});
});
};
/**
* Execute a shell command and return a promise that will resolve or exit
* when that command completes
*
* @param {string} command A shell command string e.g. "mv file1 file2"
* @param {boolean} quiet Whether to suppress outputting the command to be run
* @returns {Promise} A promise that completes when the command finishes
*/
const execCommand = ( command, quiet ) => {
return new Promise( ( resolve, reject ) => {
!quiet && console.log( command );
exec( command, ( error, stdout, stderr ) => {
if ( error ) {
return reject( error );
}
resolve();
});
});
}
const execRegardless = command => {
return execCommand( command ).catch( err => console.log( err ) );
}
/**
* Helper function that takes in an array of functions that return promises,
* then executes those functions sequentially to execute each action
*
* @param {function[]} arrOfFnsReturningPromises An array of functions
* @returns {Promise} A promise that will resolve once all the promises
* returned by that function successfully complete
*/
const runInSequence = arrOfFnsReturningPromises => {
return arrOfFnsReturningPromises.reduce(
( lastStep, startNextStep ) => lastStep.then( startNextStep ),
Promise.resolve()
);
};
const inputFile = path.join( __dirname, 'algorithm14.tif' );
// Tile output directory and helper method
const tilesDir = path.join( __dirname, 'tiles' );
const tile = filename => `${tilesDir}/${filename}`;
// Final output directory and helper method
const outputDir = path.join( __dirname, 'output' );
const output = filename => `${outputDir}/${filename}`;
const pattern = 'tiles_%d.png';
// Empty & recreate the tiles & final output directories
Promise.all([
execCommand( `rm -rf ${outputDir}` ).then( () => execCommand( `mkdir ${outputDir}` ) ),
execCommand( `rm -rf ${tilesDir}` ).then( () => execCommand( `mkdir ${tilesDir}` ) )
])
// Run our imagemagick command to tile the image
.then( () => execCommand( `convert ${inputFile} +gravity -crop 320x320 ${tile(pattern)}` ) )
// Figure out how many tiles were created to deduce the range for our -layers command input
.then( () => ls( tilesDir ) )
.then( files => {
// files will have format "tiles_0.png" through "tiles_nnn.png"
const range = `[0-${files.length-1}]`;
// Reassemble the image
return execCommand( `convert ${tile(pattern + range)} -background none -layers merge ${output('output.png')}` );
})
.catch( err => console.error( err ) );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment