Last active
September 12, 2016 19:49
-
-
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)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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